Skip to content
Open
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ pep8term
app.ini
nitunit.out
nitunit.xml
*.*~
9 changes: 7 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM nitlang/nit

# Needed for nitcorn and to build mongo-c-driver
RUN apt-get update && apt-get install -y libevent-dev libssl-dev libsasl2-dev libcurl4-openssl-dev file
RUN apt-get update && apt-get install -y libevent-dev libssl-dev libsasl2-dev libcurl4-openssl-dev file openjdk-7-jre-headless

# Install mongo-c-driver manually since it is not available in Debian/jessie
RUN curl -L https://github.com/mongodb/mongo-c-driver/releases/download/1.4.0/mongo-c-driver-1.4.0.tar.gz -o mongo-c-driver-1.4.0.tar.gz \
Expand All @@ -12,8 +12,13 @@ RUN curl -L https://github.com/mongodb/mongo-c-driver/releases/download/1.4.0/mo
&& make install \
&& ldconfig

# Copy and compile the code
WORKDIR /missions
RUN curl -L http://downloads.sourceforge.net/project/useocl/USE/4.2.0/use-4.2.0.tar.gz -o use-4.2.0.tar.gz \
&& tar xzf use-4.2.0.tar.gz \
&& echo '/missions/use-4.2.0/bin/use "$@"' > /usr/local/bin/use \
&& chmod +x /usr/local/bin/use

# Copy and compile the code
COPY . /missions/
RUN make pep8term && make

Expand Down
76 changes: 76 additions & 0 deletions share/useoclrun.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/bin/sh

# Script to execute a USE-OCL subission.
# Communication is done with the file system:
#
# INPUT
#
# * source.use : the submission source code
# * test*/input.txt : the input for each test
#
# OUTPUT
#
# * test*/output.txt : the produced output for each test
# * test*/execerr.txt : execution error messages, if any
#
# To avoid the submission to look at the expected results or to temper them, the script just compile and run.
# The evaluation of the results has to be done by the caller.

# Transform a bash return value caused by ulimit into a message for a human.
# Not really portable :(
ulimitmsg() {
code=$1
file=$2
# 128+n = signal n
case "$code" in
137)
# 128+9 = KILL = time out
echo "CPU time limit exceeded" > "$file"
return 1;;
153)
# 128+25 = XFSZ = file limit
echo "File size limit exceeded" > "$file"
return 1;;
*)
# USE OCL returned 1 (a constraint failed)
return 0
esac
}

# Try to compile
compile() {
# Try to compile
(
ulimit -t 5 # 5s CPU time
ulimit -f 128 # 1kB written files
use -nogui -nr -c source.use 2> cmperr.txt
) || {
ulimitmsg "$?" cmperr.txt
return 1
}

return 0
}

# Run a test of subdirectory
runtest() {
t=$1

# Try to execute the program on the test input
(
ulimit -t 5 # 5s CPU time
ulimit -f 128 # 1kB written files
use -nogui -nr -t -qv source.use $t/input.txt > $t/output.txt 2>&1
# $t/execerr.txt
# cat $t/output.txt
# cat $t/execerr.txt
) || {
return ulimitmsg "$?" $t/execerr.txt
}
return 0
}

# Main
compile || exit 1
for t in test*; do runtest "$t"; done
exit 0
7 changes: 6 additions & 1 deletion src/api/api_missions.nit
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ class APIMission
print "Error deserializing submitted mission: {post}"
return
end
var runner = config.engine_map[submission_form.engine]

if not config.engine_map.has_key(mission.engine) then
res.api_error("Engine {mission.engine} not found", 500)
return
end
var runner = config.engine_map[mission.engine]
var submission = new Submission(player, mission, submission_form.source.decode_base64.to_s)
runner.run(submission, config)

Expand Down
1 change: 1 addition & 0 deletions src/api/engine_configuration.nit
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ redef class AppConfig

init do
engine_map["pep8term"] = new Pep8Engine
engine_map["use-ocl"] = new UseOclEngine
end
end
2 changes: 1 addition & 1 deletion src/db_loader.nit
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ if level >= 1 then
var last_missions = new Array[Mission]
var mission_count = (10 * level).rand
for j in [1..mission_count] do
var mission = new Mission("track{i}:mission{j}", track, "Mission {i}-{j}", "desc {j}")
var mission = new Mission("track{i}:mission{j}", track, "Mission {i}-{j}", "desc {j}", "pep8term", "pep8")
if last_missions.not_empty then
if 100.rand > 75 then
mission.parents.add last_missions.last.id
Expand Down
1 change: 0 additions & 1 deletion src/model/engines/engine_base.nit
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ class Engine
test.expected_output.write_to_file(sfile)

# Compare the result with diff
# TODO: some HTML-rich diff? Maybe client-side?
res.produced_output = ofile.to_path.read_all
var r = system("cd {ts} && diff -u sav.txt output.txt > diff.txt")
if r != 0 then
Expand Down
1 change: 1 addition & 0 deletions src/model/engines/engines.nit
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ module engines
import engine_base
import pep8
import nitc
import use
46 changes: 46 additions & 0 deletions src/model/engines/use.nit
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# USE-OCL engine
module use

import engine_base

# Handler for a USE-OCL submission
class UseOclEngine
super Engine

redef fun language do return "OCL"

redef fun extension do return "use"

redef fun execute(submission)
do
var ws = submission.workspace
if ws == null then return false

# Copy scripts and requirements
system("cp share/useoclrun.sh {ws}")

# Run the payload
var r = system("share/saferun.sh {ws} ./useoclrun.sh")

# Retrieve information
if r != 0 then
var err = (ws/"cmperr.txt").to_path.read_all
submission.compilation.message = "compilation error: {err}"
return false
end

return true
end
end
10 changes: 9 additions & 1 deletion src/model/loader.nit
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ class Loader
if sd != null then track.default_size_desc = sd
var ss = ini.get_i("star.size.reward")
if ss != null then track.default_size_score = ss
var en = ini["engine"]
if en != null then track.default_engine = en
var ed = ini["editor"]
if ed != null then track.default_editor = ed

var tmpl = (path / "template").to_path.read_all
if not tmpl.is_empty then track.default_template = tmpl
Expand Down Expand Up @@ -171,7 +175,11 @@ class Loader
title_id = title.strip_id
end

var m = new Mission(title_id, track, title, html)
var engine = ini["engine"] or else (if track != null then track.default_engine else "")

var editor = ini["editor"] or else (if track != null then track.default_editor else "")

var m = new Mission(title_id, track, title, html, engine, editor)
m.path = path

var reqs = ini["req"]
Expand Down
6 changes: 6 additions & 0 deletions src/model/missions.nit
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ class Mission
var title: String
var desc: String

# Engine used to check submissions
var engine: String is writable

# Frontend code editor to use
var editor: String is writable

# List of allowed languages
var languages = new Array[String]

Expand Down
4 changes: 0 additions & 4 deletions src/model/submissions.nit
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,6 @@ class SubmissionForm

# Source code to be run
var source: String
# Engine or runner to be used
var engine: String
# Language in which the source code is writte
var lang: String
end

redef class MissionStar
Expand Down
2 changes: 1 addition & 1 deletion tests/test_base.nit
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class TestBase
end

fun new_mission(track: nullable Track, id: String): Mission do
var mission = new Mission(id, track, "title_{id}", "desc_{id}")
var mission = new Mission(id, track, "title_{id}", "desc_{id}", "engine_{id}", "editor")
mission.solve_reward = 10
config.missions.save mission
return mission
Expand Down
113 changes: 113 additions & 0 deletions tests/tracks/test_useocl.nit
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Copyright 2017 Alexandre Terrasa <alexandre@moz-code.org>.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

module test_useocl is test_suite

import test_base
import model::loader
import api::engine_configuration

class UseOclTest
super TestBase

fun test_track_load do
var mission = config.missions.find_all.first
assert mission.title == "Classes"
assert mission.testsuite.length == 2
end

fun test_compilation_error do
var player = new_player("p1")
var source = ""
var mission = config.missions.find_all.first
var sub = new Submission(player, mission, source)
var runner = config.engine_map["use-ocl"]
runner.run(sub, config)

assert sub.status == "error"
assert sub.test_errors == 0
assert sub.results.length == 0
assert sub.size_score == null
assert sub.time_score == null
assert sub.compilation.message == """
compilation error: source.use:line 1:0 mismatched input '<EOF>' expecting 'model'
"""
end

fun test_bad_input1 do
var player = new_player("p2")
var source = """
model bank

class BankAccount
attributes
balance: Integer
end

constraints

context BankAccount
inv: balance >= 0
"""
var mission = config.missions.find_all.first
var sub = new Submission(player, mission, source)
var runner = config.engine_map["use-ocl"]
runner.run(sub, config)
assert sub.status == "error"
assert sub.test_errors == 2
assert sub.results.length == 2
end

fun test_good_input1 do
var player = new_player("p2")
var source = """
model SpaceZ

abstract class Vaisseau
attributes
poids: Integer
operations
decoller()
end

class VaisseauCargo < Vaisseau
attributes
capacite: Integer
operations
charger(poids: Integer)
end

class VaisseauCombat < Vaisseau
operations
attaquer(vaisseau: Vaisseau)
end
"""
var mission = config.missions.find_all.first
var sub = new Submission(player, mission, source)
var runner = config.engine_map["use-ocl"]
runner.run(sub, config)
assert sub.status == "success"
assert sub.test_errors == 0
assert sub.results.length == 2
end
end

redef fun before_module do
var config = new AppConfig
config.parse_options(new Array[String])
var loader = new Loader(config)
loader.load_track("tracks/use-ocl")
end

redef fun after_module do super
2 changes: 0 additions & 2 deletions tracks-wip/nit/01_hello/config.ini

This file was deleted.

Loading