This folder shows concise usage patterns for single-service and multi-service setups. These snippets are meant to be copied into your repo; in this repository we also keep them buildable (//examples/...) as a regression guard.
Tip: commands use bazel for portability in consumer repos. In this
repository, use ./bazelw for local development convenience.
- Until BCR publication, install with
git_override(...)as shown in the rootREADME.md. If you are consuming a published release, keep thebazel_dep(...)lines and omit override blocks. - Add module dependencies before
use_extension(...):bazel_dep(name = "datadog-rules-test-optimization", version = "1.2.0")bazel_dep(name = "datadog-rules-test-optimization-go", version = "1.2.0")for Go macro usagebazel_dep(name = "datadog-rules-test-optimization-python", version = "1.2.0")for Python macro usagebazel_dep(name = "datadog-rules-test-optimization-java", version = "1.2.0")for Java macro usagebazel_dep(name = "datadog-rules-test-optimization-nodejs", version = "1.2.0")for NodeJS macro usagebazel_dep(name = "datadog-rules-test-optimization-dotnet", version = "1.2.0")for .NET macro usagebazel_dep(name = "datadog-rules-test-optimization-ruby", version = "1.2.0")for Ruby macro usagebazel_dep(name = "rules_go", ...)for Go examples shown below
- For NodeJS/.NET/Ruby examples shown below, also pin reference rulesets and register toolchains:
bazel_dep(name = "aspect_rules_js", version = "3.0.0-rc5")bazel_dep(name = "rules_nodejs", version = "6.7.3")bazel_dep(name = "rules_dotnet", version = "0.21.5")bazel_dep(name = "rules_ruby", version = "0.21.1")node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node"); node.toolchain(node_version = "22.22.0"); use_repo(node, "nodejs", "nodejs_host", "nodejs_toolchains"); register_toolchains("@nodejs_toolchains//:all")dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet"); dotnet.toolchain(name = "dotnet", dotnet_version = "8.0.100"); use_repo(dotnet, "dotnet_toolchains"); register_toolchains("@dotnet_toolchains//:all")ruby = use_extension("@rules_ruby//ruby:extensions.bzl", "ruby"); ruby.toolchain(name = "ruby", version = "3.3.9"); use_repo(ruby, "ruby", "ruby_toolchains"); register_toolchains("@ruby_toolchains//:all")
- Configure Go toolchains/SDK in your repo if you build Go targets.
- Provide sync credentials via environment and forward them to repository rules:
- shell/CI secret:
DD_API_KEY .bazelrc:common --repo_env=DD_API_KEY(and optionallycommon --repo_env=DD_SITE)
- shell/CI secret:
MODULE.bazel:
bazel_dep(name = "datadog-rules-test-optimization", version = "1.2.0")
bazel_dep(name = "datadog-rules-test-optimization-go", version = "1.2.0")
bazel_dep(name = "datadog-rules-test-optimization-python", version = "1.2.0")
bazel_dep(name = "datadog-rules-test-optimization-java", version = "1.2.0")
bazel_dep(name = "datadog-rules-test-optimization-nodejs", version = "1.2.0")
bazel_dep(name = "datadog-rules-test-optimization-dotnet", version = "1.2.0")
bazel_dep(name = "datadog-rules-test-optimization-ruby", version = "1.2.0")
bazel_dep(name = "rules_go", version = "0.60.0") # or your repo-selected version
bazel_dep(name = "aspect_rules_js", version = "3.0.0-rc5")
bazel_dep(name = "rules_nodejs", version = "6.7.3")
bazel_dep(name = "rules_dotnet", version = "0.21.5")
bazel_dep(name = "rules_ruby", version = "0.21.1")
git_override(
module_name = "datadog-rules-test-optimization",
remote = "https://github.com/DataDog/rules_test_optimization.git",
commit = "<commit-sha>",
)
git_override(
module_name = "datadog-rules-test-optimization-go",
remote = "https://github.com/DataDog/rules_test_optimization.git",
commit = "<commit-sha>",
strip_prefix = "modules/go",
)
git_override(
module_name = "datadog-rules-test-optimization-python",
remote = "https://github.com/DataDog/rules_test_optimization.git",
commit = "<commit-sha>",
strip_prefix = "modules/python",
)
git_override(
module_name = "datadog-rules-test-optimization-java",
remote = "https://github.com/DataDog/rules_test_optimization.git",
commit = "<commit-sha>",
strip_prefix = "modules/java",
)
git_override(
module_name = "datadog-rules-test-optimization-nodejs",
remote = "https://github.com/DataDog/rules_test_optimization.git",
commit = "<commit-sha>",
strip_prefix = "modules/nodejs",
)
git_override(
module_name = "datadog-rules-test-optimization-dotnet",
remote = "https://github.com/DataDog/rules_test_optimization.git",
commit = "<commit-sha>",
strip_prefix = "modules/dotnet",
)
git_override(
module_name = "datadog-rules-test-optimization-ruby",
remote = "https://github.com/DataDog/rules_test_optimization.git",
commit = "<commit-sha>",
strip_prefix = "modules/ruby",
)
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
node.toolchain(node_version = "22.22.0")
use_repo(node, "nodejs", "nodejs_host", "nodejs_toolchains")
register_toolchains("@nodejs_toolchains//:all")
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
dotnet.toolchain(
name = "dotnet",
dotnet_version = "8.0.100",
)
use_repo(dotnet, "dotnet_toolchains")
register_toolchains("@dotnet_toolchains//:all")
ruby = use_extension("@rules_ruby//ruby:extensions.bzl", "ruby")
ruby.toolchain(
name = "ruby",
version = "3.3.9",
)
use_repo(ruby, "ruby", "ruby_toolchains")
register_toolchains("@ruby_toolchains//:all")This mirrors the buildable examples/single_service workspace in this
repository: one Datadog service shared across several runtime-specific test
macros, with Go using the bootstrap-managed extension. If your team owns only
Python, Java, NodeJS, .NET, or Ruby, the simpler runtime-specific setup is in
docs/Language_Onboarding.md.
The generated Go wrapper uses orchestrion_mode = "test_optimization" for
standard Go testing. Manual dd_topt_go_test snippets below set the same mode
explicitly. The default Go Orchestrion mode is general; these examples choose
test_optimization because they target standard Go testing payloads rather
than broader generic Orchestrion instrumentation.
Bootstrap once after adding the module prerequisites:
bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \
--guided \
--service go-service \
--runtime-version 1.25.0 \
--dd-trace-go-version v2.9.0--dd-trace-go-version is optional. If omitted, bootstrap uses the default
v2.9.0. It accepts a tag,
pseudo-version, branch, or commit SHA. Bootstrap resolves that input to exact
versions and repins the local Go module to match what Bazel will use.
BUILD.bazel (generated wrapper path, inference via embed):
load("@rules_go//go:def.bzl", "go_library")
load("//tools/build:dd_go_test.bzl", "dd_go_test")
go_library(
name = "pkg_lib",
srcs = ["*.go"],
)
dd_go_test(
name = "pkg_go_test",
srcs = ["*_test.go"],
embed = [":pkg_lib"], # importpath inferred via rules_go provider
)Enable runtime source staging only when the tracer needs to open the source file for AST-derived metadata:
dd_go_test(
name = "pkg_go_test",
srcs = ["*_test.go"],
embed = [":pkg_lib"],
stage_sources = True,
)The wrapper forwards **kwargs, so stage_sources works the same way as on
dd_topt_go_test. It stages only direct srcs and direct embedsrcs, and it
changes the default rundir to . only when you did not already set one.
BUILD.bazel (Python companion):
load("@python_deps//:requirements.bzl", "requirement")
load("@datadog-rules-test-optimization-python//:topt_py_test.bzl", "dd_topt_py_test")
load("@test_optimization_data//:export.bzl", "topt_data")
dd_topt_py_test(
name = "pkg_py_test",
srcs = glob(["test_*.py"]),
deps = [
":pkg_lib",
requirement("ddtrace"),
requirement("pytest"),
],
imports = ["example/python/pkg"],
topt_data = topt_data,
)The macro defaults to @rules_python//python:py_test. If you omit main, it
uses the bundled pytest entry point and adds PYTEST_ADDOPTS=--ddtrace unless
you already set it or opt out with --no-ddtrace. The target still needs
pytest and ddtrace in its normal Python deps. Keep passing main only when
you want a non-pytest runner, and activate the Python tracer from that custom
runner.
Repositories with an internal Python test wrapper should use
runner_mode = "consumer_runner" and pass that wrapper through py_test_rule.
In that mode the Datadog macro does not inject run_pytest.py, does not set
main, and does not synthesize imports. Prefer module_identifier for
payload selection so onboarding does not depend on import-path mutation.
BUILD.bazel (Java companion):
load("@datadog-rules-test-optimization-java//:topt_java_test.bzl", "dd_topt_java_test")
load("@test_optimization_data//:export.bzl", "topt_data")
dd_topt_java_test(
name = "pkg_java_test",
srcs = ["*Test.java"],
deps = [":pkg_lib"],
test_class = "com.example.pkg.SampleTest",
topt_data = topt_data,
agent_jar = "@dd_java_agent//file",
)BUILD.bazel (NodeJS companion):
load("@aspect_rules_js//js:defs.bzl", "js_test")
load("@datadog-rules-test-optimization-nodejs//:topt_nodejs_test.bzl", "dd_topt_nodejs_test")
load("@test_optimization_data//:export.bzl", "topt_data")
dd_topt_nodejs_test(
name = "pkg_nodejs_test",
entry_point = "smoke_test.js",
copy_data_to_bin = False, # Datadog payload data comes from external repos.
module_identifier = "apps/nodejs/pkg",
topt_data = topt_data,
nodejs_test_rule = js_test,
)BUILD.bazel (.NET companion):
load("@datadog-rules-test-optimization-dotnet//:topt_dotnet_test.bzl", "dd_topt_dotnet_test")
load("@test_optimization_data//:export.bzl", "topt_data")
load(":dotnet_test_adapter.bzl", "dotnet_csharp_test_adapter")
dd_topt_dotnet_test(
name = "pkg_dotnet_test",
srcs = ["smoke_test.cs"],
target_frameworks = ["net8.0"],
module_identifier = "Company.Product.Package",
topt_data = topt_data,
dotnet_test_rule = dotnet_csharp_test_adapter,
)dotnet_test_adapter.bzl wraps @rules_dotnet//dotnet:defs.bzl csharp_test and maps the Datadog macro's env to csharp_test(envs = ...).
BUILD.bazel (Ruby companion):
load("@rules_ruby//ruby:defs.bzl", "rb_test")
load("@datadog-rules-test-optimization-ruby//:topt_ruby_test.bzl", "dd_topt_ruby_test")
load("@test_optimization_data//:export.bzl", "topt_data")
dd_topt_ruby_test(
name = "pkg_ruby_test",
srcs = ["smoke_test.rb"],
main = "smoke_test.rb",
module_identifier = "apps/ruby/pkg",
topt_data = topt_data,
ruby_test_rule = rb_test,
)Root BUILD.bazel (one doctor and one uploader per workspace):
load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor")
load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader")
dd_test_optimization_doctor(
name = "dd_test_optimization_doctor",
data = ["@test_optimization_data//:test_optimization_context"],
)
dd_payload_uploader(
name = "dd_upload_payloads",
data = ["@test_optimization_data//:test_optimization_context"],
)Use the single-context form above only for single-runtime workspaces. Mixed-
runtime workspaces must add one :test_optimization_context label per
runtime/service repo so uploader enrichment stays aligned with each payload.
Running tests, validating payloads, and uploading payloads:
# Vendor the full tools/test_optimization/ helper directory, or set
# DD_TEST_OPTIMIZATION_SUPPORT_BUNDLE_COLLECTOR to create_support_bundle.py.
# Run tests with BEP, doctor, enrichment dry-run, then upload payloads.
tools/test_optimization/run_test_optimization_ci.sh \
--config test-optimization \
--report-dir .topt/reports \
--support-bundle .topt/reports/dd-test-optimization-support.zip \
//...
# Add --upload only when the real upload should run after doctor and dry-run pass.
DD_API_KEY="$DD_API_KEY" DD_SITE="$DD_SITE" \
tools/test_optimization/run_test_optimization_ci.sh \
--config test-optimization \
--report-dir .topt/reports \
--support-bundle .topt/reports/dd-test-optimization-support.zip \
--upload \
//...# Vendor the full tools/test_optimization/ helper directory, or set
# DD_TEST_OPTIMIZATION_SUPPORT_BUNDLE_COLLECTOR to create_support_bundle.py.
# Run tests with BEP, doctor, enrichment dry-run, then upload payloads.
.\tools\test_optimization\run_test_optimization_ci.ps1 `
-Config test-optimization `
-ReportDir .topt\reports `
-SupportBundle .topt\reports\dd-test-optimization-support.zip `
//...
# Add -Upload only when the real upload should run after doctor and dry-run pass.
$env:DD_API_KEY = "<your-api-key>"
$env:DD_SITE = "datadoghq.com"
.\tools\test_optimization\run_test_optimization_ci.ps1 `
-Config test-optimization `
-ReportDir .topt\reports `
-SupportBundle .topt\reports\dd-test-optimization-support.zip `
-Upload `
//...Notes:
- The wrapper preserves test failures, blocks upload success when doctor or dry-run enrichment fails, and still fails on uploader errors when the earlier steps passed.
- For first-pass support after tests have run, the doctor
--support-bundle=.topt/reports/dd-test-optimization-support.zipoption creates a doctor-only bundle without vendoring the wrapper helper directory. - For the support escalation ladder and bundle triage order, see
docs/Troubleshooting.md. - Example
runtests.shscripts defaultDD_SITEtodatadoghq.comwhen not set. - Windows-friendly wrappers are provided as
examples/*/runtests.ps1and use native PowerShell + Bazel (no Git Bash dependency).
Dry-run mode for CI/debugging:
- Set
RUNTESTS_DRY_RUN=1when invokingexamples/*/runtests.shto print the commands that would run without executing Bazel test/upload operations. - PowerShell wrappers honor the same
RUNTESTS_DRY_RUN=1environment variable.
MODULE.bazel:
bazel_dep(name = "datadog-rules-test-optimization", version = "1.2.0")
bazel_dep(name = "datadog-rules-test-optimization-go", version = "1.2.0")
bazel_dep(name = "rules_go", version = "0.60.0") # or your repo-selected version
git_override(
module_name = "datadog-rules-test-optimization",
remote = "https://github.com/DataDog/rules_test_optimization.git",
commit = "<commit-sha>",
)
git_override(
module_name = "datadog-rules-test-optimization-go",
remote = "https://github.com/DataDog/rules_test_optimization.git",
commit = "<commit-sha>",
strip_prefix = "modules/go",
)
go_topt = use_extension(
"@datadog-rules-test-optimization-go//:topt_go_extension.bzl",
"test_optimization_go_extension",
)
go_topt.test_optimization_go(
name = "test_optimization_data",
services = ["go-service-a", "go-service-b"],
runtime_version = "1.25.0",
)
use_repo(
go_topt,
"test_optimization_data", # aggregator repo
"test_optimization_data_go_service_a", # per-service repos
"test_optimization_data_go_service_b",
)Bootstrap once after adding the Go module files:
bazel run @datadog-rules-test-optimization-go//:dd_topt_go_bootstrap -- \
--go-module-dir src/go-project \
--dd-trace-go-version v2.9.0As in the single-service flow, --dd-trace-go-version is optional and defaults
to v2.9.0. It may resolve to one shared tracer version or to separate exact
versions for the traced Go modules when you pass a branch or commit SHA.
This multi-service path stays on the lower-level/manual API. Guided bootstrap is only for fresh single-service Go workspaces.
Repository roles in multi-service mode:
@test_optimization_data//...(aggregator) exposes combined per-service labels such as:test_optimization_files_<service>and:module_<service>_<module_label>.@test_optimization_data_<service>//...(per-service repos) are useful when loading a service-specific export dictionary directly.- This Go extension form is for multi-service Go only. Every configured service
is materialized as
runtime_name = "go".
For Python/Java/NodeJS/.NET/Ruby multi-service onboarding, use the core
test_optimization_multi_sync_extension and the per-language guide in
docs/Language_Onboarding.md. This examples/multi_service workspace is
intentionally scoped to Go.
BUILD.bazel — Option A (explicit selection, inference via embed):
load("@rules_go//go:def.bzl", "go_library")
load("@datadog-rules-test-optimization-go//:topt_go_test.bzl", "dd_topt_go_test")
load("@test_optimization_data//:export.bzl", "topt_data_by_service")
go_library(
name = "pkg_lib",
srcs = ["*.go"],
)
dd_topt_go_test(
name = "pkg_go_test",
srcs = ["*_test.go"],
embed = [":pkg_lib"],
orchestrion_mode = "test_optimization",
topt_data = topt_data_by_service["go_service_a"], # sanitized key
)Mixed-runtime monorepo pattern:
# Keep runtime-specific sync repos separate. This remains the recommended path
# when not every service is Go and not every service needs Orchestrion.
topt_go = use_extension(
"@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl",
"test_optimization_sync_extension",
)
topt_go.test_optimization_sync(
name = "test_optimization_data_go",
service = "go-service",
runtime_name = "go",
runtime_version = "1.25.0",
)
topt_py = use_extension(
"@datadog-rules-test-optimization//tools/core:test_optimization_sync.bzl",
"test_optimization_sync_extension",
)
topt_py.test_optimization_sync(
name = "test_optimization_data_py",
service = "py-service",
runtime_name = "python",
runtime_version = "3.12",
)
use_repo(topt_go, "test_optimization_data_go")
use_repo(topt_py, "test_optimization_data_py")BUILD.bazel — Option B (mapping + key, inference via embed):
load("@rules_go//go:def.bzl", "go_library")
load("@datadog-rules-test-optimization-go//:topt_go_test.bzl", "dd_topt_go_test")
load("@test_optimization_data//:export.bzl", "topt_data_by_service")
go_library(
name = "pkg_lib",
srcs = ["*.go"],
)
dd_topt_go_test(
name = "pkg_go_test",
srcs = ["*_test.go"],
embed = [":pkg_lib"],
orchestrion_mode = "test_optimization",
topt_data = topt_data_by_service,
topt_service = "go_service_a", # or raw "go-service-a"
# If two services sanitize to the same key, use the deduped key (e.g. go_service_a_2).
)Notes on importpath inference:
- Preferred: inference via
embedabove (reads rules_go provider). - Optional: explicit
importpathongo_testtakes precedence when set. - Fallback: if neither is available, the macro computes
<module_path>/<bazel package>using the exportedtopt_data["runtimes"]["go"]["module_path"]and the current Bazel package path.
Per-module filegroup (aggregator):
# Select a single module for a specific service
filegroup(
name = "dd_mod_core_go",
srcs = ["@test_optimization_data//:module_go_service_a_core"],
)Doctor/uploader package (multi-service). Simple examples may put these in the root package, but large monorepos should prefer a lightweight package:
load("@datadog-rules-test-optimization//tools/core:test_optimization_doctor.bzl", "dd_test_optimization_doctor")
load("@datadog-rules-test-optimization//tools/core:test_optimization_uploader.bzl", "dd_payload_uploader")
dd_test_optimization_doctor(
name = "dd_test_optimization_doctor",
data = [
"@test_optimization_data//:test_optimization_context_go_service_a",
"@test_optimization_data//:test_optimization_context_go_service_b",
],
)
dd_payload_uploader(
name = "dd_upload_payloads",
data = [
"@test_optimization_data//:test_optimization_context_go_service_a",
"@test_optimization_data//:test_optimization_context_go_service_b",
],
)Mixed-runtime example rule:
- keep one sync repo per runtime/service
- keep one logical uploader for the workspace; package-local placement is fine
- add every matching context target to uploader
data - do not use
DD_TEST_OPTIMIZATION_CONTEXT_JSONas the normal mixed-runtime path