# HG changeset patch
# User jittat
# Date 2008-05-11 13:26:41
# Node ID d2c58c8570089fdf43aec5674fdb65463edaa242
# Parent d6c2c8c51d7f1dcdc68c4774e19db8b93a1a190e
[web] analysis mode
git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@265 6386c4cd-e34a-4fa8-8920-d93eb39b512e
diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb
--- a/app/controllers/main_controller.rb
+++ b/app/controllers/main_controller.rb
@@ -125,6 +125,46 @@
end
end
+ def result
+ if !Configuration.show_grading_result
+ redirect_to :action => 'list' and return
+ end
+ @user = User.find(session[:user_id])
+ @submission = Submission.find(params[:id])
+ if @submission.user!=@user
+ flash[:notice] = 'You are not allowed to view result of other users.'
+ redirect_to :action => 'list' and return
+ end
+ prepare_grading_result(@submission)
+ end
+
+ def load_output
+ if !Configuration.show_grading_result or params[:num]==nil
+ redirect_to :action => 'list' and return
+ end
+ @user = User.find(session[:user_id])
+ @submission = Submission.find(params[:id])
+ if @submission.user!=@user
+ flash[:notice] = 'You are not allowed to view result of other users.'
+ redirect_to :action => 'list' and return
+ end
+ case_num = params[:num].to_i
+ out_filename = output_filename(@user.login,
+ @submission.problem.name,
+ @submission.id,
+ case_num)
+ if !FileTest.exists?(out_filename)
+ flash[:notice] = 'Output not found.'
+ redirect_to :action => 'list' and return
+ end
+
+ response.headers['Content-Type'] = "application/force-download"
+ response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
+ response.headers["X-Sendfile"] = out_filename
+ response.headers['Content-length'] = File.size(out_filename)
+ render :nothing => true
+ end
+
def error
@user = User.find(session[:user_id])
end
@@ -156,5 +196,105 @@
end
end
+ def prepare_grading_result(submission)
+ grading_info = Configuration.task_grading_info[submission.problem.name]
+ @test_runs = []
+ if grading_info['testruns'].is_a? Integer
+ trun_count = grading_info['testruns']
+ trun_count.times do |i|
+ @test_runs << [ read_grading_result(@user.login,
+ submission.problem.name,
+ submission.id,
+ i+1) ]
+ end
+ else
+ grading_info['testruns'].keys.sort.each do |num|
+ run = []
+ testrun = grading_info['testruns'][num]
+ testrun.each do |c|
+ run << read_grading_result(@user.login,
+ submission.problem.name,
+ submission.id,
+ c)
+ end
+ @test_runs << run
+ end
+ end
+ end
+
+ def grading_result_dir(user_name, problem_name, submission_id, case_num)
+ return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
+ end
+
+ def output_filename(user_name, problem_name, submission_id, case_num)
+ dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
+ return "#{dir}/output.txt"
+ end
+
+ def read_grading_result(user_name, problem_name, submission_id, case_num)
+ dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
+ result_file_name = "#{dir}/result"
+ if !FileTest.exists?(result_file_name)
+ return {:num => case_num, :msg => 'program did not run'}
+ else
+ results = File.open(result_file_name).readlines
+ run_stat = extract_running_stat(results)
+ output_filename = "#{dir}/output.txt"
+ if FileTest.exists?(output_filename)
+ output_file = true
+ output_size = File.size(output_filename)
+ else
+ output_file = false
+ output_size = 0
+ end
+
+ return {
+ :num => case_num,
+ :msg => results[0],
+ :run_stat => run_stat,
+ :output => output_file,
+ :output_size => output_size
+ }
+ end
+ end
+
+ # copied from grader/script/lib/test_request_helper.rb
+ def extract_running_stat(results)
+ running_stat_line = results[-1]
+
+ # extract exit status line
+ run_stat = ""
+ if !(/[Cc]orrect/.match(results[0]))
+ run_stat = results[0].chomp
+ else
+ run_stat = 'Program exited normally'
+ end
+
+ logger.info "Stat line: #{running_stat_line}"
+
+ # extract running time
+ if res = /r(.*)u(.*)s/.match(running_stat_line)
+ seconds = (res[1].to_f + res[2].to_f)
+ time_stat = "Time used: #{seconds} sec."
+ else
+ seconds = nil
+ time_stat = "Time used: n/a sec."
+ end
+
+ # extract memory usage
+ if res = /s(.*)m/.match(running_stat_line)
+ memory_used = res[1].to_i
+ else
+ memory_used = -1
+ end
+
+ return {
+ :msg => "#{run_stat}\n#{time_stat}",
+ :running_time => seconds,
+ :exit_status => run_stat,
+ :memory_usage => memory_used
+ }
+ end
+
end
diff --git a/app/models/configuration.rb b/app/models/configuration.rb
--- a/app/models/configuration.rb
+++ b/app/models/configuration.rb
@@ -1,3 +1,5 @@
+require 'yaml'
+
#
# This class also contains various login of the system.
#
@@ -6,6 +8,7 @@
SYSTEM_MODE_CONF_KEY = 'system.mode'
@@configurations = nil
+ @@task_grading_info = nil
def self.get(key)
if @@configurations == nil
@@ -47,6 +50,10 @@
return true
end
+ def self.show_grading_result
+ return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
+ end
+
def self.allow_test_request(user)
mode = get(SYSTEM_MODE_CONF_KEY)
if (mode=='contest')
@@ -55,6 +62,13 @@
return false if mode=='analysis'
return true
end
+
+ def self.task_grading_info
+ if @@task_grading_info==nil
+ read_grading_info
+ end
+ return @@task_grading_info
+ end
protected
def self.read_config
@@ -74,5 +88,11 @@
end
end
end
+
+ def self.read_grading_info
+ f = File.open(TASK_GRADING_INFO_FILENAME)
+ @@task_grading_info = YAML.load(f)
+ f.close
+ end
end
diff --git a/app/views/main/_submission_short.html.haml b/app/views/main/_submission_short.html.haml
--- a/app/views/main/_submission_short.html.haml
+++ b/app/views/main/_submission_short.html.haml
@@ -12,9 +12,12 @@
%tt
= submission.grader_comment
= "]"
+ - if Configuration.show_grading_result
+ = " | "
+ = link_to '[detailed result]', :action => 'result', :id => submission.id
= " | "
= link_to('[msg]', {:action => 'compiler_msg', :id => submission.id}, {:popup => true})
= " | "
- = link_to('[source]',{:action => 'source', :id => submission.id})
+ = link_to('[src]',{:action => 'source', :id => submission.id})
= " | "
= link_to '[submissions]', :action => 'submission', :id => problem_name
diff --git a/app/views/main/_test_case_result.html.haml b/app/views/main/_test_case_result.html.haml
new file mode 100644
--- /dev/null
+++ b/app/views/main/_test_case_result.html.haml
@@ -0,0 +1,18 @@
+%td
+ = test_case[:num]
+%td{:style => 'padding-left: 5px; padding-right: 5px'}
+ = test_case[:msg]
+- if test_case[:run_stat]!=nil
+ %td{:style => 'padding-left: 5px; padding-right: 5px'}
+ = test_case[:run_stat][:exit_status]
+ %td{:style => 'padding-left: 5px; padding-right: 3px; text-align: center'}
+ = test_case[:run_stat][:running_time]
+ %td{:style => 'padding-left: 5px; padding-right: 10px; text-align: right'}
+ = number_with_delimiter(test_case[:run_stat][:memory_usage])
+ %td{:style => 'padding-left: 5px; padding-right: 5px'}
+ = link_to "output (#{number_to_human_size(test_case[:output_size])})", :action => 'load_output', :id => @submission.id, :num => test_case[:num] if test_case[:output]
+- else
+ %td
+ %td
+ %td
+ %td
diff --git a/app/views/main/result.html.haml b/app/views/main/result.html.haml
new file mode 100644
--- /dev/null
+++ b/app/views/main/result.html.haml
@@ -0,0 +1,41 @@
+= user_title_bar(@user)
+
+%h2
+ Grading Result for Task
+ = @submission.problem.full_name
+
+%p
+ = "Submission: #{@submission.number}"
+ %br/
+ = "Submitted at: #{format_short_time(@submission.submitted_at)}"
+ %br/
+ = "Graded at #{format_short_time(@submission.graded_at)} "
+ %br/
+ = "score: #{(@submission.points*100/@submission.problem.full_score).to_i} " if Configuration['ui.show_score']
+ = " ["
+ %tt
+ = @submission.grader_comment
+ = "]"
+
+%table.info
+ %tr.info-head
+ %th Runs
+ %th Cases
+ %th Result
+ %th Exit
+ %th Time (s)
+ %th Memory (KB)
+ %th Output
+ - r = 0
+ - @test_runs.each do |test_run|
+ - r += 1
+ - case_count = test_run.length
+ - first_case = true
+ - test_run.each do |test_case|
+ %tr{:class => ((r%2==0) ? "info-even" : "info-odd")}
+ - if first_case
+ %td{:rowspan => case_count}
+ = r
+ - first_case = false
+ = render :partial => 'test_case_result', :locals => {:test_case => test_case}
+
diff --git a/app/views/tasks/list.html.erb b/app/views/tasks/list.html.erb
--- a/app/views/tasks/list.html.erb
+++ b/app/views/tasks/list.html.erb
@@ -64,6 +64,23 @@
Macao, China
Thailand
+
+ Test data for all tasks:
+ .zip
+ .tgz
+ Beads:
+ .zip
+ .tgz
+ Roads:
+ .zip
+ .tgz
+ DNA:
+ .zip
+ .tgz
+ Notes:
+ Beads. The zip files contain the testing library that also outputs some magic numbers to verify the correct usage of the library. Files questions-*.txt are also prefixed with fake data.
+ Roads. The zip files contain verify.cpp that checks the output.
+