diff --git a/src/tests.c b/src/tests.c index 46830d2c..085a5d3c 100644 --- a/src/tests.c +++ b/src/tests.c @@ -782,6 +782,100 @@ static void _test_http(const tf_test_options_t* options) uv_thread_join(&thread); } +static int _http_get_status_code(const char* url) +{ + char command[1024]; + snprintf(command, sizeof(command), "curl -s -o /dev/null -w '%%{http_code}' \"%s\"", url); + char buffer[256] = ""; + FILE* file = popen(command, "r"); + char* result = fgets(buffer, sizeof(buffer), file); + pclose(file); + return result ? atoi(result) : -1; +} + +static void _http_check_status_code(const char* url, int expected_code) +{ + char command[1024]; + snprintf(command, sizeof(command), "curl -s -o /dev/null -w '%%{http_code}' \"%s\"", url); + char buffer[256] = ""; + FILE* file = popen(command, "r"); + char* result = fgets(buffer, sizeof(buffer), file); + tf_printf("%s => %s\n", command, result); + assert(atoi(buffer) == expected_code); + assert(file); + int status = pclose(file); + (void)status; + assert(WEXITSTATUS(status) == 0); +} + +static void _http_check_body_contains(const char* url, const char* expected) +{ + char command[1024]; + snprintf(command, sizeof(command), "curl -s \"%s\"", url); + char buffer[1024] = ""; + FILE* file = popen(command, "r"); + bool found = false; + while (!found) + { + char* result = fgets(buffer, sizeof(buffer), file); + if (!result) + { + break; + } + found = strstr(buffer, expected) != NULL; + if (found) + { + tf_printf("%s => found: \"%s\"\n", url, expected); + } + } + assert(found); + assert(file); + int status = pclose(file); + (void)status; + assert(WEXITSTATUS(status) == 0); +} + +static void _test_httpd(const tf_test_options_t* options) +{ + uv_loop_t loop = { 0 }; + uv_loop_init(&loop); + + unlink("out/test_db0.sqlite"); + char command[256]; + snprintf(command, sizeof(command), "%s run -b 0 --db-path=out/test_db0.sqlite" TEST_ARGS, options->exe_path); + + uv_process_t process = { 0 }; + uv_spawn(&loop, &process, + &(uv_process_options_t) + { + .file = options->exe_path, + .args = (char*[]) { (char*)options->exe_path, "run", "-b0", "--db-path=out/test_db0.sqlite", "--http-port=8080", "--https-port=0", NULL }, + }); + + for (int i = 0; i < 100; i++) + { + if (_http_get_status_code("http://localhost:8080/mem") == 200) + { + break; + } + uv_sleep(1000); + } + + _http_check_status_code("http://localhost:8080/404", 404); + _http_check_status_code("http://localhost:8080/", 303); + _http_check_status_code("http://localhost:8080/~core/apps/", 200); + _http_check_status_code("http://localhost:8080/~core/apps", 303); + _http_check_status_code("http://localhost:8080/~core/apps/view", 200); + _http_check_body_contains("http://localhost:8080/~core/apps/", "Tilde Friends"); + _http_check_body_contains("http://localhost:8080/~core/apps/view", "\"type\":\"tildefriends-app\""); + + uv_process_kill(&process, SIGTERM); + uv_close((uv_handle_t*)&process, NULL); + uv_run(&loop, UV_RUN_ONCE); + + uv_loop_close(&loop); +} + static void _test_auto_process_exit(uv_process_t* process, int64_t status, int termination_signal) { tf_printf("Process exit %d signal=%d.\n", (int)WEXITSTATUS(status), termination_signal); @@ -887,6 +981,7 @@ void tf_tests(const tf_test_options_t* options) #if !TARGET_OS_IPHONE _tf_test_run(options, "bip39", _test_bip39, false); _tf_test_run(options, "http", _test_http, false); + _tf_test_run(options, "httpd", _test_httpd, false); _tf_test_run(options, "ssb", tf_ssb_test_ssb, false); _tf_test_run(options, "ssb_id", tf_ssb_test_id_conversion, false); _tf_test_run(options, "ssb_following", tf_ssb_test_following, false);