Skip to content

Commit

Permalink
chore(jaeger): add integration tests to github action. (#835)
Browse files Browse the repository at this point in the history
  • Loading branch information
TommyCpp committed Jul 12, 2022
1 parent 2bb8eab commit b3e6e6a
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 75 deletions.
16 changes: 16 additions & 0 deletions .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions opentelemetry-jaeger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -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"]
11 changes: 4 additions & 7 deletions opentelemetry-jaeger/src/testing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ 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
.unwrap()
.get_ref()
.services
.iter()
.any(|svc_name| svc_name == service_name)
.any(|svc_name| *svc_name == *service_name)
}

/// Find trace by trace id.
Expand Down Expand Up @@ -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<JaegerSpan> {
pub async fn find_traces_from_services(&mut self, service_name: &str) -> Vec<JaegerSpan> {
let request = FindTracesRequest {
query: Some(TraceQueryParameters {
service_name: service_name.into(),
service_name: service_name.to_owned(),
..Default::default()
}),
};
Expand Down
5 changes: 4 additions & 1 deletion opentelemetry-jaeger/tests/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ services:
ports:
- "6831:6831/udp"
- "16685:16685"
- "14268:14268"
- "16686:16686"
opentelemetry-jaeger:
build:
context: ../..
dockerfile: ./opentelemetry-jaeger/tests/Dockerfile
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
174 changes: 112 additions & 62 deletions opentelemetry-jaeger/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
// ┌─────────┐
Expand Down Expand Up @@ -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()
Expand 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<String, jaeger_api::Span> = 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<dyn Fn() -> 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<String, jaeger_api::Span> = 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>) {
Expand Down
3 changes: 0 additions & 3 deletions scripts/integration-test.sh

This file was deleted.

3 changes: 3 additions & 0 deletions scripts/integration_tests.sh
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit b3e6e6a

Please sign in to comment.