初步完成Python binding

增加单元测试基础
This commit is contained in:
LiYang 2016-08-21 17:59:39 +08:00 committed by LiYang
parent 0ec206bb4b
commit 69713edb78
9 changed files with 123 additions and 107 deletions

8
.gitignore vendored
View File

@ -1,10 +1,6 @@
.idea/
build/
a.out
limit
runner
main
demo
.DS_Store
judger.log
*.log
*.swp
*.so

13
.travis.yml Normal file
View File

@ -0,0 +1,13 @@
language: python
python:
- "2.7"
sudo: required
before_install:
- sudo apt-get -qq update
- sudo apt-get install libseccomp-dev cmake
install:
- mkdir build && cd build
- cmake .. && make && make install
- cd ../bindings/Python && python setup.py install
script:
- cd tests && sudo python test.py

View File

@ -2,8 +2,7 @@ cmake_minimum_required(VERSION 2.5)
project(judger C)
#set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/output/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/output/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/output)
set(BASE_CMAKE_C_FLAGS "-Wall -Werror -O3 -std=c99")
set(CMAKE_C_FLAGS "${BASE_CMAKE_C_FLAGS}")
@ -23,7 +22,4 @@ foreach(lang_rule_path ${RULE_SOURCE})
target_link_libraries("rule_${lang_name}" seccomp)
endforeach(lang_rule_path src/rules)
# make tests
add_executable(run_test test/main.c ${SOURCE})
target_link_libraries(run_test pthread dl seccomp)
install(DIRECTORY output/ DESTINATION /usr/lib/judger)

96
bindings/Python/_judger.c Normal file
View File

@ -0,0 +1,96 @@
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <python2.7/Python.h>
#include "../../src/runner.h"
#define RaiseValueError(msg) {PyErr_SetString(PyExc_ValueError, msg); return NULL;}
static PyObject *judger_run(PyObject *self, PyObject *args, PyObject *kwargs) {
struct config _config;
struct result _result = {0, 0, 0, 0, 0, 0};
PyObject *args_list = NULL, *env_list = NULL, *args_iter = NULL, *env_iter = NULL, *next = NULL;
int count = 0;
static char *kwargs_list[] = {"max_cpu_time", "max_real_time", "max_memory",
"max_process_number", "max_output_size",
"exe_path", "input_path", "output_path",
"error_path", "args", "env", "log_path",
"seccomp_rule_so_path", "uid", "gid", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iililssssOOssii", kwargs_list,
&(_config.max_cpu_time), &(_config.max_real_time), &(_config.max_memory),
&(_config.max_process_number), &(_config.max_output_size),
&(_config.exe_path), &(_config.input_path), &(_config.output_path),
&(_config.error_path), &args_list, &env_list, &(_config.log_path),
&(_config.seccomp_rule_so_path), &(_config.uid), &(_config.gid))) {
RaiseValueError("Invalid args and kwargs");
}
if (!PyList_Check(args_list)) {
RaiseValueError("args must be a list");
}
_config.args[count++] = _config.exe_path;
args_iter = PyObject_GetIter(args_list);
while (1) {
next = PyIter_Next((args_iter));
if (!next) {
break;
}
if (!PyString_Check(next)) {
RaiseValueError("arg in args must be a string");
}
_config.args[count] = PyString_AsString(next);
count++;
}
_config.args[count] = NULL;
count = 0;
if (!PyList_Check(env_list)) {
RaiseValueError("env must be a list");
}
env_iter = PyObject_GetIter(env_list);
while (1) {
next = PyIter_Next(env_iter);
if (!next) {
break;
}
if (!PyString_Check(next) && !PyUnicode_Check(next)) {
RaiseValueError("env item must be a string");
}
_config.env[count] = PyString_AsString(next);
count++;
}
_config.env[count] = NULL;
void *handler = dlopen("/usr/lib/judger/lib/libjudger.so", RTLD_LAZY);
int (*judger_run)(struct config *, struct result *);
if (!handler) {
RaiseValueError("dlopen error")
}
judger_run = dlsym(handler, "run");
judger_run(&_config, &_result);
return Py_BuildValue("{s:l, s:i, s:i, s:i, s:i, s:i}",
"cpu_time", _result.cpu_time, "memory", _result.memory, "real_time", _result.real_time,
"signal", _result.signal, "exit_code", _result.exit_code, "error", _result.error);
}
static PyMethodDef judger_methods[] = {
{"run", (PyCFunction) judger_run, METH_KEYWORDS, NULL},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC init_judger(void) {
Py_InitModule3("_judger", judger_methods, NULL);
}

7
bindings/Python/setup.py Normal file
View File

@ -0,0 +1,7 @@
# coding=utf-8
import platform
from distutils.core import setup, Extension
setup(name='_judger',
version='1.0',
ext_modules=[Extension('_judger', sources=['_judger.c'], libraries=["dl"])])

View File

@ -1,8 +0,0 @@
#include <seccomp.h>
#include "../../runner.h"
int load_seccomp(void *dl_handler) {
return 0;
}

View File

@ -1,30 +0,0 @@
#include <stdio.h>
#include "../src/runner.h"
int main() {
runner_config config;
config.max_cpu_time = 100;
config.max_real_time = 100;
config.max_memory = 1024 * 1024 * 1024;
config.max_process_number = 1024;
config.max_output_size = 1024 * 1024 * 64;
config.log_path = "log.log";
config.seccomp_rule_so_path = NULL;//"/home/virusdefender/ClionProjects/Judger/output/lib/librule_c_cpp.so";
config.input_path = "/dev/null";
config.output_path = "output.txt";
config.error_path = "error.txt";
config.exe_path = "/bin/ls";
config.args[0] = "/bin/ls";
config.args[1] = "/dev";
config.args[2] = NULL;
config.env[0] = "PATH=test";
config.env[1] = NULL;
runner_result result;
run(&config, &result);
printf("cpu time:%d\nreal time:%d\nmemory:%ld\nsignal:%d\nexit code:%d\nerror:%d", result.cpu_time, result.real_time, result.memory, result.signal, result.exit_code, result.error);
return 0;
}

View File

@ -1,57 +0,0 @@
/* This is a really minimal testing framework for C.
*
* Example:
*
* test_cond("Check if 1 == 1", 1==1)
* test_cond("Check if 5 > 10", 5 > 10)
* test_report()
*
* ----------------------------------------------------------------------------
*
* Copyright (c) 2010-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JDGER_TESTHELP_H
#define JDGER_TESTHELP_H
int __failed_tests = 0;
int __test_num = 0;
#define test_cond(descr,_c) do { \
__test_num++; printf("%d - %s: ", __test_num, descr); \
if(_c) printf("PASSED\n"); else {printf("FAILED\n"); __failed_tests++;} \
} while(0);
#define test_report() do { \
printf("%d tests, %d passed, %d failed\n", __test_num, \
__test_num-__failed_tests, __failed_tests); \
if (__failed_tests) { \
printf("=== WARNING === We have failed tests here...\n"); \
exit(1); \
} \
} while(0);
#endif

3
tests/test.py Normal file
View File

@ -0,0 +1,3 @@
# coding=utf-8
print "todo"