Skip to content
File

Blob: src/workerd/tests/test-reprl.c++

4.1 KB
1#include <limits.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5 
6#include <kj/test.h>
7 
8// Libreprl is a .c file so the header needs to be in an 'extern "C"' block.
9extern "C" {
10#include "libreprl/libreprl.h"
11}
12 
13#include "tools/cpp/runfiles/runfiles.h"
14 
15using bazel::tools::cpp::runfiles::Runfiles;
16 
17namespace workerd {
18namespace {
19 
20#ifdef __linux__
21void print_splitter() {
22 printf("---------------------------------\n");
23}
24 
25bool execute(struct reprl_context* ctx, const char* code) {
26 uint64_t exec_time;
27 const uint64_t SECONDS = 1000000; // Timeout is in microseconds.
28 print_splitter();
29 printf("Executing: %s\n", code);
30 int status = reprl_execute(ctx, code, strlen(code), 1 * SECONDS, &exec_time, 0);
31 printf("Return code: %d\n", status);
32 
33 const char* fuzzout = reprl_fetch_fuzzout(ctx);
34 printf("Fuzzout stdout:\n%s\n", fuzzout);
35 fflush(stdout);
36 
37 const char* stdout_output = reprl_fetch_stdout(ctx);
38 printf("Workerd stdout:\n%s\n", stdout_output);
39 
40 const char* stdout_err = reprl_fetch_stderr(ctx);
41 printf("Workerd stderr:\n%s\n", stdout_err);
42 
43 if (RIFSIGNALED(status)) {
44 printf("Process was terminated by signal %d\n", RTERMSIG(status));
45 }
46 print_splitter();
47 fflush(stdout);
48 fflush(stderr);
49 
50 // Check if the process exited successfully
51 return RIFEXITED(status) && REXITSTATUS(status) == 0;
52}
53 
54void expect_success(struct reprl_context* ctx, const char* code) {
55 if (!execute(ctx, code)) {
56 KJ_FAIL_REQUIRE("Execution unexpectedly failed", code);
57 }
58}
59 
60void expect_failure(struct reprl_context* ctx, const char* code) {
61 if (execute(ctx, code)) {
62 KJ_FAIL_REQUIRE("Execution unexpectedly succeeded", code);
63 }
64}
65#endif // __linux__
66 
67KJ_TEST("REPRL basic functionality") {
68#ifdef __linux__
69 std::string error;
70 std::unique_ptr<Runfiles> runfiles(Runfiles::CreateForTest(&error));
71 KJ_REQUIRE(runfiles != nullptr, "Failed to create runfiles", error.c_str());
72 
73 auto ctx = reprl_create_context();
74 KJ_REQUIRE(ctx != nullptr, "Failed to create REPRL context");
75 
76 const char* env[] = {"LLVM_SYMBOLIZER=/usr/bin/llvm-symbolizer-19", nullptr};
77 
78 // Use Runfiles API to get absolute paths
79 std::string workerd_path = runfiles->Rlocation("workerd/src/workerd/server/workerd");
80 // Use config.capnp which has a socket (needed to trigger fetch() which calls Stdin.reprl())
81 std::string config_path = runfiles->Rlocation("workerd/fuzzilli/config.capnp");
82 
83 const char* args[] = {
84 workerd_path.c_str(), "fuzzilli", config_path.c_str(), "--experimental", nullptr};
85 
86 if (reprl_initialize_context(ctx, args, env, 1, 1) != 0) {
87 KJ_FAIL_REQUIRE("REPRL initialization failed");
88 }
89 
90 // Basic functionality test
91 expect_success(ctx, "let greeting = \"Hello World!\";");
92 
93 // Test with console.log output
94 expect_success(ctx, "console.log('Hello from JavaScript!');");
95 
96 // Verify that runtime exceptions can be detected
97 expect_failure(ctx, "throw 'failure';");
98 expect_success(ctx, "42;");
99 
100 // Verify that existing state is properly reset between executions
101 // These tests are commented out as they may not apply to workerd's execution model
102 // expect_success(ctx, "globalProp = 42; Object.prototype.foo = \"bar\";");
103 // expect_success(ctx, "if (typeof(globalProp) !== 'undefined') throw 'failure'");
104 // expect_success(ctx, "if (typeof(({}).foo) !== 'undefined') throw 'failure'");
105 
106 // Verify that rejected promises are properly reset between executions
107 expect_failure(ctx, "function fail() { throw 42; }; fail()");
108 
109 // Verify that fuzzilli crash command is detected as failure
110 expect_failure(ctx, "fuzzilli('FUZZILLI_CRASH',0);");
111 expect_failure(ctx, "fuzzilli('FUZZILLI_CRASH',1);");
112 expect_failure(ctx, "fuzzilli('FUZZILLI_CRASH',2);");
113 expect_failure(ctx, "fuzzilli('FUZZILLI_CRASH',3);");
114 expect_failure(ctx, "fuzzilli('FUZZILLI_CRASH',4);");
115 //expect_failure(ctx, "fuzzilli('FUZZILLI_CRASH',5);");
116 
117 // async is not failing in workerd (commented out from original)
118 // expect_failure(ctx, "async function fail() { throw 42; }; fail()");
119 
120 reprl_destroy_context(ctx);
121#else
122 KJ_LOG(WARNING, "REPRL tests only supported on Linux");
123#endif
124}
125 
126} // namespace
127} // namespace workerd