Skip to content

Commit

Permalink
[crashtracker] Add tests for unix socket receiver, and mark slow test…
Browse files Browse the repository at this point in the history
…s ignore (#484)
  • Loading branch information
danielsn committed Jun 14, 2024
1 parent 41aebd2 commit cd598b9
Show file tree
Hide file tree
Showing 9 changed files with 482 additions and 49 deletions.
37 changes: 33 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

298 changes: 298 additions & 0 deletions LICENSE-3rdparty.yml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions bin_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ddcommon = { path = "../ddcommon" }
tempfile = "3.3"
serde_json = { version = "1.0" }
hyper = { version = "0.14", default-features = false }
strum = { version = "0.26.2", features = ["derive"] }

[[bin]]
name = "crashtracker_bin_test"
Expand Down
89 changes: 60 additions & 29 deletions bin_tests/src/bin/crashtracker_bin_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ fn main() -> anyhow::Result<()> {
#[cfg(unix)]
mod unix {
use anyhow::Context;
use std::{env, time::Duration};
use bin_tests::ReceiverType;
use std::{env, fs::File, str::FromStr, time::Duration};

use datadog_crashtracker::{
self as crashtracker, CrashtrackerConfiguration, CrashtrackerMetadata,
Expand All @@ -27,10 +28,15 @@ mod unix {

pub fn main() -> anyhow::Result<()> {
let mut args = env::args().skip(1);
let mode = args.next().context("Unexpected number of arguments")?;
let output_url = args.next().context("Unexpected number of arguments")?;
let receiver_binary = args.next().context("Unexpected number of arguments")?;
let unix_socket_reciever_binary = args.next().context("Unexpected number of arguments")?;
let stderr_filename = args.next().context("Unexpected number of arguments")?;
let stdout_filename = args.next().context("Unexpected number of arguments")?;
let socket_path = args.next().context("Unexpected number of arguments")?;
anyhow::ensure!(args.next().is_none(), "unexpected extra arguments");

let timeout = Duration::from_secs(30);
let wait_for_receiver = true;

Expand All @@ -43,34 +49,59 @@ mod unix {
})
};

crashtracker::init_with_receiver(
CrashtrackerConfiguration {
additional_files: vec![],
create_alt_stack: true,
resolve_frames: crashtracker::StacktraceCollection::WithoutSymbols,
endpoint,
timeout,
wait_for_receiver,
},
CrashtrackerReceiverConfig::new(
vec![],
env::vars().collect(),
receiver_binary,
Some(stderr_filename),
Some(stdout_filename),
)?,
CrashtrackerMetadata {
profiling_library_name: "libdatadog".to_owned(),
profiling_library_version: "1.0.0".to_owned(),
family: "native".to_owned(),
tags: vec![
tag!("service", "foo"),
tag!("service_version", "bar"),
tag!("runtime-id", "xyz"),
tag!("language", "native"),
],
},
)?;
let config = CrashtrackerConfiguration {
additional_files: vec![],
create_alt_stack: true,
resolve_frames: crashtracker::StacktraceCollection::WithoutSymbols,
endpoint,
timeout,
wait_for_receiver,
};

let metadata = CrashtrackerMetadata {
profiling_library_name: "libdatadog".to_owned(),
profiling_library_version: "1.0.0".to_owned(),
family: "native".to_owned(),
tags: vec![
tag!("service", "foo"),
tag!("service_version", "bar"),
tag!("runtime-id", "xyz"),
tag!("language", "native"),
],
};
match ReceiverType::from_str(&mode)? {
ReceiverType::ChildProcessStdin => {
crashtracker::init_with_receiver(
config,
CrashtrackerReceiverConfig::new(
vec![],
env::vars().collect(),
receiver_binary,
Some(stderr_filename),
Some(stdout_filename),
)?,
metadata,
)?;
}
ReceiverType::UnixSocket => {
// Fork a unix socket receiver
// For now, this exits when a single message is received.
// When the listener is updated, we'll need to keep the handle and kill the receiver
// to avoid leaking a process.
std::process::Command::new(unix_socket_reciever_binary)
.stderr(File::create(stderr_filename)?)
.stdout(File::create(stdout_filename)?)
.arg(&socket_path)
.spawn()
.context("failed to spawn unix receiver")?;

// Wait long enough for the receiver to establish the socket
std::thread::sleep(std::time::Duration::from_secs(1));

crashtracker::init_with_unix_socket(config, &socket_path, metadata)?;
}
}

crashtracker::begin_profiling_op(crashtracker::ProfilingOpTypes::CollectingSample)?;
unsafe {
deref_ptr(std::ptr::null_mut::<u8>());
Expand Down
15 changes: 15 additions & 0 deletions bin_tests/src/bin/crashtracker_unix_socket_receiver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
// SPDX-License-Identifier: Apache-2.0

#[cfg(not(unix))]
fn main() {}

#[cfg(unix)]
fn main() -> anyhow::Result<()> {
let args: Vec<_> = std::env::args().collect();
anyhow::ensure!(
args.len() == 2,
"Usage: crashtracker_unix_socket_receiver path_to_unix_socket"
);
datadog_crashtracker::reciever_entry_point_unix_socket(&args[1])
}
7 changes: 7 additions & 0 deletions bin_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::{collections::HashMap, env, ops::DerefMut, path::PathBuf, process, sync

use anyhow::Ok;
use once_cell::sync::OnceCell;
use strum::{Display, EnumString};

/// This crate implements an abstraction over compilation with cargo with the purpose
/// of testing full binaries or dynamic libraries, instead if just rust static libraries.
Expand All @@ -27,6 +28,12 @@ pub enum ArtifactType {
Bin,
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, EnumString, Display)]
pub enum ReceiverType {
ChildProcessStdin,
UnixSocket,
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum BuildProfile {
Debug,
Expand Down
80 changes: 67 additions & 13 deletions bin_tests/tests/crashtracker_bin_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,52 @@ use std::process;
use std::{fs, path::PathBuf};

use anyhow::Context;
use bin_tests::{build_artifacts, ArtifactType, ArtifactsBuild, BuildProfile};
use bin_tests::{build_artifacts, ArtifactType, ArtifactsBuild, BuildProfile, ReceiverType};

#[test]
#[cfg_attr(miri, ignore)]
fn test_crash_tracking_bin_debug() {
test_crash_tracking_bin(BuildProfile::Debug);
fn test_crash_tracking_bin_debug_stdin() {
test_crash_tracking_bin(BuildProfile::Debug, ReceiverType::ChildProcessStdin);
}

#[test]
#[cfg_attr(miri, ignore)]
fn test_crash_tracking_bin_release() {
test_crash_tracking_bin(BuildProfile::Release);
fn test_crash_tracking_bin_debug_unix_socket() {
test_crash_tracking_bin(BuildProfile::Debug, ReceiverType::UnixSocket);
}

fn test_crash_tracking_bin(crash_tracking_receiver_profile: BuildProfile) {
let (crashtracker_bin, crashtracker_receiver) =
#[test]
#[ignore] // This test is slow, only run it if explicitly opted in
fn test_crash_tracking_bin_release_stdin() {
test_crash_tracking_bin(BuildProfile::Release, ReceiverType::ChildProcessStdin);
}

#[test]
#[ignore] // This test is slow, only run it if explicitly opted in
fn test_crash_tracking_bin_release_unix_socket() {
test_crash_tracking_bin(BuildProfile::Release, ReceiverType::UnixSocket);
}

fn test_crash_tracking_bin(
crash_tracking_receiver_profile: BuildProfile,
receiver_type: ReceiverType,
) {
let (crashtracker_bin, crashtracker_receiver, crashtracker_unix_socket_receiver) =
setup_crashtracking_crates(crash_tracking_receiver_profile);
let fixtures = setup_test_fixtures(&[&crashtracker_receiver, &crashtracker_bin]);
let fixtures = setup_test_fixtures(&[
&crashtracker_receiver,
&crashtracker_bin,
&crashtracker_unix_socket_receiver,
]);

let mut p = process::Command::new(&fixtures.artifacts[&crashtracker_bin])
.arg(receiver_type.to_string())
.arg(format!("file://{}", fixtures.crash_profile_path.display()))
.arg(fixtures.artifacts[&crashtracker_receiver].as_os_str())
.arg(fixtures.artifacts[&crashtracker_unix_socket_receiver].as_os_str())
.arg(&fixtures.stderr_path)
.arg(&fixtures.stdout_path)
.arg(&fixtures.unix_socket_path)
.spawn()
.unwrap();
let exit_status = bin_tests::timeit!("exit after signal", {
Expand Down Expand Up @@ -134,21 +156,41 @@ fn assert_telemetry_message(crash_telemetry: &[u8]) {
#[test]
#[cfg_attr(miri, ignore)]
#[cfg(unix)]
fn crash_tracking_empty_endpoint() {
fn crash_tracking_empty_endpoint_unix_socket() {
crash_tracking_empty_endpoint_inner(ReceiverType::UnixSocket)
}

#[test]
#[cfg_attr(miri, ignore)]
#[cfg(unix)]
fn crash_tracking_empty_endpoint_stdin() {
crash_tracking_empty_endpoint_inner(ReceiverType::ChildProcessStdin)
}

#[cfg(unix)]
fn crash_tracking_empty_endpoint_inner(receiver_type: ReceiverType) {
use std::os::unix::net::UnixListener;

let (crashtracker_bin, crashtracker_receiver) = setup_crashtracking_crates(BuildProfile::Debug);
let fixtures = setup_test_fixtures(&[&crashtracker_receiver, &crashtracker_bin]);
let (crashtracker_bin, crashtracker_receiver, crashtracker_unix_socket_receiver) =
setup_crashtracking_crates(BuildProfile::Debug);
let fixtures = setup_test_fixtures(&[
&crashtracker_receiver,
&crashtracker_bin,
&crashtracker_unix_socket_receiver,
]);

let socket_path = extend_path(fixtures.tmpdir.path(), "trace_agent.socket");
let listener = UnixListener::bind(&socket_path).unwrap();

process::Command::new(&fixtures.artifacts[&crashtracker_bin])
// empty url, endpoint will be set to none
.arg(receiver_type.to_string())
.arg("")
.arg(fixtures.artifacts[&crashtracker_receiver].as_os_str())
.arg(fixtures.artifacts[&crashtracker_unix_socket_receiver].as_os_str())
.arg(&fixtures.stderr_path)
.arg(&fixtures.stdout_path)
.arg(&fixtures.unix_socket_path)
.env(
"DD_TRACE_AGENT_URL",
format!("unix://{}", socket_path.display()),
Expand All @@ -175,6 +217,7 @@ struct TestFixtures<'a> {
crash_telemetry_path: PathBuf,
stdout_path: PathBuf,
stderr_path: PathBuf,
unix_socket_path: PathBuf,

artifacts: HashMap<&'a ArtifactsBuild, PathBuf>,
}
Expand All @@ -188,6 +231,7 @@ fn setup_test_fixtures<'a>(crates: &[&'a ArtifactsBuild]) -> TestFixtures<'a> {
crash_telemetry_path: extend_path(tmpdir.path(), "crash.telemetry"),
stdout_path: extend_path(tmpdir.path(), "out.stdout"),
stderr_path: extend_path(tmpdir.path(), "out.stderr"),
unix_socket_path: extend_path(tmpdir.path(), "crashtracker.socket"),

artifacts,
tmpdir,
Expand All @@ -196,7 +240,7 @@ fn setup_test_fixtures<'a>(crates: &[&'a ArtifactsBuild]) -> TestFixtures<'a> {

fn setup_crashtracking_crates(
crash_tracking_receiver_profile: BuildProfile,
) -> (ArtifactsBuild, ArtifactsBuild) {
) -> (ArtifactsBuild, ArtifactsBuild, ArtifactsBuild) {
let crashtracker_bin = ArtifactsBuild {
name: "crashtracker_bin_test".to_owned(),
build_profile: crash_tracking_receiver_profile,
Expand All @@ -209,7 +253,17 @@ fn setup_crashtracking_crates(
artifact_type: ArtifactType::Bin,
triple_target: None,
};
(crashtracker_bin, crashtracker_receiver)
let crashtracker_unix_socket_receiver = ArtifactsBuild {
name: "crashtracker_unix_socket_receiver".to_owned(),
build_profile: crash_tracking_receiver_profile,
artifact_type: ArtifactType::Bin,
triple_target: None,
};
(
crashtracker_bin,
crashtracker_receiver,
crashtracker_unix_socket_receiver,
)
}

fn extend_path<T: AsRef<Path>>(parent: &Path, path: T) -> PathBuf {
Expand Down
Loading

0 comments on commit cd598b9

Please sign in to comment.