Skip to content

Commit 34a19e8

Browse files
authored
chore(crashtracking): Add testing framework and add more tests to crashtracker (#1183)
* Add building of test library * Add a test and fix the build id computation * Factorize some code * Forgot to add the C file * Add license * use cc instead of clang * Add feature * Fix cross tests
1 parent ab89077 commit 34a19e8

File tree

9 files changed

+434
-9
lines changed

9 files changed

+434
-9
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,16 @@ jobs:
5151
- name: "[${{ steps.rust-version.outputs.version}}] cargo build --workspace --exclude builder --verbose"
5252
shell: bash
5353
run: cargo build --workspace --exclude builder --verbose
54-
- name: "[${{ steps.rust-version.outputs.version}}] cargo nextest run --workspace --exclude builder --profile ci --verbose -E '!test(tracing_integration_tests::)'"
54+
- name: "[${{ steps.rust-version.outputs.version}}] cargo nextest run --workspace --features datadog-crashtracker/generate-unit-test-files --exclude builder --profile ci --verbose -E '!test(tracing_integration_tests::)'"
5555
shell: bash
5656
# Run doc tests with cargo test and run tests with nextest and generate junit.xml
57-
run: cargo test --workspace --exclude builder --doc --verbose && cargo nextest run --workspace --exclude builder --profile ci --verbose -E '!test(tracing_integration_tests::)'
57+
run: cargo test --workspace --features datadog-crashtracker/generate-unit-test-files --exclude builder --doc --verbose && cargo nextest run --workspace --features datadog-crashtracker/generate-unit-test-files --exclude builder --profile ci --verbose -E '!test(tracing_integration_tests::)'
5858
env:
5959
RUST_BACKTRACE: full
60-
- name: "[${{ steps.rust-version.outputs.version}}] Tracing integration tests: cargo nextest run --workspace --exclude builder --profile ci --test-threads=1 --verbose -E 'test(tracing_integration_tests::)'"
60+
- name: "[${{ steps.rust-version.outputs.version}}] Tracing integration tests: cargo nextest run --workspace --features datadog-crashtracker/generate-unit-test-files --exclude builder --profile ci --test-threads=1 --verbose -E 'test(tracing_integration_tests::)'"
6161
if: runner.os == 'Linux'
6262
shell: bash
63-
run: cargo nextest run --workspace --exclude builder --profile ci --test-threads=1 --verbose -E 'test(tracing_integration_tests::)'
63+
run: cargo nextest run --workspace --features datadog-crashtracker/generate-unit-test-files --exclude builder --profile ci --test-threads=1 --verbose -E 'test(tracing_integration_tests::)'
6464
env:
6565
RUST_BACKTRACE: full
6666
- name: "[${{ steps.rust-version.outputs.version}}] RUSTFLAGS=\"-C prefer-dynamic\" cargo nextest run --package test_spawn_from_lib --features prefer-dynamic -E '!test(tracing_integration_tests::)'"
@@ -225,8 +225,8 @@ jobs:
225225
rust_version: cross-centos7
226226
- run: cargo install cross || true
227227
- run: cross build --workspace --target x86_64-unknown-linux-gnu --exclude builder
228-
- run: cross test --workspace --target x86_64-unknown-linux-gnu --exclude builder -- --skip "::single_threaded_tests::" --skip "tracing_integration_tests::"
229-
- run: cross test --workspace --target x86_64-unknown-linux-gnu --exclude builder --exclude bin_tests -- --skip "::tests::" --skip "::api_tests::" --test-threads 1 --skip "tracing_integration_tests::"
228+
- run: cross test --workspace --features datadog-crashtracker/generate-unit-test-files --target x86_64-unknown-linux-gnu --exclude builder -- --skip "::single_threaded_tests::" --skip "tracing_integration_tests::"
229+
- run: cross test --workspace --features datadog-crashtracker/generate-unit-test-files --target x86_64-unknown-linux-gnu --exclude builder --exclude bin_tests -- --skip "::tests::" --skip "::api_tests::" --test-threads 1 --skip "tracing_integration_tests::"
230230

231231
ffi_bake:
232232
strategy:

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

LICENSE-3rdparty.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
root_name: builder, build_common, tools, datadog-alloc, datadog-crashtracker, ddcommon, ddtelemetry, datadog-ddsketch, datadog-crashtracker-ffi, ddcommon-ffi, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, tinybytes, spawn_worker, cc_utils, datadog-library-config, datadog-library-config-ffi, datadog-live-debugger, datadog-live-debugger-ffi, datadog-profiling, datadog-profiling-protobuf, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-protobuf, datadog-trace-utils, datadog-trace-normalization, dogstatsd-client, datadog-log-ffi, datadog-log, ddsketch-ffi, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, datadog-remote-config, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, datadog-trace-obfuscation, datadog-tracer-flare, sidecar_mockgen, test_spawn_from_lib
1+
root_name: builder, build_common, tools, datadog-alloc, datadog-crashtracker, ddcommon, ddtelemetry, datadog-ddsketch, cc_utils, datadog-crashtracker-ffi, ddcommon-ffi, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, tinybytes, spawn_worker, datadog-library-config, datadog-library-config-ffi, datadog-live-debugger, datadog-live-debugger-ffi, datadog-profiling, datadog-profiling-protobuf, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-protobuf, datadog-trace-utils, datadog-trace-normalization, dogstatsd-client, datadog-log-ffi, datadog-log, ddsketch-ffi, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, datadog-remote-config, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, datadog-trace-obfuscation, datadog-tracer-flare, sidecar_mockgen, test_spawn_from_lib
22
third_party_libraries:
33
- package_name: addr2line
44
package_version: 0.24.2

datadog-crashtracker/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ collector = []
2424
receiver = []
2525
# Enables the collection of crash-info on Windows
2626
collector_windows = []
27+
generate-unit-test-files = []
2728

2829
[target.'cfg(unix)'.dependencies]
2930
# Should be kept in sync with the libdatadog symbolizer crate (also using blasesym)
@@ -63,3 +64,4 @@ tempfile = { version = "3.3" }
6364
[build-dependencies]
6465
# If we use a newer version of cc, CI fails on alpine.
6566
cc = "1.1.31"
67+
cc_utils = {path = "../tools/cc_utils"}

datadog-crashtracker/build.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,113 @@
11
// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
22
// SPDX-License-Identifier: Apache-2.0
3+
#[cfg(unix)]
4+
mod unix_imports {
5+
pub use std::path::Path;
6+
pub use std::path::PathBuf;
7+
pub use std::process::Command;
8+
}
9+
10+
#[cfg(unix)]
11+
use unix_imports::*;
12+
13+
pub use cc_utils::cc;
14+
15+
#[cfg(unix)]
16+
fn build_shared_libs() {
17+
build_c_file();
18+
build_cpp_file();
19+
}
20+
21+
#[cfg(unix)]
22+
fn get_data_folder_path() -> PathBuf {
23+
Path::new(&env!("CARGO_MANIFEST_DIR"))
24+
.join("data")
25+
.canonicalize()
26+
.expect("Failed to canonicalize base path for libtest")
27+
}
28+
29+
#[cfg(unix)]
30+
fn build_c_file() {
31+
let base_path = get_data_folder_path();
32+
33+
let src = base_path.join("libtest.c");
34+
let dst = base_path.join("libtest.so");
35+
let dst_file = dst
36+
.to_str()
37+
.expect("Failed to convert dst file path to str");
38+
39+
println!("cargo:rerun-if-changed={}", &dst_file);
40+
cc_utils::ImprovedBuild::new()
41+
.file(&src)
42+
.link_dynamically("dl")
43+
// this is needed for the cross compile (cargo cross)
44+
.flag("-std=c99")
45+
// Fix build id to ease in testing.
46+
.flag("-Wl,--build-id=0xaaaabbbbccccddddeeeeffff0011223344556677")
47+
.flag("-O0")
48+
.flag("-gdwarf-4")
49+
.flag("-Wl,--compress-debug-sections=zlib")
50+
.warnings(true)
51+
.warnings_into_errors(true)
52+
.emit_rerun_if_env_changed(true)
53+
.try_compile_shared_lib(dst_file)
54+
.unwrap();
55+
56+
// We use objcopy to change the alignment of the debug_abbrev ELF section.
57+
// By setting the alignment to 1 we make sure that the section is misaligned.
58+
// This will help to identify regressions in blazesym.
59+
// Note: we could have picked any other debug_xx sections. As long as it's a
60+
// debug ELF sections.
61+
let mut modify_alignment = Command::new("objcopy")
62+
.args(["--set-section-alignment", ".debug_abbrev=1"])
63+
.arg(dst_file)
64+
.arg(dst_file)
65+
.spawn()
66+
.expect("failed to spawn objcopy");
67+
68+
modify_alignment
69+
.wait()
70+
.expect("Failed to change alignement of debug_abbrev ELF section");
71+
}
72+
73+
#[cfg(unix)]
74+
fn build_cpp_file() {
75+
let base_path = get_data_folder_path();
76+
77+
let src = base_path.join("libtest_cpp.cpp");
78+
let dst = base_path.join("libtest_cpp.so");
79+
let dst_file = dst
80+
.to_str()
81+
.expect("Failed to convert dst file path to str");
82+
83+
println!("cargo:rerun-if-changed={}", &dst_file);
84+
cc_utils::ImprovedBuild::new()
85+
.cpp(true)
86+
.file(&src)
87+
.link_dynamically("dl")
88+
.flag("-std=c++11")
89+
// Fix build id to ease in testing.
90+
.flag("-Wl,--build-id=0x0011223344556677aaaabbbbccccddddeeeeffff")
91+
.flag("-O0")
92+
.flag("-gdwarf-4")
93+
.warnings(true)
94+
.warnings_into_errors(true)
95+
.emit_rerun_if_env_changed(true)
96+
.try_compile_shared_lib(dst_file)
97+
.unwrap();
98+
}
399

4100
#[cfg(unix)]
5101
fn main() {
6102
cc::Build::new()
7103
.file("src/crash_info/emit_sicodes.c")
8104
.compile("emit_sicodes");
105+
if cfg!(all(
106+
feature = "generate-unit-test-files",
107+
not(target_os = "macos")
108+
)) {
109+
build_shared_libs();
110+
}
9111
}
10112

11113
#[cfg(not(unix))]
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#include <stdio.h>
5+
6+
int my_function(void) {
7+
return 42;
8+
}
9+
10+
// The following code helps in generating a case where blazesym failed at
11+
// opening the file and we were failing at normalizing/symbolizing the
12+
// address.
13+
// The goal is to increase the size of the debug_XX sections and make sure
14+
// that at least one of them will be compressed (and not aligned)
15+
#define MAKE_FUNC(N) \
16+
void func##N(void) { \
17+
int arr[100]; \
18+
for (int i = 0; i < 100; i++) { \
19+
arr[i] = i * N; \
20+
} \
21+
printf("Function %d called, value = %d\n", N, arr[99]); \
22+
}
23+
24+
#define MAKE_STRUCT(N) \
25+
struct Struct##N { \
26+
int a[50]; \
27+
double b[50]; \
28+
char c[100]; \
29+
};
30+
31+
MAKE_STRUCT(1)
32+
MAKE_STRUCT(2)
33+
MAKE_STRUCT(3)
34+
MAKE_STRUCT(4)
35+
MAKE_STRUCT(5)
36+
MAKE_STRUCT(6)
37+
MAKE_STRUCT(7)
38+
MAKE_STRUCT(8)
39+
MAKE_STRUCT(9)
40+
MAKE_STRUCT(10)
41+
42+
MAKE_FUNC(1)
43+
MAKE_FUNC(2)
44+
MAKE_FUNC(3)
45+
MAKE_FUNC(4)
46+
MAKE_FUNC(5)
47+
MAKE_FUNC(6)
48+
MAKE_FUNC(7)
49+
MAKE_FUNC(8)
50+
MAKE_FUNC(9)
51+
MAKE_FUNC(10)
52+
53+
int main(void) {
54+
printf("Starting main\n");
55+
func1();
56+
func2();
57+
func3();
58+
func4();
59+
func5();
60+
func6();
61+
func7();
62+
func8();
63+
func9();
64+
func10();
65+
return 0;
66+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#include <iostream>
5+
#include <string>
6+
7+
int cpp_function() {
8+
std::cout << "Hello world" << std::endl;
9+
return 0;
10+
}
11+
12+
// For normalization/symbolization tests
13+
// do not use template class, depending on the compiler the mangled names
14+
// won't be the same and the test will fail
15+
namespace MyNamespace {
16+
class ClassInNamespace {
17+
public:
18+
void MethodInNamespace1(float, long long);
19+
static void MethodInNamespace2(double, char);
20+
21+
class InnerClassInNamespace {
22+
public:
23+
void InnerMethod1();
24+
static void InnerMethod2(int, int, long long);
25+
};
26+
};
27+
28+
void ClassInNamespace::MethodInNamespace1(float, long long) {
29+
std::cout << "ClassInNamespace::MethodInNamespace1 called" << std::endl;
30+
}
31+
32+
void ClassInNamespace::MethodInNamespace2(double, char) {
33+
std::cout << "ClassInNamespace::MethodInNamespace2 called" << std::endl;
34+
}
35+
36+
void ClassInNamespace::InnerClassInNamespace::InnerMethod1() {
37+
std::cout << "ClassInNamespace::InnerClassInNamespace::InnerMethod1 called" << std::endl;
38+
}
39+
40+
void ClassInNamespace::InnerClassInNamespace::InnerMethod2(int, int, long long) {
41+
std::cout << "ClassInNamespace::InnerClassInNamespace::InnerMethod2 called" << std::endl;
42+
}
43+
}
44+
45+
class FirstClass {
46+
public:
47+
void Method1();
48+
static void Method2(int, bool, std::string);
49+
50+
class InnerClass {
51+
public:
52+
void InnerMethod1();
53+
static void InnerMethod2();
54+
};
55+
};
56+
57+
void FirstClass::Method1() {
58+
std::cout << "FirstClass::Method1 called" << std::endl;
59+
}
60+
61+
void FirstClass::Method2(int, bool, std::string) {
62+
std::cout << "FirstClass::Method2 called" << std::endl;
63+
}
64+
65+
void FirstClass::InnerClass::InnerMethod1() {
66+
std::cout << "FirstClass::InnerClass" << std::endl;
67+
}
68+
69+
void FirstClass::InnerClass::InnerMethod2() {
70+
std::cout << "FirstClass::InnerClass::InnerMethod2 called" << std::endl;
71+
}

0 commit comments

Comments
 (0)