Extract ScoringChecks and rework RemoteEvaluations
This commit is contained in:

committed by
Sebastian Serth

parent
175c8933f3
commit
fe26378387
213
spec/controllers/remote_evaluation_controller_spec.rb
Normal file
213
spec/controllers/remote_evaluation_controller_spec.rb
Normal file
@ -0,0 +1,213 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe RemoteEvaluationController do
|
||||
let(:contributor) { create(:external_user) }
|
||||
let(:exercise) { create(:hello_world) }
|
||||
let(:programming_group) { nil }
|
||||
|
||||
let(:validation_token) { create(:remote_evaluation_mapping, user: contributor, exercise:).validation_token }
|
||||
let(:files_attributes) { {'0': {file_id: exercise.files.find_by(role: 'main_file').id, content: ''}} }
|
||||
let(:remote_evaluation_params) { {remote_evaluation: {validation_token:, files_attributes:}} }
|
||||
|
||||
let(:calculate_response) do
|
||||
[{
|
||||
status: :ok,
|
||||
stdout: '',
|
||||
stderr: '',
|
||||
waiting_for_container_time: 0,
|
||||
container_execution_time: 0,
|
||||
file_role: :teacher_defined_test,
|
||||
count: 1,
|
||||
failed: 0,
|
||||
error_messages: [],
|
||||
passed: 1,
|
||||
score:,
|
||||
filename: 'exercise_spec.rb',
|
||||
message: 'Well done.',
|
||||
weight: 1.0,
|
||||
hidden_feedback: false,
|
||||
exit_code: 0,
|
||||
}]
|
||||
end
|
||||
|
||||
shared_examples 'response' do |info|
|
||||
it 'returns a message and a status' do
|
||||
options = {}
|
||||
options[:score_sent] = (score_sent * 100).to_i if defined? score_sent
|
||||
options[:score] = (score * 100).to_i if defined? score
|
||||
options[:user] = users_error.map(&:displayname).join(', ') if defined? users_error
|
||||
options[:consumer] = contributor.consumer.name if defined? contributor
|
||||
|
||||
expect(response.parsed_body.symbolize_keys[:message]).to eq(I18n.t(info[:message], **options))
|
||||
expect(response.parsed_body.symbolize_keys[:status]).to eq(info[:status])
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(contributor)
|
||||
end
|
||||
|
||||
describe '#POST submit' do
|
||||
let(:perform_request) { proc { post :submit, params: remote_evaluation_params } }
|
||||
|
||||
let(:scoring_response) do
|
||||
{
|
||||
users: {all: users_success + users_error + users_unsupported, success: users_success, error: users_error, unsupported: users_unsupported},
|
||||
score: {original: score, sent: score_sent},
|
||||
deadline:,
|
||||
detailed_results: [],
|
||||
}
|
||||
end
|
||||
|
||||
context 'when remote evaluation mapping is available' do
|
||||
context 'when the scoring is successful' do
|
||||
let(:score) { 1 }
|
||||
let(:score_sent) { score }
|
||||
let(:deadline) { :none }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Submission).to receive_messages(calculate_score: calculate_response, score:)
|
||||
allow_any_instance_of(described_class).to receive(:send_scores).and_return(scoring_response)
|
||||
perform_request.call
|
||||
end
|
||||
|
||||
context 'when no LTI transmission was attempted' do
|
||||
let(:users_success) { [] }
|
||||
let(:users_error) { [] }
|
||||
let(:users_unsupported) { [contributor] }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.submit_failure_remote', status: 410}
|
||||
end
|
||||
|
||||
context 'when transmission of points failed for all users' do
|
||||
let(:users_success) { [] }
|
||||
let(:users_error) { [contributor] }
|
||||
let(:users_unsupported) { [] }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.submit_failure_all', status: 424}
|
||||
end
|
||||
|
||||
context 'when transmission of points failed for some users' do
|
||||
let(:users_success) { [contributor] }
|
||||
let(:users_error) { [create(:external_user)] }
|
||||
let(:users_unsupported) { [] }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.submit_failure_other_users', status: 417}
|
||||
end
|
||||
|
||||
context 'when the scoring was too late' do
|
||||
let(:users_success) { [contributor] }
|
||||
let(:users_error) { [] }
|
||||
let(:users_unsupported) { [] }
|
||||
let(:deadline) { :within_grace_period }
|
||||
let(:score_sent) { score * 0.8 }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.submit_too_late', status: 207}
|
||||
|
||||
it 'sends a reduced score' do
|
||||
expect(response.parsed_body.symbolize_keys[:score]).to eq((score_sent * 100).to_i)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when transmission of points was successful' do
|
||||
let(:users_success) { [contributor] }
|
||||
let(:users_error) { [] }
|
||||
let(:users_unsupported) { [] }
|
||||
|
||||
context 'when exercise is finished' do
|
||||
it_behaves_like 'response', {message: 'exercises.editor.exercise_finished_remote', status: 200}
|
||||
end
|
||||
|
||||
context 'when exercise is not finished' do
|
||||
let(:score) { 0.5 }
|
||||
|
||||
it_behaves_like 'response', {message: 'sessions.destroy_through_lti.success_with_outcome', status: 202}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the scoring was not successful' do
|
||||
let(:users_success) { [contributor] }
|
||||
let(:users_error) { [] }
|
||||
let(:users_unsupported) { [] }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Submission).to receive(:calculate_score).and_raise(error)
|
||||
perform_request.call
|
||||
end
|
||||
|
||||
context 'when the desired runner is already in use' do
|
||||
let(:error) { Runner::Error::RunnerInUse }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.runner_in_use', status: 409}
|
||||
end
|
||||
|
||||
context 'when no runner is available' do
|
||||
let(:error) { Runner::Error::NotAvailable }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.depleted', status: 503}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when remote evaluation mapping is not available' do
|
||||
let(:validation_token) { nil }
|
||||
|
||||
before { perform_request.call }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.submit_no_validation_token', status: 401}
|
||||
end
|
||||
end
|
||||
|
||||
describe '#POST evaluate' do
|
||||
let(:perform_request) { proc { post :evaluate, params: remote_evaluation_params } }
|
||||
|
||||
context 'when remote evaluation mapping is available' do
|
||||
context 'when the scoring is successful' do
|
||||
let(:score) { 1 }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Submission).to receive_messages(calculate_score: calculate_response, score:)
|
||||
perform_request.call
|
||||
end
|
||||
|
||||
it 'returns the feedback' do
|
||||
expect(response.body).to eq(calculate_response.to_json)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the scoring was not successful' do
|
||||
let(:users_success) { [contributor] }
|
||||
let(:users_error) { [] }
|
||||
let(:users_unsupported) { [] }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Submission).to receive(:calculate_score).and_raise(error)
|
||||
perform_request.call
|
||||
end
|
||||
|
||||
context 'when the desired runner is already in use' do
|
||||
let(:error) { Runner::Error::RunnerInUse }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.runner_in_use', status: 409}
|
||||
end
|
||||
|
||||
context 'when no runner is available' do
|
||||
let(:error) { Runner::Error::NotAvailable }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.depleted', status: 503}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when remote evaluation mapping is not available' do
|
||||
let(:validation_token) { nil }
|
||||
|
||||
before { perform_request.call }
|
||||
|
||||
it_behaves_like 'response', {message: 'exercises.editor.submit_no_validation_token', status: 401}
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user