From a6ec2395ec7e1f33526ca051ef2edf8a898366ed Mon Sep 17 00:00:00 2001 From: cleverchuk Date: Fri, 8 May 2026 17:09:04 -0400 Subject: [PATCH 1/5] refactor agent integration test to limit backend dependency --- ...nds.instrumentation-conventions.gradle.kts | 7 +- .../javaagent/build.gradle.kts | 4 + .../v3_1/HandlerNameInstrumentationTest.java | 99 ++++++++++ .../javaagent/build.gradle.kts | 5 + .../v6_0/HandlerNameInstrumentationTest.java | 98 ++++++++++ integration-tests/build.gradle.kts | 35 ++++ .../ContextPropagationTest.java | 52 ++++++ .../MetricsGenerationTest.java | 170 +++++++++++++++++ .../ProfilingSpanProcessorTest.java | 65 +++++++ .../integrationtest/SdkTracingTest.java | 103 +++++++++++ .../TransactionFilteringTest.java | 114 ++++++++++++ .../TransactionNamingTest.java | 61 +++++++ .../integrationtest/TriggerTraceTest.java | 112 ++++++++++++ settings.gradle.kts | 1 + .../test/java/com/solarwinds/SmokeTest.java | 171 ++++++++++-------- testing/agent-test-extension/build.gradle.kts | 4 + .../extensions/TestAgentListener.java | 45 +++++ .../TestAutoConfigurationCustomizer.java | 11 +- .../opentelemetry/extensions/TestSampler.java | 40 ---- 19 files changed, 1076 insertions(+), 121 deletions(-) create mode 100644 instrumentation/spring-webmvc/spring-webmvc-3.1/javaagent/src/test/java/com/solarwinds/opentelemetry/instrumentation/webmvc/v3_1/HandlerNameInstrumentationTest.java create mode 100644 instrumentation/spring-webmvc/spring-webmvc-6/javaagent/src/test/java/com/solarwinds/opentelemetry/instrumentation/webmvc/v6_0/HandlerNameInstrumentationTest.java create mode 100644 integration-tests/build.gradle.kts create mode 100644 integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ContextPropagationTest.java create mode 100644 integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/MetricsGenerationTest.java create mode 100644 integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ProfilingSpanProcessorTest.java create mode 100644 integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/SdkTracingTest.java create mode 100644 integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionFilteringTest.java create mode 100644 integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionNamingTest.java create mode 100644 integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TriggerTraceTest.java create mode 100644 testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAgentListener.java delete mode 100644 testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestSampler.java diff --git a/buildSrc/src/main/kotlin/solarwinds.instrumentation-conventions.gradle.kts b/buildSrc/src/main/kotlin/solarwinds.instrumentation-conventions.gradle.kts index 2b6922a7..f00cf114 100644 --- a/buildSrc/src/main/kotlin/solarwinds.instrumentation-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/solarwinds.instrumentation-conventions.gradle.kts @@ -147,6 +147,11 @@ class JavaagentProvider( "--add-opens=java.base/java.lang=ALL-UNNAMED", "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED", "-XX:+IgnoreUnrecognizedVMOptions", - "-Dotel.javaagent.debug=true" + "-Dotel.javaagent.debug=true", + "-Dio.opentelemetry.context.enableStrictContext=true", + "-Dotel.java.experimental.span-stacktrace.min.duration=0ms", + "-Dsw.apm.profiler.enabled=true", + "-Dsw.apm.profiler.interval=10", + "-Dsw.apm.span.stacktrace.filters=thread.id,os.description,http.request.method" ) } diff --git a/instrumentation/spring-webmvc/spring-webmvc-3.1/javaagent/build.gradle.kts b/instrumentation/spring-webmvc/spring-webmvc-3.1/javaagent/build.gradle.kts index 7e8e1f48..cb226c7b 100644 --- a/instrumentation/spring-webmvc/spring-webmvc-3.1/javaagent/build.gradle.kts +++ b/instrumentation/spring-webmvc/spring-webmvc-3.1/javaagent/build.gradle.kts @@ -49,6 +49,10 @@ dependencies { compileOnly("org.springframework:spring-webmvc:3.1.0.RELEASE") compileOnly("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api") compileOnly("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator") + + testImplementation("org.springframework:spring-webmvc:5.3.30") + testImplementation("org.springframework:spring-test:5.3.30") + testImplementation("javax.servlet:javax.servlet-api:3.1.0") } swoJava { diff --git a/instrumentation/spring-webmvc/spring-webmvc-3.1/javaagent/src/test/java/com/solarwinds/opentelemetry/instrumentation/webmvc/v3_1/HandlerNameInstrumentationTest.java b/instrumentation/spring-webmvc/spring-webmvc-3.1/javaagent/src/test/java/com/solarwinds/opentelemetry/instrumentation/webmvc/v3_1/HandlerNameInstrumentationTest.java new file mode 100644 index 00000000..dec0a364 --- /dev/null +++ b/instrumentation/spring-webmvc/spring-webmvc-3.1/javaagent/src/test/java/com/solarwinds/opentelemetry/instrumentation/webmvc/v3_1/HandlerNameInstrumentationTest.java @@ -0,0 +1,99 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.instrumentation.webmvc.v3_1; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletConfig; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@ExtendWith(MockitoExtension.class) +class HandlerNameInstrumentationTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Test + void verifyHandlerNameIsStampedOnServerSpan() { + testing.runWithSpan( + "server", + () -> { + try { + AnnotationConfigWebApplicationContext appContext = + new AnnotationConfigWebApplicationContext(); + appContext.register(TestConfig.class); + + DispatcherServlet dispatcherServlet = new DispatcherServlet(appContext); + dispatcherServlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/greet"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + try { + dispatcherServlet.service(request, response); + } finally { + dispatcherServlet.destroy(); + appContext.close(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("server") + .hasKind(SpanKind.INTERNAL) + .hasAttributesSatisfying( + attributes -> + assertEquals( + "TestController.greet", + attributes.get(AttributeKey.stringKey("HandlerName")))))); + } + + @EnableWebMvc + @org.springframework.context.annotation.Configuration + static class TestConfig { + @org.springframework.context.annotation.Bean + public TestController testController() { + return new TestController(); + } + } + + @RestController + static class TestController { + @GetMapping("/greet") + public String greet() { + return "hello"; + } + } +} diff --git a/instrumentation/spring-webmvc/spring-webmvc-6/javaagent/build.gradle.kts b/instrumentation/spring-webmvc/spring-webmvc-6/javaagent/build.gradle.kts index 6c66c6bc..c6762a23 100644 --- a/instrumentation/spring-webmvc/spring-webmvc-6/javaagent/build.gradle.kts +++ b/instrumentation/spring-webmvc/spring-webmvc-6/javaagent/build.gradle.kts @@ -37,6 +37,11 @@ dependencies { compileOnly("org.springframework:spring-webmvc:6.0.0") compileOnly("jakarta.servlet:jakarta.servlet-api:5.0.0") compileOnly("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator") + + testImplementation("org.springframework:spring-webmvc:6.0.0") + testImplementation("org.springframework:spring-test:6.0.0") + testImplementation("jakarta.servlet:jakarta.servlet-api:5.0.0") + testImplementation("org.apache.tomcat.embed:tomcat-embed-core:10.1.0") } swoJava { diff --git a/instrumentation/spring-webmvc/spring-webmvc-6/javaagent/src/test/java/com/solarwinds/opentelemetry/instrumentation/webmvc/v6_0/HandlerNameInstrumentationTest.java b/instrumentation/spring-webmvc/spring-webmvc-6/javaagent/src/test/java/com/solarwinds/opentelemetry/instrumentation/webmvc/v6_0/HandlerNameInstrumentationTest.java new file mode 100644 index 00000000..469a2622 --- /dev/null +++ b/instrumentation/spring-webmvc/spring-webmvc-6/javaagent/src/test/java/com/solarwinds/opentelemetry/instrumentation/webmvc/v6_0/HandlerNameInstrumentationTest.java @@ -0,0 +1,98 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.instrumentation.webmvc.v6_0; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@ExtendWith(MockitoExtension.class) +class HandlerNameInstrumentationTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Test + void verifyHandlerNameIsStampedOnServerSpan() { + testing.runWithSpan( + "server", + () -> { + try { + AnnotationConfigWebApplicationContext appContext = + new AnnotationConfigWebApplicationContext(); + appContext.register(TestConfig.class); + + DispatcherServlet dispatcherServlet = new DispatcherServlet(appContext); + dispatcherServlet.init(new org.springframework.mock.web.MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/greet"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + try { + dispatcherServlet.service(request, response); + } finally { + dispatcherServlet.destroy(); + appContext.close(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("server") + .hasKind(SpanKind.INTERNAL) + .hasAttributesSatisfying( + attributes -> + assertEquals( + "TestController.greet", + attributes.get(AttributeKey.stringKey("HandlerName")))))); + } + + @EnableWebMvc + @org.springframework.context.annotation.Configuration + static class TestConfig { + @org.springframework.context.annotation.Bean + public TestController testController() { + return new TestController(); + } + } + + @RestController + static class TestController { + @GetMapping("/greet") + public String greet() { + return "hello"; + } + } +} diff --git a/integration-tests/build.gradle.kts b/integration-tests/build.gradle.kts new file mode 100644 index 00000000..1e98fdb8 --- /dev/null +++ b/integration-tests/build.gradle.kts @@ -0,0 +1,35 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id("solarwinds.instrumentation-conventions") +} + +dependencies { + testImplementation(project(":solarwinds-otel-sdk")) + testImplementation(project(":libs:sampling")) + testImplementation(project(":libs:core")) + testImplementation("jakarta.servlet:jakarta.servlet-api:5.0.0") + testImplementation("org.awaitility:awaitility:4.3.0") +} + +tasks.named("compileTestJava") { + dependsOn(project(":solarwinds-otel-sdk").tasks.named("shadowJar")) +} + +swoJava { + minJavaVersionSupported.set(JavaVersion.VERSION_17) +} diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ContextPropagationTest.java b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ContextPropagationTest.java new file mode 100644 index 00000000..941c0475 --- /dev/null +++ b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ContextPropagationTest.java @@ -0,0 +1,52 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.integrationtest; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class ContextPropagationTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Test + void verifyTraceContextPropagatesViaW3CHeaders() { + testing.runWithSpan( + "service-a", + () -> { + Map headers = new HashMap<>(); + GlobalOpenTelemetry.getPropagators() + .getTextMapPropagator() + .inject(Context.current(), headers, Map::put); + + assertThat(headers).containsKey("traceparent"); + assertThat(headers.get("traceparent")) + .matches("00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}"); + + assertThat(headers).containsKey("tracestate"); + assertThat(headers.get("tracestate")).contains("sw="); + }); + } +} diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/MetricsGenerationTest.java b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/MetricsGenerationTest.java new file mode 100644 index 00000000..0492b77b --- /dev/null +++ b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/MetricsGenerationTest.java @@ -0,0 +1,170 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.integrationtest; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.sdk.metrics.data.MetricData; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class MetricsGenerationTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Test + void verifyResponseTimeMetricIsReportedAfterServerSpan() { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer.spanBuilder("GET /petclinic/api/owners").setSpanKind(SpanKind.SERVER).startSpan(); + span.end(); + + testing.waitForTraces(1); + await() + .atMost(5, TimeUnit.SECONDS) + .untilAsserted( + () -> { + List metrics = testing.metrics(); + assertThat(metrics) + .as("trace.service.response_time metric should be reported") + .anyMatch(m -> m.getName().equals("trace.service.response_time")); + }); + } + + @Test + void verifyRequestCountMetricIsReportedAfterServerSpan() { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); + span.end(); + + testing.waitForTraces(1); + await() + .atMost(5, TimeUnit.SECONDS) + .untilAsserted( + () -> { + List metrics = testing.metrics(); + assertThat(metrics) + .as("trace.service.request_count metric should be reported") + .anyMatch(m -> m.getName().equals("trace.service.request_count")); + }); + } + + @Test + void verifyTokenbucketExhaustionCountMetricIsReported() { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); + span.end(); + + testing.waitForTraces(1); + await() + .atMost(5, TimeUnit.SECONDS) + .untilAsserted( + () -> { + List metrics = testing.metrics(); + assertThat(metrics) + .as("trace.service.tokenbucket_exhaustion_count metric should be reported") + .anyMatch(m -> m.getName().equals("trace.service.tokenbucket_exhaustion_count")); + }); + } + + @Test + void verifyTraceCountMetricIsReported() { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); + span.end(); + + testing.waitForTraces(1); + await() + .atMost(5, TimeUnit.SECONDS) + .untilAsserted( + () -> { + List metrics = testing.metrics(); + assertThat(metrics) + .as("trace.service.tracecount metric should be reported") + .anyMatch(m -> m.getName().equals("trace.service.tracecount")); + }); + } + + @Test + void verifySampleCountMetricIsReported() { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); + span.end(); + + testing.waitForTraces(1); + await() + .atMost(5, TimeUnit.SECONDS) + .untilAsserted( + () -> { + List metrics = testing.metrics(); + assertThat(metrics) + .as("trace.service.samplecount metric should be reported") + .anyMatch(m -> m.getName().equals("trace.service.samplecount")); + }); + } + + @Test + void verifyThroughTraceCountMetricIsReported() { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); + span.end(); + + testing.waitForTraces(1); + await() + .atMost(5, TimeUnit.SECONDS) + .untilAsserted( + () -> { + List metrics = testing.metrics(); + assertThat(metrics) + .as("trace.service.through_trace_count metric should be reported") + .anyMatch(m -> m.getName().equals("trace.service.through_trace_count")); + }); + } + + @Test + void verifyTriggeredTraceCountMetricIsReported() { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); + span.end(); + + testing.waitForTraces(1); + await() + .atMost(5, TimeUnit.SECONDS) + .untilAsserted( + () -> { + List metrics = testing.metrics(); + assertThat(metrics) + .as("trace.service.triggered_trace_count metric should be reported") + .anyMatch(m -> m.getName().equals("trace.service.triggered_trace_count")); + }); + } +} diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ProfilingSpanProcessorTest.java b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ProfilingSpanProcessorTest.java new file mode 100644 index 00000000..6af5d59e --- /dev/null +++ b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ProfilingSpanProcessorTest.java @@ -0,0 +1,65 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.integrationtest; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class ProfilingSpanProcessorTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Test + void verifyProfilingSpanProcessorIsRegistered() { + testing.runWithSpan("profiling-test", () -> {}); + + List> traces = testing.waitForTraces(1); + assertThat(traces).isNotEmpty(); + + SpanData span = traces.get(0).get(0); + Long profileSpans = span.getAttributes().get(AttributeKey.longKey("sw.profile.spans")); + assertThat(profileSpans) + .as("sw.profile.spans attribute should be set by SolarwindsProfilingSpanProcessor") + .isNotNull(); + } + + @Test + void verifyProfilesIsCollected() { + testing.runWithSpan( + "profiling-test", + () -> { + try { + Thread.sleep(2000); + } catch (InterruptedException ignore) { + } + }); + + List> traces = testing.waitForTraces(1); + assertThat(traces).isNotEmpty(); + + SpanData span = traces.get(0).get(0); + Long profileSpans = span.getAttributes().get(AttributeKey.longKey("sw.profile.spans")); + assertThat(profileSpans).as("sw.profile.spans attribute should be set 1").isEqualTo(1); + } +} diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/SdkTracingTest.java b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/SdkTracingTest.java new file mode 100644 index 00000000..b7ee8c7a --- /dev/null +++ b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/SdkTracingTest.java @@ -0,0 +1,103 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.integrationtest; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class SdkTracingTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Test + void verifyManualSpanCreationWithSdkTracer() { + testing.runWithSpan( + "root", + () -> { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("sdk.tracing"); + Span span = tracer.spanBuilder("greet-span").startSpan(); + span.setAttribute("sw.test.source", "SDK.trace.test"); + span.end(); + }); + + List> traces = testing.waitForTraces(1); + assertThat(traces).hasSize(1); + + List spans = traces.get(0); + assertThat(spans).hasSize(2); + + SpanData greetSpan = + spans.stream().filter(s -> "greet-span".equals(s.getName())).findFirst().orElseThrow(); + assertThat(greetSpan.getAttributes().get(AttributeKey.stringKey("sw.test.source"))) + .isEqualTo("SDK.trace.test"); + } + + @Test + void verifyCodeStacktraceIsCaptured() { + testing.runWithSpan( + "root", + () -> { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("sdk.tracing"); + Span span = tracer.spanBuilder("code-stacktrace").startSpan(); + span.setAttribute("thread.id", "test-1"); + span.end(); + }); + + List> traces = testing.waitForTraces(1); + assertThat(traces).hasSize(1); + + List spans = traces.get(0); + assertThat(spans).hasSize(2); + + SpanData spanData = + spans.stream().filter(s -> "code-stacktrace".equals(s.getName())).findFirst().orElseThrow(); + assertThat(spanData.getAttributes().get(AttributeKey.stringKey("code.stacktrace"))).isNotNull(); + } + + @Test + void verifyResourceNameFromServiceKey() { + testing.runWithSpan( + "root", + () -> { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("sdk.tracing"); + Span span = tracer.spanBuilder("code-stacktrace").startSpan(); + span.setAttribute("thread.id", "test-1"); + span.end(); + }); + + List> traces = testing.waitForTraces(1); + assertThat(traces).hasSize(1); + + List spans = traces.get(0); + assertThat(spans).hasSize(2); + + SpanData spanData = + spans.stream().filter(s -> "code-stacktrace".equals(s.getName())).findFirst().orElseThrow(); + assertThat(spanData.getResource().getAttributes().get(AttributeKey.stringKey("service.name"))) + .isEqualTo("test-app"); + } +} diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionFilteringTest.java b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionFilteringTest.java new file mode 100644 index 00000000..ad42a77c --- /dev/null +++ b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionFilteringTest.java @@ -0,0 +1,114 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.integrationtest; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import com.solarwinds.joboe.core.settings.TestSettingsReader; +import com.solarwinds.joboe.core.util.TestUtils; +import com.solarwinds.joboe.sampling.SampleRateSource; +import com.solarwinds.joboe.sampling.SamplingConfiguration; +import com.solarwinds.joboe.sampling.SettingsManager; +import com.solarwinds.joboe.sampling.TraceConfig; +import com.solarwinds.joboe.sampling.TraceConfigs; +import com.solarwinds.joboe.sampling.TracingMode; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.semconv.UrlAttributes; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class TransactionFilteringTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @BeforeEach + void setUp() { + Map urlConfigs = + new LinkedHashMap<>(); + urlConfigs.put( + url -> url.contains("/specialties"), + new TraceConfig(0, SampleRateSource.FILE, TracingMode.DISABLED.toFlags())); + + TestSettingsReader reader = TestUtils.initSettingsReader(); + reader.put( + new TestSettingsReader.SettingsMockupBuilder() + .withFlags(true, false, true, true, false) + .withSampleRate(1_000_000) + .build()); + + SettingsManager.initialize( + new com.solarwinds.joboe.core.settings.SimpleSettingsFetcher(reader), + SamplingConfiguration.builder() + .internalTransactionSettings(new TraceConfigs(urlConfigs)) + .build()); + } + + @AfterEach + void tearDown() { + TestSettingsReader reader = TestUtils.initSettingsReader(); + reader.put( + new TestSettingsReader.SettingsMockupBuilder() + .withFlags(true, false, true, true, false) + .withSampleRate(1_000_000) + .build()); + } + + @Test + void verifyFilteredUrlIsNotSampled() { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer + .spanBuilder("GET /specialties") + .setSpanKind(SpanKind.SERVER) + .setAttribute(UrlAttributes.URL_PATH, "/petclinic/api/specialties") + .startSpan(); + span.end(); + + await() + .during(1, TimeUnit.SECONDS) + .atMost(3, TimeUnit.SECONDS) + .untilAsserted(() -> assertThat(testing.waitForTraces(0)).isEmpty()); + } + + @Test + void verifyNonFilteredUrlIsSampled() { + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer + .spanBuilder("GET /owners") + .setSpanKind(SpanKind.SERVER) + .setAttribute(UrlAttributes.URL_PATH, "/petclinic/api/owners") + .startSpan(); + + span.end(); + List> traces = testing.waitForTraces(1); + assertThat(traces).hasSize(1); + } +} diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionNamingTest.java b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionNamingTest.java new file mode 100644 index 00000000..87dc0d89 --- /dev/null +++ b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionNamingTest.java @@ -0,0 +1,61 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.integrationtest; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.solarwinds.api.ext.SolarwindsAgent; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class TransactionNamingTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Test + void verifySdkSetTransactionName() { + testing.runWithSpan( + "root", + () -> { + SolarwindsAgent.setTransactionName("int-test"); + }); + + List> traces = testing.waitForTraces(1); + assertThat(traces).hasSize(1); + + SpanData rootSpan = traces.get(0).get(0); + assertThat(rootSpan.getAttributes().get(AttributeKey.stringKey("sw.transaction"))) + .isEqualTo("int-test"); + } + + @Test + void verifyTransactionNameFallsBackToSpanName() { + testing.runWithSpan("GET /petclinic/api/owners", () -> {}); + + List> traces = testing.waitForTraces(1); + assertThat(traces).hasSize(1); + + SpanData rootSpan = traces.get(0).get(0); + String transactionName = rootSpan.getAttributes().get(AttributeKey.stringKey("sw.transaction")); + assertThat(transactionName).isEqualTo("GET /petclinic/api/owners"); + } +} diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TriggerTraceTest.java b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TriggerTraceTest.java new file mode 100644 index 00000000..08b1313b --- /dev/null +++ b/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TriggerTraceTest.java @@ -0,0 +1,112 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.integrationtest; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapGetter; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class TriggerTraceTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Test + void verifyTriggerTraceStampsAttributesOnRootSpan() { + Map headers = new HashMap<>(); + headers.put("X-Trace-Options", "trigger-trace;custom-info=chubi;sw-keys=lo:se,check-id:123"); + + Context extractedContext = + GlobalOpenTelemetry.getPropagators() + .getTextMapPropagator() + .extract(Context.root(), headers, MapTextMapGetter.INSTANCE); + + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer + .spanBuilder("server-request") + .setParent(extractedContext) + .setSpanKind(SpanKind.SERVER) + .startSpan(); + + span.end(); + List> traces = testing.waitForTraces(1); + + assertThat(traces).hasSize(1); + SpanData rootSpan = traces.get(0).get(0); + assertThat(rootSpan.getAttributes().get(AttributeKey.booleanKey("TriggeredTrace"))).isTrue(); + + assertThat(rootSpan.getAttributes().get(AttributeKey.stringKey("SWKeys"))) + .isEqualTo("lo:se,check-id:123"); + assertThat(rootSpan.getAttributes().get(AttributeKey.stringKey("custom-info"))) + .isEqualTo("chubi"); + } + + @Test + void verifyTriggerTraceWithoutCustomKeysOnlyStampsTriggeredTrace() { + Map headers = new HashMap<>(); + headers.put("X-Trace-Options", "trigger-trace"); + + Context extractedContext = + GlobalOpenTelemetry.getPropagators() + .getTextMapPropagator() + .extract(Context.root(), headers, MapTextMapGetter.INSTANCE); + + Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); + Span span = + tracer + .spanBuilder("simple-trigger") + .setParent(extractedContext) + .setSpanKind(SpanKind.SERVER) + .startSpan(); + span.end(); + + List> traces = testing.waitForTraces(1); + assertThat(traces).hasSize(1); + + SpanData rootSpan = traces.get(0).get(0); + assertThat(rootSpan.getAttributes().get(AttributeKey.booleanKey("TriggeredTrace"))).isTrue(); + assertThat(rootSpan.getAttributes().get(AttributeKey.stringKey("SWKeys"))).isNull(); + } + + private enum MapTextMapGetter implements TextMapGetter> { + INSTANCE; + + @Override + public Iterable keys(Map carrier) { + return carrier.keySet(); + } + + @Override + public String get(Map carrier, String key) { + return carrier == null ? null : carrier.get(key); + } + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index fe5b8038..0c3c99c7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -49,4 +49,5 @@ include("libs:core") include("libs:config") include("libs:logging") include("libs:sampling") +include("integration-tests") diff --git a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java index a6c1876e..25c1194b 100644 --- a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java +++ b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java @@ -123,20 +123,94 @@ void assertXTrace() throws IOException { } @Test - void assertTransactionFiltering() throws IOException { + void assertTraceIngestion() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double fails = ResultsCollector.read(resultJson, "$.root_group.checks.['verify that transaction is filtered'].fails"); - assertEquals(0, fails, "transaction filtering doesn't work"); + double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['trace is returned'].passes"); + assertTrue(passes > 0, "trace ingestion is not working. There maybe network issues"); } @Test - void assertTraceIngestion() throws IOException { + void assertTraceContextInLog() { + Boolean actual = logStreamAnalyzer.getAnswer().get("trace_id=[a-z0-9]+\\s+span_id=[a-z0-9]+\\s+trace_flags=[0-9a-f]{2}"); + assertTrue(actual, "trace context is not injected in logs"); + } + + @Test + void assertAgentExtensionLoading() { + Boolean actual = logStreamAnalyzer.getAnswer().get("Extension attached!"); + assertTrue(actual, "expected log output from extension was not found"); + } + + @Test + @EnabledIfSystemProperty(named = "test.cloud", matches = "AWS") + void assertAgentAwsMetadata() { + Boolean actual = logStreamAnalyzer.getAnswer().get("hostId:.*i-[0-9a-z]+"); + assertTrue(actual, "AWS metadata is not retrieved"); + } + + @Test + @EnabledIfSystemProperty(named = "test.cloud", matches = "AZURE") + void assertAgentAzureMetadata() { + Boolean actual = logStreamAnalyzer.getAnswer().get("hostId:.*[0-9a-z-]+"); + assertTrue(actual, "Azure metadata is not retrieved"); + } + + @Test + void assertThatTransactionNameBufferIsCleared() { + Boolean actual = logStreamAnalyzer.getAnswer().get("Clearing transaction name buffer. Unique transaction count: \\d+"); + assertTrue(actual, "Transaction name buffer is not getting cleared on metric flush"); + } + + @Test + void assertThatProxyIsUsed() { + Boolean actual = logStreamAnalyzer.getAnswer().get("CONNECT otel.collector.na-01.st-ssp.solarwinds.com:443"); + assertTrue(actual, "not using proxy"); + } + + @Test + void assertThatLogsAreExported() throws IOException { + String resultJson = new String( + Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, + "$.root_group.checks.['logs'].passes"); + assertTrue(passes > 0, "log export is broken"); + } + + @Test + void assertThatMetricsAreExported() throws IOException { + String resultJson = new String( + Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, + "$.root_group.checks.['otel-metrics'].passes"); + assertTrue(passes > 0, "otel metric export is broken"); + } + + @Test + void assertThatRuntimeMetrics17AreExported() throws IOException { + String resultJson = new String( + Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, + "$.root_group.checks.['otel-metrics-17'].passes"); + assertTrue(passes > 0, "JVM 17+ runtime metric export is broken"); + } + + @Test + @Disabled + void assertServiceNameIsSameAsOneInServiceKey() { + Boolean actual = logStreamAnalyzer.getAnswer().get("This log line is used for validation only: service.name: java-apm-smoke-test"); + assertTrue(actual, "service.name is not updated with name in service key"); + } + + @Test + @Disabled + void assertTransactionFiltering() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['trace is returned'].passes"); - assertTrue(passes > 0, "trace ingestion is not working. There maybe network issues"); + double fails = ResultsCollector.read(resultJson, "$.root_group.checks.['verify that transaction is filtered'].fails"); + assertEquals(0, fails, "transaction filtering doesn't work"); } @Test + @Disabled void assertJDBC() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['JDBC is not broken'].passes"); @@ -144,6 +218,7 @@ void assertJDBC() throws IOException { } @Test + @Disabled void assertXTraceOptions() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['xtrace-options is added to root span'].passes"); @@ -151,6 +226,7 @@ void assertXTraceOptions() throws IOException { } @Test + @Disabled void assertMvcInstrumentation() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['mvc handler name is added'].passes"); @@ -158,6 +234,7 @@ void assertMvcInstrumentation() throws IOException { } @Test + @Disabled void assertTriggerTrace() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['trigger trace'].passes"); @@ -165,6 +242,7 @@ void assertTriggerTrace() throws IOException { } @Test + @Disabled void assertCodeProfiling() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['code profiling'].passes"); @@ -172,6 +250,7 @@ void assertCodeProfiling() throws IOException { } @Test + @Disabled void assertContextPropagation() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['check that remote service, java-apm-smoke-test, is path of the trace'].passes"); @@ -179,90 +258,22 @@ void assertContextPropagation() throws IOException { } @Test + @Disabled void assertTransactionNaming() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['custom transaction name'].passes"); assertTrue(passes > 0, "transaction naming is broken"); } - @Test - void assertTraceContextInLog() { - Boolean actual = logStreamAnalyzer.getAnswer().get("trace_id=[a-z0-9]+\\s+span_id=[a-z0-9]+\\s+trace_flags=[0-9a-f]{2}"); - assertTrue(actual, "trace context is not injected in logs"); - } - - @Test - void assertAgentExtensionLoading() { - Boolean actual = logStreamAnalyzer.getAnswer().get("Extension attached!"); - assertTrue(actual, "expected log output from extension was not found"); - } - - @Test - @EnabledIfSystemProperty(named = "test.cloud", matches = "AWS") - void assertAgentAwsMetadata() { - Boolean actual = logStreamAnalyzer.getAnswer().get("hostId:.*i-[0-9a-z]+"); - assertTrue(actual, "AWS metadata is not retrieved"); - } - - @Test - @EnabledIfSystemProperty(named = "test.cloud", matches = "AZURE") - void assertAgentAzureMetadata() { - Boolean actual = logStreamAnalyzer.getAnswer().get("hostId:.*[0-9a-z-]+"); - assertTrue(actual, "Azure metadata is not retrieved"); - } - - @Test - void assertServiceNameIsSameAsOneInServiceKey() { - Boolean actual = logStreamAnalyzer.getAnswer().get("This log line is used for validation only: service.name: java-apm-smoke-test"); - assertTrue(actual, "service.name is not updated with name in service key"); - } - - @Test - void assertThatTransactionNameBufferIsCleared() { - Boolean actual = logStreamAnalyzer.getAnswer().get("Clearing transaction name buffer. Unique transaction count: \\d+"); - assertTrue(actual, "Transaction name buffer is not getting cleared on metric flush"); - } - @Test + @Disabled void assertThatJDBCInstrumentationIsApplied() { Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); assertTrue(actual, "sw-jdbc instrumentation is not applied"); } @Test - void assertThatProxyIsUsed() { - Boolean actual = logStreamAnalyzer.getAnswer().get("CONNECT otel.collector.na-01.st-ssp.solarwinds.com:443"); - assertTrue(actual, "not using proxy"); - } - - @Test - void assertThatLogsAreExported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, - "$.root_group.checks.['logs'].passes"); - assertTrue(passes > 0, "log export is broken"); - } - - @Test - void assertThatMetricsAreExported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, - "$.root_group.checks.['otel-metrics'].passes"); - assertTrue(passes > 0, "otel metric export is broken"); - } - - @Test - void assertThatRuntimeMetrics17AreExported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, - "$.root_group.checks.['otel-metrics-17'].passes"); - assertTrue(passes > 0, "JVM 17+ runtime metric export is broken"); - } - - @Test + @Disabled void assertThatSdkTracingIsWorking() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -272,6 +283,7 @@ void assertThatSdkTracingIsWorking() throws IOException { } @Test + @Disabled void assertThatRequestCountMetricIsReported() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -281,6 +293,7 @@ void assertThatRequestCountMetricIsReported() throws IOException { } @Test + @Disabled void assertThatTraceCountMetricIsReported() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -290,6 +303,7 @@ void assertThatTraceCountMetricIsReported() throws IOException { } @Test + @Disabled void assertThatSampleCountMetricIsReported() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -299,6 +313,7 @@ void assertThatSampleCountMetricIsReported() throws IOException { } @Test + @Disabled void assertThatResponseTimeMetricIsReported() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -308,6 +323,7 @@ void assertThatResponseTimeMetricIsReported() throws IOException { } @Test + @Disabled void assertThatCodeStacktraceIsCaptured() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -317,6 +333,7 @@ void assertThatCodeStacktraceIsCaptured() throws IOException { } @Test + @Disabled void assertThatTraceJvmMetricsAreNotCollected() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); diff --git a/testing/agent-test-extension/build.gradle.kts b/testing/agent-test-extension/build.gradle.kts index bafd9665..0ec07db7 100644 --- a/testing/agent-test-extension/build.gradle.kts +++ b/testing/agent-test-extension/build.gradle.kts @@ -4,5 +4,9 @@ plugins { dependencies { compileOnly(project(":libs:shared")) + compileOnly(project(":libs:core")) + compileOnly(project(":libs:sampling")) + compileOnly(project(":bootstrap")) compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api") } diff --git a/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAgentListener.java b/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAgentListener.java new file mode 100644 index 00000000..42cc451f --- /dev/null +++ b/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAgentListener.java @@ -0,0 +1,45 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.extensions; + +import com.google.auto.service.AutoService; +import com.solarwinds.joboe.core.settings.TestSettingsReader; +import com.solarwinds.joboe.core.util.TestUtils; +import com.solarwinds.opentelemetry.core.AgentState; +import io.opentelemetry.javaagent.extension.AgentListener; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import java.util.concurrent.TimeUnit; + +@AutoService(AgentListener.class) +public class TestAgentListener implements AgentListener { + + @Override + public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { + AgentState.waitForReady(30, TimeUnit.SECONDS); + TestSettingsReader reader = TestUtils.initSettingsReader(); + reader.put( + new TestSettingsReader.SettingsMockupBuilder() + .withFlags(true, false, true, true, false) + .withSampleRate(1_000_000) + .build()); + } + + @Override + public int order() { + return Integer.MAX_VALUE; + } +} diff --git a/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAutoConfigurationCustomizer.java b/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAutoConfigurationCustomizer.java index ca443b91..4d78f5ca 100644 --- a/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAutoConfigurationCustomizer.java +++ b/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAutoConfigurationCustomizer.java @@ -17,6 +17,8 @@ package com.solarwinds.opentelemetry.extensions; import com.google.auto.service.AutoService; +import com.solarwinds.joboe.core.settings.TestSettingsReader; +import com.solarwinds.joboe.core.util.TestUtils; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; @@ -25,9 +27,12 @@ public class TestAutoConfigurationCustomizer implements AutoConfigurationCustomi @Override public void customize(AutoConfigurationCustomizer autoConfiguration) { - autoConfiguration.addTracerProviderCustomizer( - (tracerProviderBuilder, configProperties) -> - tracerProviderBuilder.setSampler(new TestSampler())); + TestSettingsReader reader = TestUtils.initSettingsReader(); + reader.put( + new TestSettingsReader.SettingsMockupBuilder() + .withFlags(true, false, true, true, false) + .withSampleRate(1_000_000) + .build()); } @Override diff --git a/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestSampler.java b/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestSampler.java deleted file mode 100644 index d3ba5844..00000000 --- a/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestSampler.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * © SolarWinds Worldwide, LLC. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.solarwinds.opentelemetry.extensions; - -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.trace.data.LinkData; -import io.opentelemetry.sdk.trace.samplers.Sampler; -import io.opentelemetry.sdk.trace.samplers.SamplingResult; -import java.util.List; - -public class TestSampler extends SolarwindsSampler { - private final Sampler sampler = Sampler.alwaysOn(); - - @Override - public SamplingResult shouldSample( - Context parentContext, - String traceId, - String name, - SpanKind spanKind, - Attributes attributes, - List parentLinks) { - return sampler.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks); - } -} From 7a9822fe4b1e3ff55cf99dec667faf6551c15549 Mon Sep 17 00:00:00 2001 From: cleverchuk Date: Fri, 15 May 2026 11:08:45 -0400 Subject: [PATCH 2/5] disable tests covered by the refactor --- .github/workflows/lambda-test.yml | 108 ----------- build.gradle.kts | 4 - smoke-tests/k6/basic.js | 110 ++--------- .../test/java/com/solarwinds/LambdaTest.java | 175 ------------------ .../test/java/com/solarwinds/SmokeTest.java | 45 +++-- .../test/java/com/solarwinds/SmokeTestV2.java | 140 +++++++------- 6 files changed, 113 insertions(+), 469 deletions(-) delete mode 100644 .github/workflows/lambda-test.yml delete mode 100644 smoke-tests/src/test/java/com/solarwinds/LambdaTest.java diff --git a/.github/workflows/lambda-test.yml b/.github/workflows/lambda-test.yml deleted file mode 100644 index 95a5c4e6..00000000 --- a/.github/workflows/lambda-test.yml +++ /dev/null @@ -1,108 +0,0 @@ -name: Lambda Release Test - -on: - workflow_dispatch: - workflow_run: - workflows: [Push] - types: - - completed - -permissions: - packages: write - contents: read - id-token: write - security-events: write - -env: - SW_APM_DEBUG_LEVEL: trace - AGENT_DOWNLOAD_URL: https://agent-binaries.global.st-ssp.solarwinds.com/apm/java/latest/solarwinds-apm-agent.jar - SW_APM_COLLECTOR: ${{ secrets.SW_APM_COLLECTOR }} - SW_APM_SERVICE_KEY_AO: ${{ secrets.SW_APM_SERVICE_KEY_AO }} - SW_APM_SERVICE_KEY: ${{ secrets.SW_APM_SERVICE_KEY }} - GITHUB_USERNAME: ${{ github.actor }} - SWO_LOGIN_URL: ${{ secrets.SWO_LOGIN_URL }} - SWO_HOST_URL: ${{ secrets.SWO_HOST_URL }} - SWO_EMAIL: ${{ secrets.SWO_EMAIL }} - SWO_PWORD: ${{ secrets.SWO_PWORD }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} - CENTRAL_TOKEN: ${{ secrets.CENTRAL_TOKEN }} - -jobs: - lambda-release-test: - runs-on: ubuntu-latest - env: - LAMBDA: "true" - OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }} - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Free Disk Space before Build - run: | - echo "Disk space before pre-build cleanup:" - df -h - docker system prune -af - sudo rm -rf /usr/local/.ghcup - sudo rm -rf /opt/hostedtoolcache/CodeQL - sudo rm -rf /usr/local/lib/android/sdk/ndk - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf /usr/local/share/boost - echo "Disk space after pre-build cleanup:" - df -h - - - name: Set up JDK 17 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 - with: - java-version: '17' - distribution: 'temurin' - - - name: Set agent version - id: set_version - uses: ./.github/actions/version - - - name: Set snapshot version - run: | - GIT_HASH=$(git rev-parse --short "$GITHUB_SHA") - echo "AGENT_VERSION=${{ steps.set_version.outputs.version }}.$GIT_HASH" >> $GITHUB_ENV - - - name: Build smoke-test - run: | - cd smoke-tests - ./gradlew build -x test - - - name: Build webmvc jar - run: | - cd smoke-tests - ./gradlew :spring-boot-webmvc:build - - - name: Build webmvc image - run: | - cd smoke-tests/spring-boot-webmvc - docker image build --tag smt:webmvc . - - - name: Docker login - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $GITHUB_USERNAME --password-stdin - - - name: Execute smoke tests - run: | - cd smoke-tests - ./gradlew test --tests "com.solarwinds.LambdaTest" -Pno-reports - - - name: Free Disk Space After Build - run: | - echo "Disk space before post-build cleanup:" - df -h - sudo rm -rf /usr/local/.ghcup - sudo rm -rf /opt/hostedtoolcache/CodeQL - sudo rm -rf /usr/local/lib/android/sdk/ndk - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf /usr/local/share/boost - sudo rm -rf smoke-tests/build/ - echo "Disk space after post-build cleanup:" - df -h - - - name: Docker logout - if: always() - run: docker logout \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 1d4507e3..5202c194 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -82,10 +82,6 @@ allprojects { } } } - - tasks.withType { - finalizedBy(tasks.named("cleanListedDependencies")) - } } } diff --git a/smoke-tests/k6/basic.js b/smoke-tests/k6/basic.js index 6ab77dd3..c7c0af45 100644 --- a/smoke-tests/k6/basic.js +++ b/smoke-tests/k6/basic.js @@ -21,10 +21,10 @@ import names from "./names.js"; const baseUri = `http://petclinic:9966/petclinic/api`; const webMvcUri = `http://webmvc:8080`; export const options = { - duration: "30m", - minIterationDuration: "5m", - vus: 10, - iterations: 200, + duration: "5m", + minIterationDuration: "1m", + vus: 5, + iterations: 25, }; function verify_that_trace_is_persisted() { @@ -465,7 +465,6 @@ function check_transaction_name(property) { return false } - function check_code_stack_trace(property) { if (property.key === "code.stacktrace") { check(property, {"code.stacktrace": _ => true}) @@ -644,104 +643,21 @@ function silence(fn) { } export default function () { - silence(verify_that_span_data_is_persisted_0) - - const request_count = (measurement) => check(measurement, {"request_count": mrs => mrs.value > 0}) - const tracecount = (measurement) => check(measurement, {"tracecount": mrs => mrs.value > 0}) - const samplecount = (measurement) => check(measurement, {"samplecount": mrs => mrs.value > 0}) - const response_time = (measurement) => check(measurement, {"response_time": mrs => mrs.value > 0}) - - if (`${__ENV.LAMBDA}` === "true") { - - silence(function () { - verify_that_metrics_are_reported("trace.service.request_count", request_count) - }) - - silence(function () { - verify_that_metrics_are_reported("trace.service.tracecount", tracecount) - }) - + const service = "java-apm-smoke-test" silence(function () { - verify_that_metrics_are_reported("trace.service.samplecount", samplecount) + verify_that_metrics_are_reported("jvm.memory.used", + (measurement) => check(measurement, {"otel-metrics": mrs => mrs.value > 0}), + service + ) }) silence(function () { - verify_that_metrics_are_reported("trace.service.response_time", response_time) + verify_that_metrics_are_reported("jvm.network.time", + (measurement) => check(measurement, {"otel-metrics-17": mrs => mrs.value > 0}), + service + ) }) - silence(function () { - check_property(check_transaction_name) - }) - - silence(function () { - check_property(check_code_stack_trace) - }) - - silence(function () { - verify_that_metrics_are_reported("trace.jvm.Runtime.Uptime", - (measurement) => check(measurement, {"trace.jvm-metrics": mrs => mrs.value === 0}) - ) - }) - - silence(function () { - verify_that_metrics_are_reported("trace.jvm.Threading.ThreadCount", - (measurement) => check(measurement, {"trace.jvm-metrics": mrs => mrs.value === 0}) - ) - }) - - } else { - const service = "java-apm-smoke-test" - silence(function () { - verify_that_metrics_are_reported("trace.service.request_count", request_count, service) - }) - - silence(function () { - verify_that_metrics_are_reported("trace.service.tracecount", tracecount, service) - }) - - silence(function () { - verify_that_metrics_are_reported("trace.service.samplecount", samplecount, service) - }) - - silence(function () { - verify_that_metrics_are_reported("trace.service.response_time", response_time, service) - }) - - silence(function () { - verify_that_metrics_are_reported("jvm.memory.used", - (measurement) => check(measurement, {"otel-metrics": mrs => mrs.value > 0}), - service - ) - }) - - silence(function () { - verify_that_metrics_are_reported("jvm.network.time", - (measurement) => check(measurement, {"otel-metrics-17": mrs => mrs.value > 0}), - service - ) - }) - - silence(function () { - verify_that_metrics_are_reported("trace.jvm.Runtime.Uptime", - (measurement) => check(measurement, {"trace.jvm-metrics": mrs => mrs.value === 0}), - service - ) - }) - - silence(function () { - verify_that_metrics_are_reported("trace.jvm.Threading.ThreadCount", - (measurement) => check(measurement, {"trace.jvm-metrics": mrs => mrs.value === 0}), - service - ) - }) silence(verify_logs_export) - silence(verify_that_specialty_path_is_not_sampled) - silence(function () { - check_property(check_code_stack_trace) - }) - silence(verify_that_span_data_is_persisted) silence(verify_that_trace_is_persisted) - silence(verify_distributed_trace) - silence(verify_profile) - } }; diff --git a/smoke-tests/src/test/java/com/solarwinds/LambdaTest.java b/smoke-tests/src/test/java/com/solarwinds/LambdaTest.java deleted file mode 100644 index 9aa31ad1..00000000 --- a/smoke-tests/src/test/java/com/solarwinds/LambdaTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * © SolarWinds Worldwide, LLC. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.solarwinds; - -import com.jayway.jsonpath.PathNotFoundException; -import com.solarwinds.agents.Agent; -import com.solarwinds.agents.SwoLambdaAgentResolver; -import com.solarwinds.config.Configs; -import com.solarwinds.config.TestConfig; -import com.solarwinds.containers.K6Container; -import com.solarwinds.containers.PetClinicRestContainer; -import com.solarwinds.containers.PostgresContainer; -import com.solarwinds.containers.SpringBootWebMvcContainer; -import com.solarwinds.results.ResultsCollector; -import com.solarwinds.util.LogStreamAnalyzer; -import com.solarwinds.util.NamingConventions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; -import org.slf4j.LoggerFactory; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.Network; -import org.testcontainers.containers.output.Slf4jLogConsumer; - -import java.io.IOException; -import java.nio.file.Files; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -@EnabledIfEnvironmentVariable(named = "LAMBDA", matches = "true") -public class LambdaTest { - private static final Network NETWORK = Network.newNetwork(); - - private static final NamingConventions namingConventions = new NamingConventions(); - - private static final LogStreamAnalyzer logStreamAnalyzer = new LogStreamAnalyzer<>( - List.of( - "Got settings from file:", - "Applying instrumentation: sw-jdbc" - ) - , new Slf4jLogConsumer(LoggerFactory.getLogger("k6"))); - - - @BeforeAll - static void runTestConfig() { - TestConfig config = Configs.LAMBDA_E2E.config; - config - .agents() - .forEach( - agent -> { - try { - runAppOnce(agent); - } catch (Exception e) { - fail("Unhandled exception in " + config.name(), e); - } - }); - } - - static void runAppOnce(Agent agent) throws Exception { - GenericContainer postgres = new PostgresContainer(NETWORK).build(); - postgres.start(); - - GenericContainer webMvc = new SpringBootWebMvcContainer(new SwoLambdaAgentResolver(), NETWORK, agent).build(); - webMvc.start(); - - GenericContainer petClinic = new PetClinicRestContainer(new SwoLambdaAgentResolver(), NETWORK, agent).build(); - petClinic.start(); - petClinic.followOutput(logStreamAnalyzer); - - GenericContainer k6 = new K6Container(NETWORK, agent, namingConventions).build(); - k6.start(); - - petClinic.execInContainer("kill", "1"); - webMvc.execInContainer("kill", "1"); - postgres.stop(); - } - - @Test - void assertThatRequestCountMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.LAMBDA_E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['request_count'].passes"); - assertTrue(passes > 1, "Expects a count > 1 "); - } - - @Test - void assertThatTraceCountMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.LAMBDA_E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['tracecount'].passes"); - assertTrue(passes > 1, "Expects a count > 1 "); - } - - @Test - void assertThatSampleCountMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.LAMBDA_E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['samplecount'].passes"); - assertTrue(passes > 1, "Expects a count > 1 "); - } - - @Test - void assertThatResponseTimeMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.LAMBDA_E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['response_time'].passes"); - assertTrue(passes > 1, "Expects a count > 1 "); - } - - @Test - void assertThatCustomTransactionNameTakesEffect() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.LAMBDA_E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['transaction-name'].passes"); - assertTrue(passes > 1, "Environment based transaction naming is broken "); - } - - @Test - void assertThatSettingsAreReadFromFile() { - Boolean actual = logStreamAnalyzer.getAnswer().get("Got settings from file:"); - assertTrue(actual, "file based settings is not being used"); - } - - @Test - void assertThatJDBCInstrumentationIsApplied() { - Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); - assertTrue(actual, "sw-jdbc instrumentation is not applied"); - } - - @Test - void assertSDKTransactionNaming() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.LAMBDA_E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['custom transaction name'].passes"); - assertTrue(passes > 1, "SDK transaction naming is broken"); - } - - @Test - void assertThatCodeStacktraceIsCaptured() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['code.stacktrace'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - void assertThatTraceJvmMetricsAreNotCollected() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - assertThrows(PathNotFoundException.class, () -> ResultsCollector.read(resultJson, "$.root_group.checks.['trace.jvm-metrics'].fails")); - } -} diff --git a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java index 25c1194b..c722c9f6 100644 --- a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java +++ b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java @@ -38,7 +38,6 @@ import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.Network; -import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.Slf4jLogConsumer; import java.io.IOException; @@ -211,7 +210,7 @@ void assertTransactionFiltering() throws IOException { @Test @Disabled - void assertJDBC() throws IOException { + void assertJDBC() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['JDBC is not broken'].passes"); assertTrue(passes > 0, "JDBC instrumentation doesn't work"); @@ -219,7 +218,7 @@ void assertJDBC() throws IOException { @Test @Disabled - void assertXTraceOptions() throws IOException { + void assertXTraceOptions() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['xtrace-options is added to root span'].passes"); assertTrue(passes > 1, "Xtrace options is not captured in root span"); @@ -227,7 +226,7 @@ void assertXTraceOptions() throws IOException { @Test @Disabled - void assertMvcInstrumentation() throws IOException { + void assertMvcInstrumentation() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['mvc handler name is added'].passes"); assertTrue(passes > 0, "MVC instrumentation is broken"); @@ -235,7 +234,7 @@ void assertMvcInstrumentation() throws IOException { @Test @Disabled - void assertTriggerTrace() throws IOException { + void assertTriggerTrace() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['trigger trace'].passes"); assertTrue(passes > 0, "trigger trace is broken"); @@ -243,7 +242,7 @@ void assertTriggerTrace() throws IOException { @Test @Disabled - void assertCodeProfiling() throws IOException { + void assertCodeProfiling() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['code profiling'].passes"); assertTrue(passes > 0, "code profiling is broken"); @@ -251,7 +250,7 @@ void assertCodeProfiling() throws IOException { @Test @Disabled - void assertContextPropagation() throws IOException { + void assertContextPropagation() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['check that remote service, java-apm-smoke-test, is path of the trace'].passes"); assertTrue(passes > 0, "context propagation is broken"); @@ -265,22 +264,22 @@ void assertTransactionNaming() throws IOException { assertTrue(passes > 0, "transaction naming is broken"); } - @Test - @Disabled - void assertThatJDBCInstrumentationIsApplied() { - Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); - assertTrue(actual, "sw-jdbc instrumentation is not applied"); - } - - @Test - @Disabled - void assertThatSdkTracingIsWorking() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['sdk-trace'].passes"); - assertTrue(passes > 0, "SDK trace is not working, expected a count > 0"); - } + @Test + @Disabled + void assertThatJDBCInstrumentationIsApplied() { + Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); + assertTrue(actual, "sw-jdbc instrumentation is not applied"); + } + + @Test + @Disabled + void assertThatSdkTracingIsWorking() throws IOException { + String resultJson = new String( + Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + + double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['sdk-trace'].passes"); + assertTrue(passes > 0, "SDK trace is not working, expected a count > 0"); + } @Test @Disabled diff --git a/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java b/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java index a9e504c7..4a4e13e5 100644 --- a/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java +++ b/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java @@ -114,13 +114,6 @@ void assertXTrace() throws IOException { assertEquals(0, fails, "Less than a 100 percent of the responses has X-Trace header"); } - @Test - void assertTransactionFiltering() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double fails = ResultsCollector.read(resultJson, "$.root_group.checks.['verify that transaction is filtered'].fails"); - assertEquals(0, fails, "transaction filtering doesn't work"); - } - @Test void assertTraceIngestion() throws IOException { String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -128,55 +121,6 @@ void assertTraceIngestion() throws IOException { assertTrue(passes > 0, "trace ingestion is not working. There maybe network issues"); } - @Test - void assertJDBC() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['JDBC is not broken'].passes"); - assertTrue(passes > 0, "JDBC instrumentation doesn't work"); - } - - @Test - void assertXTraceOptions() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['xtrace-options is added to root span'].passes"); - assertTrue(passes > 1, "Xtrace options is not captured in root span"); - } - - @Test - void assertMvcInstrumentation() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['mvc handler name is added'].passes"); - assertTrue(passes > 0, "MVC instrumentation is broken"); - } - - @Test - void assertTriggerTrace() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['trigger trace'].passes"); - assertTrue(passes > 0, "trigger trace is broken"); - } - - @Test - void assertCodeProfiling() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['code profiling'].passes"); - assertTrue(passes > 0, "code profiling is broken"); - } - - @Test - void assertContextPropagation() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['check that remote service, java-apm-smoke-test, is path of the trace'].passes"); - assertTrue(passes > 0, "context propagation is broken"); - } - - @Test - void assertTransactionNaming() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['custom transaction name'].passes"); - assertTrue(passes > 0, "transaction naming is broken"); - } - @Test void assertTraceContextInLog() { Boolean actual = logStreamAnalyzer.getAnswer().get("trace_id=[a-z0-9]+\\s+span_id=[a-z0-9]+\\s+trace_flags=[0-9a-f]{2}"); @@ -209,12 +153,6 @@ void assertThatTransactionNameBufferIsCleared() { assertTrue(actual, "Transaction name buffer is not getting cleared on metric flush"); } - @Test - void assertThatJDBCInstrumentationIsApplied() { - Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); - assertTrue(actual, "sw-jdbc instrumentation is not applied"); - } - @Test void assertThatLogsAreExported() throws IOException { String resultJson = new String( @@ -243,6 +181,78 @@ void assertThatRuntimeMetrics17AreExported() throws IOException { } @Test + @Disabled + void assertTransactionFiltering() throws IOException { + String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double fails = ResultsCollector.read(resultJson, "$.root_group.checks.['verify that transaction is filtered'].fails"); + assertEquals(0, fails, "transaction filtering doesn't work"); + } + + @Test + @Disabled + void assertJDBC() throws IOException { + String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['JDBC is not broken'].passes"); + assertTrue(passes > 0, "JDBC instrumentation doesn't work"); + } + + @Test + @Disabled + void assertXTraceOptions() throws IOException { + String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['xtrace-options is added to root span'].passes"); + assertTrue(passes > 1, "Xtrace options is not captured in root span"); + } + + @Test + @Disabled + void assertMvcInstrumentation() throws IOException { + String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['mvc handler name is added'].passes"); + assertTrue(passes > 0, "MVC instrumentation is broken"); + } + + @Test + @Disabled + void assertTriggerTrace() throws IOException { + String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['trigger trace'].passes"); + assertTrue(passes > 0, "trigger trace is broken"); + } + + @Test + @Disabled + void assertCodeProfiling() throws IOException { + String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['code profiling'].passes"); + assertTrue(passes > 0, "code profiling is broken"); + } + + @Test + @Disabled + void assertContextPropagation() throws IOException { + String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['check that remote service, java-apm-smoke-test, is path of the trace'].passes"); + assertTrue(passes > 0, "context propagation is broken"); + } + + @Test + @Disabled + void assertTransactionNaming() throws IOException { + String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); + double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['custom transaction name'].passes"); + assertTrue(passes > 0, "transaction naming is broken"); + } + + @Test + @Disabled + void assertThatJDBCInstrumentationIsApplied() { + Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); + assertTrue(actual, "sw-jdbc instrumentation is not applied"); + } + + @Test + @Disabled void assertThatSdkTracingIsWorking() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -252,6 +262,7 @@ void assertThatSdkTracingIsWorking() throws IOException { } @Test + @Disabled void assertThatRequestCountMetricIsReported() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -261,6 +272,7 @@ void assertThatRequestCountMetricIsReported() throws IOException { } @Test + @Disabled void assertThatTraceCountMetricIsReported() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -270,6 +282,7 @@ void assertThatTraceCountMetricIsReported() throws IOException { } @Test + @Disabled void assertThatSampleCountMetricIsReported() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -279,6 +292,7 @@ void assertThatSampleCountMetricIsReported() throws IOException { } @Test + @Disabled void assertThatResponseTimeMetricIsReported() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -288,6 +302,7 @@ void assertThatResponseTimeMetricIsReported() throws IOException { } @Test + @Disabled void assertThatCodeStacktraceIsCaptured() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); @@ -297,6 +312,7 @@ void assertThatCodeStacktraceIsCaptured() throws IOException { } @Test + @Disabled void assertThatTraceJvmMetricsAreNotCollected() throws IOException { String resultJson = new String( Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); From 5c283d90dbcb2f9f429c62029538830c6e038bb0 Mon Sep 17 00:00:00 2001 From: cleverchuk Date: Fri, 15 May 2026 14:19:14 -0400 Subject: [PATCH 3/5] delete dead code from test refactor --- smoke-tests/k6/basic.js | 366 ------------------ .../test/java/com/solarwinds/SmokeTest.java | 146 ------- .../test/java/com/solarwinds/SmokeTestV2.java | 139 ------- 3 files changed, 651 deletions(-) diff --git a/smoke-tests/k6/basic.js b/smoke-tests/k6/basic.js index c7c0af45..9a157f39 100644 --- a/smoke-tests/k6/basic.js +++ b/smoke-tests/k6/basic.js @@ -70,9 +70,6 @@ function verify_that_trace_is_persisted() { "trace is returned": tdr => tdr.data.traceDetails.traceId.toLowerCase() === traceId.toLowerCase() }); - // check that db query is captured(JDBC check) - const {data: {traceDetails: {allQueries}}} = traceDetailResponse; - check(allQueries, {"JDBC is not broken": aq => aq.length > 0}) return } @@ -80,291 +77,6 @@ function verify_that_trace_is_persisted() { } -function verify_that_span_data_is_persisted() { - const newOwner = names.randomOwner(); - let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount > 0; retryCount--) { - const newOwnerResponse = http.post(`${baseUri}/owners`, JSON.stringify(newOwner), - { - headers: { - 'Content-Type': 'application/json', - "x-trace-options": "trigger-trace;custom-info=chubi;sw-keys=lo:se,check-id:123" - } - }); - - const traceContext = newOwnerResponse.headers['X-Trace'] - const [_, traceId, __, flag] = traceContext.split("-") - console.log("Trace context -> ", traceContext) - if ((parseInt(flag, 16) & 1) === 0) continue; - - const spanRawDataPayload = { - "operationName": "getSubSpanRawData", - "variables": { - "traceId": traceId.toUpperCase() - }, - "query": "query getSubSpanRawData($traceId: ID!, $spanFilter: TraceArchiveSpanFilter) {\n traceArchive(\n traceId: $traceId\n spanFilter: $spanFilter\n ) {\n traceId\n traceSpans {\n edges {\n node {\n events {\n eventId\n properties {\n key\n value\n __typename\n }\n __typename\n }\n spanId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" - } - - for (; retryCount > 0; retryCount--) { - let spanDataResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(spanRawDataPayload), - { - headers: { - 'Content-Type': 'application/json', - 'Cookie': `${__ENV.SWO_COOKIE}`, - 'X-Csrf-Token': `${__ENV.SWO_XSR_TOKEN}` - } - }); - - spanDataResponse = JSON.parse(spanDataResponse.body) - if (spanDataResponse['errors']) { - console.log("Error -> Persisted trace response:", JSON.stringify(spanDataResponse)) - continue - } - - const {data: {traceArchive: {traceSpans: {edges}}}} = spanDataResponse - for (let i = 0; i < edges.length; i++) { - const edge = edges[i] - const {node: {events}} = edge - for (let j = 0; j < events.length; j++) { - const event = events[j] - const {properties} = event - let found = false - - for (let k = 0; k < properties.length; k++) { - const property = properties[k] - check(property, {"mvc handler name is added": prop => prop.key === "HandlerName"}) - check(property, {"trigger trace": prop => prop.key === "TriggeredTrace"}) - - if (property.key === "PDKeys") { - check(property, {"xtrace-options is added to root span": prop => prop.value === "{check-id=123, lo=se}"}) - found = true - } - - if (property.key === "custom-info") { - check(property, {"xtrace-options is added to root span": prop => prop.value === "chubi"}) - found = true - } - } - if (found) return; // assumes that all checked property must exist at the same node(root span). - } - } - } - - } - -} - -function verify_profile() { - const newOwner = names.randomOwner(); - let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount > 0; retryCount--) { - const newOwnerResponse = http.post(`${baseUri}/owners`, JSON.stringify(newOwner), - { - headers: { - 'Content-Type': 'application/json', - "x-trace-options": "trigger-trace;custom-info=chubi;sw-keys=lo:se,check-id:123" - } - }); - - const traceContext = newOwnerResponse.headers['X-Trace'] - const [_, __, ___, flag] = traceContext.split("-") - console.log("Trace context -> ", traceContext) - if ((parseInt(flag, 16) & 1) === 0) continue; - - const endTime = Date.now(); - const startTime = endTime - 10 * 60 * 1000; - const profileSpanQueryPayload = { - "operationName": "getSearchedTraceRequests", - "variables": { - "searchQuery": "sw.profile.spans:1", - "orderBy": { - "direction": "DESC", - "sort": "TIME" - }, - "first": 15, - "timeFilter": { - "startTime": `${startTime}`, - "endTime": `${endTime}` - }, - "serviceNames": ["java-apm-smoke-test","java-apm-smoke-test-webmvc"] - }, - "query": "query getSearchedTraceRequests($first: Int, $serviceNames: [String!], $timeFilter: TimeRangeInput!, $orderBy: TraceRequestItemsOrderBy!, $searchQuery: String!) {\n trace {\n requests(\n context: {serviceNames: $serviceNames}\n search: {query: $searchQuery, timeRange: $timeFilter}\n paging: {first: $first}\n orderBy: $orderBy\n ) {\n totalCount\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n __typename\n }\n edges {\n node {\n id\n traceId\n spanId\n time\n transaction\n httpMethod\n httpStatus\n service\n serviceEntityId\n websiteEntityName\n awsLambdaEntityName\n awsLambdaEntityId\n hostEntityName\n hostEntityId\n websiteId\n duration {\n value\n units\n __typename\n }\n __typename\n }\n cursor\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" - } - - for (; retryCount > 0; retryCount--) { - let profileResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(profileSpanQueryPayload), - { - headers: { - 'Content-Type': 'application/json', - 'Cookie': `${__ENV.SWO_COOKIE}`, - 'X-Csrf-Token': `${__ENV.SWO_XSR_TOKEN}` - } - }); - - profileResponse = JSON.parse(profileResponse.body) - if (profileResponse['errors']) { - console.log("Error -> Profile spans response:", JSON.stringify(profileResponse)) - continue - } - - const {data: {trace: {requests: {edges}}}} = profileResponse - if (check(edges, {"code profiling": prop => prop.length > 0})) { - return; - } - } - } -} - -function verify_that_span_data_is_persisted_0() { - let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount > 0; retryCount--) { - const transactionName = "int-test" - const response = http.get(`${webMvcUri}/greet/${transactionName}`, { - headers: { - 'Content-Type': 'application/json', - "x-trace-options": "trigger-trace;custom-info=chubi;sw-keys=lo:se,check-id:123" - } - }); - - const traceContext = response.headers['X-Trace'] - const [_, traceId, __, flag] = traceContext.split("-") - console.log("Trace context -> ", traceContext) - if ((parseInt(flag, 16) & 1) === 0) continue; - - const spanRawDataPayload = { - "operationName": "getSubSpanRawData", - "variables": { - "traceId": traceId.toUpperCase() - }, - "query": "query getSubSpanRawData($traceId: ID!, $spanFilter: TraceArchiveSpanFilter) {\n traceArchive(\n traceId: $traceId\n spanFilter: $spanFilter\n ) {\n traceId\n traceSpans {\n edges {\n node {\n events {\n eventId\n properties {\n key\n value\n __typename\n }\n __typename\n }\n spanId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" - } - - for (; retryCount > 0; retryCount--) { - let spanDataResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(spanRawDataPayload), - { - headers: { - 'Content-Type': 'application/json', - 'Cookie': `${__ENV.SWO_COOKIE}`, - 'X-Csrf-Token': `${__ENV.SWO_XSR_TOKEN}` - } - }); - - spanDataResponse = JSON.parse(spanDataResponse.body) - if (spanDataResponse['errors']) { - console.log("Error -> Persisted trace response:", JSON.stringify(spanDataResponse)) - continue - } - - const {data: {traceArchive: {traceSpans: {edges}}}} = spanDataResponse - for (let i = 0; i < edges.length; i++) { - const edge = edges[i] - const {node: {events}} = edge - - for (let j = 0; j < events.length; j++) { - const event = events[j] - const {properties} = event - - for (let k = 0; k < properties.length; k++) { - const property = properties[k] - check(property, {"trigger trace": prop => prop.key === "TriggeredTrace"}) - - if (property.key === "sw.transaction") { - check(property, {"custom transaction name": prop => prop.value === transactionName}) - return; - } - } - } - } - } - } -} - -function verify_distributed_trace() { - let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount > 0; retryCount--) { - const response = http.get(`${webMvcUri}/distributed`, { - headers: { - 'Content-Type': 'application/json' - } - }); - - const traceContext = response.headers['X-Trace'] - const [_, traceId, __, flag] = traceContext.split("-") - console.log("[Distributed]Trace context -> ", traceContext) - if ((parseInt(flag, 16) & 1) === 0) continue; - - const spanRawDataPayload = { - "operationName": "getSubSpanRawData", - "variables": { - "traceId": traceId.toUpperCase() - }, - "query": "query getSubSpanRawData($traceId: ID!, $spanFilter: TraceArchiveSpanFilter) {\n traceArchive(\n traceId: $traceId\n spanFilter: $spanFilter\n ) {\n traceId\n traceSpans {\n edges {\n node {\n events {\n eventId\n properties {\n key\n value\n __typename\n }\n __typename\n }\n spanId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" - } - - for (; retryCount > 0; retryCount--) { - let spanDataResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(spanRawDataPayload), - { - headers: { - 'Content-Type': 'application/json', - 'Cookie': `${__ENV.SWO_COOKIE}`, - 'X-Csrf-Token': `${__ENV.SWO_XSR_TOKEN}` - } - }); - - spanDataResponse = JSON.parse(spanDataResponse.body) - if (spanDataResponse['errors']) { - console.log("Error -> Distributed trace response:", JSON.stringify(spanDataResponse)) - continue - } - - const {data: {traceArchive: {traceSpans: {edges}}}} = spanDataResponse - console.log("Edges: ", edges) - - - let contextCheck = false - let sdkCheck = false - for (let i = 0; i < edges.length; i++) { - const edge = edges[i] - const {node: {events}} = edge - - for (let j = 0; j < events.length; j++) { - const event = events[j] - const {properties} = event - - for (let k = 0; k < properties.length; k++) { - const property = properties[k] - check(property, { - "check that remote service, java-apm-smoke-test, is path of the trace": prop => { - contextCheck = contextCheck || prop.value === "java-apm-smoke-test" - return contextCheck - } - }) - check(property, { - "sdk-trace": prop => { - sdkCheck = sdkCheck || prop.value === "SDK.trace.test" - return sdkCheck - } - }) - } - - if (contextCheck && sdkCheck) { - return - } - } - } - } - } -} - -function verify_that_specialty_path_is_not_sampled() { - const specialtiesUrl = `${baseUri}/specialties`; - const specialtiesResponse = http.get(specialtiesUrl); - const traceContext = specialtiesResponse.headers['X-Trace'] - - const [_, __, ___, flag] = traceContext.split("-") - check(flag, {"verify that transaction is filtered": f => (parseInt(f, 16) & 1) === 0}) -} - function verify_that_metrics_are_reported(metric, checkFn, service="lambda-e2e") { let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; for (let i = 0; i < retryCount; i++) { @@ -457,84 +169,6 @@ function verify_that_metrics_are_reported(metric, checkFn, service="lambda-e2e") } } -function check_transaction_name(property) { - if (property.key === "sw.transaction") { - check(property, {"transaction-name": prop => prop.value === "lambda-test-txn"}) - return true; - } - return false -} - -function check_code_stack_trace(property) { - if (property.key === "code.stacktrace") { - check(property, {"code.stacktrace": _ => true}) - return true; - } - return false -} - -function check_property(fn) { - let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; - for (; retryCount > 0; retryCount--) { - const newOwner = names.randomOwner(); - const response = http.post(`${baseUri}/owners`, JSON.stringify(newOwner), - { - headers: { - 'Content-Type': 'application/json', - } - } - ); - - const traceContext = response.headers['X-Trace'] - const [_, traceId, __, flag] = traceContext.split("-") - console.log("Trace context -> ", traceContext) - if ((parseInt(flag, 16) & 1) === 0) continue; - - const spanRawDataPayload = { - "operationName": "getSubSpanRawData", - "variables": { - "traceId": traceId.toUpperCase() - }, - "query": "query getSubSpanRawData($traceId: ID!, $spanFilter: TraceArchiveSpanFilter) {\n traceArchive(\n traceId: $traceId\n spanFilter: $spanFilter\n ) {\n traceId\n traceSpans {\n edges {\n node {\n events {\n eventId\n properties {\n key\n value\n __typename\n }\n __typename\n }\n spanId\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" - } - - for (; retryCount > 0; retryCount--) { - let spanDataResponse = http.post(`${__ENV.SWO_HOST_URL}/common/graphql`, JSON.stringify(spanRawDataPayload), - { - headers: { - 'Content-Type': 'application/json', - 'Cookie': `${__ENV.SWO_COOKIE}`, - 'X-Csrf-Token': `${__ENV.SWO_XSR_TOKEN}` - } - }); - - spanDataResponse = JSON.parse(spanDataResponse.body) - if (spanDataResponse['errors']) { - console.log("Error -> Transaction name response:", JSON.stringify(spanDataResponse)) - continue - } - - const {data: {traceArchive: {traceSpans: {edges}}}} = spanDataResponse - for (let i = 0; i < edges.length; i++) { - const edge = edges[i] - const {node: {events}} = edge - - for (let j = 0; j < events.length; j++) { - const event = events[j] - const {properties} = event - - for (let k = 0; k < properties.length; k++) { - const property = properties[k] - if (fn(property)) { - return; - } - } - } - } - } - } -} - function getEntityId() { let retryCount = Number.parseInt(`${__ENV.SWO_RETRY_COUNT}`) || 1000; const entityQueryPayload = { diff --git a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java index c722c9f6..044baa0f 100644 --- a/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java +++ b/smoke-tests/src/test/java/com/solarwinds/SmokeTest.java @@ -192,150 +192,4 @@ void assertThatRuntimeMetrics17AreExported() throws IOException { "$.root_group.checks.['otel-metrics-17'].passes"); assertTrue(passes > 0, "JVM 17+ runtime metric export is broken"); } - - @Test - @Disabled - void assertServiceNameIsSameAsOneInServiceKey() { - Boolean actual = logStreamAnalyzer.getAnswer().get("This log line is used for validation only: service.name: java-apm-smoke-test"); - assertTrue(actual, "service.name is not updated with name in service key"); - } - - @Test - @Disabled - void assertTransactionFiltering() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double fails = ResultsCollector.read(resultJson, "$.root_group.checks.['verify that transaction is filtered'].fails"); - assertEquals(0, fails, "transaction filtering doesn't work"); - } - - @Test - @Disabled - void assertJDBC() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['JDBC is not broken'].passes"); - assertTrue(passes > 0, "JDBC instrumentation doesn't work"); - } - - @Test - @Disabled - void assertXTraceOptions() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['xtrace-options is added to root span'].passes"); - assertTrue(passes > 1, "Xtrace options is not captured in root span"); - } - - @Test - @Disabled - void assertMvcInstrumentation() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['mvc handler name is added'].passes"); - assertTrue(passes > 0, "MVC instrumentation is broken"); - } - - @Test - @Disabled - void assertTriggerTrace() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['trigger trace'].passes"); - assertTrue(passes > 0, "trigger trace is broken"); - } - - @Test - @Disabled - void assertCodeProfiling() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['code profiling'].passes"); - assertTrue(passes > 0, "code profiling is broken"); - } - - @Test - @Disabled - void assertContextPropagation() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['check that remote service, java-apm-smoke-test, is path of the trace'].passes"); - assertTrue(passes > 0, "context propagation is broken"); - } - - @Test - @Disabled - void assertTransactionNaming() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['custom transaction name'].passes"); - assertTrue(passes > 0, "transaction naming is broken"); - } - - @Test - @Disabled - void assertThatJDBCInstrumentationIsApplied() { - Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); - assertTrue(actual, "sw-jdbc instrumentation is not applied"); - } - - @Test - @Disabled - void assertThatSdkTracingIsWorking() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['sdk-trace'].passes"); - assertTrue(passes > 0, "SDK trace is not working, expected a count > 0"); - } - - @Test - @Disabled - void assertThatRequestCountMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['request_count'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatTraceCountMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['tracecount'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatSampleCountMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['samplecount'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatResponseTimeMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['response_time'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatCodeStacktraceIsCaptured() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['code.stacktrace'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatTraceJvmMetricsAreNotCollected() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - assertThrows(PathNotFoundException.class, () -> ResultsCollector.read(resultJson, "$.root_group.checks.['trace.jvm-metrics'].fails")); - } } diff --git a/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java b/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java index 4a4e13e5..9d8b6096 100644 --- a/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java +++ b/smoke-tests/src/test/java/com/solarwinds/SmokeTestV2.java @@ -179,143 +179,4 @@ void assertThatRuntimeMetrics17AreExported() throws IOException { "$.root_group.checks.['otel-metrics-17'].passes"); assertTrue(passes > 0, "JVM 17+ runtime metric export is broken"); } - - @Test - @Disabled - void assertTransactionFiltering() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double fails = ResultsCollector.read(resultJson, "$.root_group.checks.['verify that transaction is filtered'].fails"); - assertEquals(0, fails, "transaction filtering doesn't work"); - } - - @Test - @Disabled - void assertJDBC() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['JDBC is not broken'].passes"); - assertTrue(passes > 0, "JDBC instrumentation doesn't work"); - } - - @Test - @Disabled - void assertXTraceOptions() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['xtrace-options is added to root span'].passes"); - assertTrue(passes > 1, "Xtrace options is not captured in root span"); - } - - @Test - @Disabled - void assertMvcInstrumentation() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['mvc handler name is added'].passes"); - assertTrue(passes > 0, "MVC instrumentation is broken"); - } - - @Test - @Disabled - void assertTriggerTrace() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['trigger trace'].passes"); - assertTrue(passes > 0, "trigger trace is broken"); - } - - @Test - @Disabled - void assertCodeProfiling() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['code profiling'].passes"); - assertTrue(passes > 0, "code profiling is broken"); - } - - @Test - @Disabled - void assertContextPropagation() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['check that remote service, java-apm-smoke-test, is path of the trace'].passes"); - assertTrue(passes > 0, "context propagation is broken"); - } - - @Test - @Disabled - void assertTransactionNaming() throws IOException { - String resultJson = new String(Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['custom transaction name'].passes"); - assertTrue(passes > 0, "transaction naming is broken"); - } - - @Test - @Disabled - void assertThatJDBCInstrumentationIsApplied() { - Boolean actual = logStreamAnalyzer.getAnswer().get("Applying instrumentation: sw-jdbc"); - assertTrue(actual, "sw-jdbc instrumentation is not applied"); - } - - @Test - @Disabled - void assertThatSdkTracingIsWorking() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['sdk-trace'].passes"); - assertTrue(passes > 0, "SDK trace is not working, expected a count > 0"); - } - - @Test - @Disabled - void assertThatRequestCountMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['request_count'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatTraceCountMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['tracecount'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatSampleCountMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['samplecount'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatResponseTimeMetricIsReported() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['response_time'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatCodeStacktraceIsCaptured() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - - double passes = ResultsCollector.read(resultJson, "$.root_group.checks.['code.stacktrace'].passes"); - assertTrue(passes > 0, "Expects a count > 0"); - } - - @Test - @Disabled - void assertThatTraceJvmMetricsAreNotCollected() throws IOException { - String resultJson = new String( - Files.readAllBytes(namingConventions.local.k6Results(Configs.E2E.config.agents().get(0)))); - assertThrows(PathNotFoundException.class, () -> ResultsCollector.read(resultJson, "$.root_group.checks.['trace.jvm-metrics'].fails")); - } } From 192b415b0c6d8f9d985c884c838256a53c95d9dd Mon Sep 17 00:00:00 2001 From: cleverchuk Date: Fri, 15 May 2026 15:21:50 -0400 Subject: [PATCH 4/5] move module and rename package --- settings.gradle.kts | 2 +- {integration-tests => testing/feature-tests}/build.gradle.kts | 1 - .../instrumentation/feature/test}/ContextPropagationTest.java | 2 +- .../instrumentation/feature/test}/MetricsGenerationTest.java | 2 +- .../feature/test}/ProfilingSpanProcessorTest.java | 2 +- .../instrumentation/feature/test}/SdkTracingTest.java | 2 +- .../instrumentation/feature/test}/TransactionFilteringTest.java | 2 +- .../instrumentation/feature/test}/TransactionNamingTest.java | 2 +- .../instrumentation/feature/test}/TriggerTraceTest.java | 2 +- 9 files changed, 8 insertions(+), 9 deletions(-) rename {integration-tests => testing/feature-tests}/build.gradle.kts (95%) rename {integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest => testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test}/ContextPropagationTest.java (96%) rename {integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest => testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test}/MetricsGenerationTest.java (98%) rename {integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest => testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test}/ProfilingSpanProcessorTest.java (97%) rename {integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest => testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test}/SdkTracingTest.java (98%) rename {integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest => testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test}/TransactionFilteringTest.java (98%) rename {integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest => testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test}/TransactionNamingTest.java (96%) rename {integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest => testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test}/TriggerTraceTest.java (98%) diff --git a/settings.gradle.kts b/settings.gradle.kts index 0c3c99c7..85dc7d02 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -49,5 +49,5 @@ include("libs:core") include("libs:config") include("libs:logging") include("libs:sampling") -include("integration-tests") +include("testing:feature-tests") diff --git a/integration-tests/build.gradle.kts b/testing/feature-tests/build.gradle.kts similarity index 95% rename from integration-tests/build.gradle.kts rename to testing/feature-tests/build.gradle.kts index 1e98fdb8..d294d863 100644 --- a/integration-tests/build.gradle.kts +++ b/testing/feature-tests/build.gradle.kts @@ -23,7 +23,6 @@ dependencies { testImplementation(project(":libs:sampling")) testImplementation(project(":libs:core")) testImplementation("jakarta.servlet:jakarta.servlet-api:5.0.0") - testImplementation("org.awaitility:awaitility:4.3.0") } tasks.named("compileTestJava") { diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ContextPropagationTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/ContextPropagationTest.java similarity index 96% rename from integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ContextPropagationTest.java rename to testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/ContextPropagationTest.java index 941c0475..9142f6a6 100644 --- a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ContextPropagationTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/ContextPropagationTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.solarwinds.opentelemetry.integrationtest; +package com.solarwinds.opentelemetry.instrumentation.feature.test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/MetricsGenerationTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/MetricsGenerationTest.java similarity index 98% rename from integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/MetricsGenerationTest.java rename to testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/MetricsGenerationTest.java index 0492b77b..140192bb 100644 --- a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/MetricsGenerationTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/MetricsGenerationTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.solarwinds.opentelemetry.integrationtest; +package com.solarwinds.opentelemetry.instrumentation.feature.test; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ProfilingSpanProcessorTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/ProfilingSpanProcessorTest.java similarity index 97% rename from integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ProfilingSpanProcessorTest.java rename to testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/ProfilingSpanProcessorTest.java index 6af5d59e..1055a1f2 100644 --- a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/ProfilingSpanProcessorTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/ProfilingSpanProcessorTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.solarwinds.opentelemetry.integrationtest; +package com.solarwinds.opentelemetry.instrumentation.feature.test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/SdkTracingTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/SdkTracingTest.java similarity index 98% rename from integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/SdkTracingTest.java rename to testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/SdkTracingTest.java index b7ee8c7a..2b161654 100644 --- a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/SdkTracingTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/SdkTracingTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.solarwinds.opentelemetry.integrationtest; +package com.solarwinds.opentelemetry.instrumentation.feature.test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionFilteringTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionFilteringTest.java similarity index 98% rename from integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionFilteringTest.java rename to testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionFilteringTest.java index ad42a77c..7f05b5f1 100644 --- a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionFilteringTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionFilteringTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.solarwinds.opentelemetry.integrationtest; +package com.solarwinds.opentelemetry.instrumentation.feature.test; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionNamingTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionNamingTest.java similarity index 96% rename from integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionNamingTest.java rename to testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionNamingTest.java index 87dc0d89..57cfa5c6 100644 --- a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TransactionNamingTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionNamingTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.solarwinds.opentelemetry.integrationtest; +package com.solarwinds.opentelemetry.instrumentation.feature.test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TriggerTraceTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TriggerTraceTest.java similarity index 98% rename from integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TriggerTraceTest.java rename to testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TriggerTraceTest.java index 08b1313b..3d213f21 100644 --- a/integration-tests/src/test/java/com/solarwinds/opentelemetry/integrationtest/TriggerTraceTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TriggerTraceTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.solarwinds.opentelemetry.integrationtest; +package com.solarwinds.opentelemetry.instrumentation.feature.test; import static org.assertj.core.api.Assertions.assertThat; From 41711a514fccc6cc67ffd8eea83fa4798a3f3df8 Mon Sep 17 00:00:00 2001 From: cleverchuk Date: Mon, 18 May 2026 10:38:43 -0400 Subject: [PATCH 5/5] pr review --- .../TestAutoConfigurationCustomizer.java | 42 ------ .../feature/test/MetricsGenerationTest.java | 135 +++--------------- .../feature/test/SdkTracingTest.java | 4 +- .../test/TransactionFilteringTest.java | 10 +- 4 files changed, 27 insertions(+), 164 deletions(-) delete mode 100644 testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAutoConfigurationCustomizer.java diff --git a/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAutoConfigurationCustomizer.java b/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAutoConfigurationCustomizer.java deleted file mode 100644 index 4d78f5ca..00000000 --- a/testing/agent-test-extension/src/main/java/com/solarwinds/opentelemetry/extensions/TestAutoConfigurationCustomizer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * © SolarWinds Worldwide, LLC. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.solarwinds.opentelemetry.extensions; - -import com.google.auto.service.AutoService; -import com.solarwinds.joboe.core.settings.TestSettingsReader; -import com.solarwinds.joboe.core.util.TestUtils; -import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; -import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; - -@AutoService(AutoConfigurationCustomizerProvider.class) -public class TestAutoConfigurationCustomizer implements AutoConfigurationCustomizerProvider { - - @Override - public void customize(AutoConfigurationCustomizer autoConfiguration) { - TestSettingsReader reader = TestUtils.initSettingsReader(); - reader.put( - new TestSettingsReader.SettingsMockupBuilder() - .withFlags(true, false, true, true, false) - .withSampleRate(1_000_000) - .build()); - } - - @Override - public int order() { - return Integer.MAX_VALUE; - } -} diff --git a/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/MetricsGenerationTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/MetricsGenerationTest.java index 140192bb..1cea2218 100644 --- a/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/MetricsGenerationTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/MetricsGenerationTest.java @@ -27,130 +27,31 @@ import io.opentelemetry.sdk.metrics.data.MetricData; import java.util.List; import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.Test; +import java.util.stream.Stream; import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class MetricsGenerationTest { @RegisterExtension static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); - @Test - void verifyResponseTimeMetricIsReportedAfterServerSpan() { - Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); - Span span = - tracer.spanBuilder("GET /petclinic/api/owners").setSpanKind(SpanKind.SERVER).startSpan(); - span.end(); - - testing.waitForTraces(1); - await() - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> { - List metrics = testing.metrics(); - assertThat(metrics) - .as("trace.service.response_time metric should be reported") - .anyMatch(m -> m.getName().equals("trace.service.response_time")); - }); - } - - @Test - void verifyRequestCountMetricIsReportedAfterServerSpan() { - Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); - Span span = - tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); - span.end(); - - testing.waitForTraces(1); - await() - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> { - List metrics = testing.metrics(); - assertThat(metrics) - .as("trace.service.request_count metric should be reported") - .anyMatch(m -> m.getName().equals("trace.service.request_count")); - }); - } - - @Test - void verifyTokenbucketExhaustionCountMetricIsReported() { - Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); - Span span = - tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); - span.end(); - - testing.waitForTraces(1); - await() - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> { - List metrics = testing.metrics(); - assertThat(metrics) - .as("trace.service.tokenbucket_exhaustion_count metric should be reported") - .anyMatch(m -> m.getName().equals("trace.service.tokenbucket_exhaustion_count")); - }); - } - - @Test - void verifyTraceCountMetricIsReported() { - Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); - Span span = - tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); - span.end(); - - testing.waitForTraces(1); - await() - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> { - List metrics = testing.metrics(); - assertThat(metrics) - .as("trace.service.tracecount metric should be reported") - .anyMatch(m -> m.getName().equals("trace.service.tracecount")); - }); - } - - @Test - void verifySampleCountMetricIsReported() { - Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); - Span span = - tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); - span.end(); - - testing.waitForTraces(1); - await() - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> { - List metrics = testing.metrics(); - assertThat(metrics) - .as("trace.service.samplecount metric should be reported") - .anyMatch(m -> m.getName().equals("trace.service.samplecount")); - }); - } - - @Test - void verifyThroughTraceCountMetricIsReported() { - Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); - Span span = - tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); - span.end(); - - testing.waitForTraces(1); - await() - .atMost(5, TimeUnit.SECONDS) - .untilAsserted( - () -> { - List metrics = testing.metrics(); - assertThat(metrics) - .as("trace.service.through_trace_count metric should be reported") - .anyMatch(m -> m.getName().equals("trace.service.through_trace_count")); - }); + static Stream metricNames() { + return Stream.of( + Arguments.of("trace.service.response_time"), + Arguments.of("trace.service.request_count"), + Arguments.of("trace.service.tokenbucket_exhaustion_count"), + Arguments.of("trace.service.tracecount"), + Arguments.of("trace.service.samplecount"), + Arguments.of("trace.service.through_trace_count"), + Arguments.of("trace.service.triggered_trace_count")); } - @Test - void verifyTriggeredTraceCountMetricIsReported() { + @ParameterizedTest(name = "{0} metric is reported") + @MethodSource("metricNames") + void verifyMetricIsReportedAfterServerSpan(String metricName) { Tracer tracer = GlobalOpenTelemetry.get().getTracer("test"); Span span = tracer.spanBuilder("GET /petclinic/api/pettypes").setSpanKind(SpanKind.SERVER).startSpan(); @@ -163,8 +64,8 @@ void verifyTriggeredTraceCountMetricIsReported() { () -> { List metrics = testing.metrics(); assertThat(metrics) - .as("trace.service.triggered_trace_count metric should be reported") - .anyMatch(m -> m.getName().equals("trace.service.triggered_trace_count")); + .as("%s metric should be reported", metricName) + .anyMatch(m -> m.getName().equals(metricName)); }); } } diff --git a/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/SdkTracingTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/SdkTracingTest.java index 2b161654..aa20de03 100644 --- a/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/SdkTracingTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/SdkTracingTest.java @@ -84,7 +84,7 @@ void verifyResourceNameFromServiceKey() { "root", () -> { Tracer tracer = GlobalOpenTelemetry.get().getTracer("sdk.tracing"); - Span span = tracer.spanBuilder("code-stacktrace").startSpan(); + Span span = tracer.spanBuilder("resource-name").startSpan(); span.setAttribute("thread.id", "test-1"); span.end(); }); @@ -96,7 +96,7 @@ void verifyResourceNameFromServiceKey() { assertThat(spans).hasSize(2); SpanData spanData = - spans.stream().filter(s -> "code-stacktrace".equals(s.getName())).findFirst().orElseThrow(); + spans.stream().filter(s -> "resource-name".equals(s.getName())).findFirst().orElseThrow(); assertThat(spanData.getResource().getAttributes().get(AttributeKey.stringKey("service.name"))) .isEqualTo("test-app"); } diff --git a/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionFilteringTest.java b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionFilteringTest.java index 7f05b5f1..ae87848f 100644 --- a/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionFilteringTest.java +++ b/testing/feature-tests/src/test/java/com/solarwinds/opentelemetry/instrumentation/feature/test/TransactionFilteringTest.java @@ -19,8 +19,10 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; +import com.solarwinds.joboe.core.settings.SimpleSettingsFetcher; import com.solarwinds.joboe.core.settings.TestSettingsReader; import com.solarwinds.joboe.core.util.TestUtils; +import com.solarwinds.joboe.sampling.ResourceMatcher; import com.solarwinds.joboe.sampling.SampleRateSource; import com.solarwinds.joboe.sampling.SamplingConfiguration; import com.solarwinds.joboe.sampling.SettingsManager; @@ -50,8 +52,7 @@ class TransactionFilteringTest { @BeforeEach void setUp() { - Map urlConfigs = - new LinkedHashMap<>(); + Map urlConfigs = new LinkedHashMap<>(); urlConfigs.put( url -> url.contains("/specialties"), new TraceConfig(0, SampleRateSource.FILE, TracingMode.DISABLED.toFlags())); @@ -64,7 +65,7 @@ void setUp() { .build()); SettingsManager.initialize( - new com.solarwinds.joboe.core.settings.SimpleSettingsFetcher(reader), + new SimpleSettingsFetcher(reader), SamplingConfiguration.builder() .internalTransactionSettings(new TraceConfigs(urlConfigs)) .build()); @@ -78,6 +79,9 @@ void tearDown() { .withFlags(true, false, true, true, false) .withSampleRate(1_000_000) .build()); + + SettingsManager.initialize( + new SimpleSettingsFetcher(reader), SamplingConfiguration.builder().build()); } @Test