xiaohongshu
xiaohongshu
buck2-local-resources
Create Buck2 tests with local resources (processes, services, databases) using LocalResourceInfo and ExternalRunnerTestInfo. Use when tests need external dependencies like databases, HTTP servers, message queues, or Unix sockets that Buck2 should manage automatically. (project)
Full skill instructions
This skill guides you through creating Buck2 tests that depend on external processes or services. Buck2's local resources pattern manages broker processes automatically: starting them before tests, providing connection info via environment variables, and cleaning up afterward.
Use this skill when:
Don't use for:
Every local resources test has three parts:
LocalResourceInfoExternalRunnerTestInfo to consume the resourceTest execution:
1. Buck2 identifies test needs broker (via local_resources)
2. Buck2 runs broker script → service starts, JSON output
3. Buck2 parses JSON, sets environment variables
4. Buck2 runs test script with those env vars
5. Test completes → Buck2 kills broker process (automatic cleanup)
Before writing code, answer:
Example answers:
python3 -m http.server <port>Template:
#!/usr/bin/env bash
# SPDX-FileCopyrightText: © 2024-2026 Austin Seipp
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
# 1. Setup: Create temp directory for isolation
TMPDIR=${TMPDIR:-/tmp}
WORKDIR="$TMPDIR/my-service-$$" # $$ = process ID for uniqueness
mkdir -p "$WORKDIR"
# 2. Start service in background
<command-to-start-service> &
SERVICE_PID=$!
# 3. Wait for service to be ready (CRITICAL!)
for i in {1..50}; do
if <readiness-check>; then
break
fi
sleep 0.1
done
# 4. Output JSON (ONLY this to stdout, everything else to stderr!)
echo "{\"pid\": $SERVICE_PID, \"resources\": [{\"<key1>\": \"<value1>\", \"<key2>\": \"<value2>\"}]}"
Important:
&)pid (Buck2 tracks this to kill process)resources array with connection details>&2) or /dev/nullExamples:
<details> <summary>HTTP Server Broker</summary>#!/usr/bin/env bash
set -euo pipefail
TMPDIR=${TMPDIR:-/tmp}
WORKDIR="$TMPDIR/http-$$"
mkdir -p "$WORKDIR"
# Create test content
echo "Hello" > "$WORKDIR/index.html"
# Start server
cd "$WORKDIR"
python3 -m http.server 8080 > /dev/null 2>&1 &
PID=$!
# Wait for ready
for i in {1..30}; do
if curl -s http://localhost:8080 > /dev/null 2>&1; then
break
fi
sleep 0.1
done
echo "{\"pid\": $PID, \"resources\": [{\"port\": \"8080\", \"url\": \"http://localhost:8080\"}]}"
</details>
<details> <summary>Unix Socket Broker</summary>#!/usr/bin/env bash
set -euo pipefail
TMPDIR=${TMPDIR:-/tmp}
SOCKET="$TMPDIR/my-socket-$$"
# Start socket server (using socat or custom server)
socat UNIX-LISTEN:$SOCKET,fork EXEC:'/bin/cat' &
PID=$!
# Wait for socket file to exist
for i in {1..50}; do
if [[ -S "$SOCKET" ]]; then
break
fi
sleep 0.1
done
echo "{\"pid\": $PID, \"resources\": [{\"socket_path\": \"$SOCKET\"}]}"
</details>
<details> <summary>Database Broker (SQLite)</summary>#!/usr/bin/env bash
set -euo pipefail
TMPDIR=${TMPDIR:-/tmp}
DB_PATH="$TMPDIR/test-db-$$.sqlite"
# Initialize database
sqlite3 "$DB_PATH" "CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT);"
# No background process needed for SQLite, but we still need a PID
# Use sleep as a dummy process to keep broker alive
sleep infinity &
PID=$!
echo "{\"pid\": $PID, \"resources\": [{\"db_path\": \"$DB_PATH\"}]}"
</details>
defs.bzl)Template:
# SPDX-FileCopyrightText: © 2024-2026 Austin Seipp
# SPDX-License-Identifier: Apache-2.0
_<service>_broker_rule = rule(
impl = lambda ctx: [
DefaultInfo(),
RunInfo(args = cmd_args(ctx.attrs._script[DefaultInfo].default_outputs[0])),
LocalResourceInfo(
setup = cmd_args(ctx.attrs._script[DefaultInfo].default_outputs[0]),
resource_env_vars = {
"<ENV_VAR_NAME>": "<json_key>", # Map JSON key → env var
# Add more mappings as needed
},
),
],
attrs = {
"_script": attrs.default_only(
attrs.exec_dep(default = "<cell>//<package>:<broker-script-target>")
),
},
)
Key points:
LocalResourceInfo is the provider that marks this as a brokersetup: The command to run (the broker script)resource_env_vars: Dict mapping env var names (keys) to JSON keys (values)
{"HTTP_URL": "url"} means JSON's resources[0].url → test's $HTTP_URL_script: Reference to the broker script target (defined in BUILD file)Example:
_http_broker_rule = rule(
impl = lambda ctx: [
DefaultInfo(),
RunInfo(args = cmd_args(ctx.attrs._script[DefaultInfo].default_outputs[0])),
LocalResourceInfo(
setup = cmd_args(ctx.attrs._script[DefaultInfo].default_outputs[0]),
resource_env_vars = {
"HTTP_PORT": "port",
"HTTP_URL": "url",
},
),
],
attrs = {
"_script": attrs.default_only(
attrs.exec_dep(default = "depot//my/package:http-broker-script")
),
},
)
Your test script will receive environment variables from the broker:
#!/usr/bin/env bash
# SPDX-FileCopyrightText: © 2024-2026 Austin Seipp
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
# Environment variables are automatically set by Buck2
echo "Service available at: $<ENV_VAR>"
# Run your tests
<test-commands-here>
# Exit with appropriate code
if <tests-passed>; then
echo "✓ Tests passed"
exit 0
else
echo "✗ Tests failed"
exit 1
fi
Example:
#!/usr/bin/env bash
set -euo pipefail
echo "Testing HTTP server at $HTTP_URL"
# Make request
RESPONSE=$(curl -s "$HTTP_URL/index.html")
if [[ "$RESPONSE" == "Hello" ]]; then
echo "✓ Test passed"
exit 0
else
echo "✗ Test failed"
exit 1
fi
defs.bzl)Template:
_<service>_test_rule = rule(
impl = lambda ctx: [
DefaultInfo(),
RunInfo(args = cmd_args([ctx.attrs.script[DefaultInfo].default_outputs[0]])),
ExternalRunnerTestInfo(
type = "custom",
command = [cmd_args([ctx.attrs.script[DefaultInfo].default_outputs[0]])],
local_resources = {
'<resource-name>': ctx.attrs.<broker_attr>.label,
# Add more resources if needed
},
required_local_resources = [
RequiredTestLocalResource("<resource-name>", listing = False, execution = True),
# Add more if needed
],
),
],
attrs = {
"script": attrs.source(),
"<broker_attr>": attrs.exec_dep(providers = [LocalResourceInfo]),
# Add more broker attrs for multiple resources
},
)
Key points:
ExternalRunnerTestInfo marks this as a test with external dependenciestype: Usually "custom" for local resourcescommand: The test script to runlocal_resources: Dict of resource name → broker target label
required_local_resourcesrequired_local_resources: List of resources needed
listing: Usually False (not needed during buck2 targets)execution: Usually True (needed during test execution)Example:
_http_test_rule = rule(
impl = lambda ctx: [
DefaultInfo(),
RunInfo(args = cmd_args([ctx.attrs.script[DefaultInfo].default_outputs[0]])),
ExternalRunnerTestInfo(
type = "custom",
command = [cmd_args([ctx.attrs.script[DefaultInfo].default_outputs[0]])],
local_resources = {
'http': ctx.attrs.http_broker.label,
},
required_local_resources = [
RequiredTestLocalResource("http", listing = False, execution = True),
],
),
],
attrs = {
"script": attrs.source(),
"http_broker": attrs.exec_dep(providers = [LocalResourceInfo]),
},
)
Template:
# SPDX-FileCopyrightText: © 2024-2026 Austin Seipp
# SPDX-License-Identifier: Apache-2.0
load("@root//buck/shims:shims.bzl", depot = "shims")
load(":defs.bzl", "<exports-struct>")
# 1. Export broker script
depot.export_file(
name = "<broker-script-name>",
src = "<broker-script-file>",
)
# 2. Create broker target
<exports-struct>.<broker_rule>(
name = "<broker-resource-name>",
)
# 3. Create test target
<exports-struct>.<test_rule>(
name = "<test-name>",
script = "<test-script-file>",
<broker_attr> = ":<broker-resource-name>",
)
Example:
# SPDX-FileCopyrightText: © 2024-2026 Austin Seipp
# SPDX-License-Identifier: Apache-2.0
load("@root//buck/shims:shims.bzl", depot = "shims")
load(":defs.bzl", "my_resources")
# Export broker script
depot.export_file(
name = "http-broker",
src = "http-broker.sh",
)
# Create broker target
my_resources.http_broker(
name = "http-broker-resource",
)
# Create test target
my_resources.http_test(
name = "http-test",
script = "http-test.sh",
http_broker = ":http-broker-resource",
)
Don't forget to export rules in defs.bzl:
my_resources = struct(
http_broker = _http_broker_rule,
http_test = _http_test_rule,
)
bash <broker-script>.sh
Should output valid JSON. Validate:
bash <broker-script>.sh | jq .
# Run broker
bash <broker-script>.sh
# Note the PID and resource values
# Set env vars manually
export <ENV_VAR>=<value-from-json>
# Run test
bash <test-script>.sh
# Kill broker
kill <pid-from-json>
buck2 test //<package>:<test-name>
buck2 test ... -v 2bash broker.sh | jq .env | grep <PREFIX> to test scriptps aux | grep <service>pkill -f <service>For tests needing multiple services:
Create separate broker rules for each service (as shown above).
_multi_test_rule = rule(
impl = lambda ctx: [
DefaultInfo(),
RunInfo(args = cmd_args([ctx.attrs.script[DefaultInfo].default_outputs[0]])),
ExternalRunnerTestInfo(
type = "custom",
command = [cmd_args([ctx.attrs.script[DefaultInfo].default_outputs[0]])],
local_resources = {
'http': ctx.attrs.http_broker.label,
'db': ctx.attrs.db_broker.label,
'redis': ctx.attrs.redis_broker.label,
},
required_local_resources = [
RequiredTestLocalResource("http", listing = False, execution = True),
RequiredTestLocalResource("db", listing = False, execution = True),
RequiredTestLocalResource("redis", listing = False, execution = True),
],
),
],
attrs = {
"script": attrs.source(),
"http_broker": attrs.exec_dep(providers = [LocalResourceInfo]),
"db_broker": attrs.exec_dep(providers = [LocalResourceInfo]),
"redis_broker": attrs.exec_dep(providers = [LocalResourceInfo]),
},
)
my_resources.multi_test(
name = "integration-test",
script = "integration-test.sh",
http_broker = ":http-broker-resource",
db_broker = ":db-broker-resource",
redis_broker = ":redis-broker-resource",
)
Test script will have access to all environment variables from all brokers.
Avoid hardcoded ports by using port 0 (OS assigns random port):
# Start with port 0
python3 -m http.server 0 &
PID=$!
# Discover assigned port
sleep 0.2
PORT=$(lsof -ti -sTCP:LISTEN -a -p $PID)
echo "{\"pid\": $PID, \"resources\": [{\"port\": \"$PORT\"}]}"
Avoids port allocation entirely:
SOCKET="$TMPDIR/service-$$"
my_service --socket="$SOCKET" &
PID=$!
# Wait for socket file
for i in {1..50}; do
if [[ -S "$SOCKET" ]]; then
break
fi
sleep 0.1
done
echo "{\"pid\": $PID, \"resources\": [{\"socket_path\": \"$SOCKET\"}]}"
Port-based:
for i in {1..30}; do
if curl -s http://localhost:$PORT/health > /dev/null 2>&1; then
break
fi
sleep 0.1
done
Socket-based:
for i in {1..50}; do
if [[ -S "$SOCKET" ]]; then
break
fi
sleep 0.1
done
Process-based:
for i in {1..30}; do
if kill -0 $PID 2>/dev/null; then
break
fi
sleep 0.1
done
Isolation via $TMPDIR
$TMPDIR for all temp files$$ (PID) to paths for uniqueness$TMPDIR/my-service-$$Always wait for readiness
Dynamic resource allocation
Clean JSON output
/dev/nulljq .Error handling
set -euo pipefail in all bash scriptsTesting
Cause: Broker outputs non-JSON or malformed JSON.
Fix:
bash broker.sh | jq .
Look for error messages. Ensure only JSON on stdout.
Cause: Mismatch between JSON keys and resource_env_vars.
Fix: Check mapping:
{"resources": [{"my_key": "value"}]}resource_env_vars = {"MY_VAR": "my_key"}$MY_VAR should be valueCause: Name mismatch in local_resources and required_local_resources.
Fix:
local_resources = {
'myservice': ctx.attrs.broker.label, # Name must match below
},
required_local_resources = [
RequiredTestLocalResource("myservice", ...), # Must match above
],
Cause: Previous test didn't clean up or hardcoded ports conflict.
Fix:
$$ to temp directoriespkill -f my-serviceCause: Broker never becomes ready (infinite wait loop).
Fix: Add timeout to health check:
for i in {1..30}; do # Max 3 seconds
if <ready>; then
break
fi
sleep 0.1
done
# Verify ready
if ! <ready>; then
echo "Service failed to start" >&2
kill $PID 2>/dev/null
exit 1
fi
See:
buck/tests/local-resources/ - Simple examples (HTTP, socket, multi-resource)buck/third-party/qemu-static/ - Real-world example (QEMU with TPM)docs/buck2.md - Comprehensive documentationset -euo pipefail$TMPDIR/service-$$ for isolation&)$!)pid and resources arrayLocalResourceInfosetup points to broker scriptresource_env_vars maps JSON keys → env vars_script references broker script targetExternalRunnerTestInfotype = "custom"local_resources dict with broker labelsrequired_local_resources list matches dict keysexport_file for broker scriptscript =<broker_attr> = :<broker-target># Test broker script
bash <broker>.sh
bash <broker>.sh | jq .
# Test manually
bash <broker>.sh # Note PID and resources
export VAR=value # Set env vars from JSON
bash <test>.sh
kill <pid>
# Run with Buck2
buck2 test //<package>:<test>
buck2 test //<package>:<test> -v 2 # Verbose
# Debug
buck2 targets //<package>: # List targets
buck2 build //<package>:<broker> # Build broker
ps aux | grep <service> # Find processes
pkill -f <service> # Kill leaked processes
buck2-test-workflow - Testing workflows and best practicesbuck2-build-troubleshoot - Debugging Buck2 build failuresbuck2-query-helper - Querying Buck2 build graphCreating local resource tests:
LocalResourceInfo with resource_env_vars)ExternalRunnerTestInfo with local_resources)Key principles:
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience