diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/CMakeLists.txt | 28 | ||||
| -rw-r--r-- | tests/test_conda.c | 61 | ||||
| -rw-r--r-- | tests/test_envctl.c | 72 | ||||
| -rw-r--r-- | tests/test_multiprocessing.c | 92 | 
4 files changed, 237 insertions, 16 deletions
| diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f4380e0..0da290f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,30 +12,30 @@ set(win_msvc_cflags /Wall)  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/data/generic.ini ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/data/result.xml ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/data/result_error.xml ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) -file(GLOB files "test_*.c") +file(GLOB source_files "test_*.c") -if (BASH_PROGRAM) +if (BASH_PROGRAM AND BUILD_TESTING_RT)      add_test (rt_generic ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/rt_generic.sh)  endif() -foreach(file ${files}) -    string(REGEX REPLACE "(^.*/|\\.[^.]*$)" "" file_without_ext ${file}) -    add_executable(${file_without_ext} ${file}) +foreach(source_file ${source_files}) +    string(REGEX REPLACE "(^.*/|\\.[^.]*$)" "" test_executable ${source_file}) +    add_executable(${test_executable} ${source_file})      if (CMAKE_C_COMPILER_ID STREQUAL "GNU") -        target_compile_options(${file_without_ext} PRIVATE ${nix_cflags} ${nix_gnu_cflags}) +        target_compile_options(${test_executable} PRIVATE ${nix_cflags} ${nix_gnu_cflags})      elseif (CMAKE_C_COMPILER_ID MATCHES "Clang") -        target_compile_options(${file_without_ext} PRIVATE ${nix_cflags} ${nix_clang_cflags}) +        target_compile_options(${test_executable} PRIVATE ${nix_cflags} ${nix_clang_cflags})      elseif (CMAKE_C_COMPILER_ID STREQUAL "MSVC") -        target_compile_options(${file_without_ext} PRIVATE ${win_cflags} ${win_msvc_cflags}) +        target_compile_options(${test_executable} PRIVATE ${win_cflags} ${win_msvc_cflags})      endif() -    target_link_libraries(${file_without_ext} PRIVATE stasis_core) -    add_test(${file_without_ext} ${file_without_ext}) -    set_tests_properties(${file_without_ext} +    target_link_libraries(${test_executable} PRIVATE stasis_core) +    add_test(${test_executable} ${test_executable}) +    set_tests_properties(${test_executable}              PROPERTIES -            TIMEOUT 120) -    set_tests_properties(${file_without_ext} +            TIMEOUT 240) +    set_tests_properties(${test_executable}              PROPERTIES              SKIP_RETURN_CODE 127) -    set_property(TEST ${file_without_ext} +    set_property(TEST ${test_executable}              PROPERTY ENVIRONMENT "STASIS_SYSCONFDIR=${CMAKE_SOURCE_DIR}")  endforeach()
\ No newline at end of file diff --git a/tests/test_conda.c b/tests/test_conda.c index 2ed869a..9ad12c8 100644 --- a/tests/test_conda.c +++ b/tests/test_conda.c @@ -126,6 +126,57 @@ void test_conda_index() {      STASIS_ASSERT(conda_index("channel") == 0, "cannot index a simple conda channel");  } +void test_pip_index_provides() { +    struct testcase { +        const char *pindex; +        const char *name; +        int expected; +    }; +    struct testcase tc[] = { +        {.pindex = PYPI_INDEX_DEFAULT, .name = "firewatch", .expected = 1}, +        {.pindex = PYPI_INDEX_DEFAULT, .name = "doesnotexistfirewatch", .expected = 0}, +        {.pindex = "bad_index", .name = "firewatch", .expected = 0}, +        {.pindex = PYPI_INDEX_DEFAULT, .name = "", .expected = -1}, +        {.pindex = "", .name = "", .expected = -1}, +    }; +    for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { +        struct testcase *test = &tc[i]; +        int result = pip_index_provides(test->pindex, test->name) ; +        STASIS_ASSERT(result == test->expected, "Unexpected result"); +    } +} + +void test_conda_get_active_environment() { +    conda_activate(ctx.storage.conda_install_prefix, "base"); +    STASIS_ASSERT(strcmp(conda_get_active_environment(), "base") == 0, "base environment not active"); +} + +void test_conda_provides() { +    struct testcase { +        const char *name; +        int expected; +    }; +    struct testcase tc[] = { +        {.name = "fitsverify", .expected = 1}, +        {.name = "doesnotexistfitsverify", .expected = 0}, +        {.name = "", .expected = 0}, +    }; + +    for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { +        struct testcase *test = &tc[i]; +        int result = conda_provides(test->name); +        printf("%s returned %d, expecting %d\n", test->name, result, test->expected); +        STASIS_ASSERT(result == test->expected, "Unexpected result"); +    } +} + +void test_delivery_gather_tool_versions() { +    int status = delivery_gather_tool_versions(&ctx); +    STASIS_ASSERT(status == 0, "Failed to gather tool versions"); +    STASIS_ASSERT(!isempty(ctx.conda.tool_version), "conda version is empty"); +    STASIS_ASSERT(!isempty(ctx.conda.tool_build_version), "conda_build version is empty"); +} +  int main(int argc, char *argv[]) {      STASIS_TEST_BEGIN_MAIN();      STASIS_TEST_FUNC *tests[] = { @@ -133,11 +184,15 @@ int main(int argc, char *argv[]) {          test_conda_installation,          test_conda_activate,          test_conda_setup_headless, +        test_conda_provides, +        test_conda_get_active_environment,          test_conda_exec,          test_python_exec,          test_conda_env_create_from_uri,          test_conda_env_create_export_remove,          test_conda_index, +        test_pip_index_provides, +        test_delivery_gather_tool_versions,      };      const char *ws = "workspace"; @@ -165,8 +220,8 @@ int main(int argc, char *argv[]) {      ctx._stasis_ini_fp.delivery = ini;      ctx._stasis_ini_fp.delivery_path = realpath("mock.ini", NULL); -    setenv("TMPDIR", cwd_workspace, 1); -    globals.sysconfdir = getenv("STASIS_SYSCONFDIR"); +    const char *sysconfdir = getenv("STASIS_SYSCONFDIR"); +    globals.sysconfdir = strdup(sysconfdir ? sysconfdir : STASIS_SYSCONFDIR);      ctx.storage.root = strdup(cwd_workspace);      setenv("LANG", "C", 1); @@ -179,5 +234,7 @@ int main(int argc, char *argv[]) {      if (rmtree(cwd_workspace)) {          perror(cwd_workspace);      } +    delivery_free(&ctx); +    globals_free();      STASIS_TEST_END_MAIN();  }
\ No newline at end of file diff --git a/tests/test_envctl.c b/tests/test_envctl.c new file mode 100644 index 0000000..eab0186 --- /dev/null +++ b/tests/test_envctl.c @@ -0,0 +1,72 @@ +#include "testing.h" +#include "envctl.h" + +void test_envctl_init() { +    struct EnvCtl *envctl; +    STASIS_ASSERT_FATAL((envctl = envctl_init()) != NULL, "envctl could not be initialized"); +    STASIS_ASSERT(envctl->num_alloc == STASIS_ENVCTL_DEFAULT_ALLOC, "freshly initialized envctl does not have the correct number records"); +    STASIS_ASSERT(envctl->num_used == 0, "freshly initialized envctl should have no allocations in use"); +    STASIS_ASSERT(envctl->item != NULL, "freshly initialized envctl should have an empty items array. this one is NULL."); +    STASIS_ASSERT(envctl->item[0] == NULL, "freshly initialized envctl should not have any items. this one does."); +    envctl_free(&envctl); +    STASIS_ASSERT(envctl == NULL, "envctl should be NULL after envctl_free()"); +} + +static int except_passthru(const void *a, const void *b) { +    const struct EnvCtl_Item *item = a; +    const char *name = b; +    if (!envctl_check_required(item->flags) && envctl_check_present(item, name)) { +        return STASIS_ENVCTL_RET_SUCCESS; +    } +    return STASIS_ENVCTL_RET_FAIL; +} + +static int except_required(const void *a, const void *b) { +    const struct EnvCtl_Item *item = a; +    const char *name = b; +    if (envctl_check_required(item->flags) && envctl_check_present(item, name)) { +        return STASIS_ENVCTL_RET_SUCCESS; +    } +    return STASIS_ENVCTL_RET_FAIL; +} + +static int except_redact(const void *a, const void *b) { +    const struct EnvCtl_Item *item = a; +    const char *name = b; +    if (envctl_check_redact(item->flags) && envctl_check_present(item, name)) { +        return STASIS_ENVCTL_RET_SUCCESS; +    } +    return STASIS_ENVCTL_RET_FAIL; +} + +void test_envctl_register() { +    struct EnvCtl *envctl; +    envctl = envctl_init(); +    setenv("passthru", "true", 1); +    setenv("required", "true", 1); +    setenv("redact", "true", 1); +    envctl_register(&envctl, STASIS_ENVCTL_PASSTHRU, except_passthru, "passthru"); +    envctl_register(&envctl, STASIS_ENVCTL_REQUIRED, except_required, "required"); +    envctl_register(&envctl, STASIS_ENVCTL_REDACT, except_redact, "redact"); + +    unsigned flags[] = { +        STASIS_ENVCTL_PASSTHRU, +        STASIS_ENVCTL_REQUIRED, +        STASIS_ENVCTL_REDACT, +    }; +    for (size_t i = 0; i < envctl->num_used; i++) { +        struct EnvCtl_Item *item = envctl->item[i]; +        STASIS_ASSERT(item->flags == flags[i], "incorrect flag for item"); +    } +    envctl_free(&envctl); +} + +int main(int argc, char *argv[]) { +    STASIS_TEST_BEGIN_MAIN(); +    STASIS_TEST_FUNC *tests[] = { +        test_envctl_init, +        test_envctl_register, +    }; +    STASIS_TEST_RUN(tests); +    STASIS_TEST_END_MAIN(); +}
\ No newline at end of file diff --git a/tests/test_multiprocessing.c b/tests/test_multiprocessing.c index b9cd309..7c9d695 100644 --- a/tests/test_multiprocessing.c +++ b/tests/test_multiprocessing.c @@ -1,5 +1,6 @@  #include "testing.h"  #include "multiprocessing.h" +#include <pthread.h>  static struct MultiProcessingPool *pool;  char *commands[] = { @@ -12,6 +13,10 @@ char *commands[] = {  };  void test_mp_pool_init() { +    STASIS_ASSERT((pool = mp_pool_init(NULL, "mplogs")) == NULL, "Pool should not be initialized with invalid ident"); +    STASIS_ASSERT((pool = mp_pool_init("mypool", NULL)) == NULL, "Pool should not be initialized with invalid logname"); +    STASIS_ASSERT((pool = mp_pool_init(NULL, NULL)) == NULL, "Pool should not be initialized with invalid arguments"); +    pool = NULL;      STASIS_ASSERT((pool = mp_pool_init("mypool", "mplogs")) != NULL, "Pool initialization failed");      STASIS_ASSERT_FATAL(pool != NULL, "Should not be NULL");      STASIS_ASSERT(pool->num_alloc == MP_POOL_TASK_MAX, "Wrong number of default records"); @@ -56,6 +61,7 @@ void test_mp_task() {      pool = mp_pool_init("mypool", "mplogs");      if (pool) { +        pool->status_interval = 3;          for (size_t i = 0; i < sizeof(commands) / sizeof(*commands); i++) {              struct MultiProcessingTask *task;              char task_name[100] = {0}; @@ -113,6 +119,90 @@ void test_mp_pool_workflow() {      }  } +void test_mp_fail_fast() { +    char *commands_ff[128] = { +        "sleep 3; true", +        "sleep 5; false", +    }; + +    // Pad the array with tasks. None of these should execute when +    // the "fail fast" conditions are met +    char *nopcmd = "sleep 30; true"; +    for (size_t i = 2; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) { +        commands_ff[i] = nopcmd; +    } + +    struct MultiProcessingPool *p; +    STASIS_ASSERT((p = mp_pool_init("failfast", "failfastlogs")) != NULL, "Failed to initialize pool"); +    for (size_t i = 0; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) { +        char *command = commands_ff[i]; +        char taskname[100] = {0}; +        snprintf(taskname, sizeof(taskname) - 1, "task_%03zu", i); +        STASIS_ASSERT(mp_pool_task(p, taskname, NULL, (char *) command) != NULL, "Failed to queue task"); +    } + +    STASIS_ASSERT(mp_pool_join(p, get_cpu_count(), MP_POOL_FAIL_FAST) < 0, "Unexpected result"); + +    struct result { +        int total_signaled; +        int total_status_fail; +        int total_status_success; +        int total_unused; +    } result = { +        .total_signaled = 0, +        .total_status_fail = 0, +        .total_status_success = 0, +        .total_unused = 0, +    }; +    for (size_t i = 0; i < p->num_used; i++) { +        struct MultiProcessingTask *task = &p->task[i]; +        if (task->signaled_by) result.total_signaled++; +        if (task->status > 0) result.total_status_fail++; +        if (task->status == 0) result.total_status_success++; +        if (task->pid == MP_POOL_PID_UNUSED && task->status == MP_POOL_TASK_STATUS_INITIAL) result.total_unused++; +    } +    fprintf(stderr, "total_status_fail = %d\ntotal_status_success = %d\ntotal_signaled = %d\ntotal_unused = %d\n", +            result.total_status_fail, result.total_status_success, result.total_signaled, result.total_unused); +    STASIS_ASSERT(result.total_status_fail, "Should have failures"); +    STASIS_ASSERT(result.total_status_success, "Should have successes"); +    STASIS_ASSERT(result.total_signaled, "Should have signaled PIDs"); +    STASIS_ASSERT(result.total_unused, "Should have PIDs marked UNUSED."); +    mp_pool_show_summary(p); +    mp_pool_free(&p); +} + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static void *pool_container(void *data) { +    char *commands_sc[] = { +        "sleep 10; echo done sleeping" +    }; +    struct MultiProcessingPool **x = (struct MultiProcessingPool **) data; +    struct MultiProcessingPool *p = (*x); +    pthread_mutex_lock(&mutex); +    mp_pool_task(p, "stop_resume_test", NULL, commands_sc[0]); +    mp_pool_join(p, 1, 0); +    mp_pool_show_summary(p); +    mp_pool_free(&p); +    pthread_mutex_unlock(&mutex); +    return NULL; +} + +void test_mp_stop_continue() { +    struct MultiProcessingPool *p = NULL; +    STASIS_ASSERT((p = mp_pool_init("stopcontinue", "stopcontinuelogs")) != NULL, "Failed to initialize pool"); +    pthread_t th; +    pthread_create(&th, NULL, pool_container, &p); +    sleep(2); +    if (p->task[0].pid != MP_POOL_PID_UNUSED) { +        STASIS_ASSERT(kill(p->task[0].pid, SIGSTOP) == 0, "SIGSTOP failed"); +        sleep(2); +        STASIS_ASSERT(kill(p->task[0].pid, SIGCONT) == 0, "SIGCONT failed"); +    } else { +        STASIS_ASSERT(false, "Task was marked as unused when it shouldn't have been"); +    } +    pthread_join(th, NULL); +} +  int main(int argc, char *argv[]) {      STASIS_TEST_BEGIN_MAIN();      STASIS_TEST_FUNC *tests[] = { @@ -121,6 +211,8 @@ int main(int argc, char *argv[]) {          test_mp_pool_join,          test_mp_pool_free,          test_mp_pool_workflow, +        test_mp_fail_fast, +        test_mp_stop_continue      };      STASIS_TEST_RUN(tests);      STASIS_TEST_END_MAIN(); | 
