diff --git a/provision.sh b/provision.sh index 0b1dd8ca..6cb5fa74 100644 --- a/provision.sh +++ b/provision.sh @@ -7,6 +7,7 @@ postgres_version=10 ruby_version=2.5.1 rails_version=5.2.1 +geckodriver_version=0.23.0 ########## INSTALL SCRIPT ########### @@ -103,7 +104,7 @@ fi # Selenium tests sudo apt-get -qq -y install xvfb firefox -wget --quiet -O ~/geckodriverdownload.tar.gz https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz +wget --quiet -O ~/geckodriverdownload.tar.gz https://github.com/mozilla/geckodriver/releases/download/v$geckodriver_version/geckodriver-v$geckodriver_version-linux64.tar.gz sudo tar -xzf ~/geckodriverdownload.tar.gz -C /usr/local/bin rm ~/geckodriverdownload.tar.gz sudo chmod +x /usr/local/bin/geckodriver diff --git a/spec/controllers/code_ocean/files_controller_spec.rb b/spec/controllers/code_ocean/files_controller_spec.rb index 16234a66..a2886eb8 100644 --- a/spec/controllers/code_ocean/files_controller_spec.rb +++ b/spec/controllers/code_ocean/files_controller_spec.rb @@ -8,13 +8,13 @@ describe CodeOcean::FilesController do let(:submission) { FactoryBot.create(:submission, user: user) } context 'with a valid file' do - let(:request) { proc { post :create, params: { code_ocean_file: FactoryBot.build(:file, context: submission).attributes, format: :json } } } - before(:each) { request.call } + let(:perform_request) { proc { post :create, params: { code_ocean_file: FactoryBot.build(:file, context: submission).attributes, format: :json } } } + before(:each) { perform_request.call } expect_assigns(file: CodeOcean::File) it 'creates the file' do - expect { request.call }.to change(CodeOcean::File, :count) + expect { perform_request.call }.to change(CodeOcean::File, :count) end expect_json @@ -32,14 +32,14 @@ describe CodeOcean::FilesController do describe 'DELETE #destroy' do let(:exercise) { FactoryBot.create(:fibonacci) } - let(:request) { proc { delete :destroy, params: { id: exercise.files.first.id } } } - before(:each) { request.call } + let(:perform_request) { proc { delete :destroy, params: { id: exercise.files.first.id } } } + before(:each) { perform_request.call } expect_assigns(file: CodeOcean::File) it 'destroys the file' do FactoryBot.create(:fibonacci) - expect { request.call }.to change(CodeOcean::File, :count).by(-1) + expect { perform_request.call }.to change(CodeOcean::File, :count).by(-1) end expect_redirect(:exercise) diff --git a/spec/controllers/consumers_controller_spec.rb b/spec/controllers/consumers_controller_spec.rb index 5eda1e93..7ce2c378 100644 --- a/spec/controllers/consumers_controller_spec.rb +++ b/spec/controllers/consumers_controller_spec.rb @@ -7,13 +7,13 @@ describe ConsumersController do describe 'POST #create' do context 'with a valid consumer' do - let(:request) { proc { post :create, params: { consumer: FactoryBot.attributes_for(:consumer) } } } - before(:each) { request.call } + let(:perform_request) { proc { post :create, params: { consumer: FactoryBot.attributes_for(:consumer) } } } + before(:each) { perform_request.call } expect_assigns(consumer: Consumer) it 'creates the consumer' do - expect { request.call }.to change(Consumer, :count).by(1) + expect { perform_request.call }.to change(Consumer, :count).by(1) end expect_redirect(Consumer.last) diff --git a/spec/controllers/events_controller_spec.rb b/spec/controllers/events_controller_spec.rb index ecfc611c..b414a860 100644 --- a/spec/controllers/events_controller_spec.rb +++ b/spec/controllers/events_controller_spec.rb @@ -7,13 +7,13 @@ describe EventsController do describe 'POST #create' do context 'with a valid event' do - let(:request) { proc { post :create, params: { event: {category: 'foo', data: 'bar', exercise_id: exercise.id, file_id: exercise.files[0].id} } } } - before(:each) { request.call } + let(:perform_request) { proc { post :create, params: { event: {category: 'foo', data: 'bar', exercise_id: exercise.id, file_id: exercise.files[0].id} } } } + before(:each) { perform_request.call } expect_assigns(event: Event) it 'creates the Event' do - expect { request.call }.to change(Event, :count).by(1) + expect { perform_request.call }.to change(Event, :count).by(1) end expect_status(201) diff --git a/spec/controllers/execution_environments_controller_spec.rb b/spec/controllers/execution_environments_controller_spec.rb index 6e8bf4c4..60f738d8 100644 --- a/spec/controllers/execution_environments_controller_spec.rb +++ b/spec/controllers/execution_environments_controller_spec.rb @@ -9,14 +9,14 @@ describe ExecutionEnvironmentsController do before(:each) { expect(DockerClient).to receive(:image_tags).at_least(:once).and_return([]) } context 'with a valid execution environment' do - let(:request) { proc { post :create, params: { execution_environment: FactoryBot.build(:ruby).attributes } } } - before(:each) { request.call } + let(:perform_request) { proc { post :create, params: { execution_environment: FactoryBot.build(:ruby).attributes } } } + before(:each) { perform_request.call } expect_assigns(docker_images: Array) expect_assigns(execution_environment: ExecutionEnvironment) it 'creates the execution environment' do - expect { request.call }.to change(ExecutionEnvironment, :count).by(1) + expect { perform_request.call }.to change(ExecutionEnvironment, :count).by(1) end expect_redirect(ExecutionEnvironment.last) diff --git a/spec/controllers/exercises_controller_spec.rb b/spec/controllers/exercises_controller_spec.rb index 3144280a..424a5290 100644 --- a/spec/controllers/exercises_controller_spec.rb +++ b/spec/controllers/exercises_controller_spec.rb @@ -7,12 +7,12 @@ describe ExercisesController do describe 'PUT #batch_update' do let(:attributes) { { 'public': 'true'} } - let(:request) { proc { put :batch_update, params: { exercises: {0 => attributes.merge(id: exercise.id)} } } } - before(:each) { request.call } + let(:perform_request) { proc { put :batch_update, params: { exercises: {0 => attributes.merge(id: exercise.id)} } } } + before(:each) { perform_request.call } it 'updates the exercises' do expect_any_instance_of(Exercise).to receive(:update).with(attributes) - request.call + perform_request.call end expect_json @@ -20,16 +20,16 @@ describe ExercisesController do end describe 'POST #clone' do - let(:request) { proc { post :clone, params: { id: exercise.id } } } + let(:perform_request) { proc { post :clone, params: { id: exercise.id } } } context 'when saving succeeds' do - before(:each) { request.call } + before(:each) { perform_request.call } expect_assigns(exercise: Exercise) it 'clones the exercise' do expect_any_instance_of(Exercise).to receive(:duplicate).with(hash_including(public: false, user: user)).and_call_original - expect { request.call }.to change(Exercise, :count).by(1) + expect { perform_request.call }.to change(Exercise, :count).by(1) end it 'generates a new token' do @@ -42,7 +42,7 @@ describe ExercisesController do context 'when saving fails' do before(:each) do expect_any_instance_of(Exercise).to receive(:save).and_return(false) - request.call + perform_request.call end expect_assigns(exercise: Exercise) @@ -55,26 +55,26 @@ describe ExercisesController do let(:exercise_attributes) { FactoryBot.build(:dummy).attributes } context 'with a valid exercise' do - let(:request) { proc { post :create, params: { exercise: exercise_attributes } } } - before(:each) { request.call } + let(:perform_request) { proc { post :create, params: { exercise: exercise_attributes } } } + before(:each) { perform_request.call } expect_assigns(exercise: Exercise) it 'creates the exercise' do - expect { request.call }.to change(Exercise, :count).by(1) + expect { perform_request.call }.to change(Exercise, :count).by(1) end expect_redirect(Exercise.last) end context 'when including a file' do - let(:request) { proc { post :create, params: { exercise: exercise_attributes.merge(files_attributes: files_attributes) } } } + let(:perform_request) { proc { post :create, params: { exercise: exercise_attributes.merge(files_attributes: files_attributes) } } } context 'when specifying the file content within the form' do let(:files_attributes) { {'0' => FactoryBot.build(:file).attributes} } it 'creates the file' do - expect { request.call }.to change(CodeOcean::File, :count) + expect { perform_request.call }.to change(CodeOcean::File, :count) end end @@ -87,11 +87,11 @@ describe ExercisesController do let(:uploaded_file) { Rack::Test::UploadedFile.new(file_path, 'video/mp4', true) } it 'creates the file' do - expect { request.call }.to change(CodeOcean::File, :count) + expect { perform_request.call }.to change(CodeOcean::File, :count) end it 'assigns the native file' do - request.call + perform_request.call expect(Exercise.last.files.first.native_file).to be_a(FileUploader) end end @@ -102,11 +102,11 @@ describe ExercisesController do let(:uploaded_file) { Rack::Test::UploadedFile.new(file_path, 'text/x-ruby', false) } it 'creates the file' do - expect { request.call }.to change(CodeOcean::File, :count) + expect { perform_request.call }.to change(CodeOcean::File, :count) end it 'assigns the file content' do - request.call + perform_request.call expect(Exercise.last.files.first.content).to eq(File.read(file_path)) end end @@ -144,11 +144,11 @@ describe ExercisesController do end describe 'GET #implement' do - let(:request) { proc { get :implement, params: { id: exercise.id } } } + let(:perform_request) { proc { get :implement, params: { id: exercise.id } } } context 'with an exercise with visible files' do let(:exercise) { FactoryBot.create(:fibonacci) } - before(:each) { request.call } + before(:each) { perform_request.call } expect_assigns(exercise: :exercise) @@ -156,7 +156,7 @@ describe ExercisesController do let!(:submission) { FactoryBot.create(:submission, exercise_id: exercise.id, user_id: user.id, user_type: user.class.name) } it "populates the editors with the submission's files' content" do - request.call + perform_request.call expect(assigns(:files)).to eq(submission.files) end end @@ -172,7 +172,7 @@ describe ExercisesController do end context 'with an exercise without visible files' do - before(:each) { request.call } + before(:each) { perform_request.call } expect_assigns(exercise: :exercise) expect_flash_message(:alert, :'exercises.implement.no_files') @@ -229,7 +229,7 @@ describe ExercisesController do describe 'POST #submit' do let(:output) { {} } - let(:request) { post :submit, format: :json, params: { id: exercise.id, submission: {cause: 'submit', exercise_id: exercise.id} } } + let(:perform_request) { post :submit, format: :json, params: { id: exercise.id, submission: {cause: 'submit', exercise_id: exercise.id} } } let!(:external_user) { FactoryBot.create(:external_user) } let!(:lti_parameter) { FactoryBot.create(:lti_parameter, external_user: external_user, exercise: exercise) } @@ -248,7 +248,7 @@ describe ExercisesController do context 'when the score transmission succeeds' do before(:each) do expect(controller).to receive(:send_score).and_return(status: 'success') - request + perform_request end expect_assigns(exercise: :exercise) @@ -264,7 +264,7 @@ describe ExercisesController do context 'when the score transmission fails' do before(:each) do expect(controller).to receive(:send_score).and_return(status: 'unsupported') - request + perform_request end expect_assigns(exercise: :exercise) @@ -282,7 +282,7 @@ describe ExercisesController do before(:each) do expect(controller).to receive(:lti_outcome_service?).and_return(false) expect(controller).not_to receive(:send_score) - request + perform_request end expect_assigns(exercise: :exercise) diff --git a/spec/controllers/file_types_controller_spec.rb b/spec/controllers/file_types_controller_spec.rb index 77a7e372..1041d703 100644 --- a/spec/controllers/file_types_controller_spec.rb +++ b/spec/controllers/file_types_controller_spec.rb @@ -7,14 +7,14 @@ describe FileTypesController do describe 'POST #create' do context 'with a valid file type' do - let(:request) { proc { post :create, params: { file_type: FactoryBot.attributes_for(:dot_rb) } } } - before(:each) { request.call } + let(:perform_request) { proc { post :create, params: { file_type: FactoryBot.attributes_for(:dot_rb) } } } + before(:each) { perform_request.call } expect_assigns(editor_modes: Array) expect_assigns(file_type: FileType) it 'creates the file type' do - expect { request.call }.to change(FileType, :count).by(1) + expect { perform_request.call }.to change(FileType, :count).by(1) end expect_redirect(FileType.last) diff --git a/spec/controllers/hints_controller_spec.rb b/spec/controllers/hints_controller_spec.rb index dcd62d7b..d95b7efe 100644 --- a/spec/controllers/hints_controller_spec.rb +++ b/spec/controllers/hints_controller_spec.rb @@ -8,14 +8,14 @@ describe HintsController do describe 'POST #create' do context 'with a valid hint' do - let(:request) { proc { post :create, params: { execution_environment_id: execution_environment.id, hint: FactoryBot.attributes_for(:ruby_syntax_error) } } } - before(:each) { request.call } + let(:perform_request) { proc { post :create, params: { execution_environment_id: execution_environment.id, hint: FactoryBot.attributes_for(:ruby_syntax_error) } } } + before(:each) { perform_request.call } expect_assigns(execution_environment: :execution_environment) expect_assigns(hint: Hint) it 'creates the hint' do - expect { request.call }.to change(Hint, :count).by(1) + expect { perform_request.call }.to change(Hint, :count).by(1) end expect_redirect(Hint.last) diff --git a/spec/controllers/internal_users_controller_spec.rb b/spec/controllers/internal_users_controller_spec.rb index abb9c6d3..f57ebb4b 100644 --- a/spec/controllers/internal_users_controller_spec.rb +++ b/spec/controllers/internal_users_controller_spec.rb @@ -103,13 +103,13 @@ describe InternalUsersController do before(:each) { allow(controller).to receive(:current_user).and_return(user) } context 'with a valid internal user' do - let(:request) { proc { post :create, params: { internal_user: FactoryBot.build(:teacher).attributes } } } - before(:each) { request.call } + let(:perform_request) { proc { post :create, params: { internal_user: FactoryBot.build(:teacher).attributes } } } + before(:each) { perform_request.call } expect_assigns(user: InternalUser) it 'creates the internal user' do - expect { request.call }.to change(InternalUser, :count).by(1) + expect { perform_request.call }.to change(InternalUser, :count).by(1) end it 'creates an inactive user' do @@ -122,7 +122,7 @@ describe InternalUsersController do it 'sends an activation email' do expect_any_instance_of(InternalUser).to receive(:send_activation_needed_email!) - request.call + perform_request.call end expect_redirect(InternalUser.last) @@ -187,13 +187,13 @@ describe InternalUsersController do describe 'POST #forgot_password' do context 'with an email address' do - let(:request) { proc { post :forgot_password, params: { email: user.email } } } - before(:each) { request.call } + let(:perform_request) { proc { post :forgot_password, params: { email: user.email } } } + before(:each) { perform_request.call } it 'delivers instructions to reset the password' do expect(InternalUser).to receive(:find_by).and_return(user) expect(user).to receive(:deliver_reset_password_instructions!) - request.call + perform_request.call end expect_redirect(:root) @@ -264,8 +264,8 @@ describe InternalUsersController do let(:password) { 'foo' } context 'with a matching password confirmation' do - let(:request) { proc { put :reset_password, params: { internal_user: {password: password, password_confirmation: password}, id: user.id, token: user.reset_password_token } } } - before(:each) { request.call } + let(:perform_request) { proc { put :reset_password, params: { internal_user: {password: password, password_confirmation: password}, id: user.id, token: user.reset_password_token } } } + before(:each) { perform_request.call } expect_assigns(user: :user) diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index a8feb5a2..c1ea7ba1 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -72,36 +72,36 @@ describe SessionsController do context 'with valid launch parameters' do let(:locale) { :de } - let(:request) { post :create_through_lti, params: { custom_locale: locale, custom_token: exercise.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id } } + let(:perform_request) { post :create_through_lti, params: { custom_locale: locale, custom_token: exercise.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id } } let(:user) { FactoryBot.create(:external_user, consumer_id: consumer.id) } before(:each) { expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:valid_request?).and_return(true) } it 'assigns the current user' do - request + perform_request expect(assigns(:current_user)).to be_an(ExternalUser) expect(session[:external_user_id]).to eq(user.id) end it 'sets the specified locale' do expect(controller).to receive(:set_locale).and_call_original - request + perform_request expect(I18n.locale).to eq(locale) end it 'assigns the exercise' do - request + perform_request expect(assigns(:exercise)).to eq(exercise) end it 'stores LTI parameters in the session' do #Todo replace session with lti_parameter /should be done already expect(controller).to receive(:store_lti_session_data) - request + perform_request end it 'stores the OAuth nonce' do expect(controller).to receive(:store_nonce).with(nonce) - request + perform_request end context 'when LTI outcomes are supported' do @@ -109,7 +109,7 @@ describe SessionsController do before(:each) do expect(controller).to receive(:lti_outcome_service?).and_return(true) - request + perform_request end expect_flash_message(:notice, :message) @@ -120,14 +120,14 @@ describe SessionsController do before(:each) do expect(controller).to receive(:lti_outcome_service?).and_return(false) - request + perform_request end expect_flash_message(:notice, :message) end it 'redirects to the requested exercise' do - request + perform_request expect(controller).to redirect_to(implement_exercise_path(exercise.id)) end @@ -192,7 +192,7 @@ describe SessionsController do end describe 'GET #destroy_through_lti' do - let(:request) { proc { get :destroy_through_lti, params: { consumer_id: consumer.id, submission_id: submission.id } } } + let(:perform_request) { proc { get :destroy_through_lti, params: { consumer_id: consumer.id, submission_id: submission.id } } } let(:submission) { FactoryBot.create(:submission, exercise: FactoryBot.create(:dummy)) } before(:each) do @@ -202,12 +202,12 @@ describe SessionsController do # session[:lti_parameters] = {} end - before(:each) { request.call } + before(:each) { perform_request.call } it 'clears the session' do #Todo replace session with lti_parameter /should be done already expect(controller).to receive(:clear_lti_session_data) - request.call + perform_request.call end expect_status(200) diff --git a/spec/controllers/submissions_controller_spec.rb b/spec/controllers/submissions_controller_spec.rb index b6d7b145..497318e0 100644 --- a/spec/controllers/submissions_controller_spec.rb +++ b/spec/controllers/submissions_controller_spec.rb @@ -12,13 +12,13 @@ describe SubmissionsController do context 'with a valid submission' do let(:exercise) { FactoryBot.create(:hello_world) } - let(:request) { proc { post :create, format: :json, params: { submission: FactoryBot.attributes_for(:submission, exercise_id: exercise.id) } } } - before(:each) { request.call } + let(:perform_request) { proc { post :create, format: :json, params: { submission: FactoryBot.attributes_for(:submission, exercise_id: exercise.id) } } } + before(:each) { perform_request.call } expect_assigns(submission: Submission) it 'creates the submission' do - expect { request.call }.to change(Submission, :count).by(1) + expect { perform_request.call }.to change(Submission, :count).by(1) end expect_json @@ -143,7 +143,7 @@ describe SubmissionsController do describe 'GET #run' do let(:filename) { submission.collect_files.detect(&:main_file?).name_with_extension } - let(:request) { get :run, params: { filename: filename , id: submission.id } } + let(:perform_request) { get :run, params: { filename: filename , id: submission.id } } before(:each) do expect_any_instance_of(ActionController::Live::SSE).to receive(:write).at_least(3).times @@ -152,7 +152,7 @@ describe SubmissionsController do context 'when no errors occur during execution' do before(:each) do expect_any_instance_of(DockerClient).to receive(:execute_run_command).with(submission, filename).and_return({}) - request + perform_request end pending("todo") @@ -165,7 +165,7 @@ describe SubmissionsController do expect_any_instance_of(DockerClient).to receive(:execute_run_command).with(submission, filename).and_yield(:stderr, stderr) end - after(:each) { request } + after(:each) { perform_request } context 'when the error is covered by a hint' do let(:hint) { "Your object 'main' of class 'Object' does not understand the method 'foo'." } @@ -237,20 +237,20 @@ describe SubmissionsController do end describe 'GET #score' do - let(:request) { proc { get :score, params: { id: submission.id } } } - before(:each) { request.call } + let(:perform_request) { proc { get :score, params: { id: submission.id } } } + before(:each) { perform_request.call } pending("todo: mock puma webserver or encapsulate tubesock call (Tubesock::HijackNotAvailable)") end describe 'POST #stop' do - let(:request) { proc { post :stop, params: { container_id: CONTAINER.id, id: submission.id } } } + let(:perform_request) { proc { post :stop, params: { container_id: CONTAINER.id, id: submission.id } } } context 'when the container can be found' do before(:each) do expect(Docker::Container).to receive(:get).and_return(CONTAINER) #expect(Rails.logger).to receive(:debug).at_least(:once).and_call_original - request.call + perform_request.call end it 'renders nothing' do @@ -263,7 +263,7 @@ describe SubmissionsController do context 'when the container cannot be found' do before(:each) do expect(Docker::Container).to receive(:get).and_raise(Docker::Error::NotFoundError) - request.call + perform_request.call end it 'renders nothing' do diff --git a/spec/factories/error.rb b/spec/factories/code_ocean/error.rb similarity index 100% rename from spec/factories/error.rb rename to spec/factories/code_ocean/error.rb diff --git a/spec/models/error_spec.rb b/spec/models/code_ocean/error_spec.rb similarity index 100% rename from spec/models/error_spec.rb rename to spec/models/code_ocean/error_spec.rb diff --git a/spec/policies/error_policy_spec.rb b/spec/policies/code_ocean/error_policy_spec.rb similarity index 96% rename from spec/policies/error_policy_spec.rb rename to spec/policies/code_ocean/error_policy_spec.rb index 2fff2e7e..71ff72d5 100644 --- a/spec/policies/error_policy_spec.rb +++ b/spec/policies/code_ocean/error_policy_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe ErrorPolicy do +describe CodeOcean::ErrorPolicy do subject { described_class } let(:error) { FactoryBot.build(:error) }