diff --git a/app/controllers/concerns/submission_scoring.rb b/app/controllers/concerns/submission_scoring.rb index 16f1f061..9c577aca 100644 --- a/app/controllers/concerns/submission_scoring.rb +++ b/app/controllers/concerns/submission_scoring.rb @@ -9,6 +9,14 @@ module SubmissionScoring assessment = assessor.assess(output) passed = ((assessment[:passed] == assessment[:count]) and (assessment[:score] > 0)) testrun_output = passed ? nil : output[:stderr] + if !testrun_output.blank? + submission.exercise.execution_environment.error_templates.each do |template| + pattern = Regexp.new(template.signature).freeze + if pattern.match(testrun_output) + StructuredError.create_from_template(template, testrun_output) + end + end + end Testrun.new(submission: submission, file: file, passed: passed, output: testrun_output).save output.merge!(assessment) output.merge!(filename: file.name_with_extension, message: feedback_message(file, output[:score]), weight: file.weight) diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb index 9b37fde0..ae111823 100644 --- a/app/controllers/submissions_controller.rb +++ b/app/controllers/submissions_controller.rb @@ -6,7 +6,7 @@ class SubmissionsController < ApplicationController include SubmissionScoring include Tubesock::Hijack - before_action :set_submission, only: [:download, :download_file, :render_file, :run, :score, :show, :statistics, :stop, :test] + before_action :set_submission, only: [:download, :download_file, :render_file, :run, :score, :extract_errors, :show, :statistics, :stop, :test] before_action :set_docker_client, only: [:run, :test] before_action :set_files, only: [:download, :download_file, :render_file, :show] before_action :set_file, only: [:download_file, :render_file] @@ -187,6 +187,9 @@ class SubmissionsController < ApplicationController end def kill_socket(tubesock) + # search for errors and save them as StructuredError (for scoring runs see submission_scoring.rb) + extract_errors + # save the output of this "run" as a "testrun" (scoring runs are saved in submission_scoring.rb) save_run_output @@ -195,6 +198,17 @@ class SubmissionsController < ApplicationController tubesock.close end + def extract_errors + if !@message_buffer.blank? + @submission.exercise.execution_environment.error_templates.each do |template| + pattern = Regexp.new(template.signature).freeze + if pattern.match?(@message_buffer) + StructuredError.create_from_template(template, @message_buffer) + end + end + end + end + def handle_message(message, tubesock, container) @message_buffer ||= "" # Handle special commands first diff --git a/app/models/structured_error.rb b/app/models/structured_error.rb index 46f40423..2f03ec54 100644 --- a/app/models/structured_error.rb +++ b/app/models/structured_error.rb @@ -1,4 +1,12 @@ class StructuredError < ActiveRecord::Base belongs_to :error_template belongs_to :file, class_name: 'CodeOcean::File' + + def self.create_from_template(template, message_buffer) + instance = self.create(error_template: template) + template.error_template_attributes.each do |attribute| + StructuredErrorAttribute.create_from_template(attribute, instance, message_buffer) + end + instance + end end diff --git a/app/models/structured_error_attribute.rb b/app/models/structured_error_attribute.rb index 335a5901..b9967719 100644 --- a/app/models/structured_error_attribute.rb +++ b/app/models/structured_error_attribute.rb @@ -1,4 +1,9 @@ class StructuredErrorAttribute < ActiveRecord::Base belongs_to :structured_error belongs_to :error_template_attribute + + def self.create_from_template(attribute, structured_error, message_buffer) + value = message_buffer.match(attribute.regex).captures[0] + self.create(structured_error: structured_error, error_template_attribute: attribute, value: value) + end end