Browse Source

Fill out jail test case execution.

master
Ben Kurtovic 8 years ago
parent
commit
b258a7cd5e
4 changed files with 48 additions and 19 deletions
  1. +2
    -1
      lib/kgrader/assignment.rb
  2. +1
    -0
      lib/kgrader/backend/svn.rb
  3. +37
    -7
      lib/kgrader/jail.rb
  4. +8
    -11
      lib/kgrader/submission.rb

+ 2
- 1
lib/kgrader/assignment.rb View File

@@ -30,7 +30,8 @@ module KGrader


def tests def tests
@tests ||= @config['grade'].map do |it| @tests ||= @config['grade'].map do |it|
{ :name => it.keys.first, :max => it.values.first }
script = File.join @root, it.keys.first + ".rb"
{ :name => it.keys.first, :script => script, :max => it.values.first }
end end
end end




+ 1
- 0
lib/kgrader/backend/svn.rb View File

@@ -36,6 +36,7 @@ module KGrader::Backend


def commit(repo, message, paths = nil) def commit(repo, message, paths = nil)
# TODO # TODO
# run 'commit', '-m', message, *paths.map { |fn| File.join repo, fn }
end end


def commit_date(repo) def commit_date(repo)


+ 37
- 7
lib/kgrader/jail.rb View File

@@ -3,6 +3,7 @@ module KGrader


def initialize(root) def initialize(root)
@root = root @root = root
@salt = nil
end end


def reset def reset
@@ -11,6 +12,7 @@ module KGrader


def init def init
FileUtils.mkdir_p @root FileUtils.mkdir_p @root
@salt = rand 100000000
end end


def stage(source, target) def stage(source, target)
@@ -18,15 +20,43 @@ module KGrader
end end


def exec(command, logpath) def exec(command, logpath)
pid = Process.fork do
fp = File.open(logpath, 'w+')
Dir.chdir @root
# TODO: rlimit in exec, umask?
Process.exec command, :in => :close, :out => fp, :err => fp,
:close_others => true
end
pid = execute command, logpath
Process.waitpid pid, 0 Process.waitpid pid, 0
$?.exited? && $?.exitstatus == 0 $?.exited? && $?.exitstatus == 0
end end

def run_test(script, logpath)
grade_rd, grade_wr = IO.pipe
cmt_rd, cmt_wr = IO.pipe

command = ['ruby', '-r', '../lib/kgrader/runtime.rb', script, @salt]
pid = execute command, logpath do |options|
[grade_rd, cmt_rd].each &:close
options[3] = grade_wr
options[4] = cmt_wr
end

[grade_wr, cmt_wr].each &:close
Process.waitpid pid, 0

cmt_rd.read.split("\n").each { |cmt| yield cmt } if block_given?
grade = grade_rd.read.strip.to_i
[grade_rd, cmt_rd].each &:close
grade
end

private
def execute(command, logpath)
Process.fork do
fp = File.open(logpath, 'a')
Dir.chdir @root
options = {
:in => :close, :out => fp, :err => fp, :close_others => true,
:rlimit_nproc => 32
}
yield options if block_given?
Process.exec *command, options
end
end
end end
end end

+ 8
- 11
lib/kgrader/submission.rb View File

@@ -60,10 +60,9 @@ module KGrader


def commit def commit
if status == :graded && File.exists?(pendingfile) if status == :graded && File.exists?(pendingfile)
target = File.join(repo, @assignment.report)
message = @assignment.commit_message @student message = @assignment.commit_message @student
FileUtils.cp gradefile, target
@course.backend.commit repo, message, target
FileUtils.cp gradefile, File.join(repo, @assignment.report)
@course.backend.commit repo, message, @assignment.report
FileUtils.rm pendingfile FileUtils.rm pendingfile
end end
end end
@@ -113,16 +112,12 @@ module KGrader
@failure = false @failure = false
@comments = [] @comments = []
@summary = nil @summary = nil
@tests = []
@tests = @assignment.tests.clone.each { |test| test[:score] = 0 }


self.status = :ungraded self.status = :ungraded
FileUtils.rm_f [buildlog, testlog] FileUtils.rm_f [buildlog, testlog]
@fs.jail.reset @fs.jail.reset
@fs.jail.init @fs.jail.init

@assignment.tests.each do |test|
@tests.push({ :name => test[:name], :max => test[:max], :score => 0 })
end
end end


def stage def stage
@@ -142,8 +137,10 @@ module KGrader


def test def test
return if @failure return if @failure
@assignment.tests.each do |test|
# TODO: execute script in jail and update @test/@comments; out testlog
@tests.each do |test|
test[:score] = @fs.jail.run_test test[:script], testlog do |comment|
@comments.push "#{test[:name]}: #{comment}"
end
end end
end end


@@ -199,7 +196,7 @@ module KGrader
end end


def generate_summary def generate_summary
tests = @tests.each do |test|
tests = @tests.map do |test|
"#{test[:score].to_s.rjust get_span(test[:max])}/#{test[:max]}" "#{test[:score].to_s.rjust get_span(test[:max])}/#{test[:max]}"
end.join ', ' end.join ', '
"#{format_points score, max_score}: #{tests}" "#{format_points score, max_score}: #{tests}"


Loading…
Cancel
Save