diff --git a/instrumentation/grails-3.0/javaagent/src/test/java/test/GrailsTest.java b/instrumentation/grails-3.0/javaagent/src/test/java/test/GrailsTest.java index e71bfe9528ca..054269ebe1af 100644 --- a/instrumentation/grails-3.0/javaagent/src/test/java/test/GrailsTest.java +++ b/instrumentation/grails-3.0/javaagent/src/test/java/test/GrailsTest.java @@ -53,7 +53,7 @@ protected void stopServer(ConfigurableApplicationContext ctx) { @Override protected void configure(HttpServerTestOptions options) { - options.setContextPath(getContextPath()); + options.setContextPath("/xyz"); options.setHasHandlerSpan(unused -> true); options.setHasResponseSpan( endpoint -> endpoint == REDIRECT || endpoint == ERROR || endpoint == NOT_FOUND); @@ -101,10 +101,6 @@ private static Class load(String name) { } } - private static String getContextPath() { - return "/xyz"; - } - @Override public String expectedHttpRoute(ServerEndpoint endpoint) { switch (endpoint) { diff --git a/instrumentation/vaadin-14.2/javaagent/build.gradle.kts b/instrumentation/vaadin-14.2/javaagent/build.gradle.kts index 6ab07f1b2c52..c0aa1f599a59 100644 --- a/instrumentation/vaadin-14.2/javaagent/build.gradle.kts +++ b/instrumentation/vaadin-14.2/javaagent/build.gradle.kts @@ -22,7 +22,7 @@ muzzle { pass { group.set("com.vaadin") module.set("flow-server") - versions.set("[3.1.0,23.3.0)") + versions.set("[3.1.0,)") } } @@ -68,7 +68,7 @@ dependencies { testInstrumentation(project(":instrumentation:tomcat:tomcat-7.0:javaagent")) add("vaadin14LatestTestImplementation", "com.vaadin:vaadin-spring-boot-starter:14.+") - add("latestDepTestImplementation", "com.vaadin:vaadin-spring-boot-starter:23.2.+") + add("latestDepTestImplementation", "com.vaadin:vaadin-spring-boot-starter:+") } configurations { diff --git a/instrumentation/vaadin-14.2/javaagent/src/vaadin142Test/groovy/test/vaadin/Vaadin142Test.groovy b/instrumentation/vaadin-14.2/javaagent/src/vaadin142Test/groovy/test/vaadin/Vaadin142Test.groovy deleted file mode 100644 index b9fe95cf376a..000000000000 --- a/instrumentation/vaadin-14.2/javaagent/src/vaadin142Test/groovy/test/vaadin/Vaadin142Test.groovy +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package test.vaadin - -class Vaadin142Test extends AbstractVaadin14Test { - -} diff --git a/instrumentation/vaadin-14.2/javaagent/src/vaadin142Test/java/io/opentelemetry/javaagent/instrumentation/vaadin/Vaadin142Test.java b/instrumentation/vaadin-14.2/javaagent/src/vaadin142Test/java/io/opentelemetry/javaagent/instrumentation/vaadin/Vaadin142Test.java new file mode 100644 index 000000000000..e33424655424 --- /dev/null +++ b/instrumentation/vaadin-14.2/javaagent/src/vaadin142Test/java/io/opentelemetry/javaagent/instrumentation/vaadin/Vaadin142Test.java @@ -0,0 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vaadin; + +public class Vaadin142Test extends AbstractVaadin14Test {} diff --git a/instrumentation/vaadin-14.2/javaagent/src/vaadin14LatestTest/groovy/test/vaadin/Vaadin14LatestTest.groovy b/instrumentation/vaadin-14.2/javaagent/src/vaadin14LatestTest/groovy/test/vaadin/Vaadin14LatestTest.groovy deleted file mode 100644 index bf8503a035dc..000000000000 --- a/instrumentation/vaadin-14.2/javaagent/src/vaadin14LatestTest/groovy/test/vaadin/Vaadin14LatestTest.groovy +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package test.vaadin - -class Vaadin14LatestTest extends AbstractVaadin14Test { - -} diff --git a/instrumentation/vaadin-14.2/javaagent/src/vaadin14LatestTest/java/test/io/opentelemetry/javaagent/instrumentation/vaadin/Vaadin14LatestTest.java b/instrumentation/vaadin-14.2/javaagent/src/vaadin14LatestTest/java/test/io/opentelemetry/javaagent/instrumentation/vaadin/Vaadin14LatestTest.java new file mode 100644 index 000000000000..aa4b45e81354 --- /dev/null +++ b/instrumentation/vaadin-14.2/javaagent/src/vaadin14LatestTest/java/test/io/opentelemetry/javaagent/instrumentation/vaadin/Vaadin14LatestTest.java @@ -0,0 +1,10 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package test.io.opentelemetry.javaagent.instrumentation.vaadin; + +import io.opentelemetry.javaagent.instrumentation.vaadin.AbstractVaadin14Test; + +public class Vaadin14LatestTest extends AbstractVaadin14Test {} diff --git a/instrumentation/vaadin-14.2/javaagent/src/vaadin16Test/groovy/test/vaadin/Vaadin16Test.groovy b/instrumentation/vaadin-14.2/javaagent/src/vaadin16Test/groovy/test/vaadin/Vaadin16Test.groovy deleted file mode 100644 index bea0524783f3..000000000000 --- a/instrumentation/vaadin-14.2/javaagent/src/vaadin16Test/groovy/test/vaadin/Vaadin16Test.groovy +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package test.vaadin - -class Vaadin16Test extends AbstractVaadin16Test { - -} diff --git a/instrumentation/vaadin-14.2/javaagent/src/vaadin16Test/java/io/opentelemetry/javaagent/instrumentation/vaadin/Vaadin16Test.java b/instrumentation/vaadin-14.2/javaagent/src/vaadin16Test/java/io/opentelemetry/javaagent/instrumentation/vaadin/Vaadin16Test.java new file mode 100644 index 000000000000..d1abb1839a50 --- /dev/null +++ b/instrumentation/vaadin-14.2/javaagent/src/vaadin16Test/java/io/opentelemetry/javaagent/instrumentation/vaadin/Vaadin16Test.java @@ -0,0 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vaadin; + +public class Vaadin16Test extends AbstractVaadin16Test {} diff --git a/instrumentation/vaadin-14.2/javaagent/src/vaadinLatestTest/groovy/test/vaadin/VaadinLatestTest.groovy b/instrumentation/vaadin-14.2/javaagent/src/vaadinLatestTest/groovy/test/vaadin/VaadinLatestTest.groovy deleted file mode 100644 index b8f1bb26bda0..000000000000 --- a/instrumentation/vaadin-14.2/javaagent/src/vaadinLatestTest/groovy/test/vaadin/VaadinLatestTest.groovy +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package test.vaadin - -class VaadinLatestTest extends AbstractVaadin16Test { - -} diff --git a/instrumentation/vaadin-14.2/javaagent/src/vaadinLatestTest/java/io/opentelemetry/javaagent/instrumentation/vaadin/VaadinLatestTest.java b/instrumentation/vaadin-14.2/javaagent/src/vaadinLatestTest/java/io/opentelemetry/javaagent/instrumentation/vaadin/VaadinLatestTest.java new file mode 100644 index 000000000000..7727f36a4482 --- /dev/null +++ b/instrumentation/vaadin-14.2/javaagent/src/vaadinLatestTest/java/io/opentelemetry/javaagent/instrumentation/vaadin/VaadinLatestTest.java @@ -0,0 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vaadin; + +public class VaadinLatestTest extends AbstractVaadin16Test {} diff --git a/instrumentation/vaadin-14.2/testing/src/main/groovy/test/vaadin/AbstractVaadin14Test.groovy b/instrumentation/vaadin-14.2/testing/src/main/groovy/test/vaadin/AbstractVaadin14Test.groovy deleted file mode 100644 index 50b1e8b7bf4f..000000000000 --- a/instrumentation/vaadin-14.2/testing/src/main/groovy/test/vaadin/AbstractVaadin14Test.groovy +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package test.vaadin - - -import com.vaadin.flow.server.Version -import io.opentelemetry.api.trace.SpanKind - -abstract class AbstractVaadin14Test extends AbstractVaadinTest { - static final boolean VAADIN_14_4 = Version.majorVersion >= 2 && Version.minorVersion >= 4 - - List getRequestHandlers() { - List handlers = [ - "PushRequestHandler" - ] - if (VAADIN_14_4) { - handlers.add("DevModeHandler") - } - handlers.addAll([ - "StreamRequestHandler", "UnsupportedBrowserHandler", "UidlRequestHandler", - "HeartbeatHandler", "SessionRequestHandler", "FaviconHandler", "BootstrapHandler" - ]) - - return handlers - } - - @Override - void assertFirstRequest() { - assertTraces(VAADIN_14_4 ? 5 : 4) { - traces.sort(orderByRootSpanName(getContextPath() + "/main", getContextPath() + "/*")) - - def handlers = getRequestHandlers("BootstrapHandler") - trace(0, 2 + handlers.size()) { - serverSpan(it, 0, getContextPath() + "/main") - span(1) { - name "SpringVaadinServletService.handleRequest" - kind SpanKind.INTERNAL - childOf span(0) - } - - int spanIndex = 2 - handlers.each { handler -> - span(spanIndex++) { - name handler + ".handleRequest" - kind SpanKind.INTERNAL - childOf span(1) - } - } - } - // following traces are for javascript files used on page - def count = VAADIN_14_4 ? 3 : 2 - for (i in 0..count) { - trace(1 + i, 1) { - serverSpan(it, 0, getContextPath() + "/*") - } - } - } - } - - @Override - void assertButtonClick() { - assertTraces(1) { - def handlers = getRequestHandlers("UidlRequestHandler") - trace(0, 2 + handlers.size() + 1) { - serverSpan(it, 0, getContextPath() + "/main") - span(1) { - name "SpringVaadinServletService.handleRequest" - kind SpanKind.INTERNAL - childOf span(0) - } - - int spanIndex = 2 - handlers.each { handler -> - span(spanIndex++) { - name handler + ".handleRequest" - kind SpanKind.INTERNAL - childOf span(1) - } - } - span(spanIndex) { - name "EventRpcHandler.handle/click" - kind SpanKind.INTERNAL - childOf span(spanIndex - 1) - } - } - } - } -} diff --git a/instrumentation/vaadin-14.2/testing/src/main/groovy/test/vaadin/AbstractVaadin16Test.groovy b/instrumentation/vaadin-14.2/testing/src/main/groovy/test/vaadin/AbstractVaadin16Test.groovy deleted file mode 100644 index c2256108f38c..000000000000 --- a/instrumentation/vaadin-14.2/testing/src/main/groovy/test/vaadin/AbstractVaadin16Test.groovy +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package test.vaadin - - -import com.vaadin.flow.server.Version -import io.opentelemetry.api.trace.SpanKind -import io.opentelemetry.sdk.trace.data.SpanData - -abstract class AbstractVaadin16Test extends AbstractVaadinTest { - static final boolean VAADIN_17 = Version.majorVersion >= 4 - static final boolean VAADIN_19 = Version.majorVersion >= 6 - static final boolean VAADIN_21 = Version.majorVersion >= 8 - static final boolean VAADIN_22 = Version.majorVersion >= 9 - static final boolean VAADIN_23 = Version.majorVersion >= 23 - static final boolean VAADIN_23_2 = Version.majorVersion > 23 || (Version.majorVersion == 23 && Version.minorVersion >= 2) - - @Override - List getRequestHandlers() { - List handlers = [] - if (VAADIN_23_2) { - handlers.add("ViteHandler") - } else if (VAADIN_22) { - handlers.add("WebpackHandler") - } else if (VAADIN_21) { - handlers.add("DevModeHandlerImpl") - } - handlers.add("PushRequestHandler") - if (VAADIN_19) { - handlers.addAll("WebComponentBootstrapHandler", "WebComponentProvider", "PwaHandler") - } - handlers.addAll([ - "StreamRequestHandler", "UnsupportedBrowserHandler", "UidlRequestHandler", - "HeartbeatHandler", "SessionRequestHandler", "JavaScriptBootstrapHandler", "FaviconHandler"]) - if (!VAADIN_21) { - handlers.add("DevModeHandler") - } - handlers.add("IndexHtmlRequestHandler") - - return handlers - } - - @Override - void assertFirstRequest() { - def tracesCount - if (VAADIN_23_2) { - tracesCount = 12 - } else if (VAADIN_17) { - tracesCount = 9 - } else { - tracesCount = 8 - } - assertTraces(tracesCount) { - traces.sort(orderByRootSpanName("IndexHtmlRequestHandler.handleRequest", - getContextPath() + "/main", getContextPath(), getContextPath() + "/", getContextPath() + "/*", - getContextPath() + "/VAADIN/*")) - - def handlers = getRequestHandlers("IndexHtmlRequestHandler") - trace(0, 2 + handlers.size()) { - serverSpan(it, 0, "IndexHtmlRequestHandler.handleRequest") - span(1) { - name "SpringVaadinServletService.handleRequest" - kind SpanKind.INTERNAL - childOf span(0) - } - int spanIndex = 2 - sortHandlerSpans(spans, spanIndex, handlers) - handlers.each { handler -> - span(spanIndex++) { - name handler + ".handleRequest" - kind SpanKind.INTERNAL - childOf span(1) - } - } - } - handlers = getRequestHandlers("UidlRequestHandler") - trace(1, 2 + handlers.size() + 2) { - serverSpan(it, 0, getContextPath() + "/main") - span(1) { - name "SpringVaadinServletService.handleRequest" - kind SpanKind.INTERNAL - childOf span(0) - } - - int spanIndex = 2 - sortHandlerSpans(spans, spanIndex, handlers) - handlers.each { handler -> - span(spanIndex++) { - name handler + ".handleRequest" - kind SpanKind.INTERNAL - childOf span(1) - } - } - - span(spanIndex) { - name "PublishedServerEventHandlerRpcHandler.handle" - kind SpanKind.INTERNAL - childOf span(spanIndex - 1) - } - span(spanIndex + 1) { - name "JavaScriptBootstrapUI.connectClient" - kind SpanKind.INTERNAL - childOf span(spanIndex) - } - } - handlers = getRequestHandlers("JavaScriptBootstrapHandler") - trace(2, 2 + handlers.size()) { - serverSpan(it, 0, getContextPath()) - span(1) { - name "SpringVaadinServletService.handleRequest" - kind SpanKind.INTERNAL - childOf span(0) - } - int spanIndex = 2 - sortHandlerSpans(spans, spanIndex, handlers) - handlers.each { handler -> - span(spanIndex++) { - name handler + ".handleRequest" - kind SpanKind.INTERNAL - childOf span(1) - } - } - } - // following traces are for javascript files used on page - def count = traces.size() - 4 - for (i in 0..count) { - trace(3 + i, 1) { - def spanName - if (VAADIN_23_2) { - spanName = i != 0 ? getContextPath() + "/*" : getContextPath() + "/" - } else { - spanName = VAADIN_23 && i != 0 ? getContextPath() + "/VAADIN/*" : getContextPath() + "/*" - } - serverSpan(it, 0, spanName) - } - } - } - } - - @Override - void assertButtonClick() { - assertTraces(1) { - def handlers = getRequestHandlers("UidlRequestHandler") - trace(0, 2 + handlers.size() + 1) { - serverSpan(it, 0, getContextPath() + "/main") - span(1) { - name "SpringVaadinServletService.handleRequest" - kind SpanKind.INTERNAL - childOf span(0) - } - - int spanIndex = 2 - sortHandlerSpans(spans, spanIndex, handlers) - handlers.each { handler -> - span(spanIndex++) { - name handler + ".handleRequest" - kind SpanKind.INTERNAL - childOf span(1) - } - } - - span(spanIndex) { - name "EventRpcHandler.handle/click" - kind SpanKind.INTERNAL - childOf span(spanIndex - 1) - } - } - } - } - - static void sortHandlerSpans(List spans, int startIndex, List handlers) { - spans.subList(startIndex, startIndex + handlers.size()).sort({ - // strip .handleRequest from span name to get the handler name - def handlerName = it.name.substring(0, it.name.indexOf('.')) - return handlers.indexOf(handlerName) - }) - } -} diff --git a/instrumentation/vaadin-14.2/testing/src/main/groovy/test/vaadin/AbstractVaadinTest.groovy b/instrumentation/vaadin-14.2/testing/src/main/groovy/test/vaadin/AbstractVaadinTest.groovy deleted file mode 100644 index 7bafc5825b70..000000000000 --- a/instrumentation/vaadin-14.2/testing/src/main/groovy/test/vaadin/AbstractVaadinTest.groovy +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package test.vaadin - -import com.vaadin.flow.server.Version -import com.vaadin.flow.spring.annotation.EnableVaadin -import io.opentelemetry.api.trace.SpanKind -import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification -import io.opentelemetry.instrumentation.test.asserts.TraceAssert -import io.opentelemetry.instrumentation.test.base.HttpServerTestTrait -import org.openqa.selenium.chrome.ChromeOptions -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.context.ConfigurableApplicationContext -import org.testcontainers.Testcontainers -import org.testcontainers.containers.BrowserWebDriverContainer -import org.testcontainers.containers.output.Slf4jLogConsumer -import spock.lang.Shared - -import java.util.concurrent.TimeUnit - -abstract class AbstractVaadinTest extends AgentInstrumentationSpecification implements HttpServerTestTrait { - private static final Logger logger = LoggerFactory.getLogger(AbstractVaadinTest) - - @Shared - BrowserWebDriverContainer browser - - @SpringBootApplication - @EnableVaadin("test.vaadin") - static class TestApplication { - static ConfigurableApplicationContext start(int port, String contextPath) { - def app = new SpringApplication(TestApplication) - app.setDefaultProperties([ - "server.port" : port, - "server.servlet.contextPath" : contextPath, - "server.error.include-message": "always"]) - def context = app.run() - return context - } - } - - def setupSpec() { - setupServer() - - Testcontainers.exposeHostPorts(port) - - browser = new BrowserWebDriverContainer<>() - .withCapabilities(new ChromeOptions()) - .withLogConsumer(new Slf4jLogConsumer(logger)) - browser.start() - - address = new URI("http://host.testcontainers.internal:$port" + getContextPath() + "/") - } - - def cleanupSpec() { - cleanupServer() - browser?.stop() - } - - @Override - ConfigurableApplicationContext startServer(int port) { - // set directory for files generated by vaadin development mode - // by default these go to project root - System.setProperty("vaadin.project.basedir", new File("build/vaadin-" + Version.getFullVersion()).getAbsolutePath()) - return TestApplication.start(port, getContextPath()) - } - - @Override - void stopServer(ConfigurableApplicationContext ctx) { - ctx.close() - } - - @Override - String getContextPath() { - return "/xyz" - } - - def waitForStart(driver) { - // In development mode ui javascript is compiled when application starts - // this involves downloading and installing npm and a bunch of packages - // and running webpack. Wait until all of this is done before starting test. - driver.manage().timeouts().implicitlyWait(3, TimeUnit.MINUTES) - driver.get(address.resolve("main").toString()) - // wait for page to load - driver.findElementById("main.label") - // clear traces so test would start from clean state - clearExportedData() - - driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS) - } - - def getWebDriver() { - return browser.getWebDriver() - } - - abstract List getRequestHandlers() - - def getRequestHandlers(String lastHandler) { - def handlers = getRequestHandlers() - int index = handlers.indexOf(lastHandler) - if (index == -1) { - throw new IllegalStateException("unexpected handler " + lastHandler) - } - return handlers.subList(0, index + 1) - } - - abstract void assertFirstRequest() - - abstract void assertButtonClick() - - static serverSpan(TraceAssert trace, int index, String spanName) { - trace.span(index) { - hasNoParent() - - name spanName - kind SpanKind.SERVER - } - } - - def "test vaadin"() { - setup: - def driver = getWebDriver() - waitForStart(driver) - - // fetch the test page - driver.get(address.resolve("main").toString()) - - expect: - // wait for page to load - "Main view" == driver.findElementById("main.label").getText() - assertFirstRequest() - - clearExportedData() - - when: - // click a button to trigger calling java code in MainView - driver.findElementById("main.button").click() - - then: - // wait for page to load - "Other view" == driver.findElementById("other.label").getText() - assertButtonClick() - - cleanup: - driver.close() - } -} diff --git a/instrumentation/vaadin-14.2/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/vaadin/AbstractVaadin14Test.java b/instrumentation/vaadin-14.2/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/vaadin/AbstractVaadin14Test.java new file mode 100644 index 000000000000..23d6145d40b8 --- /dev/null +++ b/instrumentation/vaadin-14.2/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/vaadin/AbstractVaadin14Test.java @@ -0,0 +1,43 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vaadin; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.List; + +public class AbstractVaadin14Test extends AbstractVaadinTest { + @Override + void assertFirstRequest() { + await() + .untilAsserted( + () -> { + List> traces = testing.waitForTraces(1); + assertThat(traces.get(0)) + .satisfies( + spans -> { + OpenTelemetryAssertions.assertThat(spans.get(0)) + .hasName(getContextPath() + "/main") + .hasNoParent() + .hasKind(SpanKind.SERVER); + OpenTelemetryAssertions.assertThat(spans.get(1)) + .hasName("SpringVaadinServletService.handleRequest") + .hasParent(spans.get(0)) + .hasKind(SpanKind.INTERNAL); + // we don't assert all the handler spans as these vary between + // vaadin versions + OpenTelemetryAssertions.assertThat(spans.get(spans.size() - 1)) + .hasName("BootstrapHandler.handleRequest") + .hasParent(spans.get(1)) + .hasKind(SpanKind.INTERNAL); + }); + }); + } +} diff --git a/instrumentation/vaadin-14.2/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/vaadin/AbstractVaadin16Test.java b/instrumentation/vaadin-14.2/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/vaadin/AbstractVaadin16Test.java new file mode 100644 index 000000000000..4ce41b629ec7 --- /dev/null +++ b/instrumentation/vaadin-14.2/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/vaadin/AbstractVaadin16Test.java @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vaadin; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; +import io.opentelemetry.sdk.testing.assertj.TracesAssert; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.List; + +public class AbstractVaadin16Test extends AbstractVaadinTest { + @Override + void assertFirstRequest() { + await() + .untilAsserted( + () -> { + List> traces = testing.waitForTraces(1); + TracesAssert.assertThat(traces) + .satisfies( + trace -> { + assertThat(trace.get(0)) + .satisfies( + spans -> + OpenTelemetryAssertions.assertThat(spans.get(0)) + .hasName("IndexHtmlRequestHandler.handleRequest") + .hasNoParent() + .hasKind(SpanKind.SERVER)); + assertThat(trace) + .anySatisfy( + spans -> { + OpenTelemetryAssertions.assertThat(spans.get(0)) + .hasName(getContextPath() + "/main") + .hasNoParent() + .hasKind(SpanKind.SERVER); + OpenTelemetryAssertions.assertThat(spans.get(1)) + .hasName("SpringVaadinServletService.handleRequest") + .hasParent(spans.get(0)) + .hasKind(SpanKind.INTERNAL); + // we don't assert all the handler spans as these vary between + // vaadin versions + OpenTelemetryAssertions.assertThat(spans.get(spans.size() - 3)) + .hasName("UidlRequestHandler.handleRequest") + .hasParent(spans.get(1)) + .hasKind(SpanKind.INTERNAL); + OpenTelemetryAssertions.assertThat(spans.get(spans.size() - 2)) + .hasName("PublishedServerEventHandlerRpcHandler.handle") + .hasParent(spans.get(spans.size() - 3)) + .hasKind(SpanKind.INTERNAL); + OpenTelemetryAssertions.assertThat(spans.get(spans.size() - 1)) + .hasName("JavaScriptBootstrapUI.connectClient") + .hasParent(spans.get(spans.size() - 2)) + .hasKind(SpanKind.INTERNAL); + }); + }); + }); + } +} diff --git a/instrumentation/vaadin-14.2/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/vaadin/AbstractVaadinTest.java b/instrumentation/vaadin-14.2/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/vaadin/AbstractVaadinTest.java new file mode 100644 index 000000000000..db674675297a --- /dev/null +++ b/instrumentation/vaadin-14.2/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/vaadin/AbstractVaadinTest.java @@ -0,0 +1,183 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.vaadin; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import com.vaadin.flow.server.Version; +import com.vaadin.flow.spring.annotation.EnableVaadin; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerUsingTest; +import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension; +import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.testcontainers.Testcontainers; +import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.containers.output.Slf4jLogConsumer; + +public abstract class AbstractVaadinTest + extends AbstractHttpServerUsingTest { + + private static final Logger logger = LoggerFactory.getLogger(AbstractVaadinTest.class); + + @RegisterExtension + static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent(); + + private BrowserWebDriverContainer browser; + + @SpringBootApplication + @EnableVaadin("test.vaadin") + static class TestApplication { + public TestApplication() {} + + static ConfigurableApplicationContext start(int port, String contextPath) { + SpringApplication app = new SpringApplication(TestApplication.class); + Map properties = new HashMap<>(); + properties.put("server.port", port); + properties.put("server.servlet.contextPath", contextPath); + properties.put("server.error.include-message", "always"); + app.setDefaultProperties(properties); + return app.run(); + } + } + + @BeforeAll + void setup() throws URISyntaxException { + startServer(); + + Testcontainers.exposeHostPorts(port); + + browser = + new BrowserWebDriverContainer<>() + .withCapabilities(new ChromeOptions()) + .withLogConsumer(new Slf4jLogConsumer(logger)); + browser.start(); + + address = new URI("http://host.testcontainers.internal:" + port + getContextPath() + "/"); + } + + @AfterAll + void cleanup() { + cleanupServer(); + if (browser != null) { + browser.stop(); + } + } + + @Override + protected ConfigurableApplicationContext setupServer() { + // set directory for files generated by vaadin development mode + // by default these go to project root + System.setProperty( + "vaadin.project.basedir", + new File("build/vaadin-" + Version.getFullVersion()).getAbsolutePath()); + return TestApplication.start(port, getContextPath()); + } + + @Override + protected void stopServer(ConfigurableApplicationContext ctx) { + ctx.close(); + } + + @Override + public String getContextPath() { + return "/xyz"; + } + + private void waitForStart(RemoteWebDriver driver) { + // In development mode ui javascript is compiled when application starts + // this involves downloading and installing npm and a bunch of packages + // and running webpack. Wait until all of this is done before starting test. + driver.manage().timeouts().implicitlyWait(3, TimeUnit.MINUTES); + driver.get(address.resolve("main").toString()); + // wait for page to load + driver.findElementById("main.label"); + // clear traces so test would start from clean state + testing.clearData(); + + driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); + } + + private RemoteWebDriver getWebDriver() { + return browser.getWebDriver(); + } + + abstract void assertFirstRequest(); + + private void assertButtonClick() { + await() + .untilAsserted( + () -> { + List> traces = testing.waitForTraces(1); + assertThat(traces.get(0)) + .satisfies( + spans -> { + OpenTelemetryAssertions.assertThat(spans.get(0)) + .hasName(getContextPath() + "/main") + .hasNoParent() + .hasKind(SpanKind.SERVER); + OpenTelemetryAssertions.assertThat(spans.get(1)) + .hasName("SpringVaadinServletService.handleRequest") + .hasParent(spans.get(0)) + .hasKind(SpanKind.INTERNAL); + // we don't assert all the handler spans as these vary between + // vaadin versions + OpenTelemetryAssertions.assertThat(spans.get(spans.size() - 2)) + .hasName("UidlRequestHandler.handleRequest") + .hasParent(spans.get(1)) + .hasKind(SpanKind.INTERNAL); + OpenTelemetryAssertions.assertThat(spans.get(spans.size() - 1)) + .hasName("EventRpcHandler.handle/click") + .hasParent(spans.get(spans.size() - 2)) + .hasKind(SpanKind.INTERNAL); + }); + }); + } + + @Test + public void navigateFromMainToOtherView() { + RemoteWebDriver driver = getWebDriver(); + waitForStart(driver); + + // fetch the test page + driver.get(address.resolve("main").toString()); + + // wait for page to load + assertThat(driver.findElementById("main.label").getText()).isEqualTo("Main view"); + assertFirstRequest(); + + testing.clearData(); + + // click a button to trigger calling java code in MainView + driver.findElementById("main.button").click(); + + // wait for page to load + assertThat(driver.findElementById("other.label").getText()).isEqualTo("Other view"); + assertButtonClick(); + + driver.close(); + } +} diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java index a22674e09ff9..f86e8acc9b2d 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java @@ -26,13 +26,11 @@ import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.context.propagation.TextMapSetter; import io.opentelemetry.instrumentation.testing.GlobalTraceUtil; -import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner; import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; import io.opentelemetry.sdk.testing.assertj.TraceAssert; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.data.StatusData; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; -import io.opentelemetry.testing.internal.armeria.client.WebClient; import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpRequest; import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; import io.opentelemetry.testing.internal.armeria.common.HttpData; @@ -43,7 +41,6 @@ import io.opentelemetry.testing.internal.armeria.common.QueryParams; import io.opentelemetry.testing.internal.armeria.common.RequestHeaders; import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -53,39 +50,16 @@ import org.awaitility.Awaitility; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.ValueSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -public abstract class AbstractHttpServerTest { - private static final Logger logger = LoggerFactory.getLogger(AbstractHttpServerTest.class); +public abstract class AbstractHttpServerTest extends AbstractHttpServerUsingTest { public static final String TEST_REQUEST_HEADER = "X-Test-Request"; public static final String TEST_RESPONSE_HEADER = "X-Test-Response"; - public static final String TEST_CLIENT_IP = "1.1.1.1"; - public static final String TEST_USER_AGENT = "test-user-agent"; - private final HttpServerTestOptions options = new HttpServerTestOptions(); - private InstrumentationTestRunner testing; - private SERVER server; - public WebClient client; - public int port; - public URI address; - - protected abstract SERVER setupServer(); - - protected abstract void stopServer(SERVER server); - - protected final InstrumentationTestRunner testing() { - return testing; - } @BeforeAll void setupOptions() { @@ -94,49 +68,21 @@ void setupOptions() { configure(options); - if (address == null) { - address = buildAddress(); - } - - server = setupServer(); - if (server != null) { - logger.info( - getClass().getName() - + " http server started at: http://localhost:" - + port - + options.contextPath); - } + startServer(); } @AfterAll void cleanup() { - if (server == null) { - logger.info(getClass().getName() + " can't stop null server"); - return; - } - stopServer(server); - server = null; - logger.info(getClass().getName() + " http server stopped at: http://localhost:" + port + "/"); + cleanupServer(); } - protected URI buildAddress() { - try { - return new URI("http://localhost:" + port + options.contextPath + "/"); - } catch (URISyntaxException exception) { - throw new IllegalStateException(exception); - } + @Override + protected final String getContextPath() { + return options.contextPath; } protected void configure(HttpServerTestOptions options) {} - @BeforeEach - void verifyExtension() { - if (testing == null) { - throw new AssertionError( - "Subclasses of AbstractHttpServerTest must register HttpServerInstrumentationExtension"); - } - } - public static T controller(ServerEndpoint endpoint, Supplier closure) { assert Span.current().getSpanContext().isValid() : "Controller should have a parent span."; if (endpoint == NOT_FOUND) { @@ -145,16 +91,6 @@ public static T controller(ServerEndpoint endpoint, Supplier closure) { return GlobalTraceUtil.runWithSpan("controller", () -> closure.get()); } - String resolveAddress(ServerEndpoint uri) { - String url = uri.resolvePath(address).toString(); - // Force HTTP/1 via h1c so upgrade requests don't show up as traces - url = url.replace("http://", "h1c://"); - if (uri.getQuery() != null) { - url += "?" + uri.getQuery(); - } - return url; - } - private AggregatedHttpRequest request(ServerEndpoint uri, String method) { return AggregatedHttpRequest.of(HttpMethod.valueOf(method), resolveAddress(uri)); } @@ -676,16 +612,4 @@ public String expectedHttpRoute(ServerEndpoint endpoint) { return endpoint.resolvePath(address).getPath(); } } - - final void setTesting(InstrumentationTestRunner testing, WebClient client, int port) { - setTesting(testing, client, port, null); - } - - final void setTesting( - InstrumentationTestRunner testing, WebClient client, int port, URI address) { - this.testing = testing; - this.client = client; - this.port = port; - this.address = address; - } } diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerUsingTest.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerUsingTest.java new file mode 100644 index 000000000000..d63a8dbb3cec --- /dev/null +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerUsingTest.java @@ -0,0 +1,102 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.testing.junit.http; + +import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner; +import io.opentelemetry.testing.internal.armeria.client.WebClient; +import java.net.URI; +import java.net.URISyntaxException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public abstract class AbstractHttpServerUsingTest { + private static final Logger logger = LoggerFactory.getLogger(AbstractHttpServerUsingTest.class); + + public static final String TEST_CLIENT_IP = "1.1.1.1"; + public static final String TEST_USER_AGENT = "test-user-agent"; + + InstrumentationTestRunner testing; + private SERVER server; + public WebClient client; + public int port; + public URI address; + + protected abstract SERVER setupServer(); + + protected abstract void stopServer(SERVER server); + + protected final InstrumentationTestRunner testing() { + return testing; + } + + protected void startServer() { + if (address == null) { + address = buildAddress(); + } + + server = setupServer(); + if (server != null) { + logger.info( + getClass().getName() + + " http server started at: http://localhost:" + + port + + getContextPath()); + } + } + + protected abstract String getContextPath(); + + protected void cleanupServer() { + if (server == null) { + logger.info(getClass().getName() + " can't stop null server"); + return; + } + stopServer(server); + server = null; + logger.info(getClass().getName() + " http server stopped at: http://localhost:" + port + "/"); + } + + protected URI buildAddress() { + try { + return new URI("http://localhost:" + port + getContextPath() + "/"); + } catch (URISyntaxException exception) { + throw new IllegalStateException(exception); + } + } + + @BeforeEach + void verifyExtension() { + if (testing == null) { + throw new AssertionError( + "Subclasses of AbstractHttpServerUsingTest must register HttpServerInstrumentationExtension"); + } + } + + protected String resolveAddress(ServerEndpoint uri) { + String url = uri.resolvePath(address).toString(); + // Force HTTP/1 via h1c so upgrade requests don't show up as traces + url = url.replace("http://", "h1c://"); + if (uri.getQuery() != null) { + url += "?" + uri.getQuery(); + } + return url; + } + + final void setTesting(InstrumentationTestRunner testing, WebClient client, int port) { + setTesting(testing, client, port, null); + } + + final void setTesting( + InstrumentationTestRunner testing, WebClient client, int port, URI address) { + this.testing = testing; + this.client = client; + this.port = port; + this.address = address; + } +} diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/HttpServerInstrumentationExtension.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/HttpServerInstrumentationExtension.java index 4098f8dd4e39..1fe14e3ca953 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/HttpServerInstrumentationExtension.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/HttpServerInstrumentationExtension.java @@ -5,8 +5,8 @@ package io.opentelemetry.instrumentation.testing.junit.http; -import static io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest.TEST_CLIENT_IP; -import static io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest.TEST_USER_AGENT; +import static io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerUsingTest.TEST_CLIENT_IP; +import static io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerUsingTest.TEST_USER_AGENT; import io.opentelemetry.instrumentation.test.utils.PortUtils; import io.opentelemetry.instrumentation.testing.AgentTestRunner; @@ -22,7 +22,7 @@ /** * A {@link InstrumentationExtension} which sets up infrastructure, such as a test HTTP client, for - * {@link AbstractHttpServerTest}. + * {@link AbstractHttpServerUsingTest}. */ public final class HttpServerInstrumentationExtension extends InstrumentationExtension { @@ -65,12 +65,12 @@ public void beforeAll(ExtensionContext extensionContext) throws Exception { super.beforeAll(extensionContext); Object testInstance = extensionContext.getRequiredTestInstance(); - if (!(testInstance instanceof AbstractHttpServerTest)) { + if (!(testInstance instanceof AbstractHttpServerUsingTest)) { throw new AssertionError( "HttpServerInstrumentationExtension can only be applied to a subclass of " - + "AbstractHttpServerTest"); + + "AbstractHttpServerUsingTest"); } - ((AbstractHttpServerTest) testInstance).setTesting(getTestRunner(), client, port); + ((AbstractHttpServerUsingTest) testInstance).setTesting(getTestRunner(), client, port); } }