From: Marius Gavrilescu Date: Tue, 19 Nov 2013 21:03:12 +0000 (+0200) Subject: Initial commit X-Git-Tag: 5999.000_001~46 X-Git-Url: http://git.ieval.ro/?a=commitdiff_plain;h=5c5cd38ad5b9e3c2b331564bc0b23e9167b7d07a;p=gruntmaster-daemon.git Initial commit --- 5c5cd38ad5b9e3c2b331564bc0b23e9167b7d07a diff --git a/Changes b/Changes new file mode 100644 index 0000000..b581aa3 --- /dev/null +++ b/Changes @@ -0,0 +1,6 @@ +Revision history for Perl extension Gruntmaster::Daemon. + +0.001 Tue Oct 15 00:15:35 2013 + - original version; created by h2xs 1.23 with options + -AX -v 0.001 -b 5.14.0 --skip-exporter Gruntmaster::Daemon + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..35714c3 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,91 @@ +Changes +gruntmasterd +lib/Gruntmaster/Daemon/Base.pm +lib/Gruntmaster/Daemon/Constants.pm +lib/Gruntmaster/Daemon/Format/CPP.pm +lib/Gruntmaster/Daemon/Generator/File.pm +lib/Gruntmaster/Daemon/Generator/Run.pm +lib/Gruntmaster/Daemon/Generator/Undef.pm +lib/Gruntmaster/Daemon/Judge/Absolute.pm +lib/Gruntmaster/Daemon/Judge/Points.pm +lib/Gruntmaster/Daemon.pm +lib/Gruntmaster/Daemon/Runner/File.pm +lib/Gruntmaster/Daemon/Runner/Interactive.pm +lib/Gruntmaster/Daemon/Runner/Verifier.pm +log.conf +Makefile.PL +MANIFEST +README +selinux/gruntmasterd.te +t/00-compile.t +t/01-jobs.t +t/problems/aminusb/1.in +t/problems/aminusb/2.in +t/problems/aminusb/3.in +t/problems/aminusb/4.in +t/problems/aminusb/5.in +t/problems/aminusb/meta.yml +t/problems/aminusb/tests/ac/meta.yml +t/problems/aminusb/tests/ac/prog.cpp +t/problems/aminusb/tests/wa/meta.yml +t/problems/aminusb/tests/wa/prog.cpp +t/problems/aminusb/ver.cpp +t/problems/aplusb/1.in +t/problems/aplusb/1.ok +t/problems/aplusb/2.in +t/problems/aplusb/2.ok +t/problems/aplusb/3.in +t/problems/aplusb/3.ok +t/problems/aplusb/4.in +t/problems/aplusb/4.ok +t/problems/aplusb/5.in +t/problems/aplusb/5.ok +t/problems/aplusb/6.in +t/problems/aplusb/6.ok +t/problems/aplusb/meta.yml +t/problems/aplusb/tests/40/meta.yml +t/problems/aplusb/tests/40/prog.cpp +t/problems/aplusb/tests/ac/meta.yml +t/problems/aplusb/tests/ac/prog.cpp +t/problems/aplusb/tests/compile-error/meta.yml +t/problems/aplusb/tests/compile-error/prog.cpp +t/problems/aplusb/tests/mle/meta.yml +t/problems/aplusb/tests/mle/prog.cpp +t/problems/aplusb/tests/nzx/meta.yml +t/problems/aplusb/tests/nzx/prog.cpp +t/problems/aplusb/tests/ole/meta.yml +t/problems/aplusb/tests/ole/prog.cpp +t/problems/aplusb/tests/tle/meta.yml +t/problems/aplusb/tests/tle/prog.cpp +t/problems/double/10.in +t/problems/double/10.ok +t/problems/double/1.in +t/problems/double/1.ok +t/problems/double/2.in +t/problems/double/2.ok +t/problems/double/3.in +t/problems/double/3.ok +t/problems/double/4.in +t/problems/double/4.ok +t/problems/double/5.in +t/problems/double/5.ok +t/problems/double/6.in +t/problems/double/6.ok +t/problems/double/7.in +t/problems/double/7.ok +t/problems/double/8.in +t/problems/double/8.ok +t/problems/double/9.in +t/problems/double/9.ok +t/problems/double/meta.yml +t/problems/double/tests/wa/meta.yml +t/problems/double/tests/wa/prog.cpp +t/problems/increment/int.cpp +t/problems/increment/meta.yml +t/problems/increment/tests/ac/meta.yml +t/problems/increment/tests/ac/prog.cpp +t/problems/square/gen.cpp +t/problems/square/meta.yml +t/problems/square/tests/ac/meta.yml +t/problems/square/tests/ac/prog.cpp +t/problems/square/ver.cpp diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..49a41f1 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,48 @@ +use 5.014000; +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'Gruntmaster::Daemon', + VERSION_FROM => 'lib/Gruntmaster/Daemon.pm', + EXE_FILES => [ 'gruntmasterd' ], + ABSTRACT_FROM => 'lib/Gruntmaster/Daemon.pm', + AUTHOR => 'Marius Gavrilescu ', + MIN_PERL_VERSION => '5.14.0', + LICENSE => 'perl', + BUILD_REQUIRES => { + qw/Cwd 0 + File::Copy 0 + File::Copy::Recursive 0 + File::Path 0 + File::Temp 0 + List::Util 0 + Log::Log4perl 0 + Test::More 0 + YAML::Any 0/, + }, + SIGN => 1, + PREREQ_PM => { + qw/Exporter 0 + Fcntl 0 + File::Basename 0 + File::Copy 0 + File::Spec::Functions 0 + IO::File 0 + IPC::Open3 0 + List::Util 0 + POSIX 0 + Time::HiRes 0 + + BSD::Resource 0 + File::Slurp 0 + IPC::Signal 0 + Linux::Inotify2 0 + List::MoreUtils 0 + Log::Log4perl 0 + Try::Tiny 0 + YAML::Any 0/, + }, + META_MERGE => { + dynamic_config => 0, + } +); diff --git a/README b/README new file mode 100644 index 0000000..1b0e7ab --- /dev/null +++ b/README @@ -0,0 +1,40 @@ +Gruntmaster-Daemon version 0.001 +================================ + +The README is used to introduce the module and provide instructions on +how to install the module, any machine dependencies it may have (for +example C compilers and installed libraries) and any other information +that should be provided before the module is installed. + +A README file is required for CPAN modules since CPAN extracts the +README file from a module distribution so that people browsing the +archive can use it get an idea of the modules uses. It is usually a +good idea to provide version information here so that people can +decide whether fixes for the module are worth downloading. + +INSTALLATION + +To install this module type the following: + + perl Makefile.PL + make + make test + make install + +DEPENDENCIES + +This module requires these other modules and libraries: + + blah blah blah + +COPYRIGHT AND LICENCE + +Put the correct copyright and licence information here. + +Copyright (C) 2013 by Marius Gavrilescu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.18.1 or, +at your option, any later version of Perl 5 you may have available. + + diff --git a/gruntmasterd b/gruntmasterd new file mode 100755 index 0000000..100a78e --- /dev/null +++ b/gruntmasterd @@ -0,0 +1,5 @@ +#!/usr/bin/perl -w +use v5.14; +use Gruntmaster::Daemon; + +Gruntmaster::Daemon->run; diff --git a/lib/Gruntmaster/Daemon.pm b/lib/Gruntmaster/Daemon.pm new file mode 100644 index 0000000..f0e66f2 --- /dev/null +++ b/lib/Gruntmaster/Daemon.pm @@ -0,0 +1,191 @@ +package Gruntmaster::Daemon; + +use 5.014000; +use strict; +use warnings; + +our $VERSION = '0.001'; + +use Gruntmaster::Daemon::Constants qw/ERR/; +use Gruntmaster::Daemon::Base qw/watch/; +use Gruntmaster::Page qw/generate/; + +use Fcntl qw/:flock/; +use File::Copy qw/cp/; +use IO::File; +use Time::HiRes qw/time/; +use Try::Tiny; +use YAML::Any qw/LoadFile DumpFile/; +use Log::Log4perl qw/get_logger/; + +################################################## + +sub safe_can_nodie { + my ($type, $sub, $name) = @_; + + return unless $name =~ /^\w+$/; + no strict 'refs'; + my $pkg = __PACKAGE__ . "::${type}::${name}"; + eval "require $pkg" or get_logger->warn("Error while requiring $pkg: $@"); + $pkg->can($sub); +} + +sub safe_can { + my ($type, $sub, $name) = @_; + + safe_can_nodie @_ or get_logger->logdie("No such \l$type: '$name'"); +} + +sub prepare_files{ + my ($dir, $meta) = @_; + + for my $file (values $meta->{files}) { + my ($format, $name) = @{$file}{qw/format name/}; + + my $prepare = safe_can Format => prepare => $format; + $file->{run} = safe_can Format => run => $format; + die "No such file: '$name'" unless -e $name; + $prepare->($name); + } +} + +sub process{ + my $dir = $_[0]; + + chdir $dir; + mkdir "in"; + for (<*>) { + cp $_, "in" unless $_ eq 'in' || $_ eq 'pidfile'; + } + + my @results; + my @full_results = (); + my $meta = {}; + try { + $meta = LoadFile "meta.yml"; + if (exists $meta->{problem}) { + my $problem = $meta->{problem}; + die "No such problem: $problem" unless -d "../../pb/$problem"; + for (<../../pb/$problem/*>) { + cp $_, '.' unless $_ eq "../../pb/$problem/meta.yml" + } + + my $pbmeta = LoadFile "../../pb/$problem/meta.yml"; + $meta = {%$meta, %$pbmeta}; + } + + my ($files, $generator, $runner, $judge, $testcnt) = map { $meta->{$_} or die "Required parameter missing: $_"} qw/files generator runner judge testcnt/; + + $generator = safe_can Generator => generate => $generator; + $runner = safe_can Runner => run => $runner; + $judge = safe_can Judge => judge => $judge; + + prepare_files $dir, $meta; + for my $test (1 .. $testcnt) { + my $start_time = time; + my $result; + try { + $generator->($test, $meta); + $result = $runner->($test, $meta); + } catch { + $result = $_; + unless (ref $result) { + chomp $result; + $result = [ERR, $result]; + } + }; + + if (ref $result) { + get_logger->trace("Test $test result is " . $result->[1]); + push @full_results, {id => $test, result => $result->[0], result_text => $result->[1], time => time - $start_time} + } else { + get_logger->trace("Test $test result is $result"); + push @full_results, {id => $test, result => 0, result_text => $result, time => time - $start_time} + } + push @results, $result; + last if $meta->{judge} eq 'Absolute' && ref $result + } + + my %results = $judge->(@results); + $meta->{$_} = $results{$_} for keys %results; + } catch { + s,(.*) at .*,$1,; + chomp; + $meta->{result} = -1; + $meta->{result_text} = $_; + }; + + # Clean up + get_logger->info("Job result: " . $meta->{result_text}); + delete $meta->{files}{$_}{run} for keys $meta->{files}; + $meta->{date} = time; + $meta->{results} = \@full_results if scalar @full_results; + DumpFile "meta.yml", $meta; + for (<*>) { + unlink $_ unless $_ eq 'in' || $_ eq 'meta.yml'; + } + chdir '../..'; + mkdir 'log' unless -d 'log'; + IO::File->new('>log/meta.yml')->close unless -f 'log/meta.yml'; + flock my $logmetafh = IO::File->new('{last}++; + rename $dir, 'log/' . $logmeta->{last}; + generate 'log/' . $logmeta->{last} . '/index.htm'; + DumpFile 'log/meta.yml', $logmeta; + undef $logmetafh; + generate 'log/index.html' +} + +sub run{ + Log::Log4perl->init('log.conf'); + watch 'jobs', \&process; +} + +1; +__END__ +# Below is stub documentation for your module. You'd better edit it! + +=head1 NAME + +Gruntmaster::Daemon - Perl extension for blah blah blah + +=head1 SYNOPSIS + + use Gruntmaster::Daemon; + blah blah blah + +=head1 DESCRIPTION + +Stub documentation for Gruntmaster::Daemon, created by h2xs. It looks like the +author of the extension was negligent enough to leave the stub +unedited. + +Blah blah blah. + + +=head1 SEE ALSO + +Mention other useful documentation such as the documentation of +related modules or operating system documentation (such as man pages +in UNIX), or any relevant external documentation such as RFCs or +standards. + +If you have a mailing list set up for your module, mention it here. + +If you have a web site set up for your module, mention it here. + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@E + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2013 by Marius Gavrilescu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.18.1 or, +at your option, any later version of Perl 5 you may have available. + + +=cut diff --git a/lib/Gruntmaster/Daemon/Base.pm b/lib/Gruntmaster/Daemon/Base.pm new file mode 100644 index 0000000..b7db789 --- /dev/null +++ b/lib/Gruntmaster/Daemon/Base.pm @@ -0,0 +1,42 @@ +package Gruntmaster::Daemon::Base; + +use 5.014000; +use strict; +use warnings; +use parent qw/Exporter/; +our @EXPORT_OK = qw/watch/; +our $VERSION = '0.001'; + +use Fcntl qw/O_WRONLY O_EXCL O_CREAT/; +use Linux::Inotify2; +use Log::Log4perl qw/get_logger/; + +################################################## + +sub process{ + my ($name, $dir, $cb) = @_; + my $logger = get_logger; + $logger->debug("Taking job $name..."); + if (sysopen my $file, "$dir/$name/pidfile", O_WRONLY | O_EXCL | O_CREAT){ + $logger->debug("Successfully taken job $name, executing callback"); + $cb->("$dir/$name"); + } else { + $logger->debug("Job $name already taken"); + } +} + +sub watch{ + my ($dir, $cb) = @_; + for (<$dir/*>) { + s,$dir/,,; + process $_, $dir, $cb; + } + + my $logger = Log::Log4perl->get_logger(__PACKAGE__); + my $inotify = Linux::Inotify2->new or $logger->logdie("Unable to create Linux::Inotify2 object: $!"); + $inotify->watch($dir, IN_MOVED_TO, sub { process $_[0]->name, $dir, $cb }) or $logger->logdie("Error watching $dir: $!"); + 1 while $inotify->poll; + $logger->logdie("Inotify polling stopped: $!"); +} + +1 diff --git a/lib/Gruntmaster/Daemon/Constants.pm b/lib/Gruntmaster/Daemon/Constants.pm new file mode 100644 index 0000000..189aabe --- /dev/null +++ b/lib/Gruntmaster/Daemon/Constants.pm @@ -0,0 +1,26 @@ +package Gruntmaster::Daemon::Constants; + +use 5.014000; +use strict; +use warnings; +use parent qw/Exporter/; + +our $VERSION = '0.001'; + +use constant +{ + # Accepted + AC => 0, + + # Internal server error + ERR => -1, + + # All other errors + WA => 1, + NZX => 2, + TLE => 3, + OLE => 4, + DIED => 5, + REJ => 10, +}; + +our @EXPORT_OK = qw/AC ERR WA NZX TLE OLE DIED REJ/; diff --git a/lib/Gruntmaster/Daemon/Format/CPP.pm b/lib/Gruntmaster/Daemon/Format/CPP.pm new file mode 100644 index 0000000..707af32 --- /dev/null +++ b/lib/Gruntmaster/Daemon/Format/CPP.pm @@ -0,0 +1,76 @@ +package Gruntmaster::Daemon::Format::CPP; + +use 5.014000; +use strict; +use warnings; + +use BSD::Resource qw/setrlimit RLIMIT_AS RLIMIT_FSIZE/; +use POSIX qw//; +use File::Basename qw/fileparse/; +use Gruntmaster::Daemon::Constants qw/TLE OLE DIED NZX/; +use Log::Log4perl qw/get_logger/; +use Time::HiRes qw/alarm/; +use List::MoreUtils qw/natatime/; +use IPC::Signal qw/sig_name sig_num/; +use IPC::Open3 qw/open3/; +use File::Spec::Functions qw/devnull/; +use Fcntl qw/F_GETFD F_SETFD FD_CLOEXEC/; + +our $VERSION = '0.001'; + +################################################## + +sub prepare{ + my $name = $_[0]; + my $basename = fileparse $name, qr/\.[^.]*/; + get_logger->trace("Preparing file $name..."); + + open my $devnull, devnull; + open my $errors, '>compile-error'; + my $ret = open3 $devnull, $errors, $errors, 'g++', '-o', $basename, $name; + local $SIG{ALRM} = sub {kill KILL => $ret}; + alarm 5; + wait; + close $devnull; + close $errors; + die 'Compile error' if $? +} + +sub run{ + my ($name, %args) = @_; + my $basename = fileparse $name, qr/\.[^.]*/; + my $ret = fork // die 'Cannot fork'; + if ($ret) { + my $tle; + local $SIG{ALRM} = sub { kill KILL => $ret; $tle = 1}; + alarm $args{timeout} if exists $args{timeout}; + wait; + alarm 0; + my $sig = $? & 127; + my $signame = sig_name $sig; + die [TLE, "Time Limit Exceeded"] if $tle; + die [OLE, 'Output Limit Exceeded'] if $sig && $signame eq 'XFSZ'; + die [DIED, "Crash (SIG$signame)"] if $sig; + die [NZX, "Non-zero exit status: " . ($? >> 8)] if $?; + } else { + $^F = 50; + POSIX::close $_ for 0, 1, 3 .. $^F; + my @fds = exists $args{fds} ? @{$args{fds}} : (); + get_logger->trace("Running $basename with fds ". join ' ', @fds); + my $it = natatime 2, @fds; + while (my ($fd, $file) = $it->()) { + open my $fh, $file or die $!; + my $oldfd = fileno $fh; + if ($oldfd != $fd) { + POSIX::dup2 $oldfd, $fd or die $!; + POSIX::close $oldfd or die $!; + } + } +# POSIX::close 2; + setrlimit RLIMIT_AS, $args{mlimit}, $args{mlimit} if exists $args{mlimit}; + setrlimit RLIMIT_FSIZE, $args{olimit}, $args{olimit} if exists $args{olimit}; + exec "./$basename", exists $args{args} ? @{$args{args}} : (); + } +} + +1 diff --git a/lib/Gruntmaster/Daemon/Generator/File.pm b/lib/Gruntmaster/Daemon/Generator/File.pm new file mode 100644 index 0000000..1c37a8d --- /dev/null +++ b/lib/Gruntmaster/Daemon/Generator/File.pm @@ -0,0 +1,20 @@ +package Gruntmaster::Daemon::Generator::File; + +use 5.014000; +use strict; +use warnings; + +use File::Copy qw/cp/; +use Log::Log4perl qw/get_logger/; + +our $VERSION = '0.001'; + +################################################## + +sub generate{ + my ($test, $meta) = @_; + get_logger->trace("Generating test $test ..."); + cp "$test.in", 'input' or die "Cannot copy input for test $test: $!"; +} + +1 diff --git a/lib/Gruntmaster/Daemon/Generator/Run.pm b/lib/Gruntmaster/Daemon/Generator/Run.pm new file mode 100644 index 0000000..8182729 --- /dev/null +++ b/lib/Gruntmaster/Daemon/Generator/Run.pm @@ -0,0 +1,18 @@ +package Gruntmaster::Daemon::Generator::Run; + +use 5.014000; +use strict; +use warnings; + +use Log::Log4perl qw/get_logger/; + +our $VERSION = '0.001'; + +################################################## + +sub generate{ + my ($test, $meta) = @_; + my $gen = $meta->{files}{gen}; + get_logger->trace("Generating test $test..."); + $gen->{run}->($gen->{name}, args => [ $test ], fds => [qw/1 >input/]); +} diff --git a/lib/Gruntmaster/Daemon/Generator/Undef.pm b/lib/Gruntmaster/Daemon/Generator/Undef.pm new file mode 100644 index 0000000..836a4be --- /dev/null +++ b/lib/Gruntmaster/Daemon/Generator/Undef.pm @@ -0,0 +1,17 @@ +package Gruntmaster::Daemon::Generator::Undef; + +use 5.014000; +use strict; +use warnings; + +use Log::Log4perl qw/get_logger/; + +our $VERSION = '0.001'; + +################################################## + +sub generate{ + get_logger->trace("Pretending to generate test $_[0]..."); +} + +1 diff --git a/lib/Gruntmaster/Daemon/Judge/Absolute.pm b/lib/Gruntmaster/Daemon/Judge/Absolute.pm new file mode 100644 index 0000000..010cf0b --- /dev/null +++ b/lib/Gruntmaster/Daemon/Judge/Absolute.pm @@ -0,0 +1,19 @@ +package Gruntmaster::Daemon::Judge::Absolute; + +use 5.014000; +use strict; +use warnings; + +use Gruntmaster::Daemon::Constants qw/AC/; + +our $VERSION = '0.001'; + +################################################## + +sub judge{ + $_ = pop; + ref $_ ? (result => $_->[0], result_text => $_->[1]) : (result => AC, result_text => 'Accepted') +} + +1; +__END__ diff --git a/lib/Gruntmaster/Daemon/Judge/Points.pm b/lib/Gruntmaster/Daemon/Judge/Points.pm new file mode 100644 index 0000000..6d13ad0 --- /dev/null +++ b/lib/Gruntmaster/Daemon/Judge/Points.pm @@ -0,0 +1,21 @@ +package Gruntmaster::Daemon::Judge::Points; + +use 5.014000; +use strict; +use warnings; + +use Gruntmaster::Daemon::Constants qw/AC REJ/; +use List::Util qw/sum/; +use Log::Log4perl qw/get_logger/; +our $VERSION = '0.001'; + +################################################## + +sub judge{ + no warnings qw/numeric/; + get_logger->trace("Judging results: @_"); + my $points = sum 0, grep { $_+0 eq "$_" } @_; + $points == 100 ? (result => AC, result_text => 'Accepted') : (result => REJ, result_text => "$points points", points => $points) +} + +1 diff --git a/lib/Gruntmaster/Daemon/Runner/File.pm b/lib/Gruntmaster/Daemon/Runner/File.pm new file mode 100644 index 0000000..57555ac --- /dev/null +++ b/lib/Gruntmaster/Daemon/Runner/File.pm @@ -0,0 +1,31 @@ +package Gruntmaster::Daemon::Runner::File; + +use 5.014000; +use strict; +use warnings; + +use Gruntmaster::Daemon::Constants qw/WA/; +use File::Slurp qw/slurp/; +use Log::Log4perl qw/get_logger/; + +################################################## + +sub run{ + my ($test, $meta) = @_; + get_logger->trace("Running on test $test..."); + $meta->{files}{prog}{run}->($meta->{files}{prog}{name}, fds => [qw/0 input 1 >output/], map {defined $meta->{$_} ? ($_ => $meta->{$_}) : () } qw/timeout olimit mlimit/); + my $out = slurp 'output'; + my $ok = slurp "$test.ok"; + + $out =~ s/^\s+//; + $ok =~ s/^\s+//; + $out =~ s/\s+/ /; + $ok =~ s/\s+/ /; + $out =~ s/\s+$//; + $ok =~ s/\s+$//; + + die [WA, "Wrong answer"] if $out ne $ok; + $meta->{tests}[$test - 1] // 0 +} + +1 diff --git a/lib/Gruntmaster/Daemon/Runner/Interactive.pm b/lib/Gruntmaster/Daemon/Runner/Interactive.pm new file mode 100644 index 0000000..5edee04 --- /dev/null +++ b/lib/Gruntmaster/Daemon/Runner/Interactive.pm @@ -0,0 +1,39 @@ +package Gruntmaster::Daemon::Runner::Interactive; + +use 5.014000; +use strict; +use warnings; + +use File::Slurp qw/slurp/; +use Gruntmaster::Daemon::Constants qw/WA/; +use Log::Log4perl qw/get_logger/; +use POSIX qw/mkfifo/; +use Try::Tiny; + +################################################## + +sub run{ + my ($test, $meta) = @_; + get_logger->trace("Running on test $test..."); + my $ret = fork // get_logger->logdie("Fork failed: $!"); + + mkfifo 'fifo1', 0600 or die $! unless -e 'fifo1'; + mkfifo 'fifo2', 0600 or die $! unless -e 'fifo2'; + if ($ret) { + $meta->{files}{prog}{run}->($meta->{files}{prog}{name}, fds => [qw/0 fifo1 1 >fifo2/], map {defined $meta->{$_} ? ($_ => $meta->{$_}) : () } qw/timeout mlimit/); + wait; + die [WA, "Wrong Answer"] if $?; + } else { + try { + $meta->{files}{int}{run}->($meta->{files}{int}{name}, fds => [qw/1 >fifo1 0 fifo2 4 >result/]); + } catch { + exit 1; + }; + exit + } + + scalar slurp 'result' +} + +1; +__END__ diff --git a/lib/Gruntmaster/Daemon/Runner/Verifier.pm b/lib/Gruntmaster/Daemon/Runner/Verifier.pm new file mode 100644 index 0000000..5a0b5ed --- /dev/null +++ b/lib/Gruntmaster/Daemon/Runner/Verifier.pm @@ -0,0 +1,27 @@ +package Gruntmaster::Daemon::Runner::Verifier; + +use 5.014000; +use strict; +use warnings; + +use Gruntmaster::Daemon::Constants qw/WA/; +use File::Slurp qw/slurp/; +use Log::Log4perl qw/get_logger/; +use Try::Tiny; + +################################################## + +sub run{ + my ($test, $meta) = @_; + get_logger->trace("Running on test $test..."); + $meta->{files}{prog}{run}->($meta->{files}{prog}{name}, fds => [qw/0 input 1 >output/], map {defined $meta->{$_} ? ($_ => $meta->{$_}) : () } qw/timeout olimit mlimit/); + + try { + $meta->{files}{ver}{run}->($meta->{files}{ver}{name}, fds => [qw/0 input 3 output 1 >result/]); + } catch { + die [WA, "Wrong answer"] + }; + scalar slurp 'result'; +} + +1 diff --git a/log.conf b/log.conf new file mode 100644 index 0000000..ab2c03a --- /dev/null +++ b/log.conf @@ -0,0 +1,5 @@ +log4perl.category.Gruntmaster.Daemon = TRACE, stderr + +log4perl.appender.stderr = Log::Log4perl::Appender::Screen +log4perl.appender.stderr.layout = Log::Log4perl::Layout::PatternLayout +log4perl.appender.stderr.layout.ConversionPattern = [%d] [%F{1}:%M{1}:%L] [%p] %m%n diff --git a/selinux/gruntmasterd.te b/selinux/gruntmasterd.te new file mode 100644 index 0000000..bd0d99d --- /dev/null +++ b/selinux/gruntmasterd.te @@ -0,0 +1,24 @@ +policy_mdule(gruntmasterd, 1.0) + +type gruntmasterd_t; +type gruntmasterd_exec_t; +init_daemon_domain(gruntmasterd_t, gruntmasterd_exec_t); + +type gruntmasterd_log_t; +logging_log_file(gruntmasterd_log_t); + +type gruntmaster_job_t; +type gruntmaster_job_exec_t; +init_daemon_domain(gruntmaster_job_t, gruntmaster_job_exec_t); + +allow gruntmasterd_t self : process fork; + +allow gruntmasterd_t gruntmasterd_job_t : dir ra_dir_perms; +allow gruntmasterd_t gruntmasterd_job_t : file { create ra_file_perms }; +logging_log_filetrans(gruntmasterd_t, gruntmasterd_log_t, file) +logging_search_logs(gruntmasterd_t) + +libs_use_ld_so(gruntmasterd_t) +libs_use_ld_so(gruntmasterd_job_t) +libs_use_shared_libs(gruntmasterd_t) +libs_use_shared_libs(gruntmasterd_job_t) \ No newline at end of file diff --git a/t/00-compile.t b/t/00-compile.t new file mode 100644 index 0000000..28dd755 --- /dev/null +++ b/t/00-compile.t @@ -0,0 +1,7 @@ +#!/usr/bin/perl -w +use v5.14; +use strict; +use warnings; + +use Test::More tests => 1; +BEGIN { use_ok('Gruntmaster::Daemon') }; diff --git a/t/01-jobs.t b/t/01-jobs.t new file mode 100644 index 0000000..e573a95 --- /dev/null +++ b/t/01-jobs.t @@ -0,0 +1,65 @@ +#!/usr/bin/perl -w +use v5.14; +use strict; +use warnings; + +use Gruntmaster::Daemon; + +use Cwd qw/cwd/; +use File::Copy qw/copy/; +use File::Copy::Recursive qw/dircopy/; +use File::Path qw/remove_tree/; +use File::Temp qw/tempdir/; +use List::Util qw/sum/; +use Log::Log4perl; +use Test::More; +use YAML::Any qw/LoadFile/; + +################################################## + +my $loglevel = $ENV{TEST_LOG_LEVEL} // 'OFF'; +my $log_conf = <init(\$log_conf); + +sub check_job{ + my $job = shift; + my $meta = LoadFile "$job/meta.yml"; + if (exists $meta->{results}) { + delete $meta->{results}[$_]{time} for keys $meta->{results}; + } + is $meta->{result}, $meta->{expected_result}, "Result is correct"; + is $meta->{result_text}, $meta->{expected_result_text}, "Result text is correct"; + is_deeply $meta->{results}, $meta->{expected_results}, "Results are correct"; +} + +my @problems = exists $ENV{TEST_PROBLEMS} ? map {"t/problems/$_"} split ' ', $ENV{TEST_PROBLEMS} : ; +plan tests => 3 * sum map { my @temp = <$_/tests/*>; scalar @temp } @problems; +note "Problems to be tested: " . join ', ', @problems; + +my $tempdir = tempdir CLEANUP => 1; +mkdir "$tempdir/jobs"; +dircopy 't/problems' => "$tempdir/pb"; + +for my $problem (@problems) { + my $meta = LoadFile "$problem/meta.yml"; + TODO: { + local $TODO = $meta->{todo} if exists $meta->{todo}; + note "Now testing problem $meta->{name} ($meta->{description})"; + for my $source (<$problem/tests/*>) { + my $meta = LoadFile "$source/meta.yml"; + note "Running $meta->{test_name} ($meta->{test_description})..."; + dircopy $source => "$tempdir/jobs/job"; + my $savedcwd = cwd; + Gruntmaster::Daemon::process "$tempdir/jobs/job"; + check_job "$tempdir/log/1"; + chdir $savedcwd; + remove_tree "$tempdir/log", "$tempdir/jobs", {keep_root => 1}; + } + } +} diff --git a/t/problems/aminusb/1.in b/t/problems/aminusb/1.in new file mode 100644 index 0000000..8d04f96 --- /dev/null +++ b/t/problems/aminusb/1.in @@ -0,0 +1 @@ +1 2 diff --git a/t/problems/aminusb/2.in b/t/problems/aminusb/2.in new file mode 100644 index 0000000..2dde9d0 --- /dev/null +++ b/t/problems/aminusb/2.in @@ -0,0 +1 @@ +25926 30994 diff --git a/t/problems/aminusb/3.in b/t/problems/aminusb/3.in new file mode 100644 index 0000000..b9df610 --- /dev/null +++ b/t/problems/aminusb/3.in @@ -0,0 +1 @@ +18404 28903 diff --git a/t/problems/aminusb/4.in b/t/problems/aminusb/4.in new file mode 100644 index 0000000..d3c0e1a --- /dev/null +++ b/t/problems/aminusb/4.in @@ -0,0 +1 @@ +28523 27674 diff --git a/t/problems/aminusb/5.in b/t/problems/aminusb/5.in new file mode 100644 index 0000000..0182f9d --- /dev/null +++ b/t/problems/aminusb/5.in @@ -0,0 +1 @@ +14479 15757 diff --git a/t/problems/aminusb/meta.yml b/t/problems/aminusb/meta.yml new file mode 100644 index 0000000..1291dc9 --- /dev/null +++ b/t/problems/aminusb/meta.yml @@ -0,0 +1,17 @@ +--- +name: A-B +generator: File +judge: Points +runner: Verifier +testcnt: 5 +timeout: 1 +mlimit: 20971520 +olimit: 100 +description: The A-B problem, with a verifier +files: + ver: + format: CPP + name: ver.cpp + prog: + format: CPP + name: prog.cpp diff --git a/t/problems/aminusb/tests/ac/meta.yml b/t/problems/aminusb/tests/ac/meta.yml new file mode 100644 index 0000000..6b2bc2f --- /dev/null +++ b/t/problems/aminusb/tests/ac/meta.yml @@ -0,0 +1,21 @@ +test_name: Accepted +test_description: A program which works correctly +problem: aminusb +expected_result: 0 +expected_result_text: Accepted +expected_results: +- id: 1 + result: 0 + result_text: 20 +- id: 2 + result: 0 + result_text: 20 +- id: 3 + result: 0 + result_text: 20 +- id: 4 + result: 0 + result_text: 20 +- id: 5 + result: 0 + result_text: 20 diff --git a/t/problems/aminusb/tests/ac/prog.cpp b/t/problems/aminusb/tests/ac/prog.cpp new file mode 100644 index 0000000..298dd43 --- /dev/null +++ b/t/problems/aminusb/tests/ac/prog.cpp @@ -0,0 +1,8 @@ +#include +int main() +{ + int a,b; + scanf ("%d%d",&a,&b); + printf ("%d",a-b); + return 0; +} diff --git a/t/problems/aminusb/tests/wa/meta.yml b/t/problems/aminusb/tests/wa/meta.yml new file mode 100644 index 0000000..285d9e1 --- /dev/null +++ b/t/problems/aminusb/tests/wa/meta.yml @@ -0,0 +1,21 @@ +test_name: Wrong answer +test_description: A program which does nothing +problem: aminusb +expected_result: 10 +expected_result_text: 0 points +expected_results: +- id: 1 + result: 1 + result_text: Wrong answer +- id: 2 + result: 1 + result_text: Wrong answer +- id: 3 + result: 1 + result_text: Wrong answer +- id: 4 + result: 1 + result_text: Wrong answer +- id: 5 + result: 1 + result_text: Wrong answer diff --git a/t/problems/aminusb/tests/wa/prog.cpp b/t/problems/aminusb/tests/wa/prog.cpp new file mode 100644 index 0000000..76e8197 --- /dev/null +++ b/t/problems/aminusb/tests/wa/prog.cpp @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/t/problems/aminusb/ver.cpp b/t/problems/aminusb/ver.cpp new file mode 100644 index 0000000..87cc931 --- /dev/null +++ b/t/problems/aminusb/ver.cpp @@ -0,0 +1,14 @@ +#include + +int main(void){ + FILE *output = fdopen(3, "r"); + int a, b, ret; + scanf("%d%d", &a, &b); + fscanf(output, "%d", &ret); + if(a-b == ret){ + printf("20"); + return 0; + } else + return 1; +} + diff --git a/t/problems/aplusb/1.in b/t/problems/aplusb/1.in new file mode 100644 index 0000000..8d04f96 --- /dev/null +++ b/t/problems/aplusb/1.in @@ -0,0 +1 @@ +1 2 diff --git a/t/problems/aplusb/1.ok b/t/problems/aplusb/1.ok new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/t/problems/aplusb/1.ok @@ -0,0 +1 @@ +3 diff --git a/t/problems/aplusb/2.in b/t/problems/aplusb/2.in new file mode 100644 index 0000000..2dde9d0 --- /dev/null +++ b/t/problems/aplusb/2.in @@ -0,0 +1 @@ +25926 30994 diff --git a/t/problems/aplusb/2.ok b/t/problems/aplusb/2.ok new file mode 100644 index 0000000..16566a2 --- /dev/null +++ b/t/problems/aplusb/2.ok @@ -0,0 +1 @@ +56920 diff --git a/t/problems/aplusb/3.in b/t/problems/aplusb/3.in new file mode 100644 index 0000000..b9df610 --- /dev/null +++ b/t/problems/aplusb/3.in @@ -0,0 +1 @@ +18404 28903 diff --git a/t/problems/aplusb/3.ok b/t/problems/aplusb/3.ok new file mode 100644 index 0000000..eb07f22 --- /dev/null +++ b/t/problems/aplusb/3.ok @@ -0,0 +1 @@ +47307 diff --git a/t/problems/aplusb/4.in b/t/problems/aplusb/4.in new file mode 100644 index 0000000..d3c0e1a --- /dev/null +++ b/t/problems/aplusb/4.in @@ -0,0 +1 @@ +28523 27674 diff --git a/t/problems/aplusb/4.ok b/t/problems/aplusb/4.ok new file mode 100644 index 0000000..6a74b56 --- /dev/null +++ b/t/problems/aplusb/4.ok @@ -0,0 +1 @@ +56197 diff --git a/t/problems/aplusb/5.in b/t/problems/aplusb/5.in new file mode 100644 index 0000000..0182f9d --- /dev/null +++ b/t/problems/aplusb/5.in @@ -0,0 +1 @@ +14479 15757 diff --git a/t/problems/aplusb/5.ok b/t/problems/aplusb/5.ok new file mode 100644 index 0000000..7436ebb --- /dev/null +++ b/t/problems/aplusb/5.ok @@ -0,0 +1 @@ +30236 diff --git a/t/problems/aplusb/6.in b/t/problems/aplusb/6.in new file mode 100644 index 0000000..86e0478 --- /dev/null +++ b/t/problems/aplusb/6.in @@ -0,0 +1 @@ +2253 23718 diff --git a/t/problems/aplusb/6.ok b/t/problems/aplusb/6.ok new file mode 100644 index 0000000..d5b0367 --- /dev/null +++ b/t/problems/aplusb/6.ok @@ -0,0 +1 @@ +25971 diff --git a/t/problems/aplusb/meta.yml b/t/problems/aplusb/meta.yml new file mode 100644 index 0000000..6e20d6f --- /dev/null +++ b/t/problems/aplusb/meta.yml @@ -0,0 +1,21 @@ +--- +name: A+B +generator: File +judge: Points +runner: File +testcnt: 6 +timeout: 1 +mlimit: 20971520 +olimit: 100 +description: The simple A+B problem +files: + prog: + format: CPP + name: prog.cpp +tests: +- 20 +- 20 +- 20 +- 20 +- 10 +- 10 diff --git a/t/problems/aplusb/tests/40/meta.yml b/t/problems/aplusb/tests/40/meta.yml new file mode 100644 index 0000000..80a67ba --- /dev/null +++ b/t/problems/aplusb/tests/40/meta.yml @@ -0,0 +1,25 @@ +test_name: 40 +test_description: A program which should get 40 points +problem: aplusb +expected_result: 10 +expected_result_text: 40 points +expected_results: +- id: 1 + result: 0 + result_text: 20 +- id: 2 + result: 1 + result_text: Wrong answer +- id: 3 + result: 1 + result_text: Wrong answer +- id: 4 + result: 1 + result_text: Wrong answer +- id: 5 + result: 0 + result_text: 10 +- id: 6 + result: 0 + result_text: 10 + diff --git a/t/problems/aplusb/tests/40/prog.cpp b/t/problems/aplusb/tests/40/prog.cpp new file mode 100644 index 0000000..5a41733 --- /dev/null +++ b/t/problems/aplusb/tests/40/prog.cpp @@ -0,0 +1,7 @@ +#include +int main(void){ + short a,b; + scanf("%hd%hd", &a, &b); + printf("%hd", a+b); + return 0; +} diff --git a/t/problems/aplusb/tests/ac/meta.yml b/t/problems/aplusb/tests/ac/meta.yml new file mode 100644 index 0000000..f01b97f --- /dev/null +++ b/t/problems/aplusb/tests/ac/meta.yml @@ -0,0 +1,24 @@ +test_name: Accepted +test_description: A program which works correctly +problem: aplusb +expected_result: 0 +expected_result_text: Accepted +expected_results: +- id: 1 + result: 0 + result_text: 20 +- id: 2 + result: 0 + result_text: 20 +- id: 3 + result: 0 + result_text: 20 +- id: 4 + result: 0 + result_text: 20 +- id: 5 + result: 0 + result_text: 10 +- id: 6 + result: 0 + result_text: 10 diff --git a/t/problems/aplusb/tests/ac/prog.cpp b/t/problems/aplusb/tests/ac/prog.cpp new file mode 100644 index 0000000..f8a683a --- /dev/null +++ b/t/problems/aplusb/tests/ac/prog.cpp @@ -0,0 +1,8 @@ +#include +int main() +{ + int a,b; + scanf ("%d%d",&a,&b); + printf ("%d",a+b); + return 0; +} diff --git a/t/problems/aplusb/tests/compile-error/meta.yml b/t/problems/aplusb/tests/compile-error/meta.yml new file mode 100644 index 0000000..a610d14 --- /dev/null +++ b/t/problems/aplusb/tests/compile-error/meta.yml @@ -0,0 +1,5 @@ +test_name: Compile Error +test_description: A program which does not compile +problem: aplusb +expected_result: -1 +expected_result_text: Compile error \ No newline at end of file diff --git a/t/problems/aplusb/tests/compile-error/prog.cpp b/t/problems/aplusb/tests/compile-error/prog.cpp new file mode 100644 index 0000000..b5287f3 --- /dev/null +++ b/t/problems/aplusb/tests/compile-error/prog.cpp @@ -0,0 +1 @@ +int diff --git a/t/problems/aplusb/tests/mle/meta.yml b/t/problems/aplusb/tests/mle/meta.yml new file mode 100644 index 0000000..b71c482 --- /dev/null +++ b/t/problems/aplusb/tests/mle/meta.yml @@ -0,0 +1,24 @@ +test_name: Memory Limit Exceeded +test_description: A program which uses up a lot of memory +problem: aplusb +expected_result: 10 +expected_result_text: 0 points +expected_results: +- id: 1 + result: 5 + result_text: Crash (SIGKILL) +- id: 2 + result: 5 + result_text: Crash (SIGKILL) +- id: 3 + result: 5 + result_text: Crash (SIGKILL) +- id: 4 + result: 5 + result_text: Crash (SIGKILL) +- id: 5 + result: 5 + result_text: Crash (SIGKILL) +- id: 6 + result: 5 + result_text: Crash (SIGKILL) diff --git a/t/problems/aplusb/tests/mle/prog.cpp b/t/problems/aplusb/tests/mle/prog.cpp new file mode 100644 index 0000000..049ae69 --- /dev/null +++ b/t/problems/aplusb/tests/mle/prog.cpp @@ -0,0 +1,3 @@ +int v[1005][1005][20]; +int main(void){ +} diff --git a/t/problems/aplusb/tests/nzx/meta.yml b/t/problems/aplusb/tests/nzx/meta.yml new file mode 100644 index 0000000..97dfc8d --- /dev/null +++ b/t/problems/aplusb/tests/nzx/meta.yml @@ -0,0 +1,24 @@ +test_name: Non-Zero Exit status +test_description: A program which returns 42 +problem: aplusb +expected_result: 10 +expected_result_text: 0 points +expected_results: +- id: 1 + result: 2 + result_text: 'Non-zero exit status: 42' +- id: 2 + result: 2 + result_text: 'Non-zero exit status: 42' +- id: 3 + result: 2 + result_text: 'Non-zero exit status: 42' +- id: 4 + result: 2 + result_text: 'Non-zero exit status: 42' +- id: 5 + result: 2 + result_text: 'Non-zero exit status: 42' +- id: 6 + result: 2 + result_text: 'Non-zero exit status: 42' diff --git a/t/problems/aplusb/tests/nzx/prog.cpp b/t/problems/aplusb/tests/nzx/prog.cpp new file mode 100644 index 0000000..4a70c11 --- /dev/null +++ b/t/problems/aplusb/tests/nzx/prog.cpp @@ -0,0 +1,3 @@ +int main(void){ + return 42; +} diff --git a/t/problems/aplusb/tests/ole/meta.yml b/t/problems/aplusb/tests/ole/meta.yml new file mode 100644 index 0000000..f5248e0 --- /dev/null +++ b/t/problems/aplusb/tests/ole/meta.yml @@ -0,0 +1,24 @@ +test_name: Output Limit Exceeded +test_description: A program which outputs a lot of nonsense +problem: aplusb +expected_result: 10 +expected_result_text: 0 points +expected_results: +- id: 1 + result: 4 + result_text: Output Limit Exceeded +- id: 2 + result: 4 + result_text: Output Limit Exceeded +- id: 3 + result: 4 + result_text: Output Limit Exceeded +- id: 4 + result: 4 + result_text: Output Limit Exceeded +- id: 5 + result: 4 + result_text: Output Limit Exceeded +- id: 6 + result: 4 + result_text: Output Limit Exceeded diff --git a/t/problems/aplusb/tests/ole/prog.cpp b/t/problems/aplusb/tests/ole/prog.cpp new file mode 100644 index 0000000..92fffb1 --- /dev/null +++ b/t/problems/aplusb/tests/ole/prog.cpp @@ -0,0 +1,6 @@ +#include + +int main(void){ + for(int i=0;i<100;i++) + puts("asdasdasd"); +} diff --git a/t/problems/aplusb/tests/tle/meta.yml b/t/problems/aplusb/tests/tle/meta.yml new file mode 100644 index 0000000..976ac47 --- /dev/null +++ b/t/problems/aplusb/tests/tle/meta.yml @@ -0,0 +1,24 @@ +test_name: Time Limit Exceeded +test_description: A program which loops forever +problem: aplusb +expected_result: 10 +expected_result_text: 0 points +expected_results: +- id: 1 + result: 3 + result_text: Time Limit Exceeded +- id: 2 + result: 3 + result_text: Time Limit Exceeded +- id: 3 + result: 3 + result_text: Time Limit Exceeded +- id: 4 + result: 3 + result_text: Time Limit Exceeded +- id: 5 + result: 3 + result_text: Time Limit Exceeded +- id: 6 + result: 3 + result_text: Time Limit Exceeded diff --git a/t/problems/aplusb/tests/tle/prog.cpp b/t/problems/aplusb/tests/tle/prog.cpp new file mode 100644 index 0000000..a35c303 --- /dev/null +++ b/t/problems/aplusb/tests/tle/prog.cpp @@ -0,0 +1,3 @@ +int main(void){ + while(1); +} diff --git a/t/problems/double/1.in b/t/problems/double/1.in new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/t/problems/double/1.in @@ -0,0 +1 @@ +1 diff --git a/t/problems/double/1.ok b/t/problems/double/1.ok new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/t/problems/double/1.ok @@ -0,0 +1 @@ +2 diff --git a/t/problems/double/10.in b/t/problems/double/10.in new file mode 100644 index 0000000..8502658 --- /dev/null +++ b/t/problems/double/10.in @@ -0,0 +1 @@ +15229 diff --git a/t/problems/double/10.ok b/t/problems/double/10.ok new file mode 100644 index 0000000..1b698e7 --- /dev/null +++ b/t/problems/double/10.ok @@ -0,0 +1 @@ +30458 diff --git a/t/problems/double/2.in b/t/problems/double/2.in new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/t/problems/double/2.in @@ -0,0 +1 @@ +2 diff --git a/t/problems/double/2.ok b/t/problems/double/2.ok new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/t/problems/double/2.ok @@ -0,0 +1 @@ +4 diff --git a/t/problems/double/3.in b/t/problems/double/3.in new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/t/problems/double/3.in @@ -0,0 +1 @@ +3 diff --git a/t/problems/double/3.ok b/t/problems/double/3.ok new file mode 100644 index 0000000..1e8b314 --- /dev/null +++ b/t/problems/double/3.ok @@ -0,0 +1 @@ +6 diff --git a/t/problems/double/4.in b/t/problems/double/4.in new file mode 100644 index 0000000..76e69c8 --- /dev/null +++ b/t/problems/double/4.in @@ -0,0 +1 @@ +2594 diff --git a/t/problems/double/4.ok b/t/problems/double/4.ok new file mode 100644 index 0000000..814974a --- /dev/null +++ b/t/problems/double/4.ok @@ -0,0 +1 @@ +5188 diff --git a/t/problems/double/5.in b/t/problems/double/5.in new file mode 100644 index 0000000..f7f167e --- /dev/null +++ b/t/problems/double/5.in @@ -0,0 +1 @@ +22341 diff --git a/t/problems/double/5.ok b/t/problems/double/5.ok new file mode 100644 index 0000000..5edacf0 --- /dev/null +++ b/t/problems/double/5.ok @@ -0,0 +1 @@ +44682 diff --git a/t/problems/double/6.in b/t/problems/double/6.in new file mode 100644 index 0000000..2638034 --- /dev/null +++ b/t/problems/double/6.in @@ -0,0 +1 @@ +12612 diff --git a/t/problems/double/6.ok b/t/problems/double/6.ok new file mode 100644 index 0000000..3874ec5 --- /dev/null +++ b/t/problems/double/6.ok @@ -0,0 +1 @@ +25224 diff --git a/t/problems/double/7.in b/t/problems/double/7.in new file mode 100644 index 0000000..1661b24 --- /dev/null +++ b/t/problems/double/7.in @@ -0,0 +1 @@ +2730 diff --git a/t/problems/double/7.ok b/t/problems/double/7.ok new file mode 100644 index 0000000..4bbe087 --- /dev/null +++ b/t/problems/double/7.ok @@ -0,0 +1 @@ +5460 diff --git a/t/problems/double/8.in b/t/problems/double/8.in new file mode 100644 index 0000000..bdc067b --- /dev/null +++ b/t/problems/double/8.in @@ -0,0 +1 @@ +9037 diff --git a/t/problems/double/8.ok b/t/problems/double/8.ok new file mode 100644 index 0000000..5577366 --- /dev/null +++ b/t/problems/double/8.ok @@ -0,0 +1 @@ +18074 diff --git a/t/problems/double/9.in b/t/problems/double/9.in new file mode 100644 index 0000000..6bec6d1 --- /dev/null +++ b/t/problems/double/9.in @@ -0,0 +1 @@ +7511 diff --git a/t/problems/double/9.ok b/t/problems/double/9.ok new file mode 100644 index 0000000..2232790 --- /dev/null +++ b/t/problems/double/9.ok @@ -0,0 +1 @@ +15022 diff --git a/t/problems/double/meta.yml b/t/problems/double/meta.yml new file mode 100644 index 0000000..21ffc4b --- /dev/null +++ b/t/problems/double/meta.yml @@ -0,0 +1,14 @@ +--- +name: A-B +generator: File +judge: Absolute +runner: File +testcnt: 10 +timeout: 1 +mlimit: 20971520 +olimit: 100 +description: The A * 2 problem +files: + prog: + format: CPP + name: prog.cpp diff --git a/t/problems/double/tests/wa/meta.yml b/t/problems/double/tests/wa/meta.yml new file mode 100644 index 0000000..00f38de --- /dev/null +++ b/t/problems/double/tests/wa/meta.yml @@ -0,0 +1,18 @@ +test_name: Wrong answer +test_description: A program which fails on test 4 +problem: double +expected_result: 1 +expected_result_text: Wrong answer +expected_results: +- id: 1 + result: 0 + result_text: 0 +- id: 2 + result: 0 + result_text: 0 +- id: 3 + result: 0 + result_text: 0 +- id: 4 + result: 1 + result_text: Wrong answer diff --git a/t/problems/double/tests/wa/prog.cpp b/t/problems/double/tests/wa/prog.cpp new file mode 100644 index 0000000..8dd19c7 --- /dev/null +++ b/t/problems/double/tests/wa/prog.cpp @@ -0,0 +1,8 @@ +#include + +int main(void){ + char x; + scanf("%d", &x); + printf("%d", 2*x); + return 0; +} diff --git a/t/problems/increment/int.cpp b/t/problems/increment/int.cpp new file mode 100644 index 0000000..3b89262 --- /dev/null +++ b/t/problems/increment/int.cpp @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +int main(void){ + srand(time(NULL)); + for(int i=0;i<100;i++){ + int nr = rand() % 100; + printf("%d\n", nr); + fflush(stdout); + int ret; + scanf("%d", &ret); + if(ret != nr + 1){ + fprintf(stderr, "bad ret: %d instead of %d", ret, nr + 1); + return 1; + } + } + + if(write(4, "20", 2) == -1) + perror("write"); + return 0; +} diff --git a/t/problems/increment/meta.yml b/t/problems/increment/meta.yml new file mode 100644 index 0000000..3ca70dd --- /dev/null +++ b/t/problems/increment/meta.yml @@ -0,0 +1,16 @@ +--- +name: Increment +generator: Undef +judge: Points +runner: Interactive +testcnt: 5 +timeout: 1 +mlimit: 20971520 +description: A trivial interactive problem +files: + int: + format: CPP + name: int.cpp + prog: + format: CPP + name: prog.cpp diff --git a/t/problems/increment/tests/ac/meta.yml b/t/problems/increment/tests/ac/meta.yml new file mode 100644 index 0000000..9576c5c --- /dev/null +++ b/t/problems/increment/tests/ac/meta.yml @@ -0,0 +1,21 @@ +test_name: Accepted +test_description: A program which works correctly +problem: increment +expected_result: 0 +expected_result_text: Accepted +expected_results: +- id: 1 + result: 0 + result_text: 20 +- id: 2 + result: 0 + result_text: 20 +- id: 3 + result: 0 + result_text: 20 +- id: 4 + result: 0 + result_text: 20 +- id: 5 + result: 0 + result_text: 20 diff --git a/t/problems/increment/tests/ac/prog.cpp b/t/problems/increment/tests/ac/prog.cpp new file mode 100644 index 0000000..da549a7 --- /dev/null +++ b/t/problems/increment/tests/ac/prog.cpp @@ -0,0 +1,12 @@ +#include + +int main(void){ + for(int i=0;i<100;i++){ + int x; + scanf("%d", &x); + printf("%d\n", x + 1); + fflush(stdout); + } + + return 0; +} diff --git a/t/problems/square/gen.cpp b/t/problems/square/gen.cpp new file mode 100644 index 0000000..f5fe75b --- /dev/null +++ b/t/problems/square/gen.cpp @@ -0,0 +1,8 @@ +#include +#include + +int main(int argc, char **argv){ + int testnum = atoi(argv[0]); + printf("%d", testnum); + return 0; +} diff --git a/t/problems/square/meta.yml b/t/problems/square/meta.yml new file mode 100644 index 0000000..99ee850 --- /dev/null +++ b/t/problems/square/meta.yml @@ -0,0 +1,20 @@ +--- +name: A-B +generator: Run +judge: Points +runner: Verifier +testcnt: 10 +timeout: 1 +mlimit: 20971520 +olimit: 100 +description: The X^2 problem +files: + ver: + format: CPP + name: ver.cpp + gen: + format: CPP + name: gen.cpp + prog: + format: CPP + name: prog.cpp diff --git a/t/problems/square/tests/ac/meta.yml b/t/problems/square/tests/ac/meta.yml new file mode 100644 index 0000000..93fd38f --- /dev/null +++ b/t/problems/square/tests/ac/meta.yml @@ -0,0 +1,36 @@ +test_name: Accepted +test_description: A program which works correctly +problem: square +expected_result: 0 +expected_result_text: Accepted +expected_results: +- id: 1 + result: 0 + result_text: 10 +- id: 2 + result: 0 + result_text: 10 +- id: 3 + result: 0 + result_text: 10 +- id: 4 + result: 0 + result_text: 10 +- id: 5 + result: 0 + result_text: 10 +- id: 6 + result: 0 + result_text: 10 +- id: 7 + result: 0 + result_text: 10 +- id: 8 + result: 0 + result_text: 10 +- id: 9 + result: 0 + result_text: 10 +- id: 10 + result: 0 + result_text: 10 diff --git a/t/problems/square/tests/ac/prog.cpp b/t/problems/square/tests/ac/prog.cpp new file mode 100644 index 0000000..0a66015 --- /dev/null +++ b/t/problems/square/tests/ac/prog.cpp @@ -0,0 +1,8 @@ +#include + +int main(void){ + int x; + scanf("%d", &x); + printf("%d", x*x); + return 0; +} diff --git a/t/problems/square/ver.cpp b/t/problems/square/ver.cpp new file mode 100644 index 0000000..cb4d031 --- /dev/null +++ b/t/problems/square/ver.cpp @@ -0,0 +1,14 @@ +#include + +int main(void){ + FILE *output = fdopen(3, "r"); + int x, ret; + scanf("%d", &x); + fscanf(output, "%d", &ret); + if(x*x == ret){ + printf("10"); + return 0; + } else + return 1; +} +