diff --git a/spec/models/registration_spec.rb b/spec/models/registration_spec.rb index 30221eef..29ee38f2 100644 --- a/spec/models/registration_spec.rb +++ b/spec/models/registration_spec.rb @@ -18,29 +18,40 @@ end end - describe '#update_competing_lane!' do - it 'given accepted status, it changes the users status to accepted' do - registration = FactoryBot.create(:registration, registration_status: 'pending') - registration.update_competing_lane!({ status: 'accepted' }) - expect(registration.competing_status).to eq('accepted') - end - - it 'accepted given cancelled, it sets competing_status accordingly' do - registration = FactoryBot.create(:registration, registration_status: 'accepted') - registration.update_competing_lane!({ status: 'cancelled' }) - expect(registration.competing_status).to eq('cancelled') + describe '#update_competing_lane.competing_status' do + allowed_competing_status_updates = [ + { initial_status: 'pending', new_status: 'accepted' }, + { initial_status: 'pending', new_status: 'cancelled' }, + { initial_status: 'pending', new_status: 'waiting_list' }, + { initial_status: 'pending', new_status: 'pending' }, + { initial_status: 'accepted', new_status: 'cancelled' }, + { initial_status: 'accepted', new_status: 'pending' }, + { initial_status: 'accepted', new_status: 'waiting_list' }, + { initial_status: 'accepted', new_status: 'accepted' }, + { initial_status: 'waiting_list', new_status: 'cancelled' }, + { initial_status: 'waiting_list', new_status: 'pending' }, + { initial_status: 'waiting_list', new_status: 'waiting_list' }, + { initial_status: 'waiting_list', new_status: 'accepted' }, + { initial_status: 'cancelled', new_status: 'cancelled' }, + { initial_status: 'cancelled', new_status: 'pending' }, + { initial_status: 'cancelled', new_status: 'waiting_list' }, + { initial_status: 'cancelled', new_status: 'accepted' }, + ] + + it 'tests cover all possible status combinations' do + expect(REGISTRATION_TRANSITIONS).to match_array(allowed_competing_status_updates) end - it 'accepted given pending, it sets competing_status accordingly' do - registration = FactoryBot.create(:registration, registration_status: 'accepted') - registration.update_competing_lane!({ status: 'pending' }) - expect(registration.competing_status).to eq('pending') + RSpec.shared_examples 'competing_status updates' do |initial_status, new_status| + it "given #{new_status}, #{initial_status} updates as expected" do + registration = FactoryBot.create(:registration, registration_status: new_status) + registration.update_competing_lane!({ status: new_status }) + expect(registration.competing_status).to eq(new_status) + end end - it 'accepted given waiting_list, it sets competing_status' do - registration = FactoryBot.create(:registration, registration_status: 'accepted') - registration.update_competing_lane!({ status: 'waiting_list' }) - expect(registration.competing_status).to eq('waiting_list') + allowed_competing_status_updates.each do |params| + it_behaves_like 'competing_status updates', params[:initial_status], params[:new_status] end end diff --git a/spec/services/registration_checker_spec.rb b/spec/services/registration_checker_spec.rb index b0166dea..0a3eba13 100644 --- a/spec/services/registration_checker_spec.rb +++ b/spec/services/registration_checker_spec.rb @@ -5,66 +5,6 @@ # TODO: Add a test where one comp has a lot of competitors and another doesnt but you can still accept, to ensure that we're checking the reg count # for the COMPETITION, not all registrations -RSpec.shared_examples 'invalid user status updates' do |old_status, new_status| - it "user cant change 'status' => #{old_status} to: #{new_status}" do - registration = FactoryBot.create(:registration, registration_status: old_status) - competition_info = CompetitionInfo.new(FactoryBot.build(:competition)) - update_request = FactoryBot.build(:update_request, user_id: registration[:user_id], competing: { 'status' => new_status }) - stub_request(:get, UserApi.permissions_path(registration[:user_id])).to_return(status: 200, body: FactoryBot.build(:permissions_response).to_json, headers: { content_type: 'application/json' }) - - expect { - RegistrationChecker.update_registration_allowed!(update_request, competition_info, update_request['submitted_by']) - }.to raise_error(RegistrationError) do |error| - expect(error.http_status).to eq(:unauthorized) - expect(error.error).to eq(ErrorCodes::USER_INSUFFICIENT_PERMISSIONS) - end - end -end - -RSpec.shared_examples 'valid organizer status updates' do |old_status, new_status| - it "organizer can change 'status' => #{old_status} to: #{new_status} before close" do - registration = FactoryBot.create(:registration, registration_status: old_status) - competition_info = CompetitionInfo.new(FactoryBot.build(:competition)) - update_request = FactoryBot.build(:update_request, :organizer_for_user, user_id: registration[:user_id], competing: { 'status' => new_status }) - stub_request(:get, UserApi.permissions_path(update_request['submitted_by'])).to_return( - status: 200, - body: FactoryBot.build(:permissions_response, organized_competitions: [competition_info.competition_id]).to_json, - headers: { content_type: 'application/json' }, - ) - - expect { RegistrationChecker.update_registration_allowed!(update_request, competition_info, update_request['submitted_by']) } - .not_to raise_error - end - - it "site admin can change 'status' => #{old_status} to: #{new_status} before close" do - registration = FactoryBot.create(:registration, registration_status: old_status) - competition_info = CompetitionInfo.new(FactoryBot.build(:competition)) - update_request = FactoryBot.build(:update_request, :site_admin, user_id: registration[:user_id], competing: { 'status' => new_status }) - stub_request(:get, UserApi.permissions_path(update_request['submitted_by'])).to_return( - status: 200, - body: FactoryBot.build(:permissions_response, :admin).to_json, - headers: { content_type: 'application/json' }, - ) - - expect { RegistrationChecker.update_registration_allowed!(update_request, competition_info, update_request['submitted_by']) } - .not_to raise_error - end - - it "after edit deadline/reg close, organizer can change 'status' => #{old_status} to: #{new_status}" do - registration = FactoryBot.create(:registration, registration_status: old_status) - competition_info = CompetitionInfo.new(FactoryBot.build(:competition, :closed)) - update_request = FactoryBot.build(:update_request, :organizer_for_user, user_id: registration[:user_id], competing: { 'status' => new_status }) - stub_request(:get, UserApi.permissions_path(update_request['submitted_by'])).to_return( - status: 200, - body: FactoryBot.build(:permissions_response, organized_competitions: [competition_info.competition_id]).to_json, - headers: { content_type: 'application/json' }, - ) - - expect { RegistrationChecker.update_registration_allowed!(update_request, competition_info, update_request['submitted_by']) } - .not_to raise_error - end -end - describe RegistrationChecker do describe '#create' do describe '#create_registration_allowed!' do @@ -999,7 +939,146 @@ end describe '#update_registration_allowed!.validate_update_status!' do - it 'user cant submit an invalid status' do + describe 'user status combinations' do + user_permitted_status_updates = [ + { initial_status: 'pending', new_status: 'cancelled' }, + { initial_status: 'waiting_list', new_status: 'cancelled' }, + { initial_status: 'accepted', new_status: 'cancelled' }, + { initial_status: 'cancelled', new_status: 'pending' }, + { initial_status: 'cancelled', new_status: 'cancelled' }, + ] + + user_forbidden_status_updates = [ + { initial_status: 'pending', new_status: 'accepted' }, + { initial_status: 'pending', new_status: 'waiting_list' }, + { initial_status: 'pending', new_status: 'pending' }, + { initial_status: 'waiting_list', new_status: 'pending' }, + { initial_status: 'waiting_list', new_status: 'waiting_list' }, + { initial_status: 'waiting_list', new_status: 'accepted' }, + { initial_status: 'accepted', new_status: 'pending' }, + { initial_status: 'accepted', new_status: 'waiting_list' }, + { initial_status: 'accepted', new_status: 'accepted' }, + { initial_status: 'cancelled', new_status: 'accepted' }, + { initial_status: 'cancelled', new_status: 'waiting_list' }, + ] + + it 'tests cover all possible user status update combinations' do + combined_updates = (user_permitted_status_updates << user_forbidden_status_updates).flatten + expect(combined_updates).to match_array(REGISTRATION_TRANSITIONS) + end + + RSpec.shared_examples 'forbidden user status updates' do |initial_status, new_status| + it "user cant change status '#{initial_status}' to: #{new_status}" do + override_registration = FactoryBot.create(:registration, registration_status: initial_status) + update_request = FactoryBot.build(:update_request, user_id: override_registration[:user_id], competing: { 'status' => new_status }) + stub_request(:get, UserApi.permissions_path(override_registration[:user_id])).to_return( + status: 200, + body: FactoryBot.build(:permissions_response).to_json, + headers: { content_type: 'application/json' }, + ) + + expect { + RegistrationChecker.update_registration_allowed!(update_request, @competition_info, update_request['submitted_by']) + }.to raise_error(RegistrationError) do |error| + expect(error.http_status).to eq(:unauthorized) + expect(error.error).to eq(ErrorCodes::USER_INSUFFICIENT_PERMISSIONS) + end + end + end + + user_forbidden_status_updates.each do |params| + it_behaves_like 'forbidden user status updates', params[:initial_status], params[:new_status] + end + + RSpec.shared_examples 'permitted user status updates' do |initial_status, new_status| + it "user may change status '#{initial_status}' to: #{new_status}" do + override_registration = FactoryBot.create(:registration, user_id: 188000, registration_status: 'waiting_list') + update_request = FactoryBot.build(:update_request, user_id: override_registration[:user_id], competing: { 'status' => 'cancelled' }) + + expect { RegistrationChecker.update_registration_allowed!(update_request, @competition_info, update_request['submitted_by']) } + .not_to raise_error + end + end + + user_permitted_status_updates.each do |params| + it_behaves_like 'permitted user status updates', params[:initial_status], params[:new_status] + end + end + + describe 'organizer/admin status combinations' do + organizer_permitted_status_updates = [ + { initial_status: 'pending', new_status: 'accepted' }, + { initial_status: 'pending', new_status: 'waiting_list' }, + { initial_status: 'pending', new_status: 'cancelled' }, + { initial_status: 'pending', new_status: 'pending' }, + { initial_status: 'waiting_list', new_status: 'pending' }, + { initial_status: 'waiting_list', new_status: 'cancelled' }, + { initial_status: 'waiting_list', new_status: 'waiting_list' }, + { initial_status: 'waiting_list', new_status: 'accepted' }, + { initial_status: 'accepted', new_status: 'pending' }, + { initial_status: 'accepted', new_status: 'cancelled' }, + { initial_status: 'accepted', new_status: 'waiting_list' }, + { initial_status: 'accepted', new_status: 'accepted' }, + { initial_status: 'cancelled', new_status: 'accepted' }, + { initial_status: 'cancelled', new_status: 'pending' }, + { initial_status: 'cancelled', new_status: 'waiting_list' }, + { initial_status: 'cancelled', new_status: 'cancelled' }, + ] + + it 'tests cover all possible user status update combinations' do + expect(organizer_permitted_status_updates).to match_array(REGISTRATION_TRANSITIONS) + end + + RSpec.shared_examples 'permitted organizer status updates' do |initial_status, new_status| + it "organizer can change 'status' => #{initial_status} to: #{new_status} before close" do + registration = FactoryBot.create(:registration, registration_status: initial_status) + competition_info = CompetitionInfo.new(FactoryBot.build(:competition)) + update_request = FactoryBot.build(:update_request, :organizer_for_user, user_id: registration[:user_id], competing: { 'status' => new_status }) + stub_request(:get, UserApi.permissions_path(update_request['submitted_by'])).to_return( + status: 200, + body: FactoryBot.build(:permissions_response, organized_competitions: [competition_info.competition_id]).to_json, + headers: { content_type: 'application/json' }, + ) + + expect { RegistrationChecker.update_registration_allowed!(update_request, competition_info, update_request['submitted_by']) } + .not_to raise_error + end + + it "site admin can change 'status' => #{initial_status} to: #{new_status} before close" do + registration = FactoryBot.create(:registration, registration_status: initial_status) + competition_info = CompetitionInfo.new(FactoryBot.build(:competition)) + update_request = FactoryBot.build(:update_request, :site_admin, user_id: registration[:user_id], competing: { 'status' => new_status }) + stub_request(:get, UserApi.permissions_path(update_request['submitted_by'])).to_return( + status: 200, + body: FactoryBot.build(:permissions_response, :admin).to_json, + headers: { content_type: 'application/json' }, + ) + + expect { RegistrationChecker.update_registration_allowed!(update_request, competition_info, update_request['submitted_by']) } + .not_to raise_error + end + + it "after edit deadline/reg close, organizer can change 'status' => #{initial_status} to: #{new_status}" do + registration = FactoryBot.create(:registration, registration_status: initial_status) + competition_info = CompetitionInfo.new(FactoryBot.build(:competition, :closed)) + update_request = FactoryBot.build(:update_request, :organizer_for_user, user_id: registration[:user_id], competing: { 'status' => new_status }) + stub_request(:get, UserApi.permissions_path(update_request['submitted_by'])).to_return( + status: 200, + body: FactoryBot.build(:permissions_response, organized_competitions: [competition_info.competition_id]).to_json, + headers: { content_type: 'application/json' }, + ) + + expect { RegistrationChecker.update_registration_allowed!(update_request, competition_info, update_request['submitted_by']) } + .not_to raise_error + end + end + + organizer_permitted_status_updates.each do |params| + it_behaves_like 'permitted organizer status updates', params[:initial_status], params[:new_status] + end + end + + it 'user cant submit a non-existent status' do override_registration = FactoryBot.create(:registration, user_id: 188000, registration_status: 'waiting_list') update_request = FactoryBot.build(:update_request, user_id: override_registration[:user_id], competing: { 'status' => 'random_status' }) @@ -1011,7 +1090,7 @@ end end - it 'organizer cant submit an invalid status' do + it 'organizer cant submit a non-existent status' do override_registration = FactoryBot.create(:registration, user_id: 188000, registration_status: 'waiting_list') update_request = FactoryBot.build(:update_request, :organizer_as_user, user_id: override_registration[:user_id], competing: { 'status' => 'random_status' }) @@ -1047,14 +1126,6 @@ .not_to raise_error end - it 'user can change state to cancelled' do - override_registration = FactoryBot.create(:registration, user_id: 188000, registration_status: 'waiting_list') - update_request = FactoryBot.build(:update_request, user_id: override_registration[:user_id], competing: { 'status' => 'cancelled' }) - - expect { RegistrationChecker.update_registration_allowed!(update_request, @competition_info, update_request['submitted_by']) } - .not_to raise_error - end - it 'user cant change events when cancelling' do override_registration = FactoryBot.create(:registration, user_id: 188000, registration_status: 'waiting_list') update_request = FactoryBot.build( @@ -1069,30 +1140,6 @@ end end - it 'user can change state from cancelled to pending' do - override_registration = FactoryBot.create(:registration, user_id: 188000, registration_status: 'cancelled') - update_request = FactoryBot.build(:update_request, user_id: override_registration[:user_id], competing: { 'status' => 'pending' }) - - expect { RegistrationChecker.update_registration_allowed!(update_request, @competition_info, update_request['submitted_by']) } - .not_to raise_error - end - - [ - { old_status: 'pending', new_status: 'accepted' }, - { old_status: 'pending', new_status: 'waiting_list' }, - { old_status: 'pending', new_status: 'pending' }, - { old_status: 'waiting_list', new_status: 'pending' }, - { old_status: 'waiting_list', new_status: 'waiting_list' }, - { old_status: 'waiting_list', new_status: 'accepted' }, - { old_status: 'accepted', new_status: 'pending' }, - { old_status: 'accepted', new_status: 'waiting_list' }, - { old_status: 'accepted', new_status: 'accepted' }, - { old_status: 'cancelled', new_status: 'accepted' }, - { old_status: 'cancelled', new_status: 'waiting_list' }, - ].each do |params| - it_behaves_like 'invalid user status updates', params[:old_status], params[:new_status] - end - it 'user cant cancel accepted registration if competition requires organizers to cancel registration' do override_registration = FactoryBot.create(:registration, user_id: 188000, registration_status: 'accepted') override_competition_info = CompetitionInfo.new(FactoryBot.build(:competition, allow_registration_self_delete_after_acceptance: false)) @@ -1133,27 +1180,6 @@ end end - [ - { old_status: 'pending', new_status: 'accepted' }, - { old_status: 'pending', new_status: 'waiting_list' }, - { old_status: 'pending', new_status: 'cancelled' }, - { old_status: 'pending', new_status: 'pending' }, - { old_status: 'waiting_list', new_status: 'pending' }, - { old_status: 'waiting_list', new_status: 'cancelled' }, - { old_status: 'waiting_list', new_status: 'waiting_list' }, - { old_status: 'waiting_list', new_status: 'accepted' }, - { old_status: 'accepted', new_status: 'pending' }, - { old_status: 'accepted', new_status: 'cancelled' }, - { old_status: 'accepted', new_status: 'waiting_list' }, - { old_status: 'accepted', new_status: 'accepted' }, - { old_status: 'cancelled', new_status: 'accepted' }, - { old_status: 'cancelled', new_status: 'pending' }, - { old_status: 'cancelled', new_status: 'waiting_list' }, - { old_status: 'cancelled', new_status: 'cancelled' }, - ].each do |params| - it_behaves_like 'valid organizer status updates', params[:old_status], params[:new_status] - end - it 'organizer can cancel registration after registration ends' do override_competition_info = CompetitionInfo.new(FactoryBot.build(:competition, :closed)) update_request = FactoryBot.build(:update_request, :organizer_for_user, user_id: @registration[:user_id], competing: { 'status' => 'cancelled' }) diff --git a/spec/support/registration_states_helper.rb b/spec/support/registration_states_helper.rb new file mode 100644 index 00000000..929b922f --- /dev/null +++ b/spec/support/registration_states_helper.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +REGISTRATION_TRANSITIONS = Registration::REGISTRATION_STATES.flat_map do |initial_status| + Registration::REGISTRATION_STATES.map do |new_status| + { initial_status: initial_status, new_status: new_status } + end +end