Extend storage of Testrun Messages and truncate long output
This commit is contained in:
@ -93,6 +93,7 @@ class SubmissionsController < ApplicationController
|
||||
|
||||
client_socket.onclose do |_event|
|
||||
runner_socket&.close(:terminated_by_client)
|
||||
# We do not update the @testrun[:status] by design, it would be missleading
|
||||
end
|
||||
|
||||
client_socket.onmessage do |raw_event|
|
||||
@ -101,10 +102,17 @@ class SubmissionsController < ApplicationController
|
||||
|
||||
# Otherwise, we expect to receive a JSON: Parsing.
|
||||
event = JSON.parse(raw_event).deep_symbolize_keys
|
||||
event[:cmd] = event[:cmd].to_sym
|
||||
event[:stream] = event[:stream].to_sym if event.key? :stream
|
||||
|
||||
case event[:cmd].to_sym
|
||||
# We could store the received event. However, it is also echoed by the container
|
||||
# and correctly identified as the original input. Therefore, we don't store
|
||||
# it here to prevent duplicated events.
|
||||
# @testrun[:messages].push(event)
|
||||
|
||||
case event[:cmd]
|
||||
when :client_kill
|
||||
@testrun[:status] = :client_kill
|
||||
@testrun[:status] = :terminated_by_client
|
||||
close_client_connection(client_socket)
|
||||
Rails.logger.debug('Client exited container.')
|
||||
when :result, :canvasevent, :exception
|
||||
@ -133,18 +141,19 @@ class SubmissionsController < ApplicationController
|
||||
@testrun[:output] = +''
|
||||
durations = @submission.run(@file) do |socket, starting_time|
|
||||
runner_socket = socket
|
||||
@testrun[:starting_time] = starting_time
|
||||
client_socket.send_data JSON.dump({cmd: :status, status: :container_running})
|
||||
|
||||
runner_socket.on :stdout do |data|
|
||||
json_data = prepare data, :stdout, starting_time
|
||||
@testrun[:output] << json_data[0, max_output_buffer_size - @testrun[:output].size]
|
||||
client_socket.send_data(json_data)
|
||||
message = retrieve_message_from_output data, :stdout
|
||||
@testrun[:output] << message[:data][0, max_output_buffer_size - @testrun[:output].size] if message[:data]
|
||||
send_and_store client_socket, message
|
||||
end
|
||||
|
||||
runner_socket.on :stderr do |data|
|
||||
json_data = prepare data, :stderr, starting_time
|
||||
@testrun[:output] << json_data[0, max_output_buffer_size - @testrun[:output].size]
|
||||
client_socket.send_data(json_data)
|
||||
message = retrieve_message_from_output data, :stderr
|
||||
@testrun[:output] << message[:data][0, max_output_buffer_size - @testrun[:output].size] if message[:data]
|
||||
send_and_store client_socket, message
|
||||
end
|
||||
|
||||
runner_socket.on :exit do |exit_code|
|
||||
@ -163,9 +172,9 @@ class SubmissionsController < ApplicationController
|
||||
@testrun[:status] = :failed
|
||||
"\n#{t('exercises.implement.exit_failure', timestamp: l(Time.zone.now, format: :short), exit_code: exit_code)}"
|
||||
end
|
||||
client_socket.send_data JSON.dump({cmd: :write, stream: :stdout, data: "#{exit_statement}\n"})
|
||||
send_and_store client_socket, {cmd: :write, stream: :stdout, data: "#{exit_statement}\n"}
|
||||
if exit_code == 137
|
||||
client_socket.send_data JSON.dump({cmd: :out_of_memory})
|
||||
send_and_store client_socket, {cmd: :status, status: :out_of_memory}
|
||||
@testrun[:status] = :out_of_memory
|
||||
end
|
||||
|
||||
@ -175,17 +184,15 @@ class SubmissionsController < ApplicationController
|
||||
@testrun[:container_execution_time] = durations[:execution_duration]
|
||||
@testrun[:waiting_for_container_time] = durations[:waiting_duration]
|
||||
rescue Runner::Error::ExecutionTimeout => e
|
||||
client_socket.send_data JSON.dump({cmd: :status, status: :timeout})
|
||||
send_and_store client_socket, {cmd: :status, status: :timeout}
|
||||
close_client_connection(client_socket)
|
||||
Rails.logger.debug { "Running a submission timed out: #{e.message}" }
|
||||
@testrun[:output] = "timeout: #{@testrun[:output]}"
|
||||
@testrun[:status] = :timeout
|
||||
extract_durations(e)
|
||||
rescue Runner::Error => e
|
||||
client_socket.send_data JSON.dump({cmd: :status, status: :container_depleted})
|
||||
send_and_store client_socket, {cmd: :status, status: :container_depleted}
|
||||
close_client_connection(client_socket)
|
||||
Rails.logger.debug { "Runner error while running a submission: #{e.message}" }
|
||||
@testrun[:status] = :container_depleted
|
||||
extract_durations(e)
|
||||
ensure
|
||||
save_testrun_output 'run'
|
||||
@ -197,17 +204,17 @@ class SubmissionsController < ApplicationController
|
||||
switch_locale do
|
||||
kill_client_socket(tubesock) if @embed_options[:disable_score]
|
||||
|
||||
# The score is stored separately, we can forward it to the client immediately
|
||||
tubesock.send_data(JSON.dump(@submission.calculate_score))
|
||||
# To enable hints when scoring a submission, uncomment the next line:
|
||||
# send_hints(tubesock, StructuredError.where(submission: @submission))
|
||||
kill_client_socket(tubesock)
|
||||
rescue Runner::Error => e
|
||||
tubesock.send_data JSON.dump({cmd: :status, status: :container_depleted})
|
||||
extract_durations(e)
|
||||
send_and_store tubesock, {cmd: :status, status: :container_depleted}
|
||||
kill_client_socket(tubesock)
|
||||
Rails.logger.debug { "Runner error while scoring submission #{@submission.id}: #{e.message}" }
|
||||
@testrun[:passed] = false
|
||||
@testrun[:status] = :container_depleted
|
||||
extract_durations(e)
|
||||
save_testrun_output 'assess'
|
||||
end
|
||||
end
|
||||
@ -224,15 +231,15 @@ class SubmissionsController < ApplicationController
|
||||
switch_locale do
|
||||
kill_client_socket(tubesock) if @embed_options[:disable_run]
|
||||
|
||||
# The score is stored separately, we can forward it to the client immediately
|
||||
tubesock.send_data(JSON.dump(@submission.test(@file)))
|
||||
kill_client_socket(tubesock)
|
||||
rescue Runner::Error => e
|
||||
tubesock.send_data JSON.dump({cmd: :status, status: :container_depleted})
|
||||
extract_durations(e)
|
||||
send_and_store tubesock, {cmd: :status, status: :container_depleted}
|
||||
kill_client_socket(tubesock)
|
||||
Rails.logger.debug { "Runner error while testing submission #{@submission.id}: #{e.message}" }
|
||||
@testrun[:passed] = false
|
||||
@testrun[:status] = :container_depleted
|
||||
extract_durations(e)
|
||||
save_testrun_output 'assess'
|
||||
end
|
||||
end
|
||||
@ -253,6 +260,7 @@ class SubmissionsController < ApplicationController
|
||||
end
|
||||
|
||||
def kill_client_socket(client_socket)
|
||||
# We don't want to store this (arbitrary) exit command and redirect it ourselves
|
||||
client_socket.send_data JSON.dump({cmd: :exit})
|
||||
client_socket.close
|
||||
end
|
||||
@ -281,6 +289,7 @@ class SubmissionsController < ApplicationController
|
||||
end
|
||||
|
||||
def extract_durations(error)
|
||||
@testrun[:starting_time] = error.starting_time
|
||||
@testrun[:container_execution_time] = error.execution_duration
|
||||
@testrun[:waiting_for_container_time] = error.waiting_duration
|
||||
end
|
||||
@ -296,6 +305,13 @@ class SubmissionsController < ApplicationController
|
||||
results
|
||||
end
|
||||
|
||||
def send_and_store(client_socket, message)
|
||||
message[:timestamp] = ActiveSupport::Duration.build(Time.zone.now - @testrun[:starting_time])
|
||||
@testrun[:messages].push message
|
||||
@testrun[:status] = message[:status] if message[:status]
|
||||
client_socket.send_data JSON.dump(message)
|
||||
end
|
||||
|
||||
def max_output_buffer_size
|
||||
if @submission.cause == 'requestComments'
|
||||
5000
|
||||
@ -304,13 +320,6 @@ class SubmissionsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def prepare(data, stream, starting_time)
|
||||
message = retrieve_message_from_output data, stream
|
||||
message[:timestamp] = ActiveSupport::Duration.build(Time.zone.now - starting_time)
|
||||
@testrun[:messages].push message
|
||||
JSON.dump(message)
|
||||
end
|
||||
|
||||
def sanitize_filename
|
||||
params[:filename].gsub(/\.json$/, '')
|
||||
end
|
||||
@ -337,7 +346,7 @@ class SubmissionsController < ApplicationController
|
||||
|
||||
errors = errors.to_a.uniq(&:hint)
|
||||
errors.each do |error|
|
||||
tubesock.send_data JSON.dump({cmd: 'hint', hint: error.hint, description: error.error_template.description})
|
||||
send_and_store tubesock, {cmd: :hint, hint: error.hint, description: error.error_template.description}
|
||||
end
|
||||
end
|
||||
|
||||
|
Reference in New Issue
Block a user