Description:
fixed test run scoring bug: now it takes the minimum of each test case's score git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@273 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r66:c03ebf30fb10 - - 4 files changed: 17 inserted, 16 deleted

@@ -1,223 +1,225
1 #
1 #
2 # This part contains various test_request helpers for interfacing
2 # This part contains various test_request helpers for interfacing
3 # with Grader::Engine. There are TestRequestRoomMaker and
3 # with Grader::Engine. There are TestRequestRoomMaker and
4 # TestRequestReporter.
4 # TestRequestReporter.
5
5
6 module Grader
6 module Grader
7
7
8 #
8 #
9 # A TestRequestRoomMaker is a helper object for Engine
9 # A TestRequestRoomMaker is a helper object for Engine
10 # - finds grading room: in user_result_dir/(user)/test_request/ ...
10 # - finds grading room: in user_result_dir/(user)/test_request/ ...
11 # - prepare problem configuration for grading --- basically it copy
11 # - prepare problem configuration for grading --- basically it copy
12 # all config files, and copy user's input into the testcase
12 # all config files, and copy user's input into the testcase
13 # directory. First, it finds the template from problem template
13 # directory. First, it finds the template from problem template
14 # directory; if it can't find a template, it'll use the template
14 # directory; if it can't find a template, it'll use the template
15 # from default template.
15 # from default template.
16 class TestRequestRoomMaker
16 class TestRequestRoomMaker
17 def initialize
17 def initialize
18 @config = Grader::Configuration.get_instance
18 @config = Grader::Configuration.get_instance
19 end
19 end
20
20
21 def produce_grading_room(test_request)
21 def produce_grading_room(test_request)
22 grading_room = grading_room_dir(test_request)
22 grading_room = grading_room_dir(test_request)
23 FileUtils.mkdir_p(grading_room)
23 FileUtils.mkdir_p(grading_room)
24
24
25 #
25 #
26 # Also copy additional submitted file to this directory as well.
26 # Also copy additional submitted file to this directory as well.
27 # The program would see this file only if it is copied
27 # The program would see this file only if it is copied
28 # to the sandbox directory later. The run script should do it.
28 # to the sandbox directory later. The run script should do it.
29 #
29 #
30 + if FileTest.exists?("#{test_request.input_file_name}.files")
30 cmd = "cp #{test_request.input_file_name}.files/* #{grading_room}"
31 cmd = "cp #{test_request.input_file_name}.files/* #{grading_room}"
31 system(cmd)
32 system(cmd)
33 + end
32
34
33 grading_room
35 grading_room
34 end
36 end
35
37
36 def find_problem_home(test_request)
38 def find_problem_home(test_request)
37 problem_name = test_request.problem_name
39 problem_name = test_request.problem_name
38
40
39 template_dir = "#{@config.test_request_problem_templates_dir}/" + problem_name
41 template_dir = "#{@config.test_request_problem_templates_dir}/" + problem_name
40
42
41 raise "Test Request: error template not found" if !File.exists?(template_dir)
43 raise "Test Request: error template not found" if !File.exists?(template_dir)
42
44
43 problem_home = problem_home_dir(test_request)
45 problem_home = problem_home_dir(test_request)
44 FileUtils.mkdir_p(problem_home)
46 FileUtils.mkdir_p(problem_home)
45
47
46 copy_problem_template(template_dir,problem_home)
48 copy_problem_template(template_dir,problem_home)
47 link_input_file(test_request,problem_home)
49 link_input_file(test_request,problem_home)
48
50
49 problem_home
51 problem_home
50 end
52 end
51
53
52 def save_source(test_request,source_name)
54 def save_source(test_request,source_name)
53 dir = self.produce_grading_room(test_request)
55 dir = self.produce_grading_room(test_request)
54 submission = test_request.submission
56 submission = test_request.submission
55 f = File.open("#{dir}/#{source_name}","w")
57 f = File.open("#{dir}/#{source_name}","w")
56 f.write(submission.source)
58 f.write(submission.source)
57 f.close
59 f.close
58 end
60 end
59
61
60 def clean_up(test_request)
62 def clean_up(test_request)
61 problem_home = problem_home_dir(test_request)
63 problem_home = problem_home_dir(test_request)
62 remove_data_files(problem_home)
64 remove_data_files(problem_home)
63 end
65 end
64
66
65 protected
67 protected
66 def grading_room_dir(test_request)
68 def grading_room_dir(test_request)
67 problem_name = test_request.problem_name
69 problem_name = test_request.problem_name
68 user = test_request.user
70 user = test_request.user
69 grading_room = "#{@config.user_result_dir}" +
71 grading_room = "#{@config.user_result_dir}" +
70 "/#{user.login}/test_request" +
72 "/#{user.login}/test_request" +
71 "/#{problem_name}/#{test_request.id}"
73 "/#{problem_name}/#{test_request.id}"
72 grading_room
74 grading_room
73 end
75 end
74
76
75 def problem_home_dir(test_request)
77 def problem_home_dir(test_request)
76 problem_name = test_request.problem_name
78 problem_name = test_request.problem_name
77 user = test_request.user
79 user = test_request.user
78 "#{@config.user_result_dir}" +
80 "#{@config.user_result_dir}" +
79 "/#{user.login}/test_request/#{problem_name}"
81 "/#{user.login}/test_request/#{problem_name}"
80 end
82 end
81
83
82 def copy_problem_template(template_dir,problem_home)
84 def copy_problem_template(template_dir,problem_home)
83 cmd = "cp -R #{template_dir}/* #{problem_home}"
85 cmd = "cp -R #{template_dir}/* #{problem_home}"
84 system_and_raise_when_fail(cmd,"Test Request: cannot copy problem template")
86 system_and_raise_when_fail(cmd,"Test Request: cannot copy problem template")
85 end
87 end
86
88
87 def link_input_file(test_request,problem_home)
89 def link_input_file(test_request,problem_home)
88 input_fname = "#{test_request.input_file_name}"
90 input_fname = "#{test_request.input_file_name}"
89 if !File.exists?(input_fname)
91 if !File.exists?(input_fname)
90 raise "Test Request: input file not found."
92 raise "Test Request: input file not found."
91 end
93 end
92
94
93 input_fname_problem_home = "#{problem_home}/test_cases/1/input-1.txt"
95 input_fname_problem_home = "#{problem_home}/test_cases/1/input-1.txt"
94 if File.exists?(input_fname_problem_home)
96 if File.exists?(input_fname_problem_home)
95 FileUtils.rm([input_fname_problem_home], :force => true)
97 FileUtils.rm([input_fname_problem_home], :force => true)
96 end
98 end
97
99
98 cmd = "ln -s #{input_fname} #{input_fname_problem_home}"
100 cmd = "ln -s #{input_fname} #{input_fname_problem_home}"
99 system_and_raise_when_fail(cmd,"Test Request: cannot link input file")
101 system_and_raise_when_fail(cmd,"Test Request: cannot link input file")
100 end
102 end
101
103
102 def remove_data_files(problem_home)
104 def remove_data_files(problem_home)
103 if File.exists?("#{problem_home}/test_cases/1/input-1.txt")
105 if File.exists?("#{problem_home}/test_cases/1/input-1.txt")
104 cmd = "rm #{problem_home}/test_cases/1/*"
106 cmd = "rm #{problem_home}/test_cases/1/*"
105 system_and_raise_when_fail(cmd,"Test Request: cannot remove data files")
107 system_and_raise_when_fail(cmd,"Test Request: cannot remove data files")
106 end
108 end
107 end
109 end
108
110
109 def system_and_raise_when_fail(cmd,msg)
111 def system_and_raise_when_fail(cmd,msg)
110 if !system(cmd)
112 if !system(cmd)
111 raise msg
113 raise msg
112 end
114 end
113 end
115 end
114
116
115 end
117 end
116
118
117 class TestRequestReporter
119 class TestRequestReporter
118 def initialize
120 def initialize
119 @config = Grader::Configuration.get_instance
121 @config = Grader::Configuration.get_instance
120 end
122 end
121
123
122 def report(test_request,test_result_dir)
124 def report(test_request,test_result_dir)
123 save_result(test_request,read_result(test_result_dir))
125 save_result(test_request,read_result(test_result_dir))
124 end
126 end
125
127
126 def report_error(test_request, msg)
128 def report_error(test_request, msg)
127 save_result(test_request, {:running_stat => {
129 save_result(test_request, {:running_stat => {
128 :msg => "#{msg}",
130 :msg => "#{msg}",
129 :running_time => nil,
131 :running_time => nil,
130 :exit_status => "Some error occured. Program did not run",
132 :exit_status => "Some error occured. Program did not run",
131 :memory_usage => nil
133 :memory_usage => nil
132 }})
134 }})
133 end
135 end
134
136
135 protected
137 protected
136 def read_result(test_result_dir)
138 def read_result(test_result_dir)
137 # TODO:
139 # TODO:
138 cmp_msg_fname = "#{test_result_dir}/compiler_message"
140 cmp_msg_fname = "#{test_result_dir}/compiler_message"
139 cmp_file = File.open(cmp_msg_fname)
141 cmp_file = File.open(cmp_msg_fname)
140 cmp_msg = cmp_file.read
142 cmp_msg = cmp_file.read
141 cmp_file.close
143 cmp_file.close
142
144
143 result_file_name = "#{test_result_dir}/1/result"
145 result_file_name = "#{test_result_dir}/1/result"
144
146
145 if File.exists?(result_file_name)
147 if File.exists?(result_file_name)
146 output_file_name = "#{test_result_dir}/1/output.txt"
148 output_file_name = "#{test_result_dir}/1/output.txt"
147 results = File.open("#{test_result_dir}/1/result").readlines
149 results = File.open("#{test_result_dir}/1/result").readlines
148 stat = extract_running_stat(results)
150 stat = extract_running_stat(results)
149
151
150 return {
152 return {
151 :output_file_name => output_file_name,
153 :output_file_name => output_file_name,
152 :running_stat => stat,
154 :running_stat => stat,
153 :comment => "",
155 :comment => "",
154 :cmp_msg => cmp_msg}
156 :cmp_msg => cmp_msg}
155 else
157 else
156 return {
158 return {
157 :running_stat => nil,
159 :running_stat => nil,
158 :comment => "Compilation error",
160 :comment => "Compilation error",
159 :cmp_msg => cmp_msg}
161 :cmp_msg => cmp_msg}
160 end
162 end
161 end
163 end
162
164
163 def extract_running_stat(results)
165 def extract_running_stat(results)
164 running_stat_line = results[-1]
166 running_stat_line = results[-1]
165
167
166 # extract exit status line
168 # extract exit status line
167 run_stat = ""
169 run_stat = ""
168 if !(/[Cc]orrect/.match(results[0]))
170 if !(/[Cc]orrect/.match(results[0]))
169 run_stat = results[0].chomp
171 run_stat = results[0].chomp
170 else
172 else
171 run_stat = 'Program exited normally'
173 run_stat = 'Program exited normally'
172 end
174 end
173
175
174 # extract running time
176 # extract running time
175 if res = /r(.*)u(.*)s/.match(running_stat_line)
177 if res = /r(.*)u(.*)s/.match(running_stat_line)
176 seconds = (res[1].to_f + res[2].to_f)
178 seconds = (res[1].to_f + res[2].to_f)
177 time_stat = "Time used: #{seconds} sec."
179 time_stat = "Time used: #{seconds} sec."
178 else
180 else
179 seconds = nil
181 seconds = nil
180 time_stat = "Time used: n/a sec."
182 time_stat = "Time used: n/a sec."
181 end
183 end
182
184
183 # extract memory usage
185 # extract memory usage
184 if res = /s(.*)m/.match(running_stat_line)
186 if res = /s(.*)m/.match(running_stat_line)
185 memory_used = res[1].to_i
187 memory_used = res[1].to_i
186 else
188 else
187 memory_used = -1
189 memory_used = -1
188 end
190 end
189
191
190 return {
192 return {
191 :msg => "#{run_stat}\n#{time_stat}",
193 :msg => "#{run_stat}\n#{time_stat}",
192 :running_time => seconds,
194 :running_time => seconds,
193 :exit_status => run_stat,
195 :exit_status => run_stat,
194 :memory_usage => memory_used
196 :memory_usage => memory_used
195 }
197 }
196 end
198 end
197
199
198 def save_result(test_request,result)
200 def save_result(test_request,result)
199 if result[:output_file_name]!=nil
201 if result[:output_file_name]!=nil
200 test_request.output_file_name = link_output_file(test_request,
202 test_request.output_file_name = link_output_file(test_request,
201 result[:output_file_name])
203 result[:output_file_name])
202 end
204 end
203 test_request.graded_at = Time.now
205 test_request.graded_at = Time.now
204 test_request.compiler_message = (result[:cmp_msg] or '')
206 test_request.compiler_message = (result[:cmp_msg] or '')
205 test_request.grader_comment = (result[:comment] or '')
207 test_request.grader_comment = (result[:comment] or '')
206 if result[:running_stat]!=nil
208 if result[:running_stat]!=nil
207 test_request.running_stat = (result[:running_stat][:msg] or '')
209 test_request.running_stat = (result[:running_stat][:msg] or '')
208 test_request.running_time = (result[:running_stat][:running_time] or nil)
210 test_request.running_time = (result[:running_stat][:running_time] or nil)
209 test_request.exit_status = result[:running_stat][:exit_status]
211 test_request.exit_status = result[:running_stat][:exit_status]
210 test_request.memory_usage = result[:running_stat][:memory_usage]
212 test_request.memory_usage = result[:running_stat][:memory_usage]
211 else
213 else
212 test_request.running_stat = ''
214 test_request.running_stat = ''
213 end
215 end
214 test_request.save
216 test_request.save
215 end
217 end
216
218
217 protected
219 protected
218 def link_output_file(test_request, fname)
220 def link_output_file(test_request, fname)
219 target_file_name = random_output_file_name(test_request.user,
221 target_file_name = random_output_file_name(test_request.user,
220 test_request.problem)
222 test_request.problem)
221 FileUtils.mkdir_p(File.dirname(target_file_name))
223 FileUtils.mkdir_p(File.dirname(target_file_name))
222 cmd = "ln -s #{fname} #{target_file_name}"
224 cmd = "ln -s #{fname} #{target_file_name}"
223 if !system(cmd)
225 if !system(cmd)
@@ -1,108 +1,106
1 #!/usr/bin/ruby
1 #!/usr/bin/ruby
2
2
3 CORRECT_MARK = 'P'
3 CORRECT_MARK = 'P'
4 INCORRECT_MARK = '-'
4 INCORRECT_MARK = '-'
5 TIMEOUT_MARK = 'T'
5 TIMEOUT_MARK = 'T'
6 RUN_ERROR_MARK = 'x'
6 RUN_ERROR_MARK = 'x'
7
7
8 def log(str='')
8 def log(str='')
9 if ENV['TALKATIVE']!=nil
9 if ENV['TALKATIVE']!=nil
10 puts str
10 puts str
11 end
11 end
12 if ENV['GRADER_LOGGING']!=nil
12 if ENV['GRADER_LOGGING']!=nil
13 log_fname = ENV['GRADER_LOGGING']
13 log_fname = ENV['GRADER_LOGGING']
14 fp = File.open(log_fname,"a")
14 fp = File.open(log_fname,"a")
15 fp.puts("grade: #{Time.new.strftime("%H:%M")} #{str}")
15 fp.puts("grade: #{Time.new.strftime("%H:%M")} #{str}")
16 fp.close
16 fp.close
17 end
17 end
18 end
18 end
19
19
20 def char_comment(comment)
20 def char_comment(comment)
21 if comment =~ /[Ii]ncorrect/
21 if comment =~ /[Ii]ncorrect/
22 INCORRECT_MARK
22 INCORRECT_MARK
23 elsif comment =~ /[Cc]orrect/
23 elsif comment =~ /[Cc]orrect/
24 CORRECT_MARK
24 CORRECT_MARK
25 elsif comment =~ /[Tt]ime/
25 elsif comment =~ /[Tt]ime/
26 TIMEOUT_MARK
26 TIMEOUT_MARK
27 elsif res = /^[Cc]omment:(.*)$/.match(comment)
27 elsif res = /^[Cc]omment:(.*)$/.match(comment)
28 res[1]
28 res[1]
29 else
29 else
30 RUN_ERROR_MARK # these are run time errors
30 RUN_ERROR_MARK # these are run time errors
31 end
31 end
32 end
32 end
33
33
34 problem_home = ENV['PROBLEM_HOME']
34 problem_home = ENV['PROBLEM_HOME']
35 require "#{problem_home}/script/test_dsl.rb"
35 require "#{problem_home}/script/test_dsl.rb"
36 load "#{problem_home}/test_cases/all_tests.cfg"
36 load "#{problem_home}/test_cases/all_tests.cfg"
37 problem = Problem.get_instance
37 problem = Problem.get_instance
38
38
39 if problem.well_formed? == false
39 if problem.well_formed? == false
40 log "The problem specification is not well formed."
40 log "The problem specification is not well formed."
41 exit(127)
41 exit(127)
42 end
42 end
43
43
44 all_score = 0
44 all_score = 0
45 all_comment = ''
45 all_comment = ''
46 (1..(problem.runs.length-1)).each do |k|
46 (1..(problem.runs.length-1)).each do |k|
47 log "grade run #{k}"
47 log "grade run #{k}"
48 run = problem.runs[k]
48 run = problem.runs[k]
49 - run_score = 0
49 + run_score = nil
50 run_comment = ''
50 run_comment = ''
51 run_comment_short = ''
51 run_comment_short = ''
52 run.tests.each do |test_num|
52 run.tests.each do |test_num|
53 result_file_name = "#{test_num}/result"
53 result_file_name = "#{test_num}/result"
54 if not File.exists?(result_file_name)
54 if not File.exists?(result_file_name)
55 run_comment += "result file for test #{test_num} not found\n"
55 run_comment += "result file for test #{test_num} not found\n"
56 run_comment_short += RUN_ERROR_MARK
56 run_comment_short += RUN_ERROR_MARK
57 log "Cannot find the file #{test_num}/result!"
57 log "Cannot find the file #{test_num}/result!"
58 else
58 else
59 result_file = File.new(result_file_name, "r")
59 result_file = File.new(result_file_name, "r")
60 result_file_lines = result_file.readlines
60 result_file_lines = result_file.readlines
61 if result_file_lines.length>=2
61 if result_file_lines.length>=2
62 - run_score = run_score + result_file_lines[1].to_i
62 + current_run_score = result_file_lines[1].to_i
63 run_comment += result_file_lines[0]
63 run_comment += result_file_lines[0]
64 run_comment_short += char_comment(result_file_lines[0].chomp)
64 run_comment_short += char_comment(result_file_lines[0].chomp)
65 else
65 else
66 + current_run_score = 0
66 run_comment += "result file for test #{test_num} error\n"
67 run_comment += "result file for test #{test_num} error\n"
67 run_comment_short += RUN_ERROR_MARK
68 run_comment_short += RUN_ERROR_MARK
68 log "Error in #{test_num}/result!"
69 log "Error in #{test_num}/result!"
69 end
70 end
71 +
72 + # the score of this run should be the minimum of the score for
73 + # each test case
74 + if (run_score==nil) or (run_score>current_run_score)
75 + run_score = current_run_score
76 + end
70 result_file.close
77 result_file.close
71 end
78 end
72 end
79 end
73
80
74 - # find total score for this run
75 - run_total_score = 0
76 - problem = Problem.get_instance
77 - run.tests.each { |test_num| run_total_score += problem.get_score(test_num) }
78 -
79 - if run_total_score!=run_score # fail in some test cases, fail the run
80 - run_score = 0
81 - end
82 -
83 run_result_file = File.new("result-#{k}", "w")
81 run_result_file = File.new("result-#{k}", "w")
84 run_result_file.write run_score
82 run_result_file.write run_score
85 run_result_file.write "\n"
83 run_result_file.write "\n"
86 run_result_file.close
84 run_result_file.close
87
85
88 run_comment_file = File.new("comment-#{k}", "w")
86 run_comment_file = File.new("comment-#{k}", "w")
89 run_comment_file.write "#{run_comment}\n"
87 run_comment_file.write "#{run_comment}\n"
90 run_comment_file.close
88 run_comment_file.close
91
89
92 all_score = all_score + run_score
90 all_score = all_score + run_score
93
91
94 # append comment for test run with many test cases
92 # append comment for test run with many test cases
95 if run.tests.length > 1
93 if run.tests.length > 1
96 run_comment_short = '[' + run_comment_short + ']'
94 run_comment_short = '[' + run_comment_short + ']'
97 end
95 end
98 all_comment += run_comment_short
96 all_comment += run_comment_short
99 end
97 end
100
98
101 result_file = File.new("result", "w")
99 result_file = File.new("result", "w")
102 result_file.write all_score
100 result_file.write all_score
103 result_file.write "\n"
101 result_file.write "\n"
104 result_file.close
102 result_file.close
105
103
106 comment_file = File.new("comment", "w")
104 comment_file = File.new("comment", "w")
107 comment_file.write "#{all_comment}\n"
105 comment_file.write "#{all_comment}\n"
108 comment_file.close
106 comment_file.close
@@ -1,20 +1,20
1 problem do
1 problem do
2 num_tests <%= num_testcases %>
2 num_tests <%= num_testcases %>
3 full_score <%= num_testruns*10 %>
3 full_score <%= num_testruns*10 %>
4 time_limit_each <%= options[:time_limit] %>
4 time_limit_each <%= options[:time_limit] %>
5 mem_limit_each <%= options[:mem_limit] %>
5 mem_limit_each <%= options[:mem_limit] %>
6 score_each 10
6 score_each 10
7
7
8 <% tr_num = 0 %>
8 <% tr_num = 0 %>
9 <% testrun_info.each do |testrun| %>
9 <% testrun_info.each do |testrun| %>
10 <% tr_num += 1 %>
10 <% tr_num += 1 %>
11 run <%= tr_num %> do
11 run <%= tr_num %> do
12 tests <%= (testrun.collect {|testcase| testcase[0]}).join(", ") %>
12 tests <%= (testrun.collect {|testcase| testcase[0]}).join(", ") %>
13 <% if testrun.length==1 %>
13 <% if testrun.length==1 %>
14 scores 10
14 scores 10
15 <% else %>
15 <% else %>
16 - scores 10 <% (testrun.length-1).times do %>,0 <% end %>
16 + scores 10 <% (testrun.length-1).times do %>,10 <% end %>
17 <% end %>
17 <% end %>
18 end
18 end
19 <% end %>
19 <% end %>
20 end
20 end
@@ -1,39 +1,40
1 problem do
1 problem do
2 num_tests 10
2 num_tests 10
3 full_score 135
3 full_score 135
4 time_limit_each 1
4 time_limit_each 1
5 mem_limit_each 11
5 mem_limit_each 11
6 score_each 10
6 score_each 10
7
7
8 run 1 do
8 run 1 do
9 tests 1, 2
9 tests 1, 2
10 - scores 10, 20
10 + scores 30, 30
11 time_limits 1, 2
11 time_limits 1, 2
12 mem_limits 5, 6
12 mem_limits 5, 6
13 end
13 end
14
14
15 run 2 do
15 run 2 do
16 tests 3, 4, 5, 6, 7
16 tests 3, 4, 5, 6, 7
17 - score_each 10
17 + score_each 50
18 time_limit_each 3
18 time_limit_each 3
19 mem_limit_each 3
19 mem_limit_each 3
20 end
20 end
21
21
22 run 3 do
22 run 3 do
23 tests 8, 9, 10
23 tests 8, 9, 10
24 end
24 end
25
25
26 test 8 do
26 test 8 do
27 - score 30
27 + score 55
28 time_limit 3
28 time_limit 3
29 mem_limit 10
29 mem_limit 10
30 end
30 end
31
31
32 test 9 do
32 test 9 do
33 - score 15
33 + score 55
34 end
34 end
35
35
36 test 10 do
36 test 10 do
37 + score 55
37 time_limit 1
38 time_limit 1
38 end
39 end
39 end
40 end
You need to be logged in to leave comments. Login now