#include "testlib.h" RENDER(Request& context) { if(!test_demo_request_allowed(context)) { site_tests_restricted(context, "Filesystem", "write to local files and append server-side test data"); return; } u64 passed = 0; u64 failed = 0; u64 skipped = 0; auto check = [&](String name, bool ok, String detail) { site_tests_case(name, ok ? "pass" : "fail", detail); if(ok) passed++; else failed++; }; String file_name = path_join("/tmp", "uce-site-tests-io.txt"); bool write_ok = file_put_contents(file_name, "alpha"); file_append(file_name, "|beta"); String file_text = file_get_contents(file_name); site_tests_page_start("Filesystem", "Local-only file helper coverage using a temporary file under /tmp."); check("path_join()", file_name == "/tmp/uce-site-tests-io.txt", file_name); check("basename() / dirname() / expand_path()", basename(file_name) == "uce-site-tests-io.txt" && dirname(file_name) == "/tmp" && expand_path("child", "/tmp/base") == "/tmp/base/child" && contains(expand_path("../sibling", "/tmp/base"), "sibling"), basename(file_name) + " / " + dirname(file_name) + " / " + expand_path("../sibling", "/tmp/base")); check("file_put_contents()", write_ok, file_name); check("file_append() automatic exclusive lock", file_append(file_name, "|gamma") && contains(file_get_contents(file_name), "|gamma"), file_get_contents(file_name)); file_put_contents(file_name, "alpha|beta"); check("file_get_contents() automatic shared lock", file_text == "alpha|beta", file_text); check("file_mtime()", file_mtime(file_name) > 0, std::to_string((u64)file_mtime(file_name))); String real_tmp = path_real("/tmp"); String real_file = path_real(file_name); check("path_real() / path_is_within() canonical containment", real_tmp != "" && real_file != "" && path_is_within(file_name, "/tmp") && path_is_within("/tmp/../tmp/uce-site-tests-io.txt", "/tmp") && !path_is_within("/tmp", file_name) && !path_is_within("/tmp", "/tmp/uce-site-tests-io.txt"), real_tmp + " / " + real_file); String shell_escaped = shell_escape("a'b; echo injected"); String shell_out = shell_exec("printf %s " + shell_escaped); DValue shell_spec; shell_spec["cmd"] = "printf out; printf err >&2"; shell_spec["timeout_ms"] = (f64)500; DValue shell_dv = shell_exec(shell_spec); check("shell_escape() / shell_exec()", shell_out == "a'b; echo injected" && shell_dv["stdout"].to_string() == "out" && shell_dv["stderr"].to_string() == "err" && shell_dv["exit_code"].to_u64() == 0 && contains(shell_escaped, "'\\''"), shell_escaped + " => " + shell_out + " / " + json_encode(shell_dv)); DValue spawn_spec; spawn_spec["cmd"] = "printf spawned"; spawn_spec["timeout_ms"] = (f64)500; u64 job_id = shell_spawn(spawn_spec); DValue job_waited = job_await(job_id, 3000); DValue job_checked = job_status(job_id); DValue job_res = job_result(job_id); DValue cancel_spec; cancel_spec["cmd"] = "sleep 2"; cancel_spec["timeout_ms"] = (f64)5000; u64 cancel_job = shell_spawn(cancel_spec); bool cancel_ok = job_cancel(cancel_job); check("shell_spawn() / async job registry", job_id > 0 && job_waited["done"].to_bool() && job_checked["state"].to_string() == "done" && job_res["result"]["stdout"].to_string() == "spawned" && cancel_ok, "job=" + std::to_string(job_id) + " wait=" + json_encode(job_waited) + " cancel=" + std::to_string(cancel_job)); DValue http_req; http_req["method"] = "GET"; http_req["url"] = "http://127.0.0.1/tests/security_headers.uce"; http_req["headers"]["Host"] = "uce.openfu.com"; http_req["timeout_ms"] = (f64)2000; DValue http_res; DValue http_async; u64 http_job = 0; for(u64 attempt = 0; attempt < 3; attempt++) { if(attempt > 0) usleep(250000); http_res = http_request(http_req); http_job = http_request_async(http_req); http_async = job_await(http_job, 3000); if(http_res["status"].to_u64() == 500 && http_async["done"].to_bool() && http_async["result"]["status"].to_u64() == 500) break; } check("http_request() / http_request_async()", http_res["status"].to_u64() == 500 && contains(http_res["body"].to_string(), "security header sanitizer test") && http_job > 0 && http_async["done"].to_bool() && http_async["result"]["status"].to_u64() == 500, json_encode(http_res) + " async=" + json_encode(http_async)); String auto_lock_file = "/tmp/uce-site-tests-auto-lock.txt"; bool auto_lock_ok = file_put_contents(auto_lock_file, "one") && file_append(auto_lock_file, "|two") && file_get_contents(auto_lock_file) == "one|two"; check("automatic file locking API shape", auto_lock_ok, file_get_contents(auto_lock_file)); String stream_file = "/tmp/uce-site-tests-stream.txt"; u64 wh = file_open(stream_file, "w"); u64 stream_write_ok = wh ? file_write(wh, "abcdef") : 0; s64 stream_pos = file_tell(wh); file_close(wh); u64 rh = file_open(stream_file, "r"); String stream_read = file_read(rh, 3); String stream_pread = file_pread(rh, 2, 3); s64 stream_seek = file_seek(rh, 1, 0); String stream_after_seek = file_read(rh, 2); file_close(rh); u64 rwh = file_open(stream_file, "r+"); u64 stream_pwrite_ok = file_pwrite(rwh, 3, "XYZ"); file_close(rwh); u64 ah = file_open(stream_file, "a"); u64 stream_append_ok = file_write(ah, "!"); file_close(ah); check("streaming file handles", wh > 0 && rh > 0 && rwh > 0 && ah > 0 && stream_write_ok == 6 && stream_pos == 6 && stream_read == "abc" && stream_pread == "cde" && stream_seek == 1 && stream_after_seek == "bc" && stream_pwrite_ok == 3 && stream_append_ok == 1 && file_get_contents(stream_file) == "abcXYZ!", stream_read + " / " + stream_pread + " / " + file_get_contents(stream_file)); DValue st = file_stat(stream_file); DValue dl = dir_list("/tmp"); bool found_stream = false; dl.each([&](const DValue& item, String key) { if(item.key("name") && item.key("name")->to_string() == "uce-site-tests-stream.txt") found_stream = true; }); check("file_stat() / dir_list()", st["exists"].to_bool() && st["is_file"].to_bool() && st["size"].to_u64() == 7 && found_stream, json_encode(st)); String ops_src = "/tmp/uce-site-tests-ops-src.txt"; String ops_copy = "/tmp/uce-site-tests-ops-copy.txt"; String ops_renamed = "/tmp/uce-site-tests-ops-renamed.txt"; file_put_contents(ops_src, "abcdef"); bool copy_ok = file_copy(ops_src, ops_copy); bool trunc_ok = file_truncate(ops_copy, 3); bool rename_ok = file_rename(ops_copy, ops_renamed); String dir_ops = "/tmp/uce-site-tests-rmdir"; mkdir(dir_ops); file_put_contents(path_join(dir_ops, "child.txt"), "child"); bool dir_remove_ok = dir_remove(dir_ops, true); check("file_rename() / file_copy() / file_truncate() / dir_remove()", copy_ok && trunc_ok && rename_ok && file_get_contents(ops_renamed) == "abc" && dir_remove_ok && !file_exists(dir_ops), file_get_contents(ops_renamed)); String tmp_created = file_temp("/tmp/uce-site-tests-temp-"); bool chmod_ok = tmp_created != "" && file_chmod(tmp_created, 0600); u64 fsync_h = file_open(tmp_created, "a"); bool fsync_ok = fsync_h > 0 && file_write(fsync_h, "durable") == 7 && file_fsync(fsync_h); file_close(fsync_h); String link_path = "/tmp/uce-site-tests-link"; file_unlink(link_path); bool symlink_ok = file_symlink(tmp_created, link_path); check("file_temp() / file_chmod() / file_symlink() / file_fsync()", tmp_created != "" && file_exists(tmp_created) && chmod_ok && fsync_ok && symlink_ok, tmp_created + " -> " + link_path); String start_dir = process_start_directory(); String old_cwd = cwd_get(); cwd_set("/tmp"); String tmp_cwd = cwd_get(); cwd_set(old_cwd); check("cwd_get() / cwd_set() / process_start_directory()", old_cwd != "" && tmp_cwd == "/tmp" && process_start_directory() == start_dir && start_dir != "", "old=" + old_cwd + " tmp=" + tmp_cwd + " start=" + start_dir); StringMap cfg; cfg["u64"] = " 42 "; cfg["s64"] = " -12 "; cfg["bad"] = "42x"; cfg["f64"] = " 3.5 "; cfg["yes"] = "yes"; cfg["no"] = "off"; check("to_u64() / to_s64() / to_f64() / to_bool()", to_u64(cfg["u64"], 7) == 42 && to_u64(cfg["bad"], 7) == 7 && to_s64(cfg["s64"], 5) == -12 && to_s64(cfg["bad"], 5) == 5 && to_f64(cfg["f64"], 1.0) > 3.49 && to_f64(cfg["bad"], 1.25) == 1.25 && to_bool(cfg["yes"], false) && !to_bool(cfg["no"], true) && !to_bool("unknown", false), var_dump(cfg)); DValue perf = request_perf(); check("request_perf()", perf.get_type_name() != "invalid", json_encode(perf)); u64 parsed_epoch = time_parse("1970-01-01 00:00:05 UTC"); String utc_year = time_format_utc("%Y", parsed_epoch); String local_year = time_format_local("%Y", parsed_epoch); String relative = time_format_relative(time() - 120, "recent %deltaS", 1, "medium %deltaM", 3600, "old %deltaH"); check("time_format_local() / time_format_relative() / time_parse()", parsed_epoch == 5 && utc_year == "1970" && local_year != "" && contains(relative, "medium"), "parsed=" + std::to_string(parsed_epoch) + " utc=" + utc_year + " local=" + local_year + " rel=" + relative); String crypto_random = random_bytes(16); String crypto_b64 = base64_encode("hello"); String crypto_b64_dec = base64_decode(crypto_b64); check("sha256() / hmac_sha256() / base64 / random_bytes() / crypto_equal()", sha256_hex("abc") == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" && hmac_sha256_hex("key", "The quick brown fox jumps over the lazy dog") == "f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8" && crypto_b64 == "aGVsbG8=" && crypto_b64_dec == "hello" && crypto_random.length() == 16 && crypto_equal("same", "same") && !crypto_equal("same", "diff"), crypto_b64 + " / " + sha256_hex("abc")); StringList escaped_keys = memcache_escape_keys({"a b", "line\nkey"}); check("memcache_escape_key() / memcache_escape_keys()", memcache_escape_key("a b") == "a_b" && escaped_keys.size() == 2 && !contains(escaped_keys[1], "\n"), join(escaped_keys, ",")); check("signal_name() / runtime_safe_key() / backtrace helpers", signal_name(SIGSEGV) == "SIGSEGV" && runtime_safe_key(" task one ") == gen_sha1("task one") && runtime_safe_key(" ") == "" && backtrace_capture() == "" && backtrace_get_frames(0, 0) == "", signal_name(SIGSEGV) + " / " + runtime_safe_key(" task one ")); site_tests_summary(passed, failed, skipped, "This page limits writes to /tmp/uce-site-tests-io.txt so it stays disposable."); site_tests_page_end(); }