@@ -65,53 +65,35 @@ WINDOWS_TEMPLATE = """
6565@echo off
6666setlocal EnableDelayedExpansion
6767
68- REM Start sidecar if specified
69- if not "%SIDECAR%" == "" (
70- start /b "" "%SIDECAR%" > nul 2>&1
71- set SIDECAR_PID=!ERRORLEVEL!
72- timeout /t 1 > nul
73- )
74-
75- REM Run the actual test
76- $(RUNTEST)
77-
78- REM Cleanup sidecar if it was started
79- if defined SIDECAR_PID (
80- taskkill /F /PID !SIDECAR_PID! > nul 2>&1
68+ REM Run supervisor to start sidecar if specified
69+ if not "{sidecar}" == "" (
70+ REM These environment variables are processed by the supervisor executable
71+ set PORTS_TO_ASSIGN={port_bindings}
72+ set SIDECAR_COMMAND="{sidecar}"
73+ powershell -Command \" {supervisor} {runtest}\"
74+ ) else (
75+ {runtest}
8176)
8277
78+ set TEST_EXIT=!ERRORLEVEL!
8379exit /b !TEST_EXIT!
8480"""
8581
8682SH_TEMPLATE = """#!/bin/sh
8783set -e
8884
89- cleanup() {
90- if [ ! -z "$SIDECAR_PID" ]; then
91- kill $SIDECAR_PID 2>/dev/null || true
92- fi
93- }
94-
95- trap cleanup EXIT
96-
97- # Start sidecar if specified
98- if [ ! -z "$(SIDECAR)" ]; then
99- "$(SIDECAR)" & SIDECAR_PID=$!
100- # Wait until the process is ready
101- sleep 3
85+ # Run supervisor to start sidecar if specified
86+ if [ ! -z "{sidecar}" ]; then
87+ # These environment variables are processed by the supervisor executable
88+ PORTS_TO_ASSIGN={port_bindings} SIDECAR_COMMAND="{sidecar}" {supervisor} {runtest}
89+ else
90+ {runtest}
10291fi
103-
104- $(RUNTEST)
10592"""
10693
107- WINDOWS_RUNTEST_NORMAL = """
108- powershell -Command \" %*\" `-dTEST_TMPDIR=$ENV:TEST_TMPDIR
109- set TEST_EXIT=!ERRORLEVEL!
110- """
94+ WINDOWS_RUNTEST_NORMAL = """powershell -Command \" %*\" `-dTEST_TMPDIR=$ENV:TEST_TMPDIR"""
11195
112- SH_RUNTEST_NORMAL = """
113- "$@" -dTEST_TMPDIR=$TEST_TMPDIR
114- """
96+ SH_RUNTEST_NORMAL = """"$@" -dTEST_TMPDIR=$TEST_TMPDIR"""
11597
11698# We need variants of the RUN_TEST command for Python memory snapshot tests. We have to invoke
11799# workerd twice, once with --python-save-snapshot to produce the snapshot and once with
@@ -144,20 +126,30 @@ echo Using Python Snapshot
144126def _wd_test_impl (ctx ):
145127 is_windows = ctx .target_platform_has_constraint (ctx .attr ._platforms_os_windows [platform_common .ConstraintValueInfo ])
146128
129+ if ctx .file .sidecar and ctx .attr .python_snapshot_test :
130+ # TODO(later): Implement support for generating a combined script with these two options
131+ # if we have a test that requires it. Not doing it for now due to complexity.
132+ return print ("sidecar and python_snapshot_test currently cannot be used together" )
133+
147134 # Bazel insists that the rule must actually create the executable that it intends to run; it
148135 # can't just specify some other executable with some args. OK, fine, we'll use a script that
149136 # just execs its args.
150137 if is_windows :
151138 # Batch script executables must end with ".bat"
152139 executable = ctx .actions .declare_file ("%s_wd_test.bat" % ctx .label .name )
153- content = WINDOWS_TEMPLATE . replace ( "$(SIDECAR)" , ctx . file . sidecar . path if ctx . file . sidecar else "" )
140+ template = WINDOWS_TEMPLATE
154141 runtest = WINDOWS_RUNTEST_SNAPSHOT if ctx .attr .python_snapshot_test else WINDOWS_RUNTEST_NORMAL
155- content = content .replace ("$(RUNTEST)" , runtest )
156142 else :
157143 executable = ctx .outputs .executable
158- content = SH_TEMPLATE . replace ( "$(SIDECAR)" , ctx . file . sidecar . short_path if ctx . file . sidecar else "" )
144+ template = SH_TEMPLATE
159145 runtest = SH_RUNTEST_SNAPSHOT if ctx .attr .python_snapshot_test else SH_RUNTEST_NORMAL
160- content = content .replace ("$(RUNTEST)" , runtest )
146+
147+ content = template .format (
148+ sidecar = ctx .file .sidecar .short_path if ctx .file .sidecar else "" ,
149+ runtest = runtest ,
150+ supervisor = ctx .file .sidecar_supervisor .short_path if ctx .file .sidecar_supervisor else "" ,
151+ port_bindings = "," .join (ctx .attr .sidecar_port_bindings ),
152+ )
161153
162154 ctx .actions .write (
163155 output = executable ,
@@ -174,6 +166,13 @@ def _wd_test_impl(ctx):
174166 if default_runfiles :
175167 runfiles = runfiles .merge (default_runfiles )
176168
169+ runfiles = runfiles .merge (ctx .runfiles (files = [ctx .file .sidecar_supervisor ]))
170+
171+ # Also merge the supervisor's own runfiles if it has any
172+ default_runfiles = ctx .attr .sidecar_supervisor [DefaultInfo ].default_runfiles
173+ if default_runfiles :
174+ runfiles = runfiles .merge (default_runfiles )
175+
177176 return [
178177 DefaultInfo (
179178 executable = executable ,
@@ -185,20 +184,42 @@ _wd_test = rule(
185184 implementation = _wd_test_impl ,
186185 test = True ,
187186 attrs = {
187+ # The workerd executable is used to run all tests
188188 "workerd" : attr .label (
189189 allow_single_file = True ,
190190 executable = True ,
191191 cfg = "exec" ,
192192 default = "//src/workerd/server:workerd" ,
193193 ),
194- "flags" : attr . string_list (),
194+ # A list of files that this test requires to be present in order to run.
195195 "data" : attr .label_list (allow_files = True ),
196+ # If set, an executable that is run in parallel with the test, and provides some functionality
197+ # needed for the test. This is usually a backend server, with workerd serving as the client.
198+ # The sidecar will be killed once the test completes.
196199 "sidecar" : attr .label (
197200 allow_single_file = True ,
198201 executable = True ,
199202 cfg = "exec" ,
200203 ),
204+ # A list of binding names which will be filled in with random port numbers that the sidecar
205+ # and test can use for communication. The test will only begin once the sidecar is
206+ # listening to these ports.
207+ #
208+ # In the sidecar, access these bindings as environment variables. In the wd-test file, add
209+ # fromEnvironment bindings to expose them to the test.
210+ #
211+ # Reminder: you'll also need to add a network = ( allow = ["private"] ) service as well.
212+ "sidecar_port_bindings" : attr .string_list (),
213+ # An executable that is used to manage port assignments and child process creation when a
214+ # sidecar is specified.
215+ "sidecar_supervisor" : attr .label (
216+ allow_single_file = True ,
217+ executable = True ,
218+ cfg = "exec" ,
219+ default = "//src/workerd/api/node:sidecar-supervisor" ,
220+ ),
201221 "python_snapshot_test" : attr .bool (),
222+ # A reference to the Windows platform label, needed for the implementation of wd_test
202223 "_platforms_os_windows" : attr .label (default = "@platforms//os:windows" ),
203224 },
204225)
0 commit comments