Merge pull request #611 from openHPI/imporve_deadline_handling
Improve deadline handling
This commit is contained in:
1
Gemfile
1
Gemfile
@ -8,7 +8,6 @@ gem 'factory_bot_rails'
|
|||||||
gem 'forgery'
|
gem 'forgery'
|
||||||
gem 'highline'
|
gem 'highline'
|
||||||
gem 'jbuilder'
|
gem 'jbuilder'
|
||||||
gem 'jquery-rails'
|
|
||||||
gem 'ims-lti', '< 2.0.0'
|
gem 'ims-lti', '< 2.0.0'
|
||||||
gem 'kramdown'
|
gem 'kramdown'
|
||||||
gem 'pg'
|
gem 'pg'
|
||||||
|
15
Gemfile.lock
15
Gemfile.lock
@ -155,13 +155,8 @@ GEM
|
|||||||
ims-lti (1.2.4)
|
ims-lti (1.2.4)
|
||||||
builder (>= 1.0, < 4.0)
|
builder (>= 1.0, < 4.0)
|
||||||
oauth (>= 0.4.5, < 0.6)
|
oauth (>= 0.4.5, < 0.6)
|
||||||
jaro_winkler (1.5.4)
|
|
||||||
jbuilder (2.10.0)
|
jbuilder (2.10.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
jquery-rails (4.4.0)
|
|
||||||
rails-dom-testing (>= 1, < 3)
|
|
||||||
railties (>= 4.2.0)
|
|
||||||
thor (>= 0.14, < 2.0)
|
|
||||||
json (2.3.0)
|
json (2.3.0)
|
||||||
jwt (2.2.1)
|
jwt (2.2.1)
|
||||||
kramdown (2.2.1)
|
kramdown (2.2.1)
|
||||||
@ -228,7 +223,7 @@ GEM
|
|||||||
pry (~> 0.13.0)
|
pry (~> 0.13.0)
|
||||||
pry-rails (0.3.9)
|
pry-rails (0.3.9)
|
||||||
pry (>= 0.10.4)
|
pry (>= 0.10.4)
|
||||||
public_suffix (4.0.4)
|
public_suffix (4.0.5)
|
||||||
puma (4.3.3)
|
puma (4.3.3)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
pundit (2.1.0)
|
pundit (2.1.0)
|
||||||
@ -301,7 +296,7 @@ GEM
|
|||||||
rspec-expectations (>= 2.99.0.beta1)
|
rspec-expectations (>= 2.99.0.beta1)
|
||||||
rspec-core (3.9.2)
|
rspec-core (3.9.2)
|
||||||
rspec-support (~> 3.9.3)
|
rspec-support (~> 3.9.3)
|
||||||
rspec-expectations (3.9.1)
|
rspec-expectations (3.9.2)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.9.0)
|
rspec-support (~> 3.9.0)
|
||||||
rspec-mocks (3.9.1)
|
rspec-mocks (3.9.1)
|
||||||
@ -316,8 +311,7 @@ GEM
|
|||||||
rspec-mocks (~> 3.9)
|
rspec-mocks (~> 3.9)
|
||||||
rspec-support (~> 3.9)
|
rspec-support (~> 3.9)
|
||||||
rspec-support (3.9.3)
|
rspec-support (3.9.3)
|
||||||
rubocop (0.82.0)
|
rubocop (0.83.0)
|
||||||
jaro_winkler (~> 1.5.1)
|
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 2.7.0.1)
|
parser (>= 2.7.0.1)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
@ -356,7 +350,7 @@ GEM
|
|||||||
docile (~> 1.1)
|
docile (~> 1.1)
|
||||||
simplecov-html (~> 0.11)
|
simplecov-html (~> 0.11)
|
||||||
simplecov-html (0.12.2)
|
simplecov-html (0.12.2)
|
||||||
slim (4.0.1)
|
slim (4.1.0)
|
||||||
temple (>= 0.7.6, < 0.9)
|
temple (>= 0.7.6, < 0.9)
|
||||||
tilt (>= 2.0.6, < 2.1)
|
tilt (>= 2.0.6, < 2.1)
|
||||||
slim-rails (3.2.0)
|
slim-rails (3.2.0)
|
||||||
@ -443,7 +437,6 @@ DEPENDENCIES
|
|||||||
i18n-js
|
i18n-js
|
||||||
ims-lti (< 2.0.0)
|
ims-lti (< 2.0.0)
|
||||||
jbuilder
|
jbuilder
|
||||||
jquery-rails
|
|
||||||
kramdown
|
kramdown
|
||||||
listen
|
listen
|
||||||
mnemosyne-ruby
|
mnemosyne-ruby
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
||||||
// about supported directives.
|
// about supported directives.
|
||||||
//
|
//
|
||||||
//= require jquery_ujs
|
|
||||||
//= require turbolinks
|
//= require turbolinks
|
||||||
//= require pagedown_bootstrap
|
//= require pagedown_bootstrap
|
||||||
//= require rails-timeago
|
//= require rails-timeago
|
||||||
|
@ -39,7 +39,6 @@ CodeOceanEditorEvaluation = {
|
|||||||
$('#submit').get(0).lastChild.nodeValue = I18n.t('exercises.editor.submit_within_grace_period');
|
$('#submit').get(0).lastChild.nodeValue = I18n.t('exercises.editor.submit_within_grace_period');
|
||||||
} else if (this.late_submission_deadline && now > this.late_submission_deadline || now > this.submission_deadline) {
|
} else if (this.late_submission_deadline && now > this.late_submission_deadline || now > this.submission_deadline) {
|
||||||
// after_late_deadline
|
// after_late_deadline
|
||||||
debugger;
|
|
||||||
$('#submit').removeClass("btn-success btn-warning btn-danger").addClass("btn-danger");
|
$('#submit').removeClass("btn-success btn-warning btn-danger").addClass("btn-danger");
|
||||||
$('#submit').get(0).lastChild.nodeValue = I18n.t('exercises.editor.submit_after_late_deadline');
|
$('#submit').get(0).lastChild.nodeValue = I18n.t('exercises.editor.submit_after_late_deadline');
|
||||||
}
|
}
|
||||||
|
@ -138,14 +138,14 @@ module Lti
|
|||||||
|
|
||||||
private :return_to_consumer
|
private :return_to_consumer
|
||||||
|
|
||||||
def send_score(exercise_id, score, user_id)
|
def send_score(submission)
|
||||||
::NewRelic::Agent.add_custom_attributes({score: score, session: session})
|
::NewRelic::Agent.add_custom_attributes({score: submission.normalized_score, session: session})
|
||||||
fail(Error, "Score #{score} must be between 0 and #{MAXIMUM_SCORE}!") unless (0..MAXIMUM_SCORE).include?(score)
|
fail(Error, "Score #{submission.normalized_score} must be between 0 and #{MAXIMUM_SCORE}!") unless (0..MAXIMUM_SCORE).include?(submission.normalized_score)
|
||||||
|
|
||||||
if session[:consumer_id]
|
if session[:consumer_id]
|
||||||
lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id],
|
lti_parameter = LtiParameter.where(consumers_id: session[:consumer_id],
|
||||||
external_users_id: user_id,
|
external_users_id: submission.user_id,
|
||||||
exercises_id: exercise_id).last
|
exercises_id: submission.exercise_id).last
|
||||||
|
|
||||||
consumer = Consumer.find_by(id: session[:consumer_id])
|
consumer = Consumer.find_by(id: session[:consumer_id])
|
||||||
provider = build_tool_provider(consumer: consumer, parameters: lti_parameter.lti_parameters)
|
provider = build_tool_provider(consumer: consumer, parameters: lti_parameter.lti_parameters)
|
||||||
@ -153,15 +153,17 @@ module Lti
|
|||||||
|
|
||||||
if provider.nil?
|
if provider.nil?
|
||||||
{status: 'error'}
|
{status: 'error'}
|
||||||
|
elsif submission.after_late_deadline?
|
||||||
|
{status: 'too late'}
|
||||||
elsif provider.outcome_service?
|
elsif provider.outcome_service?
|
||||||
Raven.extra_context({
|
Raven.extra_context({
|
||||||
provider: provider.inspect,
|
provider: provider.inspect,
|
||||||
score: score,
|
score: submission.normalized_score,
|
||||||
lti_parameter: lti_parameter.inspect,
|
lti_parameter: lti_parameter.inspect,
|
||||||
session: session.to_hash,
|
session: session.to_hash,
|
||||||
exercise_id: exercise_id
|
exercise_id: submission.exercise_id
|
||||||
})
|
})
|
||||||
response = provider.post_replace_result!(score)
|
response = provider.post_replace_result!(submission.normalized_score)
|
||||||
{code: response.response_code, message: response.post_response.body, status: response.code_major}
|
{code: response.response_code, message: response.post_response.body, status: response.code_major}
|
||||||
else
|
else
|
||||||
{status: 'unsupported'}
|
{status: 'unsupported'}
|
||||||
|
@ -56,6 +56,10 @@ module SubmissionScoring
|
|||||||
unless output.nil?
|
unless output.nil?
|
||||||
score += output[:score] * output[:weight]
|
score += output[:score] * output[:weight]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if output.present? && output[:status] == :timeout
|
||||||
|
output[:stderr] += "\n\n#{t('exercises.editor.timeout', permitted_execution_time: submission.exercise.execution_environment.permitted_execution_time.to_s)}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
submission.update(score: score)
|
submission.update(score: score)
|
||||||
|
@ -459,10 +459,14 @@ class ExercisesController < ApplicationController
|
|||||||
|
|
||||||
def transmit_lti_score
|
def transmit_lti_score
|
||||||
::NewRelic::Agent.add_custom_attributes({submission: @submission.id, normalized_score: @submission.normalized_score})
|
::NewRelic::Agent.add_custom_attributes({submission: @submission.id, normalized_score: @submission.normalized_score})
|
||||||
response = send_score(@submission.exercise_id, @submission.normalized_score, @submission.user_id)
|
response = send_score(@submission)
|
||||||
|
|
||||||
if response[:status] == 'success'
|
if response[:status] == 'success'
|
||||||
redirect_after_submit
|
redirect_after_submit
|
||||||
|
elsif response[:status] == 'too late'
|
||||||
|
flash[:warning] = I18n.t('exercises.submit.too_late')
|
||||||
|
flash.keep(:warning)
|
||||||
|
redirect_after_submit
|
||||||
else
|
else
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to(implement_exercise_path(@submission.exercise)) }
|
format.html { redirect_to(implement_exercise_path(@submission.exercise)) }
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
// JS
|
// JS
|
||||||
import 'jquery';
|
import 'jquery';
|
||||||
|
import 'jquery-ujs'
|
||||||
import 'bootstrap/dist/js/bootstrap.bundle.min';
|
import 'bootstrap/dist/js/bootstrap.bundle.min';
|
||||||
import 'chosen-js/chosen.jquery';
|
import 'chosen-js/chosen.jquery';
|
||||||
import 'jstree';
|
import 'jstree';
|
||||||
|
@ -26,16 +26,17 @@ class ApplicationPolicy
|
|||||||
private :no_one
|
private :no_one
|
||||||
|
|
||||||
def everyone_in_study_group
|
def everyone_in_study_group
|
||||||
|
# !! Order is important !!
|
||||||
if @record.respond_to? :study_group # e.g. submission
|
if @record.respond_to? :study_group # e.g. submission
|
||||||
study_group = @record.study_group
|
study_group = @record.study_group
|
||||||
return false if study_group.blank?
|
return false if study_group.blank?
|
||||||
|
|
||||||
users_in_same_study_group = study_group.users
|
users_in_same_study_group = study_group.users
|
||||||
elsif @record.respond_to? :users # e.g. study_group
|
|
||||||
users_in_same_study_group = @record.users
|
|
||||||
elsif @record.respond_to? :user # e.g. exercise
|
elsif @record.respond_to? :user # e.g. exercise
|
||||||
study_groups = @record.user.study_groups
|
study_groups = @record.user.study_groups
|
||||||
users_in_same_study_group = study_groups.collect(&:users).flatten
|
users_in_same_study_group = study_groups.collect(&:users).flatten
|
||||||
|
elsif @record.respond_to? :users # e.g. study_group
|
||||||
|
users_in_same_study_group = @record.users
|
||||||
elsif @record.respond_to? :study_groups # e.g. user
|
elsif @record.respond_to? :study_groups # e.g. user
|
||||||
study_groups = @record.study_groups
|
study_groups = @record.study_groups
|
||||||
users_in_same_study_group = study_groups.collect(&:users).flatten
|
users_in_same_study_group = study_groups.collect(&:users).flatten
|
||||||
|
@ -24,12 +24,14 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise))
|
|||||||
span.date = feedback.created_at
|
span.date = feedback.created_at
|
||||||
.card-collapse role="tabpanel"
|
.card-collapse role="tabpanel"
|
||||||
.card-body.feedback
|
.card-body.feedback
|
||||||
.text = feedback.feedback_text
|
.text = render_markdown(feedback.feedback_text)
|
||||||
.difficulty = "#{t('user_exercise_feedback.difficulty')} #{comment_presets[feedback.difficulty].join(' - ')}" if feedback.difficulty
|
.difficulty = "#{t('user_exercise_feedback.difficulty')} #{comment_presets[feedback.difficulty].join(' - ')}" if feedback.difficulty
|
||||||
.worktime = "#{t('user_exercise_feedback.working_time')} #{time_presets[feedback.user_estimated_worktime].join(' - ')}" if feedback.user_estimated_worktime
|
.worktime = "#{t('user_exercise_feedback.working_time')} #{time_presets[feedback.user_estimated_worktime].join(' - ')}" if feedback.user_estimated_worktime
|
||||||
.card-footer
|
- if policy(@exercise).detailed_statistics?
|
||||||
span.points = "#{t('exercises.statistics.score')}: #{@submissions[index].score}"
|
.card-footer
|
||||||
span.working_time.pull-right = "#{t('exercises.statistics.worktime')}: #{@exercise.average_working_time_for(feedback.user.id) or 0}"
|
div.clearfix.feedback-header
|
||||||
|
span.points.flex-grow-1 = "#{t('exercises.statistics.score')}: #{@submissions[index].score}"
|
||||||
|
span.working_time.pull-right = "#{t('exercises.statistics.worktime')}: #{@exercise.average_working_time_for(feedback.user.id) or 0}"
|
||||||
|
|
||||||
= render('shared/pagination', collection: @feedbacks)
|
= render('shared/pagination', collection: @feedbacks)
|
||||||
|
|
||||||
|
@ -42,8 +42,7 @@ h1 = @exercise
|
|||||||
- submissions = Submission.where(user: @exercise.send(symbol).distinct, exercise: @exercise).in_study_group_of(current_user)
|
- submissions = Submission.where(user: @exercise.send(symbol).distinct, exercise: @exercise).in_study_group_of(current_user)
|
||||||
- if !policy(@exercise).detailed_statistics?
|
- if !policy(@exercise).detailed_statistics?
|
||||||
- submissions = submissions.final
|
- submissions = submissions.final
|
||||||
- latest_submission = submissions.latest
|
- if submissions.any?
|
||||||
- if latest_submission
|
|
||||||
.table-responsive
|
.table-responsive
|
||||||
table.table.table-striped.sortable
|
table.table.table-striped.sortable
|
||||||
thead
|
thead
|
||||||
@ -61,12 +60,13 @@ h1 = @exercise
|
|||||||
tr
|
tr
|
||||||
td = link_to_if symbol==:external_users && policy(user).statistics?, label, {controller: "exercises", action: "statistics", external_user_id: user.id, id: @exercise.id}
|
td = link_to_if symbol==:external_users && policy(user).statistics?, label, {controller: "exercises", action: "statistics", external_user_id: user.id, id: @exercise.id}
|
||||||
td = us['maximum_score'] or 0
|
td = us['maximum_score'] or 0
|
||||||
td.align-middle
|
td.align-middle
|
||||||
- if latest_submission.before_deadline?
|
- latest_user_submission = submissions.where(user: user).latest
|
||||||
|
- if latest_user_submission.before_deadline?
|
||||||
.unit-test-result.positive-result.before_deadline
|
.unit-test-result.positive-result.before_deadline
|
||||||
- elsif latest_submission.within_grace_period?
|
- elsif latest_user_submission.within_grace_period?
|
||||||
.unit-test-result.unknown-result.within_grace_period
|
.unit-test-result.unknown-result.within_grace_period
|
||||||
- elsif latest_submission.after_late_deadline?
|
- elsif latest_user_submission.after_late_deadline?
|
||||||
.unit-test-result.negative-result.after_late_deadline
|
.unit-test-result.negative-result.after_late_deadline
|
||||||
td = us['runs'] if policy(@exercise).detailed_statistics?
|
td = us['runs'] if policy(@exercise).detailed_statistics?
|
||||||
td = @exercise.average_working_time_for(user.id) or 0 if policy(@exercise).detailed_statistics?
|
td = @exercise.average_working_time_for(user.id) or 0 if policy(@exercise).detailed_statistics?
|
||||||
|
@ -13,10 +13,16 @@
|
|||||||
.form-group
|
.form-group
|
||||||
= f.text_area(:feedback_text, class: 'form-control', required: true, :rows => "10")
|
= f.text_area(:feedback_text, class: 'form-control', required: true, :rows => "10")
|
||||||
h4.mt-4 = t('user_exercise_feedback.difficulty')
|
h4.mt-4 = t('user_exercise_feedback.difficulty')
|
||||||
= f.collection_radio_buttons :difficulty, @texts, :first, :last, html_options: {class: "form-check-inline"} do |b|
|
= f.collection_radio_buttons :difficulty, @texts, :first, :last do |b|
|
||||||
= b.label(:class => 'form-check') { b.radio_button + b.text }
|
.form-check
|
||||||
|
label.form-check-label
|
||||||
|
= b.radio_button(class: 'form-check-input')
|
||||||
|
= b.text
|
||||||
h4.mt-4 = t('user_exercise_feedback.working_time')
|
h4.mt-4 = t('user_exercise_feedback.working_time')
|
||||||
= f.collection_radio_buttons :user_estimated_worktime, @times, :first, :last, html_options: {class: "form-check-inline"} do |b|
|
= f.collection_radio_buttons :user_estimated_worktime, @times, :first, :last do |b|
|
||||||
= b.label(:class => 'form-check') { b.radio_button + b.text }
|
.form-check
|
||||||
|
label.form-check-label
|
||||||
|
= b.radio_button(class: 'form-check-input')
|
||||||
|
= b.text
|
||||||
= f.hidden_field(:exercise_id, :value => @exercise.id)
|
= f.hidden_field(:exercise_id, :value => @exercise.id)
|
||||||
.actions = render('shared/submit_button', f: f, object: @uef)
|
.actions = render('shared/submit_button', f: f, object: @uef)
|
||||||
|
@ -431,6 +431,7 @@ de:
|
|||||||
finishing_rate: Abschlussrate
|
finishing_rate: Abschlussrate
|
||||||
submit:
|
submit:
|
||||||
failure: Beim Übermitteln Ihrer Punktzahl ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.
|
failure: Beim Übermitteln Ihrer Punktzahl ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.
|
||||||
|
too_late: Ihre Abgabe wurde erfolgreich gespeichert, ging jedoch nach der Abgabefrist ein.
|
||||||
full_score_redirect_to_rfc: Herzlichen Glückwunsch! Sie haben die maximale Punktzahl für diese Aufgabe an den Kurs übertragen. Ein anderer Teilnehmer hat eine Frage zu der von Ihnen gelösten Aufgabe. Er würde sich sicherlich sehr über ihre Hilfe und Kommentare freuen.
|
full_score_redirect_to_rfc: Herzlichen Glückwunsch! Sie haben die maximale Punktzahl für diese Aufgabe an den Kurs übertragen. Ein anderer Teilnehmer hat eine Frage zu der von Ihnen gelösten Aufgabe. Er würde sich sicherlich sehr über ihre Hilfe und Kommentare freuen.
|
||||||
full_score_redirect_to_own_rfc: Herzlichen Glückwunsch! Sie haben die maximale Punktzahl für diese Aufgabe an den Kurs übertragen. Ihre Frage ist damit wahrscheinlich gelöst? Falls ja, fügen Sie doch den entscheidenden Kniff als Antwort hinzu und markieren die Frage als gelöst, bevor sie das Fenster schließen.
|
full_score_redirect_to_own_rfc: Herzlichen Glückwunsch! Sie haben die maximale Punktzahl für diese Aufgabe an den Kurs übertragen. Ihre Frage ist damit wahrscheinlich gelöst? Falls ja, fügen Sie doch den entscheidenden Kniff als Antwort hinzu und markieren die Frage als gelöst, bevor sie das Fenster schließen.
|
||||||
study_group_dashboard:
|
study_group_dashboard:
|
||||||
|
@ -431,6 +431,7 @@ en:
|
|||||||
finishing_rate: Finishing Rate
|
finishing_rate: Finishing Rate
|
||||||
submit:
|
submit:
|
||||||
failure: An error occurred while transmitting your score. Please try again later.
|
failure: An error occurred while transmitting your score. Please try again later.
|
||||||
|
too_late: Your submission was saved successfully but was received after the deadline passed.
|
||||||
full_score_redirect_to_rfc: Congratulations! You achieved and submitted the highest possible score for this exercise. Another participant has a question concerning the exercise you just solved. Your help and comments will be greatly appreciated!
|
full_score_redirect_to_rfc: Congratulations! You achieved and submitted the highest possible score for this exercise. Another participant has a question concerning the exercise you just solved. Your help and comments will be greatly appreciated!
|
||||||
full_score_redirect_to_own_rfc: Congratulations! You achieved and submitted the highest possible score for this exercise. Your question concerning the exercise is solved? If so, please share the essential insight with your fellows and mark the question as solved, before you close this window!
|
full_score_redirect_to_own_rfc: Congratulations! You achieved and submitted the highest possible score for this exercise. Your question concerning the exercise is solved? If so, please share the essential insight with your fellows and mark the question as solved, before you close this window!
|
||||||
study_group_dashboard:
|
study_group_dashboard:
|
||||||
|
@ -452,7 +452,8 @@ class DockerClient
|
|||||||
output = nil
|
output = nil
|
||||||
Timeout.timeout(@execution_environment.permitted_execution_time.to_i) do
|
Timeout.timeout(@execution_environment.permitted_execution_time.to_i) do
|
||||||
# TODO: check phusion doku again if we need -i -t options here
|
# TODO: check phusion doku again if we need -i -t options here
|
||||||
output = container.exec(['bash', '-c', command])
|
# https://stackoverflow.com/questions/363223/how-do-i-get-both-stdout-and-stderr-to-go-to-the-terminal-and-a-log-file
|
||||||
|
output = container.exec(['bash', '-c', "#{command} 1> >(tee -a /tmp/stdout.log) 2> >(tee -a /tmp/stderr.log >&2); rm -f /tmp/std*.log"], tty: false)
|
||||||
end
|
end
|
||||||
Rails.logger.debug 'output from container.exec'
|
Rails.logger.debug 'output from container.exec'
|
||||||
Rails.logger.debug output
|
Rails.logger.debug output
|
||||||
@ -467,8 +468,10 @@ class DockerClient
|
|||||||
result
|
result
|
||||||
rescue Timeout::Error
|
rescue Timeout::Error
|
||||||
Rails.logger.info('got timeout error for container ' + container.to_s)
|
Rails.logger.info('got timeout error for container ' + container.to_s)
|
||||||
|
stdout = container.exec(['cat', '/tmp/stdout.log'])[0].join.force_encoding('utf-8')
|
||||||
|
stderr = container.exec(['cat', '/tmp/stderr.log'])[0].join.force_encoding('utf-8')
|
||||||
kill_container(container)
|
kill_container(container)
|
||||||
{status: :timeout}
|
{status: :timeout, stdout: stdout, stderr: stderr}
|
||||||
end
|
end
|
||||||
|
|
||||||
private :send_command
|
private :send_command
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"highlight.js": "^10.0.3",
|
"highlight.js": "^10.0.3",
|
||||||
"jquery": "^3.5.1",
|
"jquery": "^3.5.1",
|
||||||
"jquery-ui": "^1.12.1",
|
"jquery-ui": "^1.12.1",
|
||||||
|
"jquery-ujs": "^1.2.2",
|
||||||
"jstree": "^3.3.9",
|
"jstree": "^3.3.9",
|
||||||
"opensans-webkit": "^1.1.0",
|
"opensans-webkit": "^1.1.0",
|
||||||
"popper.js": "^1.16.1",
|
"popper.js": "^1.16.1",
|
||||||
|
@ -105,7 +105,8 @@ describe Lti do
|
|||||||
|
|
||||||
context 'with an invalid score' do
|
context 'with an invalid score' do
|
||||||
it 'raises an exception' do
|
it 'raises an exception' do
|
||||||
expect { controller.send(:send_score, submission.exercise_id, Lti::MAXIMUM_SCORE * 2, submission.user_id) }.to raise_error(Lti::Error)
|
allow(submission).to receive(:normalized_score).and_return Lti::MAXIMUM_SCORE * 2
|
||||||
|
expect { controller.send(:send_score, submission) }.to raise_error(Lti::Error)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -118,7 +119,8 @@ describe Lti do
|
|||||||
context 'when grading is not supported' do
|
context 'when grading is not supported' do
|
||||||
it 'returns a corresponding status' do
|
it 'returns a corresponding status' do
|
||||||
expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:outcome_service?).and_return(false)
|
expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:outcome_service?).and_return(false)
|
||||||
expect(controller.send(:send_score, submission.exercise_id, score, submission.user_id)[:status]).to eq('unsupported')
|
allow(submission).to receive(:normalized_score).and_return score
|
||||||
|
expect(controller.send(:send_score, submission)[:status]).to eq('unsupported')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -135,11 +137,13 @@ describe Lti do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'sends the score' do
|
it 'sends the score' do
|
||||||
controller.send(:send_score, submission.exercise_id, score, submission.user_id)
|
allow(submission).to receive(:normalized_score).and_return score
|
||||||
|
controller.send(:send_score, submission)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns code, message, and status' do
|
it 'returns code, message, and status' do
|
||||||
result = controller.send(:send_score, submission.exercise_id, score, submission.user_id)
|
allow(submission).to receive(:normalized_score).and_return score
|
||||||
|
result = controller.send(:send_score, submission)
|
||||||
expect(result[:code]).to eq(response.response_code)
|
expect(result[:code]).to eq(response.response_code)
|
||||||
expect(result[:message]).to eq(response.body)
|
expect(result[:message]).to eq(response.body)
|
||||||
expect(result[:status]).to eq(response.code_major)
|
expect(result[:status]).to eq(response.code_major)
|
||||||
@ -149,7 +153,8 @@ describe Lti do
|
|||||||
|
|
||||||
context 'without a tool consumer' do
|
context 'without a tool consumer' do
|
||||||
it 'returns a corresponding status' do
|
it 'returns a corresponding status' do
|
||||||
expect(controller.send(:send_score, submission.exercise_id, score, submission.user_id)[:status]).to eq('error')
|
allow(submission).to receive(:normalized_score).and_return score
|
||||||
|
expect(controller.send(:send_score, submission)[:status]).to eq('error')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -369,7 +369,10 @@ describe DockerClient, docker: true do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when a timeout occurs' do
|
context 'when a timeout occurs' do
|
||||||
before(:each) { expect(container).to receive(:exec).and_raise(Timeout::Error) }
|
before(:each) do
|
||||||
|
expect(container).to receive(:exec).once.and_raise(Timeout::Error)
|
||||||
|
expect(container).to receive(:exec).twice.and_return([ [], [] ])
|
||||||
|
end
|
||||||
|
|
||||||
it 'destroys the container asynchronously' do
|
it 'destroys the container asynchronously' do
|
||||||
pending("Container is destroyed, but not as expected in this test. ToDo update this test.")
|
pending("Container is destroyed, but not as expected in this test. ToDo update this test.")
|
||||||
|
45
yarn.lock
45
yarn.lock
@ -1720,9 +1720,9 @@ caniuse-api@^3.0.0:
|
|||||||
lodash.uniq "^4.5.0"
|
lodash.uniq "^4.5.0"
|
||||||
|
|
||||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001039, caniuse-lite@^1.0.30001043:
|
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001039, caniuse-lite@^1.0.30001043:
|
||||||
version "1.0.30001053"
|
version "1.0.30001055"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001053.tgz#b7ae027567ce2665b965b0437e4512b296ccd20d"
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001055.tgz#7b52c3537f7a8c0408aca867e83d2b04268b54cd"
|
||||||
integrity sha512-HtV4wwIZl6GA4Oznse8aR274XUOYGZnQLcf/P8vHgmlfqSNelwD+id8CyHOceqLqt9yfKmo7DUZTh1EuS9pukg==
|
integrity sha512-MbwsBmKrBSKIWldfdIagO5OJWZclpJtS4h0Jrk/4HFrXJxTdVdH23Fd+xCiHriVGvYcWyW8mR/CPsYajlH8Iuw==
|
||||||
|
|
||||||
case-sensitive-paths-webpack-plugin@^2.3.0:
|
case-sensitive-paths-webpack-plugin@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
@ -2804,9 +2804,9 @@ ee-first@1.1.1:
|
|||||||
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
||||||
|
|
||||||
electron-to-chromium@^1.3.413:
|
electron-to-chromium@^1.3.413:
|
||||||
version "1.3.430"
|
version "1.3.434"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.430.tgz#33914f7c2db771bdcf30977bd4fd6258ee8a2f37"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.434.tgz#a67dcb268e93768e2169399999ccffa4783f048e"
|
||||||
integrity sha512-HMDYkANGhx6vfbqpOf/hc6hWEmiOipOHGDeRDeUb3HLD3XIWpvKQxFgWf0tgHcr3aNv6I/8VPecplqmQsXoZSw==
|
integrity sha512-WjzGrE6appXvMyc2kH9Ide7OxsgTuRzag9sjQ5AcbOnbS9ut7P1HzOeEbJFLhr81IR7n2Hlr6qTTSGTXLIX5Pg==
|
||||||
|
|
||||||
elliptic@^6.0.0, elliptic@^6.5.2:
|
elliptic@^6.0.0, elliptic@^6.5.2:
|
||||||
version "6.5.2"
|
version "6.5.2"
|
||||||
@ -2872,9 +2872,9 @@ enhanced-resolve@^4.1.0:
|
|||||||
tapable "^1.0.0"
|
tapable "^1.0.0"
|
||||||
|
|
||||||
entities@^2.0.0:
|
entities@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
|
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.2.tgz#ac74db0bba8d33808bbf36809c3a5c3683531436"
|
||||||
integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==
|
integrity sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw==
|
||||||
|
|
||||||
errno@^0.1.3, errno@~0.1.7:
|
errno@^0.1.3, errno@~0.1.7:
|
||||||
version "0.1.7"
|
version "0.1.7"
|
||||||
@ -2962,9 +2962,9 @@ etag@~1.8.1:
|
|||||||
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
||||||
|
|
||||||
eventemitter3@^4.0.0:
|
eventemitter3@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
|
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384"
|
||||||
integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
|
integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==
|
||||||
|
|
||||||
events@^3.0.0:
|
events@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
@ -4172,7 +4172,14 @@ jquery-ui@^1.12.1:
|
|||||||
resolved "https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.12.1.tgz#bcb4045c8dd0539c134bc1488cdd3e768a7a9e51"
|
resolved "https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.12.1.tgz#bcb4045c8dd0539c134bc1488cdd3e768a7a9e51"
|
||||||
integrity sha1-vLQEXI3QU5wTS8FIjN0+dop6nlE=
|
integrity sha1-vLQEXI3QU5wTS8FIjN0+dop6nlE=
|
||||||
|
|
||||||
jquery@>=1.9.1, jquery@^3.5.1:
|
jquery-ujs@^1.2.2:
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/jquery-ujs/-/jquery-ujs-1.2.2.tgz#6a8ef1020e6b6dda385b90a4bddc128c21c56397"
|
||||||
|
integrity sha1-ao7xAg5rbdo4W5CkvdwSjCHFY5c=
|
||||||
|
dependencies:
|
||||||
|
jquery ">=1.8.0"
|
||||||
|
|
||||||
|
jquery@>=1.8.0, jquery@>=1.9.1, jquery@^3.5.1:
|
||||||
version "3.5.1"
|
version "3.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5"
|
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5"
|
||||||
integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==
|
integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==
|
||||||
@ -6093,9 +6100,9 @@ postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1:
|
|||||||
uniq "^1.0.1"
|
uniq "^1.0.1"
|
||||||
|
|
||||||
postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.5, postcss@^7.0.6:
|
postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.5, postcss@^7.0.6:
|
||||||
version "7.0.29"
|
version "7.0.30"
|
||||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.29.tgz#d3a903872bd52280b83bce38cdc83ce55c06129e"
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.30.tgz#cc9378beffe46a02cbc4506a0477d05fcea9a8e2"
|
||||||
integrity sha512-ba0ApvR3LxGvRMMiUa9n0WR4HjzcYm7tS+ht4/2Nd0NLtHpPIH77fuB9Xh1/yJVz9O/E/95Y/dn8ygWsyffXtw==
|
integrity sha512-nu/0m+NtIzoubO+xdAlwZl/u5S5vi/y6BCsoL8D+8IxsD3XvBS8X4YEADNIVXKVuQvduiucnRv+vPIqj56EGMQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk "^2.4.2"
|
chalk "^2.4.2"
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
@ -6557,9 +6564,9 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
|||||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||||
|
|
||||||
safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
|
safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
|
||||||
version "5.2.0"
|
version "5.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||||
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||||
|
|
||||||
safe-regex@^1.1.0:
|
safe-regex@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
|
Reference in New Issue
Block a user