From 7fef02d580962cbe156d8b2241c1ebde6d681569 Mon Sep 17 00:00:00 2001 From: Tony Redondo Date: Wed, 16 Jul 2025 10:02:46 +0200 Subject: [PATCH 1/9] Update README.md --- README.md | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/README.md b/README.md index 5d681b6..30fe20c 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,169 @@ This repository contains the github action workflows and release artifact of the ### SDKs It also contains SDKs for different programming languages. +## Local Development + +This repository provides comprehensive local development tools for building native libraries and working with SDKs across different platforms. + +### Building Native Libraries + +The `localdev` scripts build the native libraries locally for development and testing purposes. + +#### Available Scripts + +- **Unix/Linux/macOS**: `build/localdev.sh` +- **Windows PowerShell**: `build/localdev.ps1` +- **Windows CMD**: `build/localdev.cmd` + +#### Usage + +```bash +# Unix/Linux/macOS +cd build +./localdev.sh # Build for current platform +./localdev.sh --help # Show help + +# Windows PowerShell +cd build +.\localdev.ps1 # Build for current platform +.\localdev.ps1 -Help # Show help + +# Windows CMD +cd build +localdev.cmd # Build for current platform +localdev.cmd --help # Show help +``` + +#### Features + +- **Cross-platform support**: macOS (Universal + iOS), Linux (ARM64/AMD64), Windows (AMD64), Android +- **Automatic repository management**: Clones/updates dd-trace-go repository +- **Platform-specific optimizations**: Compiler flags, UPX compression, library stripping +- **Output organization**: All artifacts placed in `dev-output/` directory +- **Tool caching**: Downloads and caches build tools (UPX) in `tools/` directory + +#### Output Structure + +``` +dev-output/ +├── macos-libtestoptimization-static/ # macOS universal static library +├── macos-libtestoptimization-dynamic/ # macOS universal dynamic library +├── ios-libtestoptimization-static/ # iOS static library +├── linux-arm64-libtestoptimization-static/ # Linux ARM64 libraries +├── linux-arm64-libtestoptimization-dynamic/ +├── linux-x64-libtestoptimization-static/ # Linux x64 libraries +├── linux-x64-libtestoptimization-dynamic/ +├── windows-x64-libtestoptimization-static/ # Windows x64 libraries +├── windows-x64-libtestoptimization-dynamic/ +└── android-arm64-libtestoptimization-dynamic/ # Android ARM64 library +``` + +### Rust SDK Development + +The `ldevcargo` scripts provide an integrated development experience for the Rust SDK by automatically building native libraries and running cargo commands with development mode enabled. + +#### Available Scripts + +- **Unix/Linux/macOS**: `sdks/rust/test-optimization-sdk/ldevcargo.sh` +- **Windows PowerShell**: `sdks/rust/test-optimization-sdk/ldevcargo.ps1` +- **Windows CMD**: `sdks/rust/test-optimization-sdk/ldevcargo.cmd` + +#### Usage + +```bash +# Unix/Linux/macOS +cd sdks/rust/test-optimization-sdk +./ldevcargo.sh build # Build native libs + cargo build +./ldevcargo.sh test # Build native libs + cargo test +./ldevcargo.sh -sn check # Skip native build, run cargo check +./ldevcargo.sh --skip-native clippy # Skip native build, run cargo clippy +./ldevcargo.sh --help # Show help + +# Windows PowerShell +cd sdks/rust/test-optimization-sdk +pwsh -NoProfile .\ldevcargo.ps1 build # Build native libs + cargo build +pwsh -NoProfile .\ldevcargo.ps1 -sn check # Skip native build, run cargo check +pwsh -NoProfile .\ldevcargo.ps1 --help # Show help + +# Windows CMD +cd sdks/rust/test-optimization-sdk +ldevcargo.cmd build # Build native libs + cargo build +ldevcargo.cmd -sn check # Skip native build, run cargo check +ldevcargo.cmd --help # Show help +``` + +#### Options + +- `-h, --help`: Show help message and exit +- `-sn, --skip-native`: Skip building native libraries (use existing builds) + +#### Features + +- **Automatic native builds**: Runs `localdev` script before cargo commands +- **Development mode**: Automatically sets `TEST_OPTIMIZATION_DEV_MODE=1` +- **Skip option**: Fast iteration with `-sn`/`--skip-native` for quick cargo operations +- **Argument filtering**: Removes script-specific flags before passing to cargo +- **Cross-platform**: Consistent interface across all platforms +- **Clean execution**: PowerShell version uses `-NoProfile` to avoid profile interference + +#### Environment Variables + +The following environment variables enhance the development experience: + +- **`TEST_OPTIMIZATION_DEV_MODE`**: Automatically set by `ldevcargo` scripts to use local builds +- **`TEST_OPTIMIZATION_SDK_NATIVE_SEARCH_PATH`**: Custom path for native library search +- **`TEST_OPTIMIZATION_SDK_SKIP_NATIVE_INSTALL`**: Skip automatic native library installation + +### Development Workflow + +#### Initial Setup +```bash +# Clone the repository +git clone https://github.com/DataDog/test-optimization-native.git +cd test-optimization-native + +# Build native libraries for your platform +cd build +./localdev.sh # or localdev.ps1/localdev.cmd on Windows +``` + +#### Rust Development +```bash +# Navigate to Rust SDK +cd sdks/rust/test-optimization-sdk + +# Full development build (builds native libs + cargo build) +./ldevcargo.sh build + +# Quick iterations (skip native rebuild) +./ldevcargo.sh -sn check +./ldevcargo.sh -sn clippy +./ldevcargo.sh -sn test + +# Run with fresh native libraries +./ldevcargo.sh test +``` + +#### Python Development +```bash +# Navigate to Python SDK +cd sdks/python/test-optimization-sdk + +# Install in development mode with local native libraries +TEST_OPTIMIZATION_DEV_MODE=1 pip install -e . +``` + +### Requirements + +- **Go 1.24 or later** (for native library builds) +- **Git** (for repository management) +- **Platform-specific tools**: + - macOS: Xcode Command Line Tools, optional Homebrew with coreutils + - Linux: GCC, build-essential + - Windows: MinGW-w64 or Visual Studio Build Tools +- **Rust/Cargo** (for Rust SDK development) +- **Python 3.7+** (for Python SDK development) + ## Copyright Copyright (c) 2025 Datadog From 27e2d0b96a2951022f6874b50ade69b92c0dc64d Mon Sep 17 00:00:00 2001 From: Tony Redondo Date: Wed, 16 Jul 2025 12:15:43 +0200 Subject: [PATCH 2/9] Add support for impacted tests tagging on topt_test_set_source --- native/exports.go | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/native/exports.go b/native/exports.go index 1b4603c..5d64797 100644 --- a/native/exports.go +++ b/native/exports.go @@ -426,6 +426,7 @@ import ( civisibility "github.com/DataDog/dd-trace-go/v2/internal/civisibility/integrations" "github.com/DataDog/dd-trace-go/v2/internal/civisibility/utils" "github.com/DataDog/dd-trace-go/v2/internal/civisibility/utils/net" + "github.com/DataDog/dd-trace-go/v2/internal/civisibility/utils/telemetry" ) // ******************************************************************************************************************* @@ -1570,25 +1571,38 @@ func topt_test_set_error(test_id C.topt_TestId, error_type *C.char, error_messag //export topt_test_set_source func topt_test_set_source(test_id C.topt_TestId, file *C.char, start_line *C.int, end_line *C.int) C.Bool { if test, ok := getTest(test_id); ok { + var sFile string + var iStartline, iEndline int + if file != nil { - gFile := C.GoString(file) - gFile = utils.GetRelativePathFromCITagsSourceRoot(gFile) - test.SetTag(constants.TestSourceFile, gFile) + sFile = C.GoString(file) + sFile = utils.GetRelativePathFromCITagsSourceRoot(sFile) + test.SetTag(constants.TestSourceFile, sFile) // get the codeowner of the function codeOwners := utils.GetCodeOwners() if codeOwners != nil { - match, found := codeOwners.Match("/" + gFile) + match, found := codeOwners.Match("/" + sFile) if found { test.SetTag(constants.TestCodeOwners, match.GetOwnersString()) } } } if start_line != nil { - test.SetTag(constants.TestSourceStartLine, int(*start_line)) + iStartline = int(*start_line) + test.SetTag(constants.TestSourceStartLine, iStartline) } if end_line != nil { - test.SetTag(constants.TestSourceEndLine, int(*end_line)) + iEndline = int(*end_line) + test.SetTag(constants.TestSourceEndLine, iEndline) + } + if sFile != "" && iStartline > 0 && iEndline > 0 { + if analyzer := civisibility.GetImpactedTestsAnalyzer(); analyzer != nil { + if analyzer.IsImpacted(test.Name(), sFile, iStartline, iEndline) { + test.SetTag(constants.TestIsModified, "true") + telemetry.ImpactedTestsModified() + } + } } return toBool(true) } From 5326c866de7e98733498738920965298e3314367 Mon Sep 17 00:00:00 2001 From: Tony Redondo Date: Wed, 16 Jul 2025 12:31:22 +0200 Subject: [PATCH 3/9] Add api to write test logs --- native/exports.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/native/exports.go b/native/exports.go index 5d64797..2c3f1c7 100644 --- a/native/exports.go +++ b/native/exports.go @@ -1677,6 +1677,32 @@ func topt_test_set_benchmark_number_data(test_id C.topt_TestId, measure_type *C. return toBool(false) } +// topt_test_log logs a message for a test. +// +// Parameters: +// - test_id: The ID of the test. +// - message: A string message to log. +// - tags: Optional string containing tags associated with the log message. +// +// Returns: +// - C.Bool: True if the message was logged successfully, false if the test was not found or message was nil. +// +//export topt_test_log +func topt_test_log(test_id C.topt_TestId, message *C.char, tags *C.char) C.Bool { + if message == nil { + return toBool(false) + } + var sTags string + if tags != nil { + sTags = C.GoString(tags) + } + if test, ok := getTest(test_id); ok { + test.Log(C.GoString(message), sTags) + return toBool(true) + } + return toBool(false) +} + // ******************************************************************************************************************* // Spans // ******************************************************************************************************************* From f982e309b3758a76966f8ebcd23123bca9d40711 Mon Sep 17 00:00:00 2001 From: Tony Redondo Date: Wed, 16 Jul 2025 12:45:53 +0200 Subject: [PATCH 4/9] Add support for test logs --- .../src/test_optimization/lib/bindings.rs | 1 + .../src/test_optimization/test.rs | 16 ++++++++++++++++ sdks/rust/test-optimization-sdk/src/tests.rs | 2 ++ 3 files changed, 19 insertions(+) diff --git a/sdks/rust/test-optimization-sdk/src/test_optimization/lib/bindings.rs b/sdks/rust/test-optimization-sdk/src/test_optimization/lib/bindings.rs index 83c227f..091ba71 100644 --- a/sdks/rust/test-optimization-sdk/src/test_optimization/lib/bindings.rs +++ b/sdks/rust/test-optimization-sdk/src/test_optimization/lib/bindings.rs @@ -307,6 +307,7 @@ unsafe extern "C" { pub fn topt_test_set_source(test_id: topt_TestId, file: *mut c_char, start_line: *mut c_int, end_line: *mut c_int) -> Bool; pub fn topt_test_set_benchmark_string_data(test_id: topt_TestId, measure_type: *mut c_char, data_array: topt_KeyValueArray) -> Bool; pub fn topt_test_set_benchmark_number_data(test_id: topt_TestId, measure_type: *mut c_char, data_array: topt_KeyNumberArray) -> Bool; + pub fn topt_test_log(test_id: topt_TestId, message: *mut c_char, tags: *mut c_char) -> Bool; // Span functions pub fn topt_span_create(parent_id: topt_TslvId, span_options: topt_SpanStartOptions) -> topt_SpanResult; diff --git a/sdks/rust/test-optimization-sdk/src/test_optimization/test.rs b/sdks/rust/test-optimization-sdk/src/test_optimization/test.rs index 1166015..61a827a 100644 --- a/sdks/rust/test-optimization-sdk/src/test_optimization/test.rs +++ b/sdks/rust/test-optimization-sdk/src/test_optimization/test.rs @@ -297,4 +297,20 @@ impl Test { unsafe { dealloc(kn_array_ptr as *mut u8, layout); } result } + + /// Write a log message for this test + #[allow(dead_code)] + pub fn log(&self, message: impl AsRef, tags: Option>) -> bool { + let message_cstring = CString::new(message.as_ref()).unwrap(); + let tags_cstring = tags.map(|wd| CString::new(wd.as_ref()).unwrap()); + unsafe { + Bool_to_bool(topt_test_log( + self.test_id, + message_cstring.as_ptr() as *mut c_char, + tags_cstring + .as_ref() + .map_or(null_mut(), |s| s.as_ptr() as *mut c_char), + )) + } + } } diff --git a/sdks/rust/test-optimization-sdk/src/tests.rs b/sdks/rust/test-optimization-sdk/src/tests.rs index cdbd295..f8b4673 100644 --- a/sdks/rust/test-optimization-sdk/src/tests.rs +++ b/sdks/rust/test-optimization-sdk/src/tests.rs @@ -73,6 +73,8 @@ fn complete() { pass_test.set_number_tag("Pass-NumberFromRust", 42f64); pass_test.set_test_source("test.rs", &6, &58); pass_test.set_coverage_data(&["file.rs"]); + pass_test.log("Hello world", Some("tag1=value1,tag2=value2")); + pass_test.log("Hello world", None::<&str>); let mut measurement_data: HashMap<&str, f64> = HashMap::new(); measurement_data.insert("data1", 42f64); From c21540b02bf63ec5baedb203c47971a0649ee7be Mon Sep 17 00:00:00 2001 From: Tony Redondo Date: Wed, 16 Jul 2025 12:47:48 +0200 Subject: [PATCH 5/9] Bump rust sdk version --- sdks/rust/test-optimization-sdk/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdks/rust/test-optimization-sdk/Cargo.toml b/sdks/rust/test-optimization-sdk/Cargo.toml index c6b4fbd..c11f371 100644 --- a/sdks/rust/test-optimization-sdk/Cargo.toml +++ b/sdks/rust/test-optimization-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-optimization-sdk" -version = "0.0.3" +version = "0.0.4" edition = "2021" description = "Datadog's test optimization sdk" license = "Apache-2.0" From e789768bbaf3c04c01fec348895ca7608ab0c38e Mon Sep 17 00:00:00 2001 From: Tony Redondo Date: Wed, 16 Jul 2025 12:56:13 +0200 Subject: [PATCH 6/9] Add test log support to the python sdk --- .../src/test_optimization_sdk/lib.py | 1 + .../src/test_optimization_sdk/test.py | 36 ++++++++++++++++++- .../tests/test_complete.py | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/lib.py b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/lib.py index 41c82cc..7ffc458 100644 --- a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/lib.py +++ b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/lib.py @@ -392,6 +392,7 @@ def _get_library_path() -> str: "topt_test_close", "topt_test_set_benchmark_string_data", "topt_test_set_benchmark_number_data", + "topt_test_log", "topt_span_create", "topt_span_set_string_tag", "topt_span_set_number_tag", diff --git a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/test.py b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/test.py index 739675a..9b34a33 100644 --- a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/test.py +++ b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/test.py @@ -21,6 +21,7 @@ topt_send_code_coverage_payload, topt_test_set_benchmark_number_data, topt_test_set_benchmark_string_data, + topt_test_log ) from .utils import get_now from .base import BaseEntity @@ -455,4 +456,37 @@ def set_benchmark_number_data( kn_array[0], )) except Exception as e: - raise RuntimeError(f"Failed to set benchmark number data: {e}") \ No newline at end of file + raise RuntimeError(f"Failed to set benchmark number data: {e}") + + def log(self, message: str, tags: Optional[str]) -> bool: + """Log a message for this test. + + Args: + message: Message to log + tags: Optional tags to log + + Returns: + True if successful, False otherwise + + Raises: + RuntimeError: If the test is already closed + """ + if self._closed: + raise RuntimeError("Cannot log on closed test") + + try: + # Create C strings for the message and tags + message_bytes = message.encode() + tags_bytes = tags.encode() if tags else None + + message_cstr = self._track_c_string(ffi.new("char[]", message_bytes)) + tags_cstr = self._track_c_string(ffi.new("char[]", tags_bytes)) if tags else ffi.NULL + + # Log the message + return bool(topt_test_log( + self.test_id, + message_cstr, + tags_cstr, + )) + except Exception as e: + raise RuntimeError(f"Failed to log the message: {e}") diff --git a/sdks/python/test-optimization-sdk/tests/test_complete.py b/sdks/python/test-optimization-sdk/tests/test_complete.py index 07096b9..5646acd 100644 --- a/sdks/python/test-optimization-sdk/tests/test_complete.py +++ b/sdks/python/test-optimization-sdk/tests/test_complete.py @@ -110,6 +110,8 @@ def test_complete(): pass_test.set_number_tag("Pass-NumberFromPython", 42.0) pass_test.set_test_source("test.py", 6, 58) pass_test.set_coverage_data(["file.py"]) + pass_test.log("Hello world", "tag1=value1,tag2=value2") + pass_test.log("Hello world", None) # Set benchmark data for pass test measurement_data: Dict[str, float] = { From 1201bfe86918018f3da5bcd3d465f5f3d05d2b59 Mon Sep 17 00:00:00 2001 From: Tony Redondo Date: Wed, 16 Jul 2025 12:59:41 +0200 Subject: [PATCH 7/9] fix --- .../test-optimization-sdk/src/test_optimization_sdk/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/lib.py b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/lib.py index 7ffc458..28ba54e 100644 --- a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/lib.py +++ b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/lib.py @@ -257,6 +257,7 @@ Bool topt_test_close(topt_TestId test_id, topt_TestCloseOptions options); Bool topt_test_set_benchmark_string_data(topt_TestId test_id, char* measure_type, topt_KeyValueArray data); Bool topt_test_set_benchmark_number_data(topt_TestId test_id, char* measure_type, topt_KeyNumberArray data); + Bool topt_test_log(topt_TestId test_id, char* message, char* tags); topt_SpanResult topt_span_create(topt_TslvId parent_id, topt_SpanStartOptions span_options); Bool topt_span_set_string_tag(topt_TslvId span_id, char* key, char* value); From 1a9046ebac66069b331a36976c61fce5792c9e19 Mon Sep 17 00:00:00 2001 From: Tony Redondo Date: Wed, 16 Jul 2025 13:02:31 +0200 Subject: [PATCH 8/9] bump version --- sdks/python/test-optimization-sdk/setup.py | 2 +- .../test-optimization-sdk/src/test_optimization_sdk/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdks/python/test-optimization-sdk/setup.py b/sdks/python/test-optimization-sdk/setup.py index 4161c4f..4d31f8e 100644 --- a/sdks/python/test-optimization-sdk/setup.py +++ b/sdks/python/test-optimization-sdk/setup.py @@ -5,7 +5,7 @@ setup( name="test-optimization-sdk", - version="0.0.2", + version="0.0.3", description="Datadog's test optimization SDK for Python", author="Datadog", author_email="info@datadoghq.com", diff --git a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/__init__.py b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/__init__.py index af2df23..f5cb8f0 100644 --- a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/__init__.py +++ b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/__init__.py @@ -26,7 +26,7 @@ TEST_OPTIMIZATION_DOWNLOAD_URL_FORMAT, ) -__version__ = "0.0.1" +__version__ = "0.0.4" __all__ = [ "TestOptimization", From 32e2039f76c92e03c58144f62f800e24ea8799b7 Mon Sep 17 00:00:00 2001 From: Tony Redondo Date: Wed, 16 Jul 2025 13:05:22 +0200 Subject: [PATCH 9/9] bump version --- .../src/test_optimization_sdk/constants.py | 2 +- sdks/rust/test-optimization-sdk/build.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/constants.py b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/constants.py index fe1f899..2675571 100644 --- a/sdks/python/test-optimization-sdk/src/test_optimization_sdk/constants.py +++ b/sdks/python/test-optimization-sdk/src/test_optimization_sdk/constants.py @@ -6,4 +6,4 @@ TEST_OPTIMIZATION_SDK_SKIP_NATIVE_INSTALL = "TEST_OPTIMIZATION_SDK_SKIP_NATIVE_INSTALL" TEST_OPTIMIZATION_SDK_NATIVE_SEARCH_PATH = "TEST_OPTIMIZATION_SDK_NATIVE_SEARCH_PATH" TEST_OPTIMIZATION_DEV_MODE = "TEST_OPTIMIZATION_DEV_MODE" -TEST_OPTIMIZATION_DOWNLOAD_URL_FORMAT = "https://github.com/DataDog/test-optimization-native/releases/download/v0.0.3-preview/" \ No newline at end of file +TEST_OPTIMIZATION_DOWNLOAD_URL_FORMAT = "https://github.com/DataDog/test-optimization-native/releases/download/v0.0.4-preview/" \ No newline at end of file diff --git a/sdks/rust/test-optimization-sdk/build.rs b/sdks/rust/test-optimization-sdk/build.rs index e8b97ec..0246590 100644 --- a/sdks/rust/test-optimization-sdk/build.rs +++ b/sdks/rust/test-optimization-sdk/build.rs @@ -12,7 +12,7 @@ use ureq::AsSendBody; const TEST_OPTIMIZATION_SDK_SKIP_NATIVE_INSTALL: &str = "TEST_OPTIMIZATION_SDK_SKIP_NATIVE_INSTALL"; const TEST_OPTIMIZATION_SDK_NATIVE_SEARCH_PATH: &str = "TEST_OPTIMIZATION_SDK_NATIVE_SEARCH_PATH"; const TEST_OPTIMIZATION_DEV_MODE: &str = "TEST_OPTIMIZATION_DEV_MODE"; -const TEST_OPTIMIZATION_DOWNLOAD_URL_FORMAT: &str = "https://github.com/DataDog/test-optimization-native/releases/download/v0.0.3-preview/"; +const TEST_OPTIMIZATION_DOWNLOAD_URL_FORMAT: &str = "https://github.com/DataDog/test-optimization-native/releases/download/v0.0.4-preview/"; fn main() { let target = env::var("TARGET").expect("Cargo did not provide TARGET");