Show More
Commit Description:
[grader] import script now support raw with testruns...
Commit Description:
[grader] import script now support raw with testruns
git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@267 6386c4cd-e34a-4fa8-8920-d93eb39b512e
References:
File last commit:
Show/Diff file:
Action:
lib/test_request_helper.rb
| 240 lines
| 7.4 KiB
| text/x-ruby
| RubyLexer
|
|
r23 | # | ||
# This part contains various test_request helpers for interfacing | ||||
# with Grader::Engine. There are TestRequestRoomMaker and | ||||
# TestRequestReporter. | ||||
module Grader | ||||
# | ||||
# A TestRequestRoomMaker is a helper object for Engine | ||||
# - finds grading room: in user_result_dir/(user)/test_request/ ... | ||||
# - prepare problem configuration for grading --- basically it copy | ||||
# all config files, and copy user's input into the testcase | ||||
# directory. First, it finds the template from problem template | ||||
# directory; if it can't find a template, it'll use the template | ||||
# from default template. | ||||
class TestRequestRoomMaker | ||||
def initialize | ||||
@config = Grader::Configuration.get_instance | ||||
end | ||||
def produce_grading_room(test_request) | ||||
grading_room = grading_room_dir(test_request) | ||||
FileUtils.mkdir_p(grading_room) | ||||
|
r55 | |||
# | ||||
# Also copy additional submitted file to this directory as well. | ||||
# The program would see this file only if it is copied | ||||
# to the sandbox directory later. The run script should do it. | ||||
# | ||||
cmd = "cp #{test_request.input_file_name}.files/* #{grading_room}" | ||||
system(cmd) | ||||
|
r23 | grading_room | ||
end | ||||
def find_problem_home(test_request) | ||||
problem_name = test_request.problem_name | ||||
template_dir = "#{@config.test_request_problem_templates_dir}/" + problem_name | ||||
raise "Test Request: error template not found" if !File.exists?(template_dir) | ||||
problem_home = problem_home_dir(test_request) | ||||
FileUtils.mkdir_p(problem_home) | ||||
copy_problem_template(template_dir,problem_home) | ||||
link_input_file(test_request,problem_home) | ||||
problem_home | ||||
end | ||||
def save_source(test_request,source_name) | ||||
dir = self.produce_grading_room(test_request) | ||||
submission = test_request.submission | ||||
f = File.open("#{dir}/#{source_name}","w") | ||||
f.write(submission.source) | ||||
f.close | ||||
end | ||||
def clean_up(test_request) | ||||
problem_home = problem_home_dir(test_request) | ||||
remove_data_files(problem_home) | ||||
end | ||||
protected | ||||
def grading_room_dir(test_request) | ||||
problem_name = test_request.problem_name | ||||
user = test_request.user | ||||
|
r55 | grading_room = "#{@config.user_result_dir}" + | ||
|
r23 | "/#{user.login}/test_request" + | ||
"/#{problem_name}/#{test_request.id}" | ||||
|
r55 | grading_room | ||
|
r23 | end | ||
def problem_home_dir(test_request) | ||||
problem_name = test_request.problem_name | ||||
user = test_request.user | ||||
"#{@config.user_result_dir}" + | ||||
"/#{user.login}/test_request/#{problem_name}" | ||||
end | ||||
def copy_problem_template(template_dir,problem_home) | ||||
cmd = "cp -R #{template_dir}/* #{problem_home}" | ||||
system_and_raise_when_fail(cmd,"Test Request: cannot copy problem template") | ||||
end | ||||
def link_input_file(test_request,problem_home) | ||||
|
r45 | input_fname = "#{test_request.input_file_name}" | ||
if !File.exists?(input_fname) | ||||
raise "Test Request: input file not found." | ||||
end | ||||
input_fname_problem_home = "#{problem_home}/test_cases/1/input-1.txt" | ||||
if File.exists?(input_fname_problem_home) | ||||
FileUtils.rm([input_fname_problem_home], :force => true) | ||||
end | ||||
cmd = "ln -s #{input_fname} #{input_fname_problem_home}" | ||||
|
r23 | system_and_raise_when_fail(cmd,"Test Request: cannot link input file") | ||
end | ||||
def remove_data_files(problem_home) | ||||
if File.exists?("#{problem_home}/test_cases/1/input-1.txt") | ||||
cmd = "rm #{problem_home}/test_cases/1/*" | ||||
system_and_raise_when_fail(cmd,"Test Request: cannot remove data files") | ||||
end | ||||
end | ||||
def system_and_raise_when_fail(cmd,msg) | ||||
if !system(cmd) | ||||
raise msg | ||||
end | ||||
end | ||||
end | ||||
class TestRequestReporter | ||||
def initialize | ||||
@config = Grader::Configuration.get_instance | ||||
end | ||||
def report(test_request,test_result_dir) | ||||
save_result(test_request,read_result(test_result_dir)) | ||||
end | ||||
def report_error(test_request, msg) | ||||
|
r45 | save_result(test_request, {:running_stat => { | ||
:msg => "#{msg}", | ||||
:running_time => nil, | ||||
:exit_status => "Some error occured. Program did not run", | ||||
:memory_usage => nil | ||||
}}) | ||||
|
r23 | end | ||
protected | ||||
def read_result(test_result_dir) | ||||
# TODO: | ||||
cmp_msg_fname = "#{test_result_dir}/compiler_message" | ||||
cmp_file = File.open(cmp_msg_fname) | ||||
cmp_msg = cmp_file.read | ||||
cmp_file.close | ||||
result_file_name = "#{test_result_dir}/1/result" | ||||
if File.exists?(result_file_name) | ||||
output_file_name = "#{test_result_dir}/1/output.txt" | ||||
results = File.open("#{test_result_dir}/1/result").readlines | ||||
|
r42 | stat = extract_running_stat(results) | ||
|
r23 | |||
return { | ||||
:output_file_name => output_file_name, | ||||
:running_stat => stat, | ||||
:comment => "", | ||||
:cmp_msg => cmp_msg} | ||||
else | ||||
return { | ||||
|
r41 | :running_stat => nil, | ||
|
r23 | :comment => "Compilation error", | ||
:cmp_msg => cmp_msg} | ||||
end | ||||
end | ||||
|
r42 | def extract_running_stat(results) | ||
running_stat_line = results[-1] | ||||
|
r23 | |||
|
r41 | # extract exit status line | ||
|
r23 | run_stat = "" | ||
if !(/[Cc]orrect/.match(results[0])) | ||||
run_stat = results[0].chomp | ||||
|
r41 | else | ||
run_stat = 'Program exited normally' | ||||
|
r23 | end | ||
|
r41 | # extract running time | ||
|
r42 | if res = /r(.*)u(.*)s/.match(running_stat_line) | ||
|
r23 | seconds = (res[1].to_f + res[2].to_f) | ||
time_stat = "Time used: #{seconds} sec." | ||||
else | ||||
|
r41 | seconds = nil | ||
|
r23 | time_stat = "Time used: n/a sec." | ||
end | ||||
|
r42 | |||
# extract memory usage | ||||
if res = /s(.*)m/.match(running_stat_line) | ||||
memory_used = res[1].to_i | ||||
else | ||||
memory_used = -1 | ||||
end | ||||
|
r41 | return { | ||
:msg => "#{run_stat}\n#{time_stat}", | ||||
:running_time => seconds, | ||||
|
r42 | :exit_status => run_stat, | ||
:memory_usage => memory_used | ||||
|
r41 | } | ||
|
r23 | end | ||
def save_result(test_request,result) | ||||
if result[:output_file_name]!=nil | ||||
test_request.output_file_name = link_output_file(test_request, | ||||
result[:output_file_name]) | ||||
end | ||||
test_request.graded_at = Time.now | ||||
test_request.compiler_message = (result[:cmp_msg] or '') | ||||
test_request.grader_comment = (result[:comment] or '') | ||||
|
r41 | if result[:running_stat]!=nil | ||
test_request.running_stat = (result[:running_stat][:msg] or '') | ||||
test_request.running_time = (result[:running_stat][:running_time] or nil) | ||||
|
r42 | test_request.exit_status = result[:running_stat][:exit_status] | ||
test_request.memory_usage = result[:running_stat][:memory_usage] | ||||
|
r41 | else | ||
test_request.running_stat = '' | ||||
end | ||||
|
r23 | test_request.save | ||
end | ||||
protected | ||||
def link_output_file(test_request, fname) | ||||
target_file_name = random_output_file_name(test_request.user, | ||||
test_request.problem) | ||||
FileUtils.mkdir_p(File.dirname(target_file_name)) | ||||
cmd = "ln -s #{fname} #{target_file_name}" | ||||
if !system(cmd) | ||||
raise "TestRequestReporter: cannot move output file" | ||||
end | ||||
return target_file_name | ||||
end | ||||
def random_output_file_name(user,problem) | ||||
problem_name = TestRequest.name_of(problem) | ||||
begin | ||||
tmpname = "#{@config.test_request_output_base_dir}" + | ||||
"/#{user.login}/#{problem_name}/#{rand(10000)}" | ||||
end while File.exists?(tmpname) | ||||
tmpname | ||||
end | ||||
end | ||||
end | ||||