Convert jsf jakarta tests from groovy to java (#11694)

This commit is contained in:
Jay DeLuca 2024-07-04 02:27:47 -04:00 committed by GitHub
parent 4916fb109c
commit d7bd53971f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 401 additions and 349 deletions

View File

@ -1,266 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
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 io.opentelemetry.sdk.trace.data.SpanData
import io.opentelemetry.semconv.ServerAttributes
import io.opentelemetry.semconv.ClientAttributes
import io.opentelemetry.semconv.UserAgentAttributes
import io.opentelemetry.semconv.HttpAttributes
import io.opentelemetry.semconv.NetworkAttributes
import io.opentelemetry.semconv.UrlAttributes
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpRequest
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse
import io.opentelemetry.testing.internal.armeria.common.HttpData
import io.opentelemetry.testing.internal.armeria.common.HttpMethod
import io.opentelemetry.testing.internal.armeria.common.MediaType
import io.opentelemetry.testing.internal.armeria.common.QueryParams
import io.opentelemetry.testing.internal.armeria.common.RequestHeaders
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.util.resource.Resource
import org.eclipse.jetty.webapp.WebAppContext
import org.jsoup.Jsoup
import spock.lang.Unroll
import static io.opentelemetry.api.trace.SpanKind.INTERNAL
import static io.opentelemetry.api.trace.StatusCode.ERROR
abstract class BaseJsfTest extends AgentInstrumentationSpecification implements HttpServerTestTrait<Server> {
def setupSpec() {
setupServer()
}
def cleanupSpec() {
cleanupServer()
}
@Override
Server startServer(int port) {
WebAppContext webAppContext = new WebAppContext()
webAppContext.setContextPath(getContextPath())
// set up test application
webAppContext.setBaseResource(Resource.newSystemResource("test-app"))
Resource extraResource = Resource.newSystemResource("test-app-extra")
if (extraResource != null) {
webAppContext.getMetaData().addWebInfResource(extraResource)
}
def jettyServer = new Server(port)
jettyServer.connectors.each {
it.setHost('localhost')
}
jettyServer.setHandler(webAppContext)
jettyServer.start()
return jettyServer
}
@Override
void stopServer(Server server) {
server.stop()
server.destroy()
}
@Override
String getContextPath() {
return "/jetty-context"
}
@Unroll
def "test #path"() {
setup:
AggregatedHttpResponse response = client.get(address.resolve(path).toString()).aggregate().join()
expect:
response.status().code() == 200
response.contentUtf8().trim() == "Hello"
and:
assertTraces(1) {
trace(0, 1) {
span(0) {
name getContextPath() + "/hello.xhtml"
kind SpanKind.SERVER
hasNoParent()
attributes {
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" "/jetty-context/" + path
"$UserAgentAttributes.USER_AGENT_ORIGINAL" TEST_USER_AGENT
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$HttpAttributes.HTTP_ROUTE" "/jetty-context/" + route
"$ClientAttributes.CLIENT_ADDRESS" { it == null || it == TEST_CLIENT_IP }
}
}
}
}
where:
path | route
"hello.xhtml" | "*.xhtml"
"faces/hello.xhtml" | "faces/*"
}
def "test greeting"() {
// we need to display the page first before posting data to it
setup:
AggregatedHttpResponse response = client.get(address.resolve("greeting.xhtml").toString()).aggregate().join()
def doc = Jsoup.parse(response.contentUtf8())
expect:
response.status().code() == 200
doc.selectFirst("title").text() == "Hello, World!"
and:
assertTraces(1) {
trace(0, 1) {
span(0) {
name getContextPath() + "/greeting.xhtml"
kind SpanKind.SERVER
hasNoParent()
}
}
}
clearExportedData()
when:
// extract parameters needed to post back form
def viewState = doc.selectFirst("[name=jakarta.faces.ViewState]")?.val()
def formAction = doc.selectFirst("#app-form").attr("action")
def jsessionid = formAction.substring(formAction.indexOf("jsessionid=") + "jsessionid=".length())
then:
viewState != null
jsessionid != null
when:
// set up form parameter for post
QueryParams formBody = QueryParams.builder()
.add("app-form", "app-form")
// value used for name is returned in app-form:output-message element
.add("app-form:name", "test")
.add("app-form:submit", "Say hello")
.add("app-form_SUBMIT", "1") // MyFaces
.add("jakarta.faces.ViewState", viewState)
.build()
// use the session created for first request
def request2 = AggregatedHttpRequest.of(
RequestHeaders.builder(HttpMethod.POST, address.resolve("greeting.xhtml;jsessionid=" + jsessionid).toString())
.contentType(MediaType.FORM_DATA)
.build(),
HttpData.ofUtf8(formBody.toQueryString()))
AggregatedHttpResponse response2 = client.execute(request2).aggregate().join()
def responseContent = response2.contentUtf8()
def doc2 = Jsoup.parse(responseContent)
then:
response2.status().code() == 200
doc2.getElementById("app-form:output-message").text() == "Hello test"
and:
assertTraces(1) {
trace(0, 2) {
span(0) {
name getContextPath() + "/greeting.xhtml"
kind SpanKind.SERVER
hasNoParent()
}
handlerSpan(it, 1, span(0), "#{greetingForm.submit()}")
}
}
}
def "test exception"() {
// we need to display the page first before posting data to it
setup:
AggregatedHttpResponse response = client.get(address.resolve("greeting.xhtml").toString()).aggregate().join()
def doc = Jsoup.parse(response.contentUtf8())
expect:
response.status().code() == 200
doc.selectFirst("title").text() == "Hello, World!"
and:
assertTraces(1) {
trace(0, 1) {
span(0) {
name getContextPath() + "/greeting.xhtml"
kind SpanKind.SERVER
hasNoParent()
}
}
}
clearExportedData()
when:
// extract parameters needed to post back form
def viewState = doc.selectFirst("[name=jakarta.faces.ViewState]").val()
def formAction = doc.selectFirst("#app-form").attr("action")
def jsessionid = formAction.substring(formAction.indexOf("jsessionid=") + "jsessionid=".length())
then:
viewState != null
jsessionid != null
when:
// set up form parameter for post
QueryParams formBody = QueryParams.builder()
.add("app-form", "app-form")
// setting name parameter to "exception" triggers throwing exception in GreetingForm
.add("app-form:name", "exception")
.add("app-form:submit", "Say hello")
.add("app-form_SUBMIT", "1") // MyFaces
.add("jakarta.faces.ViewState", viewState)
.build()
// use the session created for first request
def request2 = AggregatedHttpRequest.of(
RequestHeaders.builder(HttpMethod.POST, address.resolve("greeting.xhtml;jsessionid=" + jsessionid).toString())
.contentType(MediaType.FORM_DATA)
.build(),
HttpData.ofUtf8(formBody.toQueryString()))
AggregatedHttpResponse response2 = client.execute(request2).aggregate().join()
then:
response2.status().code() == 500
def ex = new Exception("submit exception")
and:
assertTraces(1) {
trace(0, 2) {
span(0) {
name getContextPath() + "/greeting.xhtml"
kind SpanKind.SERVER
hasNoParent()
status ERROR
errorEvent(ex.class, ex.message)
}
handlerSpan(it, 1, span(0), "#{greetingForm.submit()}", ex)
}
}
}
void handlerSpan(TraceAssert trace, int index, Object parent, String spanName, Exception expectedException = null) {
trace.span(index) {
name spanName
kind INTERNAL
if (expectedException != null) {
status ERROR
errorEvent(expectedException.getClass(), expectedException.getMessage())
}
childOf((SpanData) parent)
}
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import jakarta.servlet.Filter
import jakarta.servlet.FilterChain
import jakarta.servlet.FilterConfig
import jakarta.servlet.ServletException
import jakarta.servlet.ServletRequest
import jakarta.servlet.ServletResponse
class ExceptionFilter implements Filter {
@Override
void init(FilterConfig filterConfig) throws ServletException {
}
@Override
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response)
} catch (Exception exception) {
// to ease testing unwrap our exception to root cause
Exception tmp = exception
while (tmp.getCause() != null) {
tmp = tmp.getCause()
}
if (tmp.getMessage() != null && tmp.getMessage().contains("submit exception")) {
throw tmp
}
throw exception
}
}
@Override
void destroy() {
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
class GreetingForm {
String name = ""
String message = ""
String getName() {
name
}
void setName(String name) {
this.name = name
}
String getMessage() {
return message
}
void submit() {
message = "Hello " + name
if (name == "exception") {
throw new Exception("submit exception")
}
}
}

View File

@ -0,0 +1,317 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.jsf.jakarta;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
import static org.assertj.core.api.Assertions.assertThat;
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.SpanDataAssert;
import io.opentelemetry.sdk.testing.assertj.TraceAssert;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.semconv.ClientAttributes;
import io.opentelemetry.semconv.ExceptionAttributes;
import io.opentelemetry.semconv.HttpAttributes;
import io.opentelemetry.semconv.NetworkAttributes;
import io.opentelemetry.semconv.ServerAttributes;
import io.opentelemetry.semconv.UrlAttributes;
import io.opentelemetry.semconv.UserAgentAttributes;
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpRequest;
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse;
import io.opentelemetry.testing.internal.armeria.common.HttpData;
import io.opentelemetry.testing.internal.armeria.common.HttpMethod;
import io.opentelemetry.testing.internal.armeria.common.MediaType;
import io.opentelemetry.testing.internal.armeria.common.QueryParams;
import io.opentelemetry.testing.internal.armeria.common.RequestHeaders;
import jakarta.servlet.ServletException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
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.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
public abstract class BaseJsfTest extends AbstractHttpServerUsingTest<Server> {
@RegisterExtension
public static final InstrumentationExtension testing =
HttpServerInstrumentationExtension.forAgent();
@BeforeAll
protected void setUp() {
startServer();
}
@AfterAll
protected void cleanUp() {
cleanupServer();
}
@Override
protected Server setupServer() throws Exception {
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath(getContextPath());
// set up test application
webAppContext.setBaseResource(Resource.newSystemResource("test-app"));
Resource extraResource = Resource.newSystemResource("test-app-extra");
if (extraResource != null) {
webAppContext.getMetaData().addWebInfResource(extraResource);
}
Server jettyServer = new Server(port);
jettyServer.setHandler(webAppContext);
jettyServer.start();
return jettyServer;
}
@Override
protected void stopServer(Server server) throws Exception {
server.stop();
server.destroy();
}
@Override
protected String getContextPath() {
return "/jetty-context";
}
@ParameterizedTest
@ArgumentsSource(PathTestArgs.class)
void testPath(String path, String route) {
AggregatedHttpResponse response =
client.get(address.resolve(path).toString()).aggregate().join();
assertThat(response.status().code()).isEqualTo(200);
assertThat(response.contentUtf8().trim()).isEqualTo("Hello");
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName(getContextPath() + "/hello.xhtml")
.hasKind(SpanKind.SERVER)
.hasAttributesSatisfyingExactly(
equalTo(NetworkAttributes.NETWORK_PROTOCOL_VERSION, "1.1"),
equalTo(ServerAttributes.SERVER_ADDRESS, "localhost"),
equalTo(ServerAttributes.SERVER_PORT, port),
equalTo(NetworkAttributes.NETWORK_PEER_ADDRESS, "127.0.0.1"),
satisfies(
NetworkAttributes.NETWORK_PEER_PORT,
val -> val.isInstanceOf(Long.class)),
equalTo(HttpAttributes.HTTP_REQUEST_METHOD, "GET"),
equalTo(UrlAttributes.URL_SCHEME, "http"),
equalTo(UrlAttributes.URL_PATH, getContextPath() + "/" + path),
equalTo(UserAgentAttributes.USER_AGENT_ORIGINAL, TEST_USER_AGENT),
equalTo(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 200),
equalTo(HttpAttributes.HTTP_ROUTE, getContextPath() + "/" + route),
satisfies(
ClientAttributes.CLIENT_ADDRESS,
val ->
val.satisfiesAnyOf(
v -> assertThat(v).isEqualTo(TEST_CLIENT_IP),
v -> assertThat(v).isNull())))));
}
static class PathTestArgs implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of("hello.xhtml", "*.xhtml"), Arguments.of("faces/hello.xhtml", "faces/*"));
}
}
@Test
void testGreeting() {
AggregatedHttpResponse response =
client.get(address.resolve("greeting.xhtml").toString()).aggregate().join();
Document doc = Jsoup.parse(response.contentUtf8());
assertThat(response.status().code()).isEqualTo(200);
assertThat(doc.selectFirst("title").text()).isEqualTo("Hello, World!");
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName(getContextPath() + "/greeting.xhtml")
.hasKind(SpanKind.SERVER)
.hasNoParent()));
testing.clearData();
String viewState = doc.selectFirst("[name=jakarta.faces.ViewState]").val();
String formAction = doc.selectFirst("#app-form").attr("action");
String jsessionid =
formAction.substring(formAction.indexOf("jsessionid=") + "jsessionid=".length());
assertThat(viewState).isNotNull();
assertThat(jsessionid).isNotNull();
// set up form parameter for post
QueryParams formBody =
QueryParams.builder()
.add("app-form", "app-form")
// value used for name is returned in app-form:output-message element
.add("app-form:name", "test")
.add("app-form:submit", "Say hello")
.add("app-form_SUBMIT", "1") // MyFaces
.add("jakarta.faces.ViewState", viewState)
.build();
// use the session created for first request
AggregatedHttpRequest request2 =
AggregatedHttpRequest.of(
RequestHeaders.builder(
HttpMethod.POST,
address.resolve("greeting.xhtml;jsessionid=" + jsessionid).toString())
.contentType(MediaType.FORM_DATA)
.build(),
HttpData.ofUtf8(formBody.toQueryString()));
AggregatedHttpResponse response2 = client.execute(request2).aggregate().join();
String responseContent = response2.contentUtf8();
Document doc2 = Jsoup.parse(responseContent);
assertThat(response2.status().code()).isEqualTo(200);
assertThat(doc2.getElementById("app-form:output-message").text()).isEqualTo("Hello test");
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName(getContextPath() + "/greeting.xhtml")
.hasKind(SpanKind.SERVER)
.hasNoParent(),
span -> handlerSpan(trace, 0, "#{greetingForm.submit()}", null)));
}
@Test
void testException() {
// we need to display the page first before posting data to it
AggregatedHttpResponse response =
client.get(address.resolve("greeting.xhtml").toString()).aggregate().join();
Document doc = Jsoup.parse(response.contentUtf8());
assertThat(response.status().code()).isEqualTo(200);
assertThat(doc.selectFirst("title").text()).isEqualTo("Hello, World!");
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName(getContextPath() + "/greeting.xhtml")
.hasKind(SpanKind.SERVER)
.hasNoParent()));
testing.clearData();
String viewState = doc.selectFirst("[name=jakarta.faces.ViewState]").val();
String formAction = doc.selectFirst("#app-form").attr("action");
String jsessionid =
formAction.substring(formAction.indexOf("jsessionid=") + "jsessionid=".length());
assertThat(viewState).isNotNull();
assertThat(jsessionid).isNotNull();
// set up form parameter for post
QueryParams formBody =
QueryParams.builder()
.add("app-form", "app-form")
// setting name parameter to "exception" triggers throwing exception in GreetingForm
.add("app-form:name", "exception")
.add("app-form:submit", "Say hello")
.add("app-form_SUBMIT", "1") // MyFaces
.add("jakarta.faces.ViewState", viewState)
.build();
// use the session created for first request
AggregatedHttpRequest request2 =
AggregatedHttpRequest.of(
RequestHeaders.builder(
HttpMethod.POST,
address.resolve("greeting.xhtml;jsessionid=" + jsessionid).toString())
.contentType(MediaType.FORM_DATA)
.build(),
HttpData.ofUtf8(formBody.toQueryString()));
AggregatedHttpResponse response2 = client.execute(request2).aggregate().join();
assertThat(response2.status().code()).isEqualTo(500);
ServletException ex = new ServletException("submit exception");
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName(getContextPath() + "/greeting.xhtml")
.hasKind(SpanKind.SERVER)
.hasNoParent()
.hasStatus(StatusData.error())
.hasEventsSatisfyingExactly(
event ->
event
.hasName("exception")
.hasAttributesSatisfyingExactly(
equalTo(
ExceptionAttributes.EXCEPTION_TYPE,
ex.getClass().getName()),
satisfies(
ExceptionAttributes.EXCEPTION_STACKTRACE,
stacktrace -> stacktrace.contains("submit exception")),
satisfies(
ExceptionAttributes.EXCEPTION_MESSAGE,
message -> message.endsWith(ex.getMessage())))),
span -> handlerSpan(trace, 0, "#{greetingForm.submit()}", ex)));
}
List<Consumer<SpanDataAssert>> handlerSpan(
TraceAssert trace, int parentIndex, String spanName, Exception expectedException) {
List<Consumer<SpanDataAssert>> assertions =
new ArrayList<>(
Arrays.asList(
span ->
span.hasName(spanName)
.hasKind(SpanKind.INTERNAL)
.hasParent(trace.getSpan(parentIndex))));
if (expectedException != null) {
assertions.add(
span ->
span.hasStatus(StatusData.error())
.hasEventsSatisfyingExactly(
event ->
event
.hasName("exception")
.hasAttributesSatisfyingExactly(
equalTo(
ExceptionAttributes.EXCEPTION_TYPE,
expectedException.getClass().getName()),
satisfies(
ExceptionAttributes.EXCEPTION_MESSAGE,
message ->
message.startsWithIgnoringCase(
expectedException.getMessage())))));
}
return assertions;
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.jsf.jakarta;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
public class ExceptionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException {
try {
chain.doFilter(request, response);
} catch (Exception exception) {
throw new ServletException(exception);
}
}
@Override
public void destroy() {}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.jsf.jakarta;
public class GreetingForm {
private String name = "";
private String message = "";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMessage() {
return message;
}
public void submit() throws Exception {
message = "Hello " + name;
if (name.equals("exception")) {
throw new Exception("submit exception");
}
}
}

View File

@ -5,7 +5,7 @@
<managed-bean>
<managed-bean-name>greetingForm</managed-bean-name>
<managed-bean-class>GreetingForm</managed-bean-class>
<managed-bean-class>io.opentelemetry.javaagent.instrumentation.jsf.jakarta.GreetingForm</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

View File

@ -5,7 +5,7 @@
<filter>
<filter-name>ExceptionFilter</filter-name>
<filter-class>ExceptionFilter</filter-class>
<filter-class>io.opentelemetry.javaagent.instrumentation.jsf.jakarta.ExceptionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ExceptionFilter</filter-name>

View File

@ -1,7 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
class Mojarra3Test extends BaseJsfTest {
}

View File

@ -0,0 +1,10 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.mojarra.v3_0;
import io.opentelemetry.javaagent.instrumentation.jsf.jakarta.BaseJsfTest;
class Mojarra3Test extends BaseJsfTest {}

View File

@ -1,7 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
class Myfaces3Test extends BaseJsfTest {
}

View File

@ -0,0 +1,10 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.myfaces.v3_0;
import io.opentelemetry.javaagent.instrumentation.jsf.jakarta.BaseJsfTest;
class Myfaces3Test extends BaseJsfTest {}