CSC/ECE 517 Spring 2022 - E2202- Testing for badges controller, publishing controller

From Expertiza_Wiki
Jump to navigation Jump to search

About Expertiza

Expertiza is the software benefits for both instructors and students by supporting various types of submissions and providing reusable objects for peer review. It is an open-source project based on Ruby on Rails framework. It allows the instructors not only to create and customize new or existing assignments but also to create a list of topics the students can sign up for. Students can form teams to work on various projects and assignments. Expertiza also lets students peer-review other students' submissions, enabling them to work together to improve others' learning experiences.

Description about project

This page is a description of Expertiza OSS project E2202 which is adding test cases for badges_controller.rb and publishing_controller.rb. The badges controller allows users to create badges by entering the badge name, description and an image that serves as the badge icon. The publishing controller enables the students to grant/revoke publishing rights to past assignments. It does this by either allowing the students to grant and deny rights individually or all of them together. It makes use of the private key to verify the digital signature of the user granting the rights.

Files Involved

badges_controller.rb

badges_controller_spec.rb

publishing_controller.rb

publishing_controller_spec.rb

Running Tests


rspec spec/controllers/publishing_controller_spec.rb spec/controllers/badges_controller_spec.rb

  • If you're having any difficulty in running the tests, please drop an email to sbose2@ncsu.edu, apatil25@ncsu.edu or kkhulla@ncsu.edu.

Test Plan

After setting up the development environment, we ran the original test cases for the badges_controller. However the test cases were very limited and only partially covered one of the methods. We wrote additional test cases to cover all the 5 methods badges controller and expanded the existing test case. For the publishing_controller no tests were available so we had to write every test from scratch. We have written tests to cover all the 6 methods in the publishing_controller. In total we wrote 27 test cases for both the controllers. We used object mocking for creating the unit test cases.

Badges Controller Methods

The methods in the controller are:

  • action_allowed?
  • new
  • redirect_to_assignment
  • create
  • badge_params

Publishing Controller Methods

The methods in the controller are:

  • action_allowed?
  • view
  • set_publish_permission
  • update_publish_permissions
  • grant
  • grant_with_private_key

Test Frame for Badges Controller

1. action_allowed? - When user tries to access the badges this method is called to check if the current user is authorized to view this page. All the users except the user with student privileges has access to perform actions in badges.

Code snippet:

 describe '#action_allowed?' do
    it 'allows super_admin to perform certain action' do
      stub_current_user(super_admin, super_admin.role.name, super_admin.role)
      expect(controller.send(:action_allowed?)).to be_truthy
    end
  
    it 'allows instructor to perform certain action' do
      stub_current_user(instructor1, instructor1.role.name, instructor1.role)
      expect(controller.send(:action_allowed?)).to be_truthy
    end
  
    it 'refuses student from performing certain action' do
      stub_current_user(student1, student1.role.name, student1.role)
      expect(controller.send(:action_allowed?)).to be_falsey
    end
  
    it 'allows teaching assisstant to perform certain action' do
      stub_current_user(ta, ta.role.name, ta.role)
      expect(controller.send(:action_allowed?)).to be_truthy
    end
  
    it 'allows admin to perform certain action' do
      stub_current_user(admin, admin.role.name, admin.role)
      expect(controller.send(:action_allowed?)).to be_truthy
    end    
  end

2. New - When user tries to create a new badge it redirects to the new create badge page and allow the user to enter details for the badge creation.

Code snippet:

 describe '#new' do
    context 'when user wants to create a new badge' do
      it 'should call the new#badge page url' do
        get :new
        expect(get: 'badges/new').to route_to('badges#new')
      end

      it 'should render the create new form and allow the user to enter details' do
        allow(Badge).to receive(:new).and_return(badge)
        params = {}
        session = { user: instructor1 }
        get :new, params, session
        expect(response).to render_template('new')
      end
    end
  end

3. redirect_to_assignment - When the user has successfully created a badge it redirects to the assignment page.

Code Snippet:

 describe 'redirect_to_assignment' do
    context 'after user successfully creates a badge' do
      it 'calls the redirect_to_assignment url' do
        session[:return_to] ||= 'http://test.host/assignments/844/edit'
        get :redirect_to_assignment
        expect(get: 'badges/redirect_to_assignment').to route_to('badges#redirect_to_assignment')
      end
    
      it 'redirects to the assignment page' do
        stub_current_user(ta, ta.role.name, ta.role)
        session[:return_to] ||= 'http://test.host/assignments/844/edit'
        get :redirect_to_assignment
        response.should redirect_to("http://test.host/assignments/844/edit")
      end
    end
  end

4. create - When the user tries to create a badge by entering all the required details, it saves the badge. If there are any missing required details for badge creation it throws an error for missing fields.

Code Snippet:

 describe '#create' do
    context 'when user enters all the required badge details correctly' do
        it 'should save the badge successfully' do
        @file = fixture_file_upload('app/assets/images/badges/test.png', 'image/png')
        allow(@file).to receive(:original_filename).and_return("test.png")
        session = { user: instructor1 }
        params = {
          badge:{
            name: 'test',
            description: 'test badge',
            image_name: 'test.png',
          image_file: @file
          }
        }
        session[:return_to] ||= 'http://test.host/assignments/844/edit'
        allow(Badge).to receive(:get_id_from_name).with('test').and_return(badge)
        allow(Badge).to receive(:get_image_name_from_name).with('test').and_return(badge)
        post :create, params, session, "file" => @file
        expect(response).to redirect_to 'http://test.host/assignments/844/edit'
      end
    end

    context 'when user forgets to enter few of the required badge details' do
      it 'should throw an error for missing image file' do
        @file = nil
        session = { user: instructor1 }
        params = {
          badge:{
            name: 'test',
            description: 'test badge',
            image_name: 'test.png',
          image_file: @file
          }
        }
        session[:return_to] ||= 'http://test.host/assignments/844/edit'
        allow(Badge).to receive(:get_id_from_name).with('test').and_return(badge)
        allow(Badge).to receive(:get_image_name_from_name).with('test').and_return(badge)
        post :create, params, session, "file" => @file
        expect(response).to render_template('new')
      end
    
    
      it 'should throw an error for missing badge name' do
        @file = fixture_file_upload('app/assets/images/badges/test.png', 'image/png')
        allow(@file).to receive(:original_filename).and_return("test.png")
        session = { user: instructor1 }
        params = {
        badge:{
          name: '',
          description: 'test badge',
          image_name: 'test.png',
          image_file: @file
          }
        }
        session[:return_to] ||= 'http://test.host/assignments/844/edit'
        allow(Badge).to receive(:get_id_from_name).with('test').and_return(badge)
        allow(Badge).to receive(:get_image_name_from_name).with('test').and_return(badge)
        post :create, params, session, "file" => @file
        expect(response).to render_template('new')
      end
    
      it 'should throw an error for missing badge description' do
        @file = fixture_file_upload('app/assets/images/badges/test.png', 'image/png')
        allow(@file).to receive(:original_filename).and_return("test.png")
        session = { user: instructor1 }
        params = {
        badge:{
          name: 'test',
          description: '',
          image_name: 'test.png',
          image_file: @file
        }
        }
        session[:return_to] ||= 'http://test.host/assignments/844/edit'
        allow(Badge).to receive(:get_id_from_name).with('test').and_return(badge)
        allow(Badge).to receive(:get_image_name_from_name).with('test').and_return(badge)
        post :create, params, session, "file" => @file
        expect(response).to render_template('new')   
      end
    end
  end

Test Frame for Publishing Controller

1. action_allowed? - When user tries to grant or view publishing rights this method is called to check if the current user is authorized to perform the action. All users with student privileges have access to perform actions for publishing.

Code Snippet:

describe '#action_allowed?' do
    it 'allows super_admin to perform certain action' do
      stub_current_user(super_admin, super_admin.role.name, super_admin.role)
      expect(controller.send(:action_allowed?)).to be_truthy
    end

    it 'allows instructor to perform certain action' do
      stub_current_user(instructor1, instructor1.role.name, instructor1.role)
      expect(controller.send(:action_allowed?)).to be_truthy
    end

    it 'allows student to perform certain action' do
      stub_current_user(student1, student1.role.name, student1.role)
      expect(controller.send(:action_allowed?)).to be_truthy
    end

    it 'allows teaching assisstant to peform certain action' do
      stub_current_user(ta, ta.role.name, ta.role)
      expect(controller.send(:action_allowed?)).to be_truthy
    end

    it 'allows admin to perform certain action' do
      stub_current_user(admin, admin.role.name, admin.role)
      expect(controller.send(:action_allowed?)).to be_truthy
    end
  end

2. view - When user visits the publishing rights page, it displays all past assignment participants.

Code Snippet:

describe 'view' do
    context 'user visits the publishing rights page' do
      it 'displays all the assignment participants' do
          stub_current_user(student1, student1.role.name, student1.role)
          params = { id: 21 }
          get :view, params
          expect(assigns(:user)).to eq(student1)
        end
      end
    end

3. set_publish_permission - When the user matches with the participant and the user clicks on the grant button next to the assignment, it redirects to the grant page. When the user matches with the participant and the assignment is already granted permission, it redirects to the view page.

Code Snippet:

describe 'set_publish_permission' do
    context 'user matches with participant and user clicks on the grant button next to the assignment' do
      it 'redirects to the grant page' do
        allow(AssignmentParticipant).to receive(:find).with('1').and_return(assignment_participant1)
        stub_current_user(student1, student1.role.name, student1.role)
        params ={id: 1, allow: 1}
        post :set_publish_permission, params
        expect(response).to redirect_to(action: :grant)
      end
    end

    context 'user matches with participant and the assignment is already granted permission' do
      it 'redirects to the view page' do
        stub_current_user(student1, student1.role.name, student1.role)
        allow(AssignmentParticipant).to receive(:find).with('1').and_return(assignment_participant1)
        allow(assignment_participant1).to receive(:update_attribute).and_return(true)
        params ={id: 1, allow: '0'}
        post :set_publish_permission, params
        expect(response).to redirect_to(action: :view)
      end
    end
  end

4. update_publish_permissions - When a user clicks on the grant publishing rights to all past assignments button it redirects to the grant page. When a user clicks on the deny publishing rights to all past assignments button it redirects to the view page.

Code Snippet:

describe 'update_publish_permissions' do
    context 'user clicks on the grant publishing rights to all past assignments button' do
      it 'redirects to grant page' do
        allow(AssignmentParticipant).to receive(:find).with('3').and_return(assignment_participant2)
        stub_current_user(student1, student1.role.name, student1.role)
        params ={id: 3, allow: 1}
        post :update_publish_permissions, params
        expect(response).to redirect_to(action: :grant)
      end
    end
      
    context 'user clicks on the deny publishing rights to all past assignments button' do
      it 'redirects to view page' do
          allow(AssignmentParticipant).to receive(:where).with(user_id: 21).and_return([assignment_participant1])
        stub_current_user(student1, student1.role.name, student1.role)
        params ={id: 3, allow: 0}
        [assignment_participant1].each do |participant|
          allow(participant).to receive(:update_attribute).and_return(true)
          allow(participant).to receive(:save).and_return(true)
        end
        post :update_publish_permissions, params
        expect(response).to redirect_to(action: :view)
      end
    end      
  end

5. grant - When a user clicks on the grant publishing option, it displays the page where the user can supply their private key and grant publishing rights.

Code Snippet:

describe 'grant' do
    context 'user clicks on grant option' do
      it 'displays the page where the user can supply their private key and grant publishing rights' do
        allow(AssignmentParticipant).to receive(:find).with('3').and_return(assignment_participant2)
        stub_current_user(student1, student1.role.name, student1.role)
        params ={id: 3}
        get :grant, params
        expect(assigns(:user)).to eq(student1)
      end
    end
  end

6. grant_with_private_key - When a user visits the grant page without id and enters incorrect RSA private key, it throws StandardError, displays notice and redirects to grant page. When a user visits the grant page with id and enters correct RSA private key, it verifies key to be successful for all past assignments and redirects to view page. When a user visits the grant page with id and enters incorrect RSA private key, it throws StandardError, displays notice and redirects to grant.

Code Snippet:

describe 'grant_with_private_key' do

    context 'user visits the grant page without id and enters incorrect RSA private key' do
      it 'displays notice and redirects to grant' do
        allow(AssignmentParticipant).to receive(:where).with(user_id: 21).and_return([assignment_participant1])
        stub_current_user(student1, student1.role.name, student1.role)
        params = {}
        private_key = double(:private_key)
        [assignment_participant1].each do |participant|
          allow(participant).to receive(:verify_digital_signature).with(private_key).and_return(true)
          allow(participant).to receive(:assign_copyright).with(private_key).and_raise('The private key you inputted was invalid.', StandardError)
        end
        post :grant_with_private_key, params
        expect(flash[:notice]).to eq('The private key you inputted was invalid.')
        expect(response).to redirect_to(action: :grant)
      end
    end
      
            
    context 'user visits the grant page with id and enters correct RSA private key' do
      it 'verifies to be successful for all past assignments and redirect to view' do
        allow(AssignmentParticipant).to receive(:find).with('2').and_return(assignment_participant1)
        stub_current_user(student1, student1.role.name, student1.role)
        private_key = OpenSSL::PKey::RSA.new 2048
        params = {id: 2, private_key: private_key}
        [assignment_participant1].each do |participant|
          allow(participant).to receive(:verify_digital_signature).with(any_args).and_return(true)
          allow(participant).to receive(:assign_copyright).with(any_args).and_return(true)
        end
        post :grant_with_private_key, params
        expect(response).to redirect_to(action: :view)
      end
    end 
      
    context 'user visits the grant page with id and enters incorrect RSA private key' do
      it 'displays notice and redirects to grant' do
        allow(AssignmentParticipant).to receive(:find).with('2').and_return(assignment_participant1)
        stub_current_user(student1, student1.role.name, student1.role)
        private_key = OpenSSL::PKey::RSA.new 2048
        params = {id: 2, private_key: private_key}
        [assignment_participant1].each do |participant|
          allow(participant).to receive(:verify_digital_signature).with(any_args).and_return(true)
          allow(participant).to receive(:assign_copyright).with(any_args).and_raise('The private key you inputted was invalid.', StandardError)
        end
        post :grant_with_private_key, params
        expect(flash[:notice]).to eq('The private key you inputted was invalid.')
        expect(response).to redirect_to(action: :grant,params:{id:2})
      end
    end          
  end

Results

The total coverage of the tests is 100%. We covered all the edges cases to ensure maximum coverage.

The screenshot for test coverage can be found here

Related Links

A video of all the tests running can be found here

The pull request can be accessed here

The forked git repository for this project can be found here

Conclusion

We followed a behavior-driven approach to write unit tests for badges_controller and publishing_controller. We considered all edge cases to achieve 100% coverage of both the controllers.