From b3e6e6a1f1ba4f7b7537cdd76cb2c72862ca2800 Mon Sep 17 00:00:00 2001 From: Zhongyang Wu Date: Tue, 12 Jul 2022 09:50:45 -0700 Subject: [PATCH] chore(jaeger): add integration tests to github action. (#835) --- .github/workflows/integration_tests.yml | 16 ++ opentelemetry-jaeger/Cargo.toml | 4 +- opentelemetry-jaeger/src/testing/mod.rs | 11 +- .../tests/docker-compose.yaml | 5 +- .../tests/integration_test.rs | 174 +++++++++++------- scripts/integration-test.sh | 3 - scripts/integration_tests.sh | 3 + 7 files changed, 141 insertions(+), 75 deletions(-) create mode 100644 .github/workflows/integration_tests.yml delete mode 100755 scripts/integration-test.sh create mode 100755 scripts/integration_tests.sh diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml new file mode 100644 index 0000000000..47101e3607 --- /dev/null +++ b/.github/workflows/integration_tests.yml @@ -0,0 +1,16 @@ +name: integration tests + +on: + pull_request: + types: [ labeled, synchronize, opened, reopened ] + +jobs: + integration_tests: + runs-on: ubuntu-latest + timeout-minutes: 10 + if: ${{ github.event.label.name == 'integration tests' || contains(github.event.pull_request.labels.*.name, 'integration tests') }} + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Run integration tests using docker compose + run: ./scripts/integration_tests.sh diff --git a/opentelemetry-jaeger/Cargo.toml b/opentelemetry-jaeger/Cargo.toml index 97a8f5066a..9ff0c4d496 100644 --- a/opentelemetry-jaeger/Cargo.toml +++ b/opentelemetry-jaeger/Cargo.toml @@ -35,7 +35,7 @@ opentelemetry-http = { version = "0.6", path = "../opentelemetry-http", optional opentelemetry-semantic-conventions = { version = "0.9", path = "../opentelemetry-semantic-conventions" } pin-project = { version = "1.0", optional = true } reqwest = { version = "0.11", default-features = false, optional = true } -surf = { version = "2.0", default-features = false, optional = true } +surf = { version = "2.0", optional = true } thiserror = "1.0" thrift = "0.15" tokio = { version = "1.0", features = ["net", "sync"], optional = true } @@ -97,4 +97,4 @@ wasm_collector_client = [ rt-tokio = ["tokio", "opentelemetry/rt-tokio"] rt-tokio-current-thread = ["tokio", "opentelemetry/rt-tokio-current-thread"] rt-async-std = ["async-std", "opentelemetry/rt-async-std"] -integration_test = ["tonic", "prost", "prost-types", "rt-tokio", "collector_client"] +integration_test = ["tonic", "prost", "prost-types", "rt-tokio", "collector_client", "reqwest_collector_client", "surf_collector_client", "isahc_collector_client"] diff --git a/opentelemetry-jaeger/src/testing/mod.rs b/opentelemetry-jaeger/src/testing/mod.rs index 9a3c495e8d..04231664a2 100644 --- a/opentelemetry-jaeger/src/testing/mod.rs +++ b/opentelemetry-jaeger/src/testing/mod.rs @@ -25,7 +25,7 @@ pub mod jaeger_client { } /// Check if the jaeger contains the service - pub async fn contain_service(&mut self, service_name: &'static str) -> bool { + pub async fn contain_service(&mut self, service_name: &String) -> bool { self.query_service_client .get_services(GetServicesRequest {}) .await @@ -33,7 +33,7 @@ pub mod jaeger_client { .get_ref() .services .iter() - .any(|svc_name| svc_name == service_name) + .any(|svc_name| *svc_name == *service_name) } /// Find trace by trace id. @@ -62,13 +62,10 @@ pub mod jaeger_client { /// Find traces belongs the service. /// It assumes the service exists. - pub async fn find_traces_from_services( - &mut self, - service_name: &'static str, - ) -> Vec { + pub async fn find_traces_from_services(&mut self, service_name: &str) -> Vec { let request = FindTracesRequest { query: Some(TraceQueryParameters { - service_name: service_name.into(), + service_name: service_name.to_owned(), ..Default::default() }), }; diff --git a/opentelemetry-jaeger/tests/docker-compose.yaml b/opentelemetry-jaeger/tests/docker-compose.yaml index 0e77a04f8b..445ab85fb5 100644 --- a/opentelemetry-jaeger/tests/docker-compose.yaml +++ b/opentelemetry-jaeger/tests/docker-compose.yaml @@ -6,6 +6,8 @@ services: ports: - "6831:6831/udp" - "16685:16685" + - "14268:14268" + - "16686:16686" opentelemetry-jaeger: build: context: ../.. @@ -13,8 +15,9 @@ services: container_name: opentelemetry-jaeger-integration-test-exporter environment: OTEL_TEST_JAEGER_AGENT_ENDPOINT: "jaeger:6831" + OTEL_TEST_JAEGER_COLLECTOR_ENDPOINT: "http://jaeger:14268/api/traces" OTEL_TEST_JAEGER_ENDPOINT: "http://jaeger:16685" command: [ "cargo", "test", "--package", "opentelemetry-jaeger", "--test", "integration_test", - "--features=integration_test", "tests::integration_test", "--", "--exact" ] + "--features=integration_test", "tests::integration_test", "--", "--exact", "--ignored" ] depends_on: - jaeger diff --git a/opentelemetry-jaeger/tests/integration_test.rs b/opentelemetry-jaeger/tests/integration_test.rs index dd987f050c..d5ff2ada6f 100644 --- a/opentelemetry-jaeger/tests/integration_test.rs +++ b/opentelemetry-jaeger/tests/integration_test.rs @@ -8,6 +8,10 @@ mod tests { }; use std::collections::HashMap; + const SERVICE_NAME: &str = "opentelemetry_jaeger_integration_test"; + const CRATE_VERSION: &str = env!("CARGO_PKG_VERSION"); + const CRATE_NAME: &str = env!("CARGO_PKG_NAME"); + // the sample application that will be traced. // Expect the following span relationship: // ┌─────────┐ @@ -44,10 +48,11 @@ mod tests { // This tests requires a jaeger agent running on the localhost. // You can override the agent end point using OTEL_TEST_JAEGER_AGENT_ENDPOINT env var // You can override the query API endpoint using OTEL_TEST_JAEGER_ENDPOINT env var - // Alternative you can run scripts/integration-test.sh from project root path. + // Alternative you can run scripts/integration_tests.sh from project root path. // #[test] - #[ignore] + #[ignore] // ignore this when running unit tests + #[allow(clippy::type_complexity)] fn integration_test() { let runtime = tokio::runtime::Builder::new_multi_thread() .enable_all() @@ -56,68 +61,113 @@ mod tests { let agent_endpoint = option_env!("OTEL_TEST_JAEGER_AGENT_ENDPOINT").unwrap_or("localhost:6831"); + let collector_endpoint = option_env!("OTEL_TEST_JAEGER_COLLECTOR_ENDPOINT") + .unwrap_or("http://localhost:14268/api/traces"); let query_api_endpoint = option_env!("OTEL_TEST_JAEGER_ENDPOINT").unwrap_or("http://localhost:16685"); - const SERVICE_NAME: &str = "opentelemetry_jaeger_integration_test"; - const CRATE_VERSION: &str = env!("CARGO_PKG_VERSION"); - const CRATE_NAME: &str = env!("CARGO_PKG_NAME"); - - println!("{}, {}", agent_endpoint, query_api_endpoint); - - runtime.block_on(async { - let tracer = opentelemetry_jaeger::new_agent_pipeline() - .with_endpoint(agent_endpoint) - .with_service_name(SERVICE_NAME) - .install_batch(opentelemetry::runtime::Tokio) - .expect("cannot create tracer using default configuration"); - - sample_application(&tracer).await; - - tracer.provider().unwrap().force_flush(); - }); - - runtime.block_on(async { - // build client - let mut client = JaegerTestClient::new(query_api_endpoint); - assert!( - client.contain_service(SERVICE_NAME).await, - "jaeger cannot find service" - ); - let spans = client.find_traces_from_services(SERVICE_NAME).await; - assert_eq!(spans.len(), 5); - - for span in spans.iter() { - assert_common_attributes(span, SERVICE_NAME, CRATE_NAME, CRATE_VERSION) - } - - // convert to span name/operation name -> span map - let span_map: HashMap = spans - .into_iter() - .map(|spans| (spans.operation_name.clone(), spans)) - .collect(); - - let step_1 = span_map.get("step-1").expect("cannot find step-1 span"); - assert_parent(step_1, None); - assert_eq!(step_1.logs.len(), 1); - - let step_2_1 = span_map.get("step-2-1").expect("cannot find step-2-1 span"); - assert_parent(step_2_1, Some(step_1)); - - let step_2_2 = span_map.get("step-2-2").expect("cannot find step-2-2 span"); - assert_parent(step_2_2, Some(step_1)); - - let step_3_1 = span_map.get("step-3-1").expect("cannot find step-3-1 span"); - assert_parent(step_3_1, Some(step_2_2)); - assert_tags_contains(step_3_1, "otel.status_code", "ERROR"); - assert_tags_contains(step_3_1, "error", "true"); - assert_eq!(step_3_1.flags, 1); - - let step_3_2 = span_map - .get("step-3-2") - .expect("cannot find step 3-2 spans"); - assert_parent(step_3_2, Some(step_2_2)); - assert_tags_contains(step_3_2, "tag-3-2-1", "tag-value-3-2-1"); - }); + + let test_cases: Vec<(&str, Box SdkTracer>)> = vec![ + ( + "agent", + Box::new(|| { + opentelemetry_jaeger::new_agent_pipeline() + .with_endpoint(agent_endpoint) + .with_service_name(format!("{}-{}", SERVICE_NAME, "agent")) + .install_batch(opentelemetry::runtime::Tokio) + .expect("cannot create tracer using default configuration") + }), + ), + ( + "collector_reqwest", + Box::new(|| { + opentelemetry_jaeger::new_collector_pipeline() + .with_endpoint(collector_endpoint) + .with_reqwest() + .with_service_name(format!("{}-{}", SERVICE_NAME, "collector_reqwest")) + .install_batch(opentelemetry::runtime::Tokio) + .expect("cannot create tracer using default configuration") + }), + ), + ( + "collector_isahc", + Box::new(|| { + opentelemetry_jaeger::new_collector_pipeline() + .with_endpoint(collector_endpoint) + .with_isahc() + .with_service_name(format!("{}-{}", SERVICE_NAME, "collector_isahc")) + .install_batch(opentelemetry::runtime::Tokio) + .expect("cannot create tracer using default configuration") + }), + ), + ( + "collector_surf", + Box::new(|| { + opentelemetry_jaeger::new_collector_pipeline() + .with_endpoint(collector_endpoint) + .with_surf() + .with_service_name(format!("{}-{}", SERVICE_NAME, "collector_surf")) + .install_batch(opentelemetry::runtime::Tokio) + .expect("cannot create tracer using default configuration") + }), + ), + ]; + + for (name, build_tracer) in test_cases { + println!("Running test case: {}", name); + + runtime.block_on(async { + let tracer = build_tracer(); + sample_application(&tracer).await; + + tracer.provider().unwrap().force_flush(); + }); + + // assert the results by the jaeger query API + runtime.block_on(async { + // build client + let mut client = JaegerTestClient::new(query_api_endpoint); + let service_name = format!("{}-{}", SERVICE_NAME, name); + assert!( + client.contain_service(&service_name).await, + "jaeger cannot find service with name {}", + service_name + ); + let spans = client.find_traces_from_services(&service_name).await; + assert_eq!(spans.len(), 5); + + for span in spans.iter() { + assert_common_attributes(span, service_name.as_str(), CRATE_NAME, CRATE_VERSION) + } + + // convert to span name/operation name -> span map + let span_map: HashMap = spans + .into_iter() + .map(|spans| (spans.operation_name.clone(), spans)) + .collect(); + + let step_1 = span_map.get("step-1").expect("cannot find step-1 span"); + assert_parent(step_1, None); + assert_eq!(step_1.logs.len(), 1); + + let step_2_1 = span_map.get("step-2-1").expect("cannot find step-2-1 span"); + assert_parent(step_2_1, Some(step_1)); + + let step_2_2 = span_map.get("step-2-2").expect("cannot find step-2-2 span"); + assert_parent(step_2_2, Some(step_1)); + + let step_3_1 = span_map.get("step-3-1").expect("cannot find step-3-1 span"); + assert_parent(step_3_1, Some(step_2_2)); + assert_tags_contains(step_3_1, "otel.status_code", "ERROR"); + assert_tags_contains(step_3_1, "error", "true"); + assert_eq!(step_3_1.flags, 1); + + let step_3_2 = span_map + .get("step-3-2") + .expect("cannot find step 3-2 spans"); + assert_parent(step_3_2, Some(step_2_2)); + assert_tags_contains(step_3_2, "tag-3-2-1", "tag-value-3-2-1"); + }); + } } fn assert_parent(span: &jaeger_api::Span, parent_span: Option<&jaeger_api::Span>) { diff --git a/scripts/integration-test.sh b/scripts/integration-test.sh deleted file mode 100755 index 649f99ee3c..0000000000 --- a/scripts/integration-test.sh +++ /dev/null @@ -1,3 +0,0 @@ -COMPOSE_FILE=./opentelemetry-jaeger/tests/docker-compose.yaml -docker-compose -f $COMPOSE_FILE down -v && -docker-compose -f $COMPOSE_FILE up --build --exit-code-from opentelemetry-jaeger diff --git a/scripts/integration_tests.sh b/scripts/integration_tests.sh new file mode 100755 index 0000000000..8d7ee2e965 --- /dev/null +++ b/scripts/integration_tests.sh @@ -0,0 +1,3 @@ +COMPOSE_FILE=./opentelemetry-jaeger/tests/docker-compose.yaml +docker-compose -f $COMPOSE_FILE down -v && +docker-compose -f $COMPOSE_FILE up --build --abort-on-container-exit --exit-code-from opentelemetry-jaeger