Description:
added grading report
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r92:274af5f15b1f - - 4 files changed: 95 inserted, 21 deleted

@@ -47,30 +47,24
47 Grader.
47 Grader.
48 using: (1) grader
48 using: (1) grader
49 (2) grader environment [mode]
49 (2) grader environment [mode]
50 (3) grader stop [all|pids-list]
50 (3) grader stop [all|pids-list]
51 (4) grader --help
51 (4) grader --help
52 (1) call grader with environment = 'exam', mode = 'queue'
52 (1) call grader with environment = 'exam', mode = 'queue'
53 (2) possible modes are: 'queue', 'prob', 'test_request'
53 (2) possible modes are: 'queue', 'prob', 'test_request'
54 (3) create stop-file to stop running grader in queue mode
54 (3) create stop-file to stop running grader in queue mode
55 (4) You are here.
55 (4) You are here.
56 USAGE
56 USAGE
57 end
57 end
58
58
59 - #########################################
60 - # main program
61 - #########################################
62 -
63 - # Reading environment and options.
64 -
65 def process_options_and_stop_file
59 def process_options_and_stop_file
66 # The list of options are:
60 # The list of options are:
67 # - stop [all|process ids]
61 # - stop [all|process ids]
68 # -
62 # -
69
63
70 # Process 'help' option
64 # Process 'help' option
71 if (ARGV.length==1) and (/help/.match(ARGV[0]))
65 if (ARGV.length==1) and (/help/.match(ARGV[0]))
72 display_manual
66 display_manual
73 exit(0)
67 exit(0)
74 end
68 end
75
69
76 # Process 'stop' option.
70 # Process 'stop' option.
@@ -106,32 +100,83
106 }
100 }
107
101
108 # Process mode and environment option
102 # Process mode and environment option
109 if ARGV.length >= 1
103 if ARGV.length >= 1
110 options[:environment] = ARGV.shift
104 options[:environment] = ARGV.shift
111 if ARGV.length >=1
105 if ARGV.length >=1
112 options[:mode] = ARGV.shift
106 options[:mode] = ARGV.shift
113 end
107 end
114 end
108 end
115
109
116 options[:dry_run] = (ARGV.delete('--dry') != nil)
110 options[:dry_run] = (ARGV.delete('--dry') != nil)
117 if options[:dry_run] and (not options[:mode] == 'prob')
111 if options[:dry_run] and (not options[:mode] == 'prob')
118 - puts "Dry run currently works for 'prob' mode."
112 + puts "Dry run currently works only for 'prob' mode."
113 + exit(0)
114 + end
115 +
116 + options[:report] = (ARGV.delete('--report') != nil)
117 + if options[:report] and (not options[:mode] == 'prob')
118 + puts "Report currently works only for 'prob' mode."
119 exit(0)
119 exit(0)
120 end
120 end
121
121
122 return options
122 return options
123 end
123 end
124
124
125 - # ======= Main ========
125 + class ResultCollector
126 + def initialize
127 + @results = {}
128 + @problems = {}
129 + @users = {}
130 + end
131 +
132 + def save(user, problem, grading_result)
133 + if not @problems.has_key? problem.id
134 + @problems[problem.id] = problem
135 + end
136 + if not @users.has_key? user.id
137 + @users[user.id] = user
138 + end
139 + @results[[user.id, problem.id]] = grading_result
140 + end
141 +
142 + def print_report_by_user
143 + puts "---------------------"
144 + puts " REPORT"
145 + puts "---------------------"
146 +
147 + print "login"
148 + @problems.each_value do |problem|
149 + print ",#{problem.name}"
150 + end
151 + print "\n"
152 +
153 + @users.each_value do |user|
154 + print "#{user.login}"
155 + @problems.each_value do |problem|
156 + if @results.has_key? [user.id, problem.id]
157 + print ",#{@results[[user.id,problem.id]][:points]}"
158 + else
159 + print ","
160 + end
161 + end
162 + print "\n"
163 + end
164 + end
165 + end
166 +
167 + #########################################
168 + # main program
169 + #########################################
170 +
126 options = process_options_and_stop_file
171 options = process_options_and_stop_file
127 GRADER_ENV = options[:environment]
172 GRADER_ENV = options[:environment]
128 grader_mode = options[:mode]
173 grader_mode = options[:mode]
129 dry_run = options[:dry_run]
174 dry_run = options[:dry_run]
130
175
131 puts "environment: #{GRADER_ENV}"
176 puts "environment: #{GRADER_ENV}"
132 require File.join(File.dirname(__FILE__),'config/environment')
177 require File.join(File.dirname(__FILE__),'config/environment')
133
178
134 # add grader_mode to config
179 # add grader_mode to config
135 # this is needed because method log needs it. TODO: clean this up
180 # this is needed because method log needs it. TODO: clean this up
136 class << config
181 class << config
137 attr_accessor :grader_mode
182 attr_accessor :grader_mode
@@ -165,62 +210,75
165 end
210 end
166
211
167 #
212 #
168 # MAIN LOOP
213 # MAIN LOOP
169 #
214 #
170
215
171 case grader_mode
216 case grader_mode
172 when "queue", "test_request"
217 when "queue", "test_request"
173 log "Grader: #{grader_mode}"
218 log "Grader: #{grader_mode}"
174 if grader_mode=="queue"
219 if grader_mode=="queue"
175 engine = Grader::Engine.new
220 engine = Grader::Engine.new
176 else
221 else
177 - engine = Grader::Engine.new(Grader::TestRequestRoomMaker.new,
222 + engine = Grader::Engine.new(:room_maker => Grader::TestRequestRoomMaker.new,
178 - Grader::TestRequestReporter.new)
223 + :reporter => Grader::TestRequestReporter.new)
179 end
224 end
180
225
181 runner = Grader::Runner.new(engine, grader_proc)
226 runner = Grader::Runner.new(engine, grader_proc)
182 while true
227 while true
183
228
184 if check_stopfile # created by calling grader stop
229 if check_stopfile # created by calling grader stop
185 clear_stopfile
230 clear_stopfile
186 log "stopped (with stop file)"
231 log "stopped (with stop file)"
187 break
232 break
188 end
233 end
189
234
190 if grader_mode=="queue"
235 if grader_mode=="queue"
191 task = runner.grade_oldest_task
236 task = runner.grade_oldest_task
192 else
237 else
193 task = runner.grade_oldest_test_request
238 task = runner.grade_oldest_test_request
194 end
239 end
195 if task==nil
240 if task==nil
196 sleep(1)
241 sleep(1)
197 end
242 end
198 end
243 end
199
244
200 when "prob"
245 when "prob"
201 - engine = Grader::Engine.new(nil, Grader::SubmissionReporter.new(dry_run))
246 + if options[:report]
247 + result_collector = ResultCollector.new
248 + else
249 + result_collector = nil
250 + end
251 +
252 + engine = (Grader::Engine.
253 + new(:reporter =>
254 + Grader::SubmissionReporter.new(:dry_run => dry_run,
255 + :result_collector => result_collector)))
202 runner = Grader::Runner.new(engine, grader_proc)
256 runner = Grader::Runner.new(engine, grader_proc)
203 -
257 +
204 grader_proc.report_active if grader_proc!=nil
258 grader_proc.report_active if grader_proc!=nil
205 -
259 +
206 ARGV.each do |prob_name|
260 ARGV.each do |prob_name|
207 prob = Problem.find_by_name(prob_name)
261 prob = Problem.find_by_name(prob_name)
208 if prob==nil
262 if prob==nil
209 puts "cannot find problem: #{prob_name}"
263 puts "cannot find problem: #{prob_name}"
210 else
264 else
211 runner.grade_problem(prob)
265 runner.grade_problem(prob)
212 end
266 end
213 end
267 end
214
268
269 + if options[:report]
270 + result_collector.print_report_by_user
271 + end
272 +
215 when "sub"
273 when "sub"
216 engine = Grader::Engine.new
274 engine = Grader::Engine.new
217 runner = Grader::Runner.new(engine, grader_proc)
275 runner = Grader::Runner.new(engine, grader_proc)
218
276
219 grader_proc.report_active if grader_proc!=nil
277 grader_proc.report_active if grader_proc!=nil
220
278
221 ARGV.each do |sub_id|
279 ARGV.each do |sub_id|
222 puts "Grading #{sub_id}"
280 puts "Grading #{sub_id}"
223 begin
281 begin
224 submission = Submission.find(sub_id.to_i)
282 submission = Submission.find(sub_id.to_i)
225 rescue ActiveRecord::RecordNotFound
283 rescue ActiveRecord::RecordNotFound
226 puts "Record not found"
284 puts "Record not found"
@@ -5,29 +5,37
5 module Grader
5 module Grader
6
6
7 #
7 #
8 # A grader engine grades a submission, against anything: a test
8 # A grader engine grades a submission, against anything: a test
9 # data, or a user submitted test data. It uses two helpers objects:
9 # data, or a user submitted test data. It uses two helpers objects:
10 # room_maker and reporter.
10 # room_maker and reporter.
11 #
11 #
12 class Engine
12 class Engine
13
13
14 attr_writer :room_maker
14 attr_writer :room_maker
15 attr_writer :reporter
15 attr_writer :reporter
16
16
17 - def initialize(room_maker=nil, reporter=nil)
17 + def initialize(options={})
18 + # default options
19 + if not options.include? :room_maker
20 + options[:room_maker] = Grader::SubmissionRoomMaker.new
21 + end
22 + if not options.include? :reporter
23 + options[:reporter] = Grader::SubmissionReporter.new
24 + end
25 +
18 @config = Grader::Configuration.get_instance
26 @config = Grader::Configuration.get_instance
19
27
20 - @room_maker = room_maker || Grader::SubmissionRoomMaker.new
28 + @room_maker = options[:room_maker]
21 - @reporter = reporter || Grader::SubmissionReporter.new
29 + @reporter = options[:reporter]
22 end
30 end
23
31
24 # takes a submission, asks room_maker to produce grading directories,
32 # takes a submission, asks room_maker to produce grading directories,
25 # calls grader scripts, and asks reporter to save the result
33 # calls grader scripts, and asks reporter to save the result
26 def grade(submission)
34 def grade(submission)
27 current_dir = `pwd`.chomp
35 current_dir = `pwd`.chomp
28
36
29 user = submission.user
37 user = submission.user
30 problem = submission.problem
38 problem = submission.problem
31
39
32 # TODO: will have to create real exception for this
40 # TODO: will have to create real exception for this
33 if user==nil or problem == nil
41 if user==nil or problem == nil
@@ -23,31 +23,39
23 def save_source(submission,source_name)
23 def save_source(submission,source_name)
24 dir = self.produce_grading_room(submission)
24 dir = self.produce_grading_room(submission)
25 f = File.open("#{dir}/#{source_name}","w")
25 f = File.open("#{dir}/#{source_name}","w")
26 f.write(submission.source)
26 f.write(submission.source)
27 f.close
27 f.close
28 end
28 end
29
29
30 def clean_up(submission)
30 def clean_up(submission)
31 end
31 end
32 end
32 end
33
33
34 class SubmissionReporter
34 class SubmissionReporter
35 - def initialize(dry_run=false)
35 + def initialize(options={})
36 + options = {:dry_run => false, :result_collector => nil}.merge(options)
36 @config = Grader::Configuration.get_instance
37 @config = Grader::Configuration.get_instance
37 - @dry_run = dry_run
38 + @dry_run = options[:dry_run]
39 + @result_collector = options[:result_collector]
38 end
40 end
39
41
40 def report(sub,test_result_dir)
42 def report(sub,test_result_dir)
41 - save_result(sub,read_result(test_result_dir))
43 + result = read_result(test_result_dir)
44 + if @result_collector
45 + @result_collector.save(sub.user,
46 + sub.problem,
47 + result)
48 + end
49 + save_result(sub,result)
42 end
50 end
43
51
44 def report_error(sub,msg)
52 def report_error(sub,msg)
45 save_result(sub,{:points => 0,
53 save_result(sub,{:points => 0,
46 :comment => "Grading error: #{msg}" })
54 :comment => "Grading error: #{msg}" })
47 end
55 end
48
56
49 protected
57 protected
50 def read_result(test_result_dir)
58 def read_result(test_result_dir)
51 cmp_msg_fname = "#{test_result_dir}/compiler_message"
59 cmp_msg_fname = "#{test_result_dir}/compiler_message"
52 if FileTest.exist?(cmp_msg_fname)
60 if FileTest.exist?(cmp_msg_fname)
53 cmp_file = File.open(cmp_msg_fname)
61 cmp_file = File.open(cmp_msg_fname)
@@ -147,26 +147,26
147 def create_normal_submission_mock_from_file(source_fname)
147 def create_normal_submission_mock_from_file(source_fname)
148 create_submission_from_file(1, @user_user1, @problem_test_normal, source_fname)
148 create_submission_from_file(1, @user_user1, @problem_test_normal, source_fname)
149 end
149 end
150
150
151 end
151 end
152
152
153 describe "A grader engine, when grading test requests" do
153 describe "A grader engine, when grading test requests" do
154
154
155 include GraderEngineHelperMethods
155 include GraderEngineHelperMethods
156
156
157 before(:each) do
157 before(:each) do
158 @config = Grader::Configuration.get_instance
158 @config = Grader::Configuration.get_instance
159 - @engine = Grader::Engine.new(Grader::TestRequestRoomMaker.new,
159 + @engine = Grader::Engine.new(:room_maker => Grader::TestRequestRoomMaker.new,
160 - Grader::TestRequestReporter.new)
160 + :reporter => Grader::TestRequestReporter.new)
161 init_sandbox
161 init_sandbox
162 end
162 end
163
163
164 it "should report error if there is no problem template" do
164 it "should report error if there is no problem template" do
165 problem = stub(Problem,
165 problem = stub(Problem,
166 :id => 1, :name => 'nothing')
166 :id => 1, :name => 'nothing')
167 grader_should(:grade => 'test1_correct.c',
167 grader_should(:grade => 'test1_correct.c',
168 :on => problem,
168 :on => problem,
169 :with => 'in1.txt',
169 :with => 'in1.txt',
170 :and_report => {
170 :and_report => {
171 :graded_at= => nil,
171 :graded_at= => nil,
172 :compiler_message= => '',
172 :compiler_message= => '',
You need to be logged in to leave comments. Login now