diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..f4a671349c424ab6d76f4631eeb21b064283c341 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "libdap-python"] + path = libdap-python + url = https://gitlab.demlabs.net/cellframe/libdap-python.git + branch = features-2466 +[submodule "libdap"] + path = libdap + url = https://gitlab.demlabs.net/cellframe/libdap.git +[submodule "libdap-server-core-python"] + path = libdap-server-core-python + url = https://gitlab.demlabs.net/cellframe/libdap-server-core-python.git + branch = features-2466 +[submodule "libdap-crypto-python"] + path = libdap-crypto-python + url = https://gitlab.demlabs.net/cellframe/libdap-crypto-python.git + branch = features-2466 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..173b4819fbc4afbc820ff4275d7d05539c2311df --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,86 @@ +project(CellFrame C) +cmake_minimum_required(VERSION 2.8) + +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(CMAKE_C_STANDARD 11) +set(SUBMODULES_NO_BUILD ON) + +add_subdirectory(libdap) +add_subdirectory(libdap-python) +add_subdirectory(libdap-crypto-python) +add_subdirectory(libdap-server-core-python) +#add_subdirectory(libdap) +#add_subdirectory(libdap-crypto) + +file(GLOB PYTHON_CELLFRAME_SRCS src/*.c) +file(GLOB PYTHON_CELLFRAME_HEADERS include/*.h) + +set(Python_ADDITIONAL_VERSIONS 3.7) +find_package (PythonLibs REQUIRED) + +include_directories(${PYTHON_INCLUDE_DIR} include/) + +if (SKBUILD) + message(STATUS "The project is built using scikit-build") + find_package(PythonExtensions REQUIRED) + add_library(${PROJECT_NAME} MODULE ${PYTHON_CELLFRAME_SRCS} ${PYTHON_CELLFRAME_HEADERS}) + python_extension_module(${PROJECT_NAME}) + python_extension_module(${PROJECT_NAME} LINKED_MODULES_VAR dap_python_module) + python_extension_module(${PROJECT_NAME} LINKED_MODULES_VAR dap_crypto_python_module) + python_extension_module(${PROJECT_NAME} LINKED_MODULES_VAR DapServerCore) + install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION CellFrame) + install(FILES src/__init__.py DESTINATION CellFrame) +# install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libdap-python/libdap_python_module.so DESTINATION CellFrame/lib) +# install(TARGETS dap_python_module LIBRARY DESTINATION CellFrame) +# install(TARGETS dap_crypto_python_module LIBRARY DESTINATION CellFrame) +# install(TARGETS DapServerCore LIBRARY DESTINATION CellFrame) +else() + add_library(${PROJECT_NAME} SHARED ${PYTHON_CELLFRAME_SRCS} ${PYTHON_CELLFRAME_HEADERS}) +endif() + + target_link_libraries(${PROJECT_NAME}) + + target_link_libraries(${PROJECT_NAME} ${PYTHON_LIBRARIES}) + +#target_compile_options( +# dap_core PRIVATE +# "-fpic" +#) + +#target_compile_options( +# dap_python_module PRIVATE +# "-fpic" +#) + +#target_compile_options( +# dap_crypto_python_module PRIVATE +# "-fpic" +#) + +#target_compile_options( +# DapServerCore PRIVATE +# "-fpic" +#) + +target_link_libraries(${PROJECT_NAME} dap_python_module + dap_crypto_python_module + DapServerCore + ) +#target_link_libraries(${PROJECT_NAME} dap_core dap_crypto) + +target_include_directories(${PROJECT_NAME} INTERFACE include/) + + +#file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/libdapConnector.py +# DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + +#file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test/main_test.py +# DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) + +#if(BUILD_DAP_TESTS) +# file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test/main_test.py +# DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) +# enable_testing() + #add_subdirectory(test) +#endif() diff --git a/README.md b/README.md index 30e0d9ac0f135df4dd06f6c453ddd59f178682c5..69f3274b627177c835ddbd296a04842771a1fdf2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ # python-cellframe +## Build and Run tests: +To install, you must have Python3.7 and a scikit-build. +``` +git clone https://gitlab.demlabs.net/cellframe/python-cellframe.git +cd python-cellframe +git submodule update --init --recursive +sudo python3.7 setup.py install +python3.7 test/main_test.py +``` + diff --git a/include/python-cellframe.h b/include/python-cellframe.h new file mode 100644 index 0000000000000000000000000000000000000000..df1b7ca7a29a215a7508836d45ddf5ff8eb84c73 --- /dev/null +++ b/include/python-cellframe.h @@ -0,0 +1,61 @@ +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "libdap-python.h" +#include "libdap-crypto-python.h" +#include "libdap-server-core-python.h" +#include "libdap_crypto_key_type_python.h" +#include "libdap_crypto_data_type.h" +#include "dap_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#undef LOG_TAG +#define LOG_TAG "python-cellframe" + +static bool init_crypto; + +static PyObject* CellFrame_error; + +static PyObject *python_cellframe_init(PyObject *self, PyObject *args); + +static PyObject *python_cellframe_deinit(PyObject *self, PyObject *args); + +static PyMethodDef CellFramePythonMethods[] = { + {"init", python_cellframe_init, METH_VARARGS, "Initialization of the python-cellframe interface DAP (Deus Applicaions Prototypes)"}, + {"deinit", python_cellframe_deinit, METH_VARARGS, "Deinitialization of the python-cellframe interface DAP (Deus Applicaions Prototypes)"}, + {"setLogLevel", (PyCFunction)dap_set_log_level, METH_VARARGS, "Setting the logging level"}, + {"logIt", (PyCFunction)dap_log_it, METH_VARARGS, "The wrapper of the log_it function for the libdap library"}, + {"logItDebug", (PyCFunction)dap_log_it_debug, METH_VARARGS, "The log_it wrapper for the libdap library displays information with the logging level DEBUG"}, + {"logItInfo", (PyCFunction)dap_log_it_info, METH_VARARGS, "The log_it wrapper for the libdap library displays information with the logging level INFO"}, + {"logItNotice", (PyCFunction)dap_log_it_notice, METH_VARARGS, "The log_it wrapper for the libdap library displays information with the logging level NOTICE"}, + {"logItMessage", (PyCFunction)dap_log_it_message, METH_VARARGS, "The log_it wrapper for the libdap library displays information with the logging level MESSAGE"}, + {"logItDap", (PyCFunction)dap_log_it_dap, METH_VARARGS, "The log_it wrapper for the libdap library displays information with the logging level DAP"}, + {"logItWarning", (PyCFunction)dap_log_it_warning, METH_VARARGS, "The log_it wrapper for the libdap library displays information with the logging level WARNING"}, + {"logItAtt", (PyCFunction)dap_log_it_att, METH_VARARGS, "The log_it wrapper for the libdap library displays information with the logging level ATT"}, + {"logItError", (PyCFunction)dap_log_it_error, METH_VARARGS, "The log_it wrapper for the libdap library displays information with the logging level ERROR"}, + {"logItCritical", (PyCFunction)dap_log_it_critical, METH_VARARGS, "The log_it wrapper for the libdap library displays information with the logging level CRITICAL"}, + + {"configGetItem", (PyCFunction)py_m_dap_config_get_item, METH_VARARGS, ""}, + {"configGetItemDefault", (PyCFunction)py_m_dap_config_get_item_default, METH_VARARGS, ""}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef CellFramePythonModule = { + PyModuleDef_HEAD_INIT, + "CellFrame", /* name of module */ + NULL, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, + or -1 if the module keeps state in global variables. */ + CellFramePythonMethods +}; + +PyMODINIT_FUNC PyInit_CellFrame(void); + +#ifdef __cplusplus +} +#endif + + diff --git a/libdap b/libdap new file mode 160000 index 0000000000000000000000000000000000000000..d6b17b0bc60ae9c7015edd0a74523c43d9d5a628 --- /dev/null +++ b/libdap @@ -0,0 +1 @@ +Subproject commit d6b17b0bc60ae9c7015edd0a74523c43d9d5a628 diff --git a/libdap-crypto-python b/libdap-crypto-python new file mode 160000 index 0000000000000000000000000000000000000000..edd62ffc6b588b3bc877833e3585960b192b83d0 --- /dev/null +++ b/libdap-crypto-python @@ -0,0 +1 @@ +Subproject commit edd62ffc6b588b3bc877833e3585960b192b83d0 diff --git a/libdap-python b/libdap-python new file mode 160000 index 0000000000000000000000000000000000000000..0cddffd9bcbf28646ef996473e25d45852417f6a --- /dev/null +++ b/libdap-python @@ -0,0 +1 @@ +Subproject commit 0cddffd9bcbf28646ef996473e25d45852417f6a diff --git a/libdap-server-core-python b/libdap-server-core-python new file mode 160000 index 0000000000000000000000000000000000000000..f6f2041893f5bf0a9ffccbdf8d94d25fec8987c0 --- /dev/null +++ b/libdap-server-core-python @@ -0,0 +1 @@ +Subproject commit f6f2041893f5bf0a9ffccbdf8d94d25fec8987c0 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..108c2e6a86eea29113ff41deb6e6b34d09a49777 --- /dev/null +++ b/setup.py @@ -0,0 +1,22 @@ +import sys + +from skbuild import setup + +# Require pytest-runner only when running tests +#pytest_runner = (['pytest-runner>=2.0,<3dev'] +# if any(arg in sys.argv for arg in ('pytest', 'test')) +# else []) + +#setup_requires = pytest_runner + +setup( + name="CellFrame", + version="0.5.0", + description="SDK CellFrame network", + author='DEMLABS Inc. (2017-2019)', + license="GNU GPL", + packages=['CellFrame'], +# tests_require=['pytest'], +# setup_requires=setup_requires +) + diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4e6e61f68ce394fff2a156e04c7176d04252ed04 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1 @@ +from .CellFrame import * diff --git a/src/python-cellframe.c b/src/python-cellframe.c new file mode 100644 index 0000000000000000000000000000000000000000..1fd7abf735c70f5c883add35f5ee775ecdf9fbf9 --- /dev/null +++ b/src/python-cellframe.c @@ -0,0 +1,169 @@ +#include "python-cellframe.h" + + +static PyObject *python_cellframe_init(PyObject *self, PyObject *args){ + const char *app_name; + const char *file_name_log; + const char *config_dir; + const char *log_level; + const char *JSON_str; + init_crypto = false; + if (!PyArg_ParseTuple(args, "s", &JSON_str)){ + return NULL; + } + + PyObject *JSON_Module = PyImport_ImportModule("json"); + if (JSON_Module == NULL) { + PyErr_SetString(CellFrame_error, "ERROR importing module"); + return NULL; + } + PyObject* JSONLoadsFunction = PyObject_GetAttrString(JSON_Module, "loads"); + if (JSONLoadsFunction == NULL) + return NULL; + PyObject* argsInLoadsJSON = PyTuple_Pack(1,PyUnicode_FromString(JSON_str)); + PyObject* result = PyObject_CallObject(JSONLoadsFunction, argsInLoadsJSON); + if (result == NULL) + return NULL; + PyObject* getModules = PyDict_GetItemString(result, "modules"); + if (getModules == NULL) + return NULL; + PyObject* getDap = PyDict_GetItemString(result, "DAP"); + if (getDap == NULL) + return NULL; + /*Parse DAP*/ + PyObject* config_dir_PyObject = PyDict_GetItemString(getDap, "config_dir"); + PyObject* application_name_PyObject = PyDict_GetItemString(getDap, "application_name"); + PyObject* file_name_log_PyObject = PyDict_GetItemString(getDap, "file_name_log"); + PyObject* logLevel_PyObject = PyDict_GetItemString(getDap, "log_level"); + if (config_dir_PyObject == NULL || application_name_PyObject == NULL || + logLevel_PyObject == NULL || file_name_log_PyObject == NULL) + return NULL; + app_name = PyUnicode_AsUTF8(application_name_PyObject); + file_name_log = PyUnicode_AsUTF8(file_name_log_PyObject); + config_dir = PyUnicode_AsUTF8(config_dir_PyObject); + log_level = PyUnicode_AsUTF8(logLevel_PyObject); + + if (dap_common_init(app_name, file_name_log) != 0){ + PyErr_SetString(CellFrame_error, "Can't init common functions module"); + return NULL; + } + + dap_config_init(config_dir); + if ((g_config = dap_config_open(app_name) ) == NULL){ + PyErr_SetString(CellFrame_error, "Can't init general configurations"); + return NULL; + } + //Init modules + log_it(L_INFO, "Initializing modules ..."); + if (!PyList_Check(getModules)){ + PyErr_SetString(CellFrame_error, "Can't find an array of module names"); + return NULL; + } + Py_ssize_t size_list = PyList_Size(getModules); + for (int i=0; i < size_list;i++){ + PyObject *value = PyList_GetItem(getModules, i); + const char *c_value = PyUnicode_AsUTF8(value); + if (strcmp(c_value, "Crypto") == 0){ //Init crypto + log_it(L_INFO, "Initializing the %s module", c_value); + init_crypto = true; + if (dap_crypto_init() != 0){ + PyErr_SetString(CellFrame_error, "An error occurred while initializing the libdap-crypto-python module."); + return NULL; + } + } + if (strcmp(c_value, "ServerCore") == 0){ + PyObject* getServerCoreData = PyDict_GetItemString(result, "ServerCore"); + if (getServerCoreData == NULL){ + PyErr_SetString(CellFrame_error, "Initialization failed. ServerCore object not found in JSON." + " No settings are specified for initializing libdap-server-core-python."); + return NULL; + } + PyObject* Nl_thread_cnt = PyDict_GetItemString(getServerCoreData, "thread_cnt"); + PyObject* Nl_conn = PyDict_GetItemString(getServerCoreData, "conn"); + if ( (Nl_thread_cnt == NULL || Nl_conn == NULL) || !PyNumber_Check(Nl_thread_cnt) || + !PyNumber_Check(Nl_conn)){ + PyErr_SetString(CellFrame_error, "Failed to initialize ServerCore. " + "Fields thread_cnt and conn are not numerical or absent."); + return NULL; + } + PyObject *ll_thread_cnt= PyNumber_Long(Nl_thread_cnt); + PyObject *ll_conn = PyNumber_Long(Nl_conn); + uint32_t ul_thread_cnt = (uint32_t)PyLong_AsUnsignedLong(ll_thread_cnt); + size_t ul_conn = PyLong_AsSize_t(ll_conn); + if(dap_server_core_init(ul_thread_cnt, ul_conn) != 0 ){ + PyErr_SetString(CellFrame_error, "Failed to initialize ServerCore."); + return NULL; + } + } + } + return PyLong_FromLong(0); +} + +PyMODINIT_FUNC PyInit_CellFrame(void){ + + if (PyType_Ready(&DapObject_DapObjectType) < 0 || PyType_Ready(&dapCrypto_dapCryptoType) < 0 || + PyType_Ready(&ServerCore_ServerCoreType) < 0 || PyType_Ready(&dapEvents_dapEventsType) < 0 || + PyType_Ready(&dapEventsSocket_dapEventsSocketType) < 0 || + PyType_Ready(&CryptoKeyTypeObjecy_CryptoKeyTypeObjecyType) < 0 || + PyType_Ready(&CryptoDataTypeObjecy_CryptoDataTypeObjecyType) < 0) + return NULL; + + PyObject *module = PyModule_Create(&CellFramePythonModule); + + CellFrame_error = PyErr_NewException("libCellFrame.error", NULL, NULL); + PyModule_AddObject(module, "error", CellFrame_error); + PyModule_AddObject(module, "DEBUG", PyLong_FromLong(L_DEBUG)); + PyModule_AddObject(module, "INFO", PyLong_FromLong(L_INFO)); + PyModule_AddObject(module, "NOTICE", PyLong_FromLong(L_NOTICE)); + PyModule_AddObject(module, "MESSAGE", PyLong_FromLong(L_MSG)); + PyModule_AddObject(module, "DAP", PyLong_FromLong(L_DAP)); + PyModule_AddObject(module, "WARNING", PyLong_FromLong(L_WARNING)); + PyModule_AddObject(module, "ATT", PyLong_FromLong(L_ATT)); + PyModule_AddObject(module, "ERROR", PyLong_FromLong(L_ERROR)); + PyModule_AddObject(module, "CRITICAL", PyLong_FromLong(L_CRITICAL)); + + PyModule_AddObject(module, "Crypto", (PyObject*)&dapCrypto_dapCryptoType); + + PyModule_AddObject(module, "ServerCore", (PyObject*)&ServerCore_ServerCoreType); + PyModule_AddObject(module, "Events", (PyObject*)&dapEvents_dapEventsType); + PyModule_AddObject(module, "EventsSocket", (PyObject*)&dapEventsSocket_dapEventsSocketType); + + PyModule_AddObject(module, "CryptoKeyType", (PyObject*)&CryptoKeyTypeObjecy_CryptoKeyTypeObjecyType); + PyModule_AddObject(module, "CryptoDataType", (PyObject*)&CryptoDataTypeObjecy_CryptoDataTypeObjecyType); + + + return module; +} + +static PyObject *python_cellframe_deinit(PyObject *self, PyObject *args){ + dap_config_close(g_config); + dap_config_deinit(); + if (init_crypto) + dap_crypto_deinit(); + return PyLong_FromLong(0); +} + +int main(int argc, char **argv) { + wchar_t *program = Py_DecodeLocale(argv[0], NULL); + if (program == NULL) { + fprintf(stderr, "Fatal error: cannot decode argv[0]\n"); + exit(1); + } + + /* Add a built-in module, before Py_Initialize */ + PyImport_AppendInittab("CellFrame", PyInit_CellFrame); + + /* Pass argv[0] to the Python interpreter */ + Py_SetProgramName(program); + + /* Initialize the Python interpreter. Required. */ + Py_Initialize(); + + /* Optionally import the module; alternatively, + import can be deferred until the embedded script + imports it. */ + PyImport_ImportModule("CellFrame"); + + PyMem_RawFree(program); + return 0; +} diff --git a/test/main_test.py b/test/main_test.py new file mode 100644 index 0000000000000000000000000000000000000000..7ff2e64084608ac89ce7855237dde9102ccfa429 --- /dev/null +++ b/test/main_test.py @@ -0,0 +1,118 @@ +from CellFrame import * +import pickle +import os +import sys + +def create_config_file(app_name): + f = open(app_name+".cfg", "w") + f.write("[server]\nlisten_address=0.0.0.0\n") + f.close() + +print("Start main test") +app_name = "testAPP" +print("Create config file") +create_config_file(app_name) + +json_string = """{ + "modules": ["crypto"], + "DAP": { + "config_dir": \""""+os.getcwd()+"""\", + "log_level": "L_DEBUG", + "application_name": \""""+app_name+"""\", + "file_name_log": \""""+app_name+""".text\" + } + }""" + + +print("init start") +init(json_string) +logItInfo("Initialization of the DAP done") +setLogLevel(DEBUG) +logItInfo("Level logging ""DEBUG"" done") +logItInfo( "Test. Outputting a string using the log_it function in the libdap library") +logItInfo("Outputting a string using the log_it function done") +res1 = configGetItem("server", "listen_address") +logItInfo("Output [server] 'listen_address' = "+res1+"\n") +res2 = configGetItemDefault("server1", "listen_address", "8.8.8.8") +logItInfo("Output default value '8.8.8.8' [server1] 'listen_address' = "+res2+"\n") +logItInfo( "TEST. Get default config done") + +logItInfo ("Create KEY") +key = Crypto.newKey(CryptoKeyType.DAP_ENC_KEY_TYPE_IAES()) +del key +logItInfo("Create KEY TWO") +key2 = Crypto.newKey(CryptoKeyType.DAP_ENC_KEY_TYPE_OAES()) +logItInfo ("Dellete key") +del key2 + +logItInfo("TEST BASE58. START...") +s = """Test! I will crush Base58!""" +base_in = pickle.dumps(s) +crypt = Crypto.encodeBase58(base_in) +decrypt = Crypto.decodeBase58(crypt) +out_data = pickle.loads(decrypt) +if s == out_data: + logItInfo ("TEST 1. Encode/Decode base58 done") +else: + logItInfo ("TEST 1. Encode/Decode base58 faild") + sys.exit(1) +logItInfo("TEST. BASE64 START...") +s = "Test! I will crush Base64!" +crypt = Crypto.encodeBase64(bytes(s, "utf-8"), CryptoDataType.DAP_ENC_DATA_TYPE_B64()) +decrypt = Crypto.decodeBase64(crypt, CryptoDataType.DAP_ENC_DATA_TYPE_B64()) +if bytes(s, "utf-8") == decrypt: + logItInfo ("TEST 1. Encode/Decode base64 done") +else: + logItInfo ("TEST 1. Encode/Decode base64 faild") + sys.exit(1) +logItInfo ("TEST.BASE64 URLSAFE START...") +u = "http://kelvin.foundation/" +crypt_u = Crypto.encodeBase64(bytes(u, "utf-8"), CryptoDataType.DAP_ENC_DATA_TYPE_B64_URLSAFE()) +decrypt_u = Crypto.decodeBase64(crypt_u, CryptoDataType.DAP_ENC_DATA_TYPE_B64_URLSAFE()) +if bytes(u, "utf-8") == decrypt_u: + logItInfo ("TEST 2. Encode/Decode base64 urlsafe done") +else: + logItInfo ("TEST 2. Encode/Decode base64 urlsafe faild") + sys.exit(2) + +logItInfo ("TEST. IAES256 CBC START...") +s = "Test! I will crush iaes256!" +kex_buff = bytes("123", "utf-8") +size_kex_buff = len(kex_buff) +seed = bytes(112771128) +seed_size = len(seed) +key_n = Crypto.generateNewKey(CryptoKeyType.DAP_ENC_KEY_TYPE_IAES(), kex_buff, size_kex_buff, seed, seed_size, 0) +source = bytes(s, "utf-8") +enc = Crypto.encryptIAES256CBCFast(key_n, source, len(source), 2048) +decrypt = Crypto.decryptIAES256CBCFast(key_n, enc, len(enc), 2048) +if bytes(s, "utf-8") == decrypt: + logItInfo ("TEST 1. Encode/Decode IAES256 CBC FAST done") +else: + logItInfo ("TEST 1. Encode/Decode IAES256 CBC FAST faild") + sys.exit(1) + +logItInfo ("TEST. OAES START...") +s = "Test! I will crush OAES!" +kex_buff = bytes("114151400014314485131FGXVGHcJFIH", "utf-8") +size_kex_buff = len(kex_buff) +seed = bytes(112771128) +seed_size = len(seed) +key_id = Crypto.generateNewKey(CryptoKeyType.DAP_ENC_KEY_TYPE_OAES(), kex_buff, size_kex_buff, seed, seed_size, 32) +source = bytes(s, "utf-8") +enc = Crypto.encryptOAESFast(key_id, source, len(source), 2048) +decrypt = Crypto.decryptOAESFast(key_id, enc, len(enc), 2048) +if bytes(s, "utf-8") == decrypt: + logItInfo ("TEST 1. Encode/Decode OAES FAST done") +else: + logItInfo ("TEST 1. Encode/Decode OAES CBC FAST faild") + sys.exit(1) + + + +deinit() +logItInfo("Deinitialization done") + +os.remove(app_name+".cfg") +logItInfo( "Main test done"); + +sys.exit(0)