Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion go/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -789,8 +789,13 @@ def _compile_tinygo_module(ctx, tinygo, go_binary, wasm_opt_binary, wasm_tools,
mnemonic = "TinyGoCompile",
progress_message = "Compiling %s with TinyGo" % ctx.attr.name,
use_default_shell_env = False,
# RBE Status: Currently requires local execution due to Go module resolution
# and TINYGOROOT environment management. Future work (Issue #18):
# - Pre-resolve Go modules to enable hermetic builds
# - Cache TINYGOROOT in toolchain provider
# - Replace with "no-network": "1" + "supports-path-mapping": "1"
execution_requirements = {
"local": "1", # TinyGo requires local execution
"local": "1",
},
)

Expand Down
6 changes: 5 additions & 1 deletion js/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,12 @@ def _npm_install_impl(ctx):
tools = [npm],
mnemonic = "NPMInstall",
progress_message = "Installing NPM dependencies for %s" % ctx.label,
# RBE Status: Requires local execution for NPM network access.
# This is intentional - npm install needs to fetch packages.
# Future work (Issue #18) could pre-download deps via repository rule
# to enable hermetic builds with "no-network": "1".
execution_requirements = {
"local": "1", # NPM install requires network access
"local": "1",
},
)

Expand Down
192 changes: 192 additions & 0 deletions test/wrpc/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
"""WRPC rules unit and integration tests.

This package validates:
- wrpc_bindgen rule generates correct output structure
- wrpc_rust_bindings/wrpc_go_bindings macros work correctly
- Transport configuration rules provide WrpcTransportInfo correctly
- wrpc_serve/wrpc_invoke generate valid launcher scripts

Following Bazel 2026 testing best practices with build_test and analysistest.
"""

load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@rules_wasm_component//wit:defs.bzl", "wit_library")
load("@rules_wasm_component//wrpc:defs.bzl", "wrpc_bindgen", "wrpc_go_bindings", "wrpc_rust_bindings")
load("@rules_wasm_component//wrpc:transports.bzl", "nats_transport", "quic_transport", "tcp_transport", "unix_transport")
load(":wrpc_tests.bzl", "transport_provider_test", "wrpc_bindgen_test")

package(default_testonly = True)

# =============================================================================
# Test Fixtures
# =============================================================================

wit_library(
name = "calculator_wit",
package_name = "test:calculator@1.0.0",
testonly = True,
srcs = ["fixtures/calculator.wit"],
world = "calculator-server",
)

# =============================================================================
# Transport Configuration Tests
# =============================================================================

tcp_transport(
name = "test_tcp_transport",
testonly = True,
address = "localhost:8080",
)

nats_transport(
name = "test_nats_transport",
testonly = True,
address = "nats://localhost:4222",
prefix = "test-service",
)

unix_transport(
name = "test_unix_transport",
testonly = True,
socket_path = "/tmp/wrpc-test.sock",
)

quic_transport(
name = "test_quic_transport",
testonly = True,
address = "localhost:4433",
insecure = True,
)

# =============================================================================
# Binding Generation Tests
# =============================================================================

wrpc_bindgen(
name = "test_bindgen_rust",
testonly = True,
language = "rust",
wit = ":calculator_wit",
world = "calculator-server",
)

wrpc_bindgen(
name = "test_bindgen_go",
testonly = True,
language = "go",
wit = ":calculator_wit",
world = "calculator-server",
)

# Language-specific macro tests
wrpc_rust_bindings(
name = "test_rust_bindings_macro",
testonly = True,
wit = ":calculator_wit",
world = "calculator-client",
)

wrpc_go_bindings(
name = "test_go_bindings_macro",
testonly = True,
wit = ":calculator_wit",
world = "calculator-client",
)

# =============================================================================
# Build Tests (Smoke Tests)
# =============================================================================

build_test(
name = "transport_build_test",
targets = [
":test_tcp_transport",
":test_nats_transport",
":test_unix_transport",
":test_quic_transport",
],
)

build_test(
name = "bindgen_build_test",
targets = [
":test_bindgen_rust",
":test_bindgen_go",
":test_rust_bindings_macro",
":test_go_bindings_macro",
],
)

# =============================================================================
# Analysis Tests (Provider Validation)
# =============================================================================

transport_provider_test(
name = "test_tcp_transport_provider",
expected_transport_type = "tcp",
target_under_test = ":test_tcp_transport",
)

transport_provider_test(
name = "test_nats_transport_provider",
expected_transport_type = "nats",
target_under_test = ":test_nats_transport",
)

transport_provider_test(
name = "test_unix_transport_provider",
expected_transport_type = "unix",
target_under_test = ":test_unix_transport",
)

transport_provider_test(
name = "test_quic_transport_provider",
expected_transport_type = "quic",
target_under_test = ":test_quic_transport",
)

wrpc_bindgen_test(
name = "test_bindgen_rust_output",
expected_language = "rust",
target_under_test = ":test_bindgen_rust",
)

wrpc_bindgen_test(
name = "test_bindgen_go_output",
expected_language = "go",
target_under_test = ":test_bindgen_go",
)

# =============================================================================
# Test Suites
# =============================================================================

test_suite(
name = "build_tests",
tests = [
":bindgen_build_test",
":transport_build_test",
],
)

test_suite(
name = "provider_tests",
tests = [
":test_bindgen_go_output",
":test_bindgen_rust_output",
":test_nats_transport_provider",
":test_quic_transport_provider",
":test_tcp_transport_provider",
":test_unix_transport_provider",
],
)

test_suite(
name = "wrpc_tests",
tests = [
":build_tests",
":provider_tests",
],
visibility = ["//visibility:public"],
)
16 changes: 16 additions & 0 deletions test/wrpc/fixtures/calculator.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Simple calculator interface for WRPC testing
package test:calculator@1.0.0;

interface operations {
add: func(a: s32, b: s32) -> s32;
subtract: func(a: s32, b: s32) -> s32;
multiply: func(a: s32, b: s32) -> s32;
}

world calculator-server {
export operations;
}

world calculator-client {
import operations;
}
149 changes: 149 additions & 0 deletions test/wrpc/wrpc_tests.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
"""Analysis tests for WRPC rules.

Tests validate:
- Transport rules provide WrpcTransportInfo with correct fields
- wrpc_bindgen generates output directory structure
- Language-specific binding macros work correctly
"""

load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("@rules_wasm_component//providers:providers.bzl", "WrpcTransportInfo")

# =============================================================================
# Transport Provider Tests
# =============================================================================

def _transport_provider_test_impl(ctx):
"""Test that transport rules provide WrpcTransportInfo correctly."""
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)

# Check that target provides WrpcTransportInfo
asserts.true(
env,
WrpcTransportInfo in target_under_test,
"Transport rule should provide WrpcTransportInfo",
)

transport_info = target_under_test[WrpcTransportInfo]

# Check required fields exist
required_fields = [
"transport_type",
"address",
"cli_args",
"extra_args",
"address_format",
"metadata",
]
for field in required_fields:
asserts.true(
env,
hasattr(transport_info, field),
"WrpcTransportInfo should have {} field".format(field),
)

# Check transport_type matches expected
if ctx.attr.expected_transport_type:
asserts.equals(
env,
ctx.attr.expected_transport_type,
transport_info.transport_type,
"transport_type should match expected value",
)

# Check address is non-empty
asserts.true(
env,
transport_info.address != "",
"address should not be empty",
)

# Check cli_args is a list
asserts.true(
env,
type(transport_info.cli_args) == "list",
"cli_args should be a list",
)

# Check metadata is a dict
asserts.true(
env,
type(transport_info.metadata) == "dict",
"metadata should be a dict",
)

return analysistest.end(env)

transport_provider_test = analysistest.make(
_transport_provider_test_impl,
attrs = {
"expected_transport_type": attr.string(
doc = "Expected transport type (tcp, nats, unix, quic)",
),
},
)

# =============================================================================
# Binding Generation Tests
# =============================================================================

def _wrpc_bindgen_test_impl(ctx):
"""Test that wrpc_bindgen produces correct output."""
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)

# Check DefaultInfo provides files
default_info = target_under_test[DefaultInfo]
files = default_info.files.to_list()

asserts.true(
env,
len(files) > 0,
"wrpc_bindgen should provide output files",
)

# Check output is a directory (indicated by no extension in typical naming)
# wrpc_bindgen produces a directory of generated source files

return analysistest.end(env)

wrpc_bindgen_test = analysistest.make(
_wrpc_bindgen_test_impl,
attrs = {
"expected_language": attr.string(
doc = "Expected language (rust, go)",
),
},
)

# =============================================================================
# Serve/Invoke Launcher Tests
# =============================================================================

def _wrpc_launcher_test_impl(ctx):
"""Test that wrpc_serve/wrpc_invoke produce executable launchers."""
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)

# Check DefaultInfo provides executable
default_info = target_under_test[DefaultInfo]

asserts.true(
env,
default_info.files_to_run != None,
"wrpc launcher should provide files_to_run",
)

# Check executable exists
executable = default_info.files_to_run.executable
if executable:
asserts.true(
env,
executable.basename.endswith(".py") or not executable.basename.endswith(".wasm"),
"Launcher should be a Python script, not a WASM file",
)

return analysistest.end(env)

wrpc_launcher_test = analysistest.make(_wrpc_launcher_test_impl)
Loading