Skip to content

Add test for environments #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions go/src/pythia/backend/job.go
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
package backend

import (
"bytes"
"encoding/json"
"errors"
"flag"
@@ -185,6 +186,10 @@ func (job *Job) gatherOutput(stdout io.Reader) {
if read > job.Task.Limits.Output {
read = job.Task.Limits.Output
}
// Trim NULL bytes that could occur at the end of the buffer
if bytes.IndexByte(buffer, 0) != -1 {
read = bytes.IndexByte(buffer, 0)
}
job.output = strings.Replace(string(buffer[:read]), "\r\n", "\n", -1)
}

55 changes: 7 additions & 48 deletions go/src/pythia/backend/job_test.go
Original file line number Diff line number Diff line change
@@ -23,62 +23,21 @@ import (
"time"
)

// NewTestJob creates a job, configured with the paths exported from make.
func newTestJob(task pythia.Task, input string) *Job {
job := NewJob()
job.Task = task
job.Input = input
job.UmlPath = pytest.UmlPath
job.EnvDir = pytest.VmDir
job.TasksDir = pytest.TasksDir
return job
}

// RunTask executes task with input.
// It checks that the execution time and output length are within the specified
// limits.
func runTask(t *testing.T, task pythia.Task, input string) (status pythia.Status, output string) {
job := newTestJob(task, input)
wd := testutils.Watchdog(t, task.Limits.Time+1)
status, output = job.Execute()
wd.Stop()
if len(output) > task.Limits.Output {
t.Errorf("Job output is too large: max %d, got %d.", task.Limits.Output,
len(output))
}
return
}

// RunTaskCheck behaves like RunTask, but additionally checks for expected
// status and output.
func runTaskCheck(t *testing.T, task pythia.Task, input string,
status pythia.Status, output string) {
st, out := runTask(t, task, input)
testutils.Expect(t, "status", status, st)
testutils.Expect(t, "output", output, out)
}

// Shortcut for runTask(t, pytest.ReadTask(t, basename), ...)
func run(t *testing.T, basename string, input string, status pythia.Status,
output string) {
runTaskCheck(t, pytest.ReadTask(t, basename), input, status, output)
}

// Basic hello world task.
func TestJobHelloWorld(t *testing.T) {
run(t, "hello-world", "", pythia.Success, "Hello world!\n")
Run(t, "hello-world", "", pythia.Success, "Hello world!\n")
}

// Check that the goroutines are cleaned correctly.
func TestJobCleanup(t *testing.T) {
testutils.CheckGoroutines(t, func() {
run(t, "hello-world", "", pythia.Success, "Hello world!\n")
Run(t, "hello-world", "", pythia.Success, "Hello world!\n")
})
}

// Hello world task with input.
func TestJobHelloInput(t *testing.T) {
run(t, "hello-input", "me\npythia\n",
Run(t, "hello-input", "me\npythia\n",
pythia.Success, "Hello me!\nHello pythia!\n")
}

@@ -87,7 +46,7 @@ func TestJobTimeout(t *testing.T) {
if testing.Short() {
t.Skip("skipping timeout test in short mode")
}
run(t, "timeout", "", pythia.Timeout, "Start\n")
Run(t, "timeout", "", pythia.Timeout, "Start\n")
}

// This task should overflow the output buffer.
@@ -113,20 +72,20 @@ func TestJobOverflow(t *testing.T) {
// This task should overflow and be killed before the end.
func TestJobOverflowKill(t *testing.T) {
wd := testutils.Watchdog(t, 2)
run(t, "overflow-kill", "", pythia.Overflow, "abcde")
Run(t, "overflow-kill", "", pythia.Overflow, "abcde")
wd.Stop()
}

// This task is a fork bomb. It should succeed, but not take the whole time.
func TestJobForkbomb(t *testing.T) {
wd := testutils.Watchdog(t, 2)
run(t, "forkbomb", "", pythia.Success, "Start\nDone\n")
Run(t, "forkbomb", "", pythia.Success, "Start\nDone\n")
wd.Stop()
}

// Flooding the disk should not have any adverse effect.
func TestJobFlooddisk(t *testing.T) {
run(t, "flooddisk", "", pythia.Success, "Start\nDone\n")
Run(t, "flooddisk", "", pythia.Success, "Start\nDone\n")
}

// Aborting a job shall be immediate.
65 changes: 65 additions & 0 deletions go/src/pythia/backend/job_test_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2013 The Pythia Authors.
// This file is part of Pythia.
//
// Pythia is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Pythia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Pythia. If not, see <http://www.gnu.org/licenses/>.

package backend

import (
"pythia"
"testing"
"testutils"
"testutils/pytest"
)

// NewTestJob creates a job, configured with the paths exported from make.
func newTestJob(task pythia.Task, input string) *Job {
job := NewJob()
job.Task = task
job.Input = input
job.UmlPath = pytest.UmlPath
job.EnvDir = pytest.VmDir
job.TasksDir = pytest.TasksDir
return job
}

// RunTask executes task with input.
// It checks that the execution time and output length are within the specified
// limits.
func runTask(t *testing.T, task pythia.Task, input string) (status pythia.Status, output string) {
job := newTestJob(task, input)
wd := testutils.Watchdog(t, task.Limits.Time+1)
status, output = job.Execute()
wd.Stop()
if len(output) > task.Limits.Output {
t.Errorf("Job output is too large: max %d, got %d.", task.Limits.Output,
len(output))
}
return
}

// RunTaskCheck behaves like RunTask, but additionally checks for expected
// status and output.
func runTaskCheck(t *testing.T, task pythia.Task, input string,
status pythia.Status, output string) {
st, out := runTask(t, task, input)
testutils.Expect(t, "status", status, st)
testutils.Expect(t, "output", output, out)
}

// Shortcut for runTask(t, pytest.ReadTask(t, basename), ...)
// Warning: This function should not used except for testing purpose
func Run(t *testing.T, basename string, input string, status pythia.Status,
output string) {
runTaskCheck(t, pytest.ReadTask(t, basename), input, status, output)
}
10 changes: 10 additions & 0 deletions tasks/test-bash.task
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"environment": "busybox",
"taskfs": "test-bash.sfs",
"limits": {
"time": 60,
"memory": 32,
"disk": 50,
"output": 1024
}
}
1 change: 1 addition & 0 deletions tasks/test-bash/control
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/task/test-bash.sh
2 changes: 2 additions & 0 deletions tasks/test-bash/test-bash.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
cat
10 changes: 10 additions & 0 deletions tasks/test-c.task
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"environment": "c",
"taskfs": "test-c.sfs",
"limits": {
"time": 60,
"memory": 32,
"disk": 50,
"output": 1024
}
}
1 change: 1 addition & 0 deletions tasks/test-c/control
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/task/run.sh
6 changes: 6 additions & 0 deletions tasks/test-c/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
mkdir /tmp/work
cp /task/test-c.c /tmp/work/test-c.c
cd /tmp/work
make --silent test-c
./test-c
11 changes: 11 additions & 0 deletions tasks/test-c/test-c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include<stdio.h>

#define MAX_INPUT 100

int main() {
char line[MAX_INPUT];
while (fgets(line, MAX_INPUT, stdin)) {
printf("%s", line);
}
return 0;
}
10 changes: 10 additions & 0 deletions tasks/test-java.task
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"environment": "java",
"taskfs": "test-java.sfs",
"limits": {
"time": 60,
"memory": 32,
"disk": 50,
"output": 1024
}
}
10 changes: 10 additions & 0 deletions tasks/test-java/TestJava.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import java.io.IOException;

public class TestJava {
public static void main (String[] arg) throws java.io.IOException {
int i;
do {
System.out.write(i = System.in.read());
} while (i != -1);
}
}
1 change: 1 addition & 0 deletions tasks/test-java/control
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/task/run.sh
7 changes: 7 additions & 0 deletions tasks/test-java/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
PATH=/usr/lib/jvm/java-7-openjdk-i386/bin:$PATH
mkdir /tmp/work
cp /task/TestJava.java /tmp/work/TestJava.java
cd /tmp/work
javac TestJava.java
java TestJava
10 changes: 10 additions & 0 deletions tasks/test-mono.task
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"environment": "mono",
"taskfs": "test-mono.sfs",
"limits": {
"time": 60,
"memory": 32,
"disk": 50,
"output": 1024
}
}
15 changes: 15 additions & 0 deletions tasks/test-mono/TestMono.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Main
{
public class TestMono {
public static void Main (string[] args)
{
while (true) {
int input = Console.In.Read();
if (input == -1) break;
Console.Out.Write((char)input);
}
}
}
}
1 change: 1 addition & 0 deletions tasks/test-mono/control
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/task/run.sh
6 changes: 6 additions & 0 deletions tasks/test-mono/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
mkdir /tmp/work
cp /task/TestMono.cs /tmp/work/TestMono.cs
cd /tmp/work
mcs TestMono.cs
mono TestMono.exe
10 changes: 10 additions & 0 deletions tasks/test-python.task
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"environment": "python",
"taskfs": "test-python.sfs",
"limits": {
"time": 60,
"memory": 32,
"disk": 50,
"output": 1024
}
}
1 change: 1 addition & 0 deletions tasks/test-python/control
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/task/test-python.py
5 changes: 5 additions & 0 deletions tasks/test-python/test-python.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/python3

from sys import stdout, stdin

stdout.write(stdin.read())