From e19d535244e6986608c3edd75e0c5aa1203b552b Mon Sep 17 00:00:00 2001 From: Jorge Bescos Gascon Date: Fri, 15 Dec 2023 07:51:02 +0100 Subject: [PATCH] 4.x: Enable disabled TCKs (#7781) Contains JakartaEE10 TCKs and changes in Helidon to pass them. Signed-off-by: Jorge Bescos Gascon --- dependencies/pom.xml | 2 +- .../java/io/helidon/http/PathMatchers.java | 6 +- .../micrometer/cdi/HelloWorldTest.java | 2 + .../cdi/HelidonContainerImpl.java | 9 +- .../config/ConfigCdiExtension.java | 3 +- .../lra/LoadBalancedCoordinatorTest.java | 4 +- .../microprofile/metrics/HelloWorldTest.java | 3 + microprofile/server/pom.xml | 5 + .../server/CatchAllExceptionMapper.java | 60 ++++++ .../server/JaxRsCdiExtension.java | 24 --- .../microprofile/server/JaxRsService.java | 76 +++----- .../server/JaxRsApplicationCodesTest.java | 146 +++++++++++++++ .../JaxRsApplicationMatrixEntityTest.java | 155 ++++++++++++++++ .../JaxRsApplicationOrderFiltersTest.java | 122 ++++++++++++ .../server/JaxRsApplicationPathTest.java | 173 ++++++++++++++++++ .../microprofile/server/ServerSseTest.java | 157 +++++++++++----- .../HelidonContainerConfiguration.java | 60 +++++- .../HelidonDeployableContainer.java | 156 +++++++++------- .../arquillian/HelidonMethodExecutor.java | 7 +- .../microprofile/arquillian/ServerRunner.java | 12 +- microprofile/tests/tck/pom.xml | 1 + .../tests/tck/tck-cdi-lang-model/pom.xml | 103 +++++++++++ .../lang/model/tck/LangModelExtension.java | 43 +++++ .../cdi/lang/model/tck/LangModelTckTest.java | 64 +++++++ .../resources/META-INF/cdi-tck.properties | 24 +++ .../src/test/resources/application.yaml | 19 ++ .../src/test/resources/arquillian.xml | 34 ++++ microprofile/tests/tck/tck-cdi/pom.xml | 66 ++++--- .../tck-cdi/src/test/resources/arquillian.xml | 1 + .../tck-core-profile-test/pom.xml | 8 +- .../src/test/resources/arquillian.xml | 2 +- .../tests/inject/TckInjectTest.java | 21 ++- .../tck/tck-jsonb/tck-jsonb-test/pom.xml | 28 ++- .../META-INF/microprofile-config.properties | 18 ++ .../tests/tck/tck-jsonp/artifact-install.sh | 70 ------- microprofile/tests/tck/tck-jsonp/pom.xml | 29 +-- .../tck-jsonp-pluggability-test/pom.xml | 97 ++++++++++ .../tck/tck-jsonp/tck-jsonp-test/pom.xml | 24 ++- .../metrics/tck/MetricsTckCdiExtension.java | 3 + microprofile/tests/tck/tck-restful/pom.xml | 2 +- .../tck/tck-restful/tck-restful-test/pom.xml | 88 ++++----- .../META-INF/microprofile-config.properties | 17 ++ .../src/test/resources/arquillian.xml | 4 + pom.xml | 22 ++- .../webclient/http1/Http1CallChainBase.java | 1 + .../helidon/webserver/http/HttpRouting.java | 4 +- .../webserver/http1/Http1ServerResponse.java | 3 +- 47 files changed, 1588 insertions(+), 390 deletions(-) create mode 100644 microprofile/server/src/main/java/io/helidon/microprofile/server/CatchAllExceptionMapper.java create mode 100644 microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationCodesTest.java create mode 100644 microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationMatrixEntityTest.java create mode 100644 microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationOrderFiltersTest.java create mode 100644 microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationPathTest.java create mode 100644 microprofile/tests/tck/tck-cdi-lang-model/pom.xml create mode 100644 microprofile/tests/tck/tck-cdi-lang-model/src/test/java/io/helidon/microprofile/cdi/lang/model/tck/LangModelExtension.java create mode 100644 microprofile/tests/tck/tck-cdi-lang-model/src/test/java/io/helidon/microprofile/cdi/lang/model/tck/LangModelTckTest.java create mode 100644 microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/META-INF/cdi-tck.properties create mode 100644 microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/application.yaml create mode 100644 microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/arquillian.xml create mode 100644 microprofile/tests/tck/tck-jsonb/tck-jsonb-test/src/test/resources/META-INF/microprofile-config.properties delete mode 100755 microprofile/tests/tck/tck-jsonp/artifact-install.sh create mode 100644 microprofile/tests/tck/tck-jsonp/tck-jsonp-pluggability-test/pom.xml create mode 100644 microprofile/tests/tck/tck-restful/tck-restful-test/src/test/resources/META-INF/microprofile-config.properties diff --git a/dependencies/pom.xml b/dependencies/pom.xml index e045490d990..0ec8324814e 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -89,7 +89,7 @@ 1.3.0.Final 3.5.3.Final 4.0.3 - 3.1.3 + 3.1.4 6.7.0.202309050840-r 5.9.3 3.6.0 diff --git a/http/http/src/main/java/io/helidon/http/PathMatchers.java b/http/http/src/main/java/io/helidon/http/PathMatchers.java index 9aa0eff66d4..bbaaff18a86 100644 --- a/http/http/src/main/java/io/helidon/http/PathMatchers.java +++ b/http/http/src/main/java/io/helidon/http/PathMatchers.java @@ -24,6 +24,7 @@ import java.util.regex.Pattern; import io.helidon.common.parameters.Parameters; +import io.helidon.common.uri.UriEncoding; import io.helidon.common.uri.UriPath; /** @@ -276,8 +277,9 @@ static final class ExactPathMatcher implements PathMatcher { private final String pathWithTrailingSlash; ExactPathMatcher(String path) { - this.path = path; - this.pathWithTrailingSlash = path + "/"; + // We work with decoded URIs + this.path = UriEncoding.decodeUri(path); + this.pathWithTrailingSlash = this.path + "/"; } @Override diff --git a/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/HelloWorldTest.java b/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/HelloWorldTest.java index 20090adbea3..8bb6a8753eb 100644 --- a/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/HelloWorldTest.java +++ b/integrations/micrometer/cdi/src/test/java/io/helidon/integrations/micrometer/cdi/HelloWorldTest.java @@ -19,6 +19,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.IntStream; +import io.helidon.microprofile.server.CatchAllExceptionMapper; import io.helidon.microprofile.testing.junit5.AddBean; import io.helidon.microprofile.testing.junit5.HelidonTest; @@ -41,6 +42,7 @@ */ @HelidonTest @AddBean(HelloWorldResource.class) +@AddBean(CatchAllExceptionMapper.class) public class HelloWorldTest { @Inject diff --git a/microprofile/cdi/src/main/java/io/helidon/microprofile/cdi/HelidonContainerImpl.java b/microprofile/cdi/src/main/java/io/helidon/microprofile/cdi/HelidonContainerImpl.java index 14d993db4ee..4444c1c6c1d 100644 --- a/microprofile/cdi/src/main/java/io/helidon/microprofile/cdi/HelidonContainerImpl.java +++ b/microprofile/cdi/src/main/java/io/helidon/microprofile/cdi/HelidonContainerImpl.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Map; import java.util.ServiceLoader; -import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Handler; @@ -46,6 +45,8 @@ import jakarta.enterprise.context.BeforeDestroyed; import jakarta.enterprise.context.Destroyed; import jakarta.enterprise.context.Initialized; +import jakarta.enterprise.event.Startup; +import jakarta.enterprise.inject.Any; import jakarta.enterprise.inject.se.SeContainer; import jakarta.enterprise.inject.spi.BeanManager; import jakarta.enterprise.inject.spi.CDI; @@ -96,6 +97,8 @@ final class HelidonContainerImpl extends Weld implements HelidonContainer { private static final Context ROOT_CONTEXT; // whether the current shutdown was invoked by the shutdown hook private static final AtomicBoolean FROM_SHUTDOWN_HOOK = new AtomicBoolean(); + // Default Weld container id. TCKs assumes this value. + private static final String STATIC_INSTANCE = "STATIC_INSTANCE"; static { HelidonFeatures.flavor(HelidonFlavor.MP); @@ -119,7 +122,7 @@ final class HelidonContainerImpl extends Weld implements HelidonContainer { HelidonContainerImpl() { this.bootstrap = new WeldBootstrap(); - id = UUID.randomUUID().toString(); + this.id = STATIC_INSTANCE; } /** @@ -205,6 +208,7 @@ public Collection getResources(String name) { } deployment.getServices().add(ExternalConfiguration.class, configurationBuilder.build()); + // CDI TCK tests expects SE to be excluded, which means Helidon may require to do things that Weld is supposed to do. bootstrap.startContainer(id, Environments.SE, deployment); bootstrap.startInitialization(); @@ -315,6 +319,7 @@ private HelidonContainerImpl doStart() { keepLoggingActive(shutdownHook); bm.getEvent().select(Initialized.Literal.APPLICATION).fire(new ContainerInitialized(id)); + bm.getEvent().select(Any.Literal.INSTANCE).fire(new Startup()); now = System.currentTimeMillis() - now; LOGGER.fine("Container started in " + now + " millis (this excludes the initialization time)"); diff --git a/microprofile/config/src/main/java/io/helidon/microprofile/config/ConfigCdiExtension.java b/microprofile/config/src/main/java/io/helidon/microprofile/config/ConfigCdiExtension.java index 3f1cadb526c..74ed37620b0 100644 --- a/microprofile/config/src/main/java/io/helidon/microprofile/config/ConfigCdiExtension.java +++ b/microprofile/config/src/main/java/io/helidon/microprofile/config/ConfigCdiExtension.java @@ -46,6 +46,7 @@ import jakarta.enterprise.context.Dependent; import jakarta.enterprise.context.spi.CreationalContext; import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.Vetoed; import jakarta.enterprise.inject.spi.AfterBeanDiscovery; import jakarta.enterprise.inject.spi.AfterDeploymentValidation; import jakarta.enterprise.inject.spi.Annotated; @@ -136,7 +137,7 @@ private void processAnnotatedType(@Observes @WithAnnotations(ConfigProperties.cl private void harvestConfigPropertyInjectionPointsFromEnabledObserverMethod(@Observes ProcessObserverMethod event, BeanManager beanManager) { AnnotatedMethod annotatedMethod = event.getAnnotatedMethod(); - if (annotatedMethod != null) { + if (annotatedMethod != null && !annotatedMethod.getDeclaringType().isAnnotationPresent(Vetoed.class)) { List> annotatedParameters = annotatedMethod.getParameters(); if (annotatedParameters != null) { for (AnnotatedParameter annotatedParameter : annotatedParameters) { diff --git a/microprofile/lra/jax-rs/src/test/java/io/helidon/microprofile/lra/LoadBalancedCoordinatorTest.java b/microprofile/lra/jax-rs/src/test/java/io/helidon/microprofile/lra/LoadBalancedCoordinatorTest.java index a9a2e6d37ff..fe31cc26999 100644 --- a/microprofile/lra/jax-rs/src/test/java/io/helidon/microprofile/lra/LoadBalancedCoordinatorTest.java +++ b/microprofile/lra/jax-rs/src/test/java/io/helidon/microprofile/lra/LoadBalancedCoordinatorTest.java @@ -46,6 +46,7 @@ import io.helidon.microprofile.lra.resources.StartAndAfter; import io.helidon.microprofile.lra.resources.Timeout; import io.helidon.microprofile.lra.resources.Work; +import io.helidon.microprofile.server.CatchAllExceptionMapper; import io.helidon.microprofile.server.JaxRsCdiExtension; import io.helidon.microprofile.server.ServerCdiExtension; import io.helidon.microprofile.testing.junit5.AddBean; @@ -94,7 +95,8 @@ @AddExtension(CdiComponentProvider.class) // LRA client @AddExtension(LraCdiExtension.class) -// Test resources +// resources +@AddBean(CatchAllExceptionMapper.class) @AddBean(JaxRsCompleteOrCompensate.class) @AddBean(NonJaxRsCompleteOrCompensate.class) @AddBean(NonJaxRsCompleteOrCompensateCS.class) diff --git a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldTest.java b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldTest.java index 2b53203fbcf..dc346892d0d 100644 --- a/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldTest.java +++ b/microprofile/metrics/src/test/java/io/helidon/microprofile/metrics/HelloWorldTest.java @@ -24,6 +24,8 @@ import java.util.regex.Pattern; import java.util.stream.IntStream; +import io.helidon.microprofile.server.CatchAllExceptionMapper; +import io.helidon.microprofile.testing.junit5.AddBean; import io.helidon.microprofile.testing.junit5.AddConfig; import io.helidon.microprofile.testing.junit5.HelidonTest; @@ -55,6 +57,7 @@ @HelidonTest @AddConfig(key = "metrics." + MetricsCdiExtension.REST_ENDPOINTS_METRIC_ENABLED_PROPERTY_NAME, value = "true") @AddConfig(key = "metrics.permit-all", value = "true") +@AddBean(CatchAllExceptionMapper.class) class HelloWorldTest { @Inject diff --git a/microprofile/server/pom.xml b/microprofile/server/pom.xml index b053fed4313..90b31feeb94 100644 --- a/microprofile/server/pom.xml +++ b/microprofile/server/pom.xml @@ -31,6 +31,11 @@ Helidon Microprofile Server Server of the microprofile implementation + + -Xmx1024m -Dfile.encoding=UTF-8 -Dorg.jboss.weld.construction.relaxed=false + -Xmx1024m -Dfile.encoding=UTF-8 -Dorg.jboss.weld.construction.relaxed=false + + io.helidon.config diff --git a/microprofile/server/src/main/java/io/helidon/microprofile/server/CatchAllExceptionMapper.java b/microprofile/server/src/main/java/io/helidon/microprofile/server/CatchAllExceptionMapper.java new file mode 100644 index 00000000000..43ff30379ed --- /dev/null +++ b/microprofile/server/src/main/java/io/helidon/microprofile/server/CatchAllExceptionMapper.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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 io.helidon.microprofile.server; + +import java.lang.System.Logger.Level; + +import io.helidon.webserver.http.ServerRequest; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +/** + * Mapper for exceptions that are not caught. + * + * It is not configured by default in Helidon but it is provided for explicit usage. + */ +@Provider +@Priority(5000) +public class CatchAllExceptionMapper implements ExceptionMapper { + + private static final System.Logger LOGGER = System.getLogger(CatchAllExceptionMapper.class.getName()); + + @Context + private ServerRequest serverRequest; + + /** + * Default empty constructor. + */ + public CatchAllExceptionMapper() { + } + + @Override + public Response toResponse(Exception exception) { + serverRequest.context().register("unmappedException", exception); + if (exception instanceof WebApplicationException wae) { + return wae.getResponse(); + } else { + LOGGER.log(Level.WARNING, () -> "Internal server error", exception); + return Response.serverError().build(); + } + } +} diff --git a/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsCdiExtension.java b/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsCdiExtension.java index 1cb1cbe845e..e74fc4a1cca 100644 --- a/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsCdiExtension.java +++ b/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsCdiExtension.java @@ -26,8 +26,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import io.helidon.webserver.http.ServerRequest; - import jakarta.annotation.Priority; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.Initialized; @@ -35,11 +33,7 @@ import jakarta.enterprise.inject.spi.Extension; import jakarta.enterprise.inject.spi.ProcessManagedBean; import jakarta.ws.rs.Path; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Application; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; @@ -277,29 +271,11 @@ JaxRsService toJerseySupport(JaxRsApplication jaxRsApplication, InjectionManager injectionManager) { ResourceConfig resourceConfig = jaxRsApplication.resourceConfig(); - resourceConfig.register(new CatchAllExceptionMapper()); return JaxRsService.create(resourceConfig, injectionManager); } - @Provider - private static class CatchAllExceptionMapper implements ExceptionMapper { - @Context - private ServerRequest serverRequest; - - @Override - public Response toResponse(Exception exception) { - serverRequest.context().register("unmappedException", exception); - if (exception instanceof WebApplicationException wae) { - return wae.getResponse(); - } else { - LOGGER.log(Level.WARNING, () -> "Internal server error", exception); - return Response.serverError().build(); - } - } - } - Optional findContextRoot(io.helidon.config.Config config, JaxRsApplication jaxRsApplication) { return config.get(jaxRsApplication.appClassName() + "." + RoutingPath.CONFIG_KEY_PATH) .asString() diff --git a/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsService.java b/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsService.java index bdaeb5a4138..04188e1c769 100644 --- a/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsService.java +++ b/microprofile/server/src/main/java/io/helidon/microprofile/server/JaxRsService.java @@ -69,9 +69,6 @@ import org.glassfish.jersey.server.spi.Container; import org.glassfish.jersey.server.spi.ContainerResponseWriter; -import static org.glassfish.jersey.CommonProperties.PROVIDER_DEFAULT_DISABLE; -import static org.glassfish.jersey.server.ServerProperties.WADL_FEATURE_DISABLE; - class JaxRsService implements HttpService { /** * If set to {@code "true"}, Jersey will ignore responses in exceptions. @@ -98,8 +95,6 @@ private JaxRsService(ResourceConfig resourceConfig, } static JaxRsService create(ResourceConfig resourceConfig, InjectionManager injectionManager) { - resourceConfig.property(PROVIDER_DEFAULT_DISABLE, "ALL"); - resourceConfig.property(WADL_FEATURE_DISABLE, "true"); InjectionManager ij = injectionManager == null ? null : new InjectionManagerWrapper(injectionManager, resourceConfig); ApplicationHandler appHandler = new ApplicationHandler(resourceConfig, @@ -121,7 +116,7 @@ static JaxRsService create(ResourceConfig resourceConfig, InjectionManager injec return new JaxRsService(resourceConfig, appHandler, container); } - static String basePath(UriPath path) { + private static String basePath(UriPath path) { String reqPath = path.path(); String absPath = path.absolute().path(); String basePath = absPath.substring(0, absPath.length() - reqPath.length() + 1); @@ -179,14 +174,6 @@ private static Application getApplication(ResourceConfig resourceConfig) { return application; } - private static URI baseUri(ServerRequest req) { - String uri = (req.isSecure() ? "https" : "http") - + "://" + req.authority() - + basePath(req.path()); - - return URI.create(uri); - } - private void handle(ServerRequest req, ServerResponse res) { Context context = req.context(); @@ -199,19 +186,9 @@ private void handle(ServerRequest req, ServerResponse res) { } private void doHandle(Context ctx, ServerRequest req, ServerResponse res) { - URI baseUri = baseUri(req); - URI requestUri; - - String rawPath = req.path().rawPath(); - rawPath = rawPath.startsWith("/") ? rawPath.substring(1) : rawPath; - if (req.query().isEmpty()) { - requestUri = baseUri.resolve(rawPath); - } else { - requestUri = baseUri.resolve(rawPath + "?" + req.query().rawValue()); - } - - ContainerRequest requestContext = new ContainerRequest(baseUri, - requestUri, + BaseUriRequestUri uris = BaseUriRequestUri.resolve(req); + ContainerRequest requestContext = new ContainerRequest(uris.baseUri, + uris.requestUri, req.prologue().method().text(), new HelidonMpSecurityContext(), new MapPropertiesDelegate(), resourceConfig); @@ -357,7 +334,7 @@ public OutputStream writeResponseStatusAndHeaders(long contentLengthParam, if (contentLength > 0) { res.header(HeaderValues.create(HeaderNames.CONTENT_LENGTH, String.valueOf(contentLength))); } - this.outputStream = new NoFlushOutputStream(res.outputStream()); + this.outputStream = res.outputStream(); return outputStream; } @@ -414,36 +391,25 @@ public void await() { } } - private static class NoFlushOutputStream extends OutputStream { - private final OutputStream delegate; - - private NoFlushOutputStream(OutputStream delegate) { - this.delegate = delegate; - } - - @Override - public void write(byte[] b) throws IOException { - delegate.write(b); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - delegate.write(b, off, len); - } + private static class BaseUriRequestUri { + private final URI baseUri; + private final URI requestUri; - @Override - public void flush() { - // intentional no-op, flush did not work nicely with Jersey + private BaseUriRequestUri(URI baseUri, URI requestUri) { + this.baseUri = baseUri; + this.requestUri = requestUri; } - @Override - public void close() throws IOException { - delegate.close(); - } - - @Override - public void write(int b) throws IOException { - delegate.write(b); + private static BaseUriRequestUri resolve(ServerRequest req) { + String processedBasePath = basePath(req.path()); + String rawPath = req.path().absolute().rawPath(); + String prefix = (req.isSecure() ? "https" : "http") + "://" + req.authority(); + String serverBasePath = prefix + processedBasePath; + String requestPath = prefix + rawPath; + if (!req.query().isEmpty()) { + requestPath = requestPath + "?" + req.query().rawValue(); + } + return new BaseUriRequestUri(URI.create(serverBasePath), URI.create(requestPath)); } } } diff --git a/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationCodesTest.java b/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationCodesTest.java new file mode 100644 index 00000000000..49d1da892c5 --- /dev/null +++ b/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationCodesTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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 io.helidon.microprofile.server; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerResponseContext; +import jakarta.ws.rs.container.ContainerResponseFilter; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.ResponseBuilder; +import jakarta.ws.rs.core.UriInfo; +import jakarta.ws.rs.ext.Provider; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class JaxRsApplicationCodesTest { + + private static Server server; + private static Client client; + private static int port; + + @BeforeAll + static void beforeAll() { + server = Server.builder().addApplication(MyApplication.class).build(); + server.start(); + port = server.port(); + client = ClientBuilder.newBuilder().build(); + } + + @AfterAll + static void afterAll() { + server.stop(); + client.close(); + } + + @Test + void codesTest() { + for (Response.Status status : Response.Status.values()) { + testChecks(status); + } + } + + @Test + void issue304Test() { + testChecks(Response.Status.NO_CONTENT); + testChecks(Response.Status.NOT_MODIFIED); + testChecks(Response.Status.OK); + } + + private void testChecks(Response.Status status) { + Entity entity = Entity.text(String.valueOf(status.getStatusCode())); + int statusCode = client.target("http://localhost:" + port) + .path("/resource/setstatus") + .request() + .post(entity) + .getStatus(); + assertThat(statusCode, is(status.getStatusCode())); + } + + @ApplicationPath("/") + static class MyApplication extends Application { + + @Override + public java.util.Set> getClasses() { + Set> resources = new HashSet>(); + resources.add(TestResource.class); + resources.add(TestFilter.class); + return resources; + } + } + + @Path("/resource") + public static class TestResource { + + @Context + UriInfo info; + + @POST + @Path("setstatus") + public Response setStatus(String status) { + ResponseBuilder builder = createResponseWithHeader(); + Response response = builder.entity(status).build(); + return response; + } + + private ResponseBuilder createResponseWithHeader() { + Response.ResponseBuilder builder = Response.ok(); + // set a header with ContextOperation so that the filter knows what to do + builder = builder.header("OPERATION", "SETSTATUS"); + return builder; + } + } + + @Provider + public static class TestFilter implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + String entity = (String) responseContext.getEntity(); + int status = Integer.parseInt(entity); + responseContext.setStatus(status); + resetStatusEntity(status, responseContext); + } + + private void resetStatusEntity(int status, ContainerResponseContext responseContext) { + switch (status) { + case 204: + case 304: + case 205: + responseContext.setEntity(null); + break; + } + } + } + +} diff --git a/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationMatrixEntityTest.java b/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationMatrixEntityTest.java new file mode 100644 index 00000000000..58a4f8cd680 --- /dev/null +++ b/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationMatrixEntityTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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 io.helidon.microprofile.server; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +import java.util.HashSet; +import java.util.Set; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.MatrixParam; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class JaxRsApplicationMatrixEntityTest { + + private static final String FOO = "foo"; + private static final String BAR = "bar"; + private static Server server; + private static Client client; + private static int port; + + @BeforeAll + static void beforeAll() { + server = Server.builder().addApplication(MyApplication.class).build(); + server.start(); + port = server.port(); + client = ClientBuilder.newClient(); + } + + @AfterAll + static void afterAll() { + server.stop(); + client.close(); + } + + @Test + void defaultValueField() { + String getResponse = client.target("http://localhost:" + port) + .path("/field").request().get(String.class); + assertThat(getResponse, is(equalTo(FOO))); + } + + @Test + void customValueField() { + String getResponse = client.target("http://localhost:" + port) + .path("/field;matrix=" + BAR).request().get(String.class); + assertThat(getResponse, is(equalTo(BAR))); + } + + @Test + void customAndDefaultValueField() { + String getResponse = client.target("http://localhost:" + port) + .path("/field").request().get(String.class); + assertThat(getResponse, is(equalTo(FOO))); + getResponse = client.target("http://localhost:" + port) + .path("/field;matrix=" + BAR).request().get(String.class); + assertThat(getResponse, is(equalTo(BAR))); + } + + @Test + void defaultValueParam() { + String getResponse = client.target("http://localhost:" + port) + .path("/param").request().get(String.class); + assertThat(getResponse, is(equalTo(FOO))); + } + + @Test + void customValueParam() { + String getResponse = client.target("http://localhost:" + port) + .path("/param;matrix=" + BAR).request().get(String.class); + assertThat(getResponse, is(equalTo(BAR))); + } + + @ApplicationPath("/") + static class MyApplication extends Application { + + @Override + public java.util.Set> getClasses() { + Set> resources = new HashSet>(); + resources.add(TestResource.class); + return resources; + } + } + + @Path("/") + public static class TestResource { + + @BeanParam + MatrixBeanParamEntity entity; + + @GET + @Path("field") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public String field() { + return entity.field.value; + } + + @GET + @Path("param") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public String param(@BeanParam MatrixBeanParamEntity entity) { + return entity.field.value; + } + + } + + public static class MatrixBeanParamEntity { + + @DefaultValue(FOO) + @MatrixParam("matrix") + public FieldStr field; + + } + + public static class FieldStr { + + private final String value; + + public FieldStr(String value) { + this.value = value; + } + + } +} diff --git a/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationOrderFiltersTest.java b/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationOrderFiltersTest.java new file mode 100644 index 00000000000..c96d858ef5c --- /dev/null +++ b/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationOrderFiltersTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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 io.helidon.microprofile.server; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import jakarta.annotation.Priority; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.Provider; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class JaxRsApplicationOrderFiltersTest { + + private static Server server; + private static Client client; + private static int port; + + @BeforeAll + static void beforeAll() { + server = Server.builder().addApplication(MyApplication.class).build(); + server.start(); + port = server.port(); + client = ClientBuilder.newClient(); + } + + @AfterAll + static void afterAll() { + server.stop(); + client.close(); + } + + @Test + void changeOrderTest() { + Response response = client.target("http://localhost:" + port) + .path("/echo").register(SecondFilter.class, 100) + .register(FirstFilter.class, 200) + .request().post(Entity.text("test")); + assertThat(response.readEntity(String.class), is(FirstFilter.class.getName())); + } + + @Test + void priorityOrderTest() { + Response response = client.target("http://localhost:" + port) + .path("/echo").register(SecondFilter.class) + .register(FirstFilter.class) + .request().post(Entity.text("test")); + assertThat(response.readEntity(String.class), is(SecondFilter.class.getName())); + } + + @ApplicationPath("/") + static class MyApplication extends Application { + + @Override + public java.util.Set> getClasses() { + Set> resources = new HashSet>(); + resources.add(Resource.class); + return resources; + } + } + + @Path("/") + public static class Resource { + @POST + @Path("echo") + public String echo(String value) { + return value; + } + } + + @Provider + @Priority(100) + public static class FirstFilter implements ClientRequestFilter { + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + requestContext.setEntity(getClass().getName(), null, MediaType.WILDCARD_TYPE); + } + + } + + @Provider + @Priority(200) + public static class SecondFilter implements ClientRequestFilter { + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + requestContext.setEntity(getClass().getName(), null, MediaType.WILDCARD_TYPE); + } + + } +} diff --git a/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationPathTest.java b/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationPathTest.java new file mode 100644 index 00000000000..523b596d162 --- /dev/null +++ b/microprofile/server/src/test/java/io/helidon/microprofile/server/JaxRsApplicationPathTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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 io.helidon.microprofile.server; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.util.HashSet; +import java.util.Set; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Encoded; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.UriInfo; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +class JaxRsApplicationPathTest { + + private static Server server; + private static Client client; + private static int port; + + @BeforeAll + static void beforeAll() { + server = Server.builder().addApplication(MyApplication.class).build(); + server.start(); + port = server.port(); + client = ClientBuilder.newClient(); + } + + @AfterAll + static void afterAll() { + server.stop(); + client.close(); + } + + @Test + void okTest() { + String getResponse = client.target("http://localhost:" + port) + .path("/ApplicationPath!/Resource").request().get(String.class); + assertThat(getResponse, is("ok")); + } + + @Test + void nokTest() { + int status = client.target("http://localhost:" + port) + .path("/Resource").request().get().getStatus(); + assertThat(status, is(404)); + } + + @Test + void emptyParamTest() { + String getResponse = client.target("http://localhost:" + port) + .path("/ApplicationPath!/Resource/pathparam1/%20/%2010").request().get(String.class); + assertThat(getResponse, is("a= b= 10")); + } + + @Test + public void testEncoded() { + String getResponse = client.target("http://localhost:" + port) + .path("/ApplicationPath!/Resource/encoded").queryParam("query", "%dummy23+a") + .request().get(String.class); + assertThat(getResponse, is("true:%25dummy23%2Ba")); + } + + @Test + public void testDecoded() { + String getResponse = client.target("http://localhost:" + port) + .path("/ApplicationPath!/Resource/decoded").queryParam("query", "%dummy23+a") + .request().get(String.class); + assertThat(getResponse, is("true:%dummy23+a")); + } + + @Test + void encodedEntityTest() { + String getResponse = client.target("http://localhost:" + port) + .path("/ApplicationPath!/Resource/ParamEntityWithFromString/test%21/test!/test!/test%21") + .request().get(String.class); + assertThat(getResponse, is("test%21test!test!test!")); + } + + @ApplicationPath("/ApplicationPath%21") + static class MyApplication extends Application { + + @Override + public java.util.Set> getClasses() { + Set> resources = new HashSet>(); + resources.add(TestResource.class); + return resources; + } + } + + @Path("/Resource") + public static class TestResource { + + @GET + public String param() { + return "ok"; + } + + @GET + @Path("/pathparam1/{a}/{b}") + public String pathparamTest1(@Context UriInfo info) { + StringBuilder buf = new StringBuilder(); + for (String param : info.getPathParameters(true).keySet()) { + buf.append(param + "=" + info.getPathParameters(true).getFirst(param)); + } + return buf.toString(); + } + + @GET + @Path("/ParamEntityWithFromString/{encoded}/{notEncoded}/{encoded2}/{notEncoded2}") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public String stringParamHandlingFromString( + @BeanParam PathBeanParamEntity bean) { + return bean.encoded + bean.notEncoded + bean.encoded2 + bean.notEncoded2; + } + + @GET + @Path("encoded") + public String getEncoded(@Encoded @QueryParam("query") String queryParam) { + return queryParam.equals("%25dummy23%2Ba") + ":" + queryParam; + } + + @GET + @Path("decoded") + public String getDecoded(@QueryParam("query") String queryParam) { + return queryParam.equals("%dummy23+a") + ":" + queryParam; + } + } + + static class PathBeanParamEntity { + @Encoded + @PathParam("encoded") + public String encoded; + @PathParam("notEncoded") + public String notEncoded; + @Encoded + @PathParam("encoded2") + public String encoded2; + @PathParam("notEncoded2") + public String notEncoded2; + } +} diff --git a/microprofile/server/src/test/java/io/helidon/microprofile/server/ServerSseTest.java b/microprofile/server/src/test/java/io/helidon/microprofile/server/ServerSseTest.java index bdb3d82d7af..437f55e1749 100644 --- a/microprofile/server/src/test/java/io/helidon/microprofile/server/ServerSseTest.java +++ b/microprofile/server/src/test/java/io/helidon/microprofile/server/ServerSseTest.java @@ -30,12 +30,15 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.WebTarget; import jakarta.ws.rs.core.Application; import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; import jakarta.ws.rs.sse.Sse; import jakarta.ws.rs.sse.SseEventSink; import jakarta.ws.rs.sse.SseEventSource; @@ -55,6 +58,7 @@ class ServerSseTest { private final CompletableFuture connClosedFuture = new CompletableFuture<>(); private final CompletableFuture multiTestFuture = new CompletableFuture<>(); + private final CompletableFuture retryAfterFuture = new CompletableFuture<>(); @BeforeAll static void initClass() { @@ -68,92 +72,134 @@ static void destroyClass() { @Test void testSse() throws Exception { - innerTest("test1", connClosedFuture, 4); + Server server = Server.builder() + .addApplication("/", new TestApplication1()) + .port(0) + .build(); + server.start(); + try { + innerTest("test1", connClosedFuture, 4, server.port()); + // Give some time to close + TimeUnit.SECONDS.sleep(5); + assertThat(TestResource1.closed, is(true)); + } finally { + server.stop(); + } } @Test // succeeds void testSseMulti() throws Exception { - innerTest("test2", multiTestFuture, 4); + Server server = Server.builder() + .addApplication("/", new TestApplication1()) + .port(0) + .build(); + server.start(); + try { + innerTest("test2", multiTestFuture, 4, server.port()); + } finally { + server.stop(); + } } @Test void testSseSingleEvent() throws Exception { - innerTest("test3", null, 1); + Server server = Server.builder() + .addApplication("/", new TestApplication1()) + .port(0) + .build(); + server.start(); + try { + innerTest("test3", null, 1, server.port()); + } finally { + server.stop(); + } } - private void innerTest(String endpoint, CompletableFuture future, int eventNum) { + @Test + void testRetryAfter() throws Exception { Server server = Server.builder() .addApplication("/", new TestApplication1()) .port(0) .build(); - server.start(); try { - // Set up SSE event source - WebTarget target = client.target("http://localhost:" + server.port()).path(endpoint).path("sse"); + WebTarget target = client.target("http://localhost:" + server.port()) + .path("test4").path("sse"); SseEventSource sseEventSource = SseEventSource.target(target).build(); - CountDownLatch count = new CountDownLatch(eventNum); - sseEventSource.register(event -> { - try { - event.readData(String.class); - } finally { - count.countDown(); - } - }, - exception -> { + sseEventSource.register(event -> event.readData(String.class)); + sseEventSource.open(); + retryAfterFuture.get(5000, TimeUnit.MILLISECONDS); + assertThat(sseEventSource.close(5, TimeUnit.SECONDS), is(true)); + } finally { + server.stop(); + } + } + + private void innerTest(String endpoint, CompletableFuture future, int eventNum, int port) { + // Set up SSE event source + WebTarget target = client.target("http://localhost:" + port).path(endpoint).path("sse"); + SseEventSource sseEventSource = SseEventSource.target(target).build(); + CountDownLatch count = new CountDownLatch(eventNum); + sseEventSource.register(event -> { + try { + event.readData(String.class); + } finally { count.countDown(); } - ); - - // Open SSE source for a few millis and then close it - assertThat(sseEventSource.isOpen(), is(false)); - try { - sseEventSource.open(); // hangs indefinitely for test3? - } catch (IllegalStateException e) { - fail("sseEventSource.open() should have worked", e); + }, + exception -> { + count.countDown(); } - try { + ); + + // Open SSE source for a few millis and then close it + assertThat(sseEventSource.isOpen(), is(false)); + try { + sseEventSource.open(); // hangs indefinitely for test3? + } catch (IllegalStateException e) { + fail("sseEventSource.open() should have worked", e); + } + try { assertThat(count.await(250, TimeUnit.MILLISECONDS), is(true)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + fail("Await method should not have timed out", e); + } finally { + assertThat(sseEventSource.close(5, TimeUnit.SECONDS), is(true)); + } + assertThat(count.getCount(), is(0L)); + + // Wait for server to detect connection closed + if (future != null) { + try { + future.get(2000, TimeUnit.MILLISECONDS); + } catch (RuntimeException | Error e) { + fail("Closing of SSE connection not detected!", e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - fail("Await method should not have timed out", e); - } finally { - assertThat(sseEventSource.close(5, TimeUnit.SECONDS), is(true)); - } - assertThat(count.getCount(), is(0L)); - - // Wait for server to detect connection closed - if (future != null) { - try { - future.get(2000, TimeUnit.MILLISECONDS); - } catch (RuntimeException | Error e) { - fail("Closing of SSE connection not detected!", e); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - fail("Closing of SSE connection not detected!", e); - } catch (ExecutionException | TimeoutException e) { - fail("Closing of SSE connection not detected!", e); - } + fail("Closing of SSE connection not detected!", e); + } catch (ExecutionException | TimeoutException e) { + fail("Closing of SSE connection not detected!", e); } - } finally { - server.stop(); } } private final class TestApplication1 extends Application { @Override public Set getSingletons() { - return Set.of(new TestResource1(), new TestResource2(), new TestResource3()); + return Set.of(new TestResource1(), new TestResource2(), new TestResource3(), new TestResource4()); } } @Path("/test1") public final class TestResource1 { + private static volatile boolean closed; @GET @Path("sse") @Produces(MediaType.SERVER_SENT_EVENTS) public void listenToEvents(@Context SseEventSink eventSink, @Context Sse sse) { while (true) { + closed = eventSink.isClosed(); try { eventSink.send(sse.newEvent("hello")).thenAccept(t -> { if (t != null) { @@ -197,4 +243,23 @@ public void listenToEvents(@Context SseEventSink eventSink, @Context Sse sse) { .thenRun(eventSink::close); // critical } } + + @Path("/test4") + public final class TestResource4 { + private static final int TIME_SECONDS = 2; + private boolean fail = true; + + @GET + @Path("sse") + @Produces(MediaType.SERVER_SENT_EVENTS) + public void listenToEvents(@Context SseEventSink eventSink, @Context Sse sse) { + if (fail) { + fail = false; + throw new WebApplicationException(Response.status(503) + .header(HttpHeaders.RETRY_AFTER, String.valueOf(TIME_SECONDS)).build()); + } else { + eventSink.send(sse.newEvent("success")).thenAccept(i -> retryAfterFuture.complete(null)); + } + } + } } diff --git a/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonContainerConfiguration.java b/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonContainerConfiguration.java index 54863b4524e..176eb0b6a2b 100644 --- a/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonContainerConfiguration.java +++ b/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonContainerConfiguration.java @@ -17,7 +17,10 @@ package io.helidon.microprofile.arquillian; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Consumer; import org.eclipse.microprofile.config.spi.ConfigBuilder; @@ -36,7 +39,14 @@ * is empty) *
  • replaceConfigSourcesWithMp: (Optional) defaults to false: whether to replace config sources with microprofile if it * exists
  • - *
  • inWebContainer: defaults to false: sets web app context root, load WEB-INF/beans.xml and find any jakarta.ws.rs.core.Application in the webapp classes
  • + *
  • inWebContainer: (Optional) defaults to false: loads WEB-INF/beans.xml and find any + * jakarta.ws.rs.core.Application in the webapp classes
  • + *
  • useBeanXmlTemplate: (Optional) defaults to true: will create the default templates/beans.xml when beans.xml is missing
  • + *
  • includeWarContextPath: (Optional) defaults to false: will include the war name as a root context. + * For example, if a example.war is deployed, the root context is going to be /example.
  • + *
  • skipContextPaths: (Optional) defaults to empty: define the context paths to be excluded.
  • + *
  • multipleDeployments: (Optional) defaults to true: workaround for tests that unintentionally + * executes 1+ times @org.jboss.arquillian.container.test.api.Deployment
  • * */ public class HelidonContainerConfiguration implements ContainerConfiguration { @@ -47,7 +57,15 @@ public class HelidonContainerConfiguration implements ContainerConfiguration { private boolean useRelativePath = false; private boolean useParentClassloader = true; private boolean inWebContainer = false; + private boolean useBeanXmlTemplate = true; + private boolean multipleDeployments = true; + /* + * Restful requires it, but core profile don't (because rest used to be deployed in a + * web container together with other apps and in core profile there is only one app) + */ + private boolean includeWarContextPath = false; private final List> builderConsumers = new ArrayList<>(); + private final Set skipContextPaths = new HashSet<>(); /** * Access container's config builder. @@ -114,6 +132,30 @@ public void setInWebContainer(boolean inWebContainer) { this.inWebContainer = inWebContainer; } + public boolean isUseBeanXmlTemplate() { + return useBeanXmlTemplate; + } + + public void setUseBeanXmlTemplate(boolean useBeanXmlTemplate) { + this.useBeanXmlTemplate = useBeanXmlTemplate; + } + + public boolean isIncludeWarContextPath() { + return includeWarContextPath; + } + + public void setIncludeWarContextPath(boolean includeWarContextPath) { + this.includeWarContextPath = includeWarContextPath; + } + + public boolean isMultipleDeployments() { + return multipleDeployments; + } + + public void setMultipleDeployments(boolean multipleDeployments) { + this.multipleDeployments = multipleDeployments; + } + @Override public void validate() throws ConfigurationException { if ((port <= 0) || (port > Short.MAX_VALUE)) { @@ -129,4 +171,20 @@ ConfigBuilder useBuilder(ConfigBuilder configBuilder) { this.builderConsumers.forEach(builderConsumer -> builderConsumer.accept(configBuilder)); return configBuilder; } + + /** + * Getter of skipContextPaths. + * @return the skipContextPaths + */ + public Set getSkipContextPaths() { + return skipContextPaths; + } + + /** + * List of comma separated context roots that should be excluded. + * @param skipContextPaths the context paths + */ + public void setSkipContextPaths(String skipContextPaths) { + this.skipContextPaths.addAll(Arrays.asList(skipContextPaths.trim().split(","))); + } } diff --git a/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonDeployableContainer.java b/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonDeployableContainer.java index 36e5185b838..1d58a944a34 100644 --- a/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonDeployableContainer.java +++ b/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonDeployableContainer.java @@ -58,6 +58,7 @@ import jakarta.enterprise.inject.spi.CDI; import jakarta.enterprise.inject.spi.DefinitionException; import jakarta.enterprise.util.AnnotationLiteral; +import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; @@ -90,7 +91,7 @@ *
  • The WebArchive contents are written to the temporary directory
  • *
  • beans.xml is created in WEB-INF/classes if not present
  • *
  • WEB-INF/beans.xml will be moved to WEB-INF/classes/META-INF if present
  • - *
  • The server is started with WEB-INF/classes and all libraries in WEB-INF/libon the classpath.
  • + *
  • The server is started with WEB-INF/classes and all libraries in WEB-INF/lib on the classpath.
  • * * * Control is then returned to the test harness (in this case, generally testng) to run tests over HTTP. @@ -189,77 +190,84 @@ public ProtocolDescription getDefaultProtocol() { @Override public ProtocolMetaData deploy(Archive archive) throws DeploymentException { - // Because helidon doesn't have a dynamic war deployment model, we need to actually start the server here. - RunContext context = new RunContext(); - contexts.put(archive.getId(), context); + if (containerConfig.isMultipleDeployments() || (!containerConfig.isMultipleDeployments() && contexts.isEmpty())) { + // Because helidon doesn't have a dynamic war deployment model, we need to actually start the server here. + RunContext context = new RunContext(); + contexts.put(archive.getId(), context); - // Is it a JavaArchive? - boolean isJavaArchive = archive instanceof JavaArchive; + // Is it a JavaArchive? + boolean isJavaArchive = archive instanceof JavaArchive; - try { - // Create the temporary deployment directory. - if (containerConfig.getUseRelativePath()) { - context.deployDir = Paths.get("target/helidon-arquillian-test"); - } else { - context.deployDir = Files.createTempDirectory("helidon-arquillian-test"); - } - LOGGER.log(Level.INFO, "Running Arquillian tests in directory: " + context.deployDir.toAbsolutePath()); + try { + // Create the temporary deployment directory. + if (containerConfig.getUseRelativePath()) { + context.deployDir = Paths.get("target/helidon-arquillian-test"); + } else { + context.deployDir = Files.createTempDirectory("helidon-arquillian-test"); + } + LOGGER.log(Level.INFO, "Running Arquillian tests in directory: " + context.deployDir.toAbsolutePath()); - copyArchiveToDeployDir(archive, context.deployDir); + copyArchiveToDeployDir(archive, context.deployDir); - for (Archive additionalArchive : additionalArchives) { - copyArchiveToDeployDir(additionalArchive, context.deployDir); - } + for (Archive additionalArchive : additionalArchives) { + copyArchiveToDeployDir(additionalArchive, context.deployDir); + } - List classPath = new ArrayList<>(); + List classPath = new ArrayList<>(); - Path rootDir = context.deployDir.resolve(""); - if (isJavaArchive) { - ensureBeansXml(rootDir, null); - classPath.add(rootDir); - } else { - // Prepare the launcher files - Path webInfDir = context.deployDir.resolve("WEB-INF"); - Path classesDir = webInfDir.resolve("classes"); - Path libDir = webInfDir.resolve("lib"); - ensureBeansXml(classesDir, webInfDir); - addServerClasspath(classPath, classesDir, libDir, rootDir); - if (containerConfig.isInWebContainer()) { - context.rootContext = archive.getName().split("\\.")[0]; - if (!loadApplicationFromWebXml(context, webInfDir)) { - // Search Application in classes - loadApplicationFromClasses(context, archive); + Path rootDir = context.deployDir.resolve(""); + if (isJavaArchive) { + ensureBeansXml(rootDir, null); + classPath.add(rootDir); + } else { + // Prepare the launcher files + Path webInfDir = context.deployDir.resolve("WEB-INF"); + Path classesDir = webInfDir.resolve("classes"); + Path libDir = webInfDir.resolve("lib"); + ensureBeansXml(classesDir, webInfDir); + addServerClasspath(classPath, classesDir, libDir, rootDir); + if (containerConfig.isInWebContainer()) { + if (containerConfig.isIncludeWarContextPath()) { + String rootContext = archive.getName().split("\\.")[0]; + if (!containerConfig.getSkipContextPaths().contains(rootContext)) { + context.rootContext = rootContext; + } + } + if (!loadApplicationFromWebXml(context, webInfDir)) { + // Search Application in classes + loadApplicationFromClasses(context, archive); + } } } - } - startServer(context, classPath.toArray(new Path[0])); - } catch (IOException | SAXException | ParserConfigurationException e) { - LOGGER.log(Level.INFO, "Failed to start container", e); - throw new DeploymentException("Failed to copy the archive assets into the deployment directory", e); - } catch (InvocationTargetException e) { + startServer(context, classPath.toArray(new Path[0])); + } catch (IOException | SAXException | ParserConfigurationException e) { + LOGGER.log(Level.INFO, "Failed to start container", e); + throw new DeploymentException("Failed to copy the archive assets into the deployment directory", e); + } catch (InvocationTargetException e) { - try { - context.runnerClass - .getDeclaredMethod("abortedCleanup") - .invoke(context.runner); - } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) { - ex.printStackTrace(); - } + try { + context.runnerClass + .getDeclaredMethod("abortedCleanup") + .invoke(context.runner); + } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) { + ex.printStackTrace(); + } - throw lookForSupressedDeploymentException(e.getTargetException()) - .map(d -> + throw lookForSupressedDeploymentException(e.getTargetException()) + .map(d -> new org.jboss.arquillian.container.spi.client.container.DeploymentException("Deployment failure!", d)) - .orElseThrow(() -> new DefinitionException(e)); - } catch (ReflectiveOperationException e) { - LOGGER.log(Level.INFO, "Failed to start container", e); - throw new DefinitionException(e); // validation exceptions - } + .orElseThrow(() -> new DefinitionException(e)); + } catch (ReflectiveOperationException e) { + LOGGER.log(Level.INFO, "Failed to start container", e); + throw new DefinitionException(e); // validation exceptions + } - // Server has started, so we're done. - // ProtocolMetaData pm = new ProtocolMetaData(); - // pm.addContext(new HTTPContext("Helidon", "localhost", containerConfig.getPort())); - // return pm; + // Server has started, so we're done. + // ProtocolMetaData pm = new ProtocolMetaData(); + // pm.addContext(new HTTPContext("Helidon", "localhost", containerConfig.getPort())); + // return pm; + } return new ProtocolMetaData(); } @@ -306,6 +314,7 @@ private boolean loadApplicationFromWebXml(RunContext context, Path webInfDir) th NodeList childs = nodes.item(i).getChildNodes(); Class application = application(childs); if (application != null) { + context.explicitRsApplication = Optional.of(application); context.applications.add(application); return true; } @@ -341,10 +350,12 @@ static Optional lookForSupressedDeploymentException(Throwable t) { } if (jakarta.enterprise.inject.spi.DeploymentException.class.isAssignableFrom(t.getClass())) { return Optional.of((jakarta.enterprise.inject.spi.DeploymentException) t); - } - if (IllegalStateException.class.isAssignableFrom(t.getClass())) { + } else if (IllegalStateException.class.isAssignableFrom(t.getClass())) { return Optional.of((IllegalStateException) t); + } else if (java.lang.Error.class.isAssignableFrom(t.getClass())) { + return Optional.of((new jakarta.enterprise.inject.spi.DeploymentException(t))); } + var deploymentException = lookForSupressedDeploymentException(t.getCause()); for (Throwable suppressed : t.getSuppressed()) { var candicate = lookForSupressedDeploymentException(suppressed); @@ -410,7 +421,11 @@ void startServer(RunContext context, Path[] classPath) Map properties = new HashMap<>(); for (Class app : context.applications) { String key = app.getName() + ".routing-path.path"; + ApplicationPath path = app.getDeclaredAnnotation(ApplicationPath.class); String value = "/" + context.rootContext; + if (path != null && !"/".equals(path.value()) && !"".equals(path.value())) { + value = value + "/" + path.value(); + } properties.put(key, value); } configBuilder.withSources(MpConfigSources.create(properties)); @@ -438,8 +453,8 @@ void startServer(RunContext context, Path[] classPath) } context.runnerClass - .getDeclaredMethod("start", Config.class, Integer.TYPE) - .invoke(context.runner, config, containerConfig.getPort()); + .getDeclaredMethod("start", Config.class, Integer.TYPE, Optional.class) + .invoke(context.runner, config, containerConfig.getPort(), context.explicitRsApplication); } private URL[] toUrls(Path[] classPath) { @@ -519,12 +534,13 @@ private void ensureBeansXml(Path classesDir, Path webinfDir) throws IOException if (Files.exists(beansPath)) { return; } - try (InputStream beanXmlTemplate = HelidonDeployableContainer.class.getResourceAsStream("/templates/beans.xml")) { - if (null == beanXmlTemplate) { - Files.write(beansPath, new byte[0]); - } else { - - Files.copy(beanXmlTemplate, beansPath); + if (containerConfig.isUseBeanXmlTemplate()) { + try (InputStream beanXmlTemplate = HelidonDeployableContainer.class.getResourceAsStream("/templates/beans.xml")) { + if (null == beanXmlTemplate) { + Files.write(beansPath, new byte[0]); + } else { + Files.copy(beanXmlTemplate, beansPath); + } } } } @@ -672,6 +688,8 @@ private static class RunContext { // existing class loader private ClassLoader oldClassLoader; private String rootContext; + // It is explicit when it is defined in web.xml. CDI has nothing to do with that. + private Optional> explicitRsApplication = Optional.empty(); private Set> applications = new HashSet<>(); } diff --git a/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonMethodExecutor.java b/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonMethodExecutor.java index 7af711de2a6..619c747e1db 100644 --- a/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonMethodExecutor.java +++ b/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/HelidonMethodExecutor.java @@ -33,6 +33,7 @@ import io.helidon.microprofile.arquillian.HelidonContainerExtension.HelidonCDIInjectionEnricher; +import jakarta.enterprise.context.ContextNotActiveException; import jakarta.enterprise.context.control.RequestContextController; import org.jboss.arquillian.container.test.spi.ContainerMethodExecutor; import org.jboss.arquillian.test.api.ArquillianResource; @@ -83,7 +84,11 @@ public TestResult invoke(TestMethodExecutor testMethodExecutor) { } catch (Throwable t) { return TestResult.failed(t); } finally { - controller.deactivate(); + try { + controller.deactivate(); + } catch (ContextNotActiveException e) { + LOGGER.log(Level.WARNING, "Controller " + controller + " was already deactivated"); + } } return TestResult.passed(); } diff --git a/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/ServerRunner.java b/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/ServerRunner.java index 17d15c086a0..c17166afcec 100644 --- a/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/ServerRunner.java +++ b/microprofile/tests/arquillian/src/main/java/io/helidon/microprofile/arquillian/ServerRunner.java @@ -18,12 +18,14 @@ import java.lang.System.Logger.Level; import java.lang.reflect.Field; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import io.helidon.microprofile.server.Server; import io.helidon.microprofile.server.ServerCdiExtension; import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.spi.ConfigProviderResolver; @@ -56,18 +58,20 @@ private static String getContextRoot(Class application) { * * @param config configuration * @param port port to start the server on + * @param explicitRsApplication defined in web.xml */ - public void start(Config config, int port) { + public void start(Config config, int port, Optional> explicitRsApplication) { // attempt a stop stop(); ConfigProviderResolver.instance() .registerConfig(config, Thread.currentThread().getContextClassLoader()); - server = Server.builder() + Server.Builder builder = Server.builder() .port(port) - .config(config) - .build() + .config(config); + explicitRsApplication.ifPresent(c -> builder.addApplication(c)); + server = builder.build() // this is a blocking operation, we will be released once the server is started // or it fails to start .start(); diff --git a/microprofile/tests/tck/pom.xml b/microprofile/tests/tck/pom.xml index fa882fe3669..39ef17b01d4 100644 --- a/microprofile/tests/tck/pom.xml +++ b/microprofile/tests/tck/pom.xml @@ -47,6 +47,7 @@ tck-telemetry tck-core-profile tck-cdi + tck-cdi-lang-model tck-restful tck-jsonb tck-jsonp diff --git a/microprofile/tests/tck/tck-cdi-lang-model/pom.xml b/microprofile/tests/tck/tck-cdi-lang-model/pom.xml new file mode 100644 index 00000000000..826038b280e --- /dev/null +++ b/microprofile/tests/tck/tck-cdi-lang-model/pom.xml @@ -0,0 +1,103 @@ + + + + + 4.0.0 + + io.helidon.microprofile.tests.tck + helidon-microprofile-tests-tck-project + 4.0.0-SNAPSHOT + ../pom.xml + + tck-cdi-lang-model + Helidon Microprofile Tests TCK CDI Lang model + + + + io.helidon.microprofile.cdi + helidon-microprofile-cdi + test + + + io.helidon.microprofile.tests + helidon-arquillian + ${project.version} + test + + + org.jboss.arquillian.junit + arquillian-junit-container + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + jakarta.enterprise + cdi-tck-api + test + + + jakarta.enterprise + cdi-tck-lang-model + test + + + jakarta.enterprise + cdi-tck-core-impl + test + + + org.jboss.weld + weld-porting-package-tck + test + + + org.jboss.arquillian.junit5 + arquillian-junit5-core + test + + + org.glassfish + jakarta.el + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + false + + 1 + false + + **/*Test.java + + + + + + diff --git a/microprofile/tests/tck/tck-cdi-lang-model/src/test/java/io/helidon/microprofile/cdi/lang/model/tck/LangModelExtension.java b/microprofile/tests/tck/tck-cdi-lang-model/src/test/java/io/helidon/microprofile/cdi/lang/model/tck/LangModelExtension.java new file mode 100644 index 00000000000..fe627d7c9d8 --- /dev/null +++ b/microprofile/tests/tck/tck-cdi-lang-model/src/test/java/io/helidon/microprofile/cdi/lang/model/tck/LangModelExtension.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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 io.helidon.microprofile.cdi.lang.model.tck; + +import jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension; +import jakarta.enterprise.inject.build.compatible.spi.Discovery; +import jakarta.enterprise.inject.build.compatible.spi.Enhancement; +import jakarta.enterprise.inject.build.compatible.spi.ScannedClasses; +import jakarta.enterprise.lang.model.declarations.ClassInfo; +import org.jboss.cdi.lang.model.tck.LangModelVerifier; + +public class LangModelExtension implements BuildCompatibleExtension { + + public static int ENHANCEMENT_INVOKED = 0; + + public LangModelExtension(){} + + @Enhancement(types = LangModelVerifier.class) + public void run(ClassInfo clazz) { + ENHANCEMENT_INVOKED++; + LangModelVerifier.verify(clazz); + } + + @Discovery + public void addVerifier(ScannedClasses sc) { + sc.add(LangModelVerifier.class.getName()); + } +} + diff --git a/microprofile/tests/tck/tck-cdi-lang-model/src/test/java/io/helidon/microprofile/cdi/lang/model/tck/LangModelTckTest.java b/microprofile/tests/tck/tck-cdi-lang-model/src/test/java/io/helidon/microprofile/cdi/lang/model/tck/LangModelTckTest.java new file mode 100644 index 00000000000..2717c18acfe --- /dev/null +++ b/microprofile/tests/tck/tck-cdi-lang-model/src/test/java/io/helidon/microprofile/cdi/lang/model/tck/LangModelTckTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * 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 io.helidon.microprofile.cdi.lang.model.tck; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension; +import jakarta.enterprise.lang.model.declarations.ClassInfo; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit5.ArquillianExtension; +import org.jboss.cdi.lang.model.tck.LangModelVerifier; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.jboss.shrinkwrap.impl.BeansXml; +import org.jboss.shrinkwrap.api.BeanDiscoveryMode; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + *

    + * Executes CDI TCK for language model used in CDI Lite, current setup requires discovery mode ALL plus adding + * {@link LangModelVerifier} into the deployment to discover it as a bean. Alternatively, this could be added + * synthetically inside {@link LangModelExtension}. + *

    + * + *

    + * Actual test happens inside {@link LangModelExtension} by calling {@link LangModelVerifier#verify(ClassInfo)}. + *

    + */ +@ExtendWith(ArquillianExtension.class) +class LangModelTckTest { + + @Deployment + public static Archive deploy() { + return ShrinkWrap.create(WebArchive.class, LangModelTckTest.class.getSimpleName() + ".war") + // beans.xml with discovery mode "all" + .addAsWebInfResource(new BeansXml(BeanDiscoveryMode.ANNOTATED), "beans.xml") + .addAsServiceProvider(BuildCompatibleExtension.class, LangModelExtension.class) + .addClasses(LangModelExtension.class) + // add this package into the deployment so that it's subject to discovery, including its dependencies + .addPackage(LangModelVerifier.class.getPackage()); + } + + @Test + public void testLangModel() { + // test is executed in LangModelExtension; here we just assert that the relevant extension method was invoked + assertTrue(LangModelExtension.ENHANCEMENT_INVOKED == 1); + } +} \ No newline at end of file diff --git a/microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/META-INF/cdi-tck.properties b/microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/META-INF/cdi-tck.properties new file mode 100644 index 00000000000..eb25158ccef --- /dev/null +++ b/microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/META-INF/cdi-tck.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 2023 Oracle and/or its affiliates. +# +# 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. +# +org.jboss.cdi.tck.cdiLiteMode=true +org.jboss.cdi.tck.libraryDirectory= +org.jboss.cdi.tck.testDataSource= +org.jboss.cdi.tck.testJmsConnectionFactory= +org.jboss.cdi.tck.testJmsQueue= +org.jboss.cdi.tck.testJmsTopic= +org.jboss.cdi.tck.spi.Beans=org.jboss.weld.tck.BeansImpl +org.jboss.cdi.tck.spi.Contexts=org.jboss.weld.tck.ContextsImpl +org.jboss.cdi.tck.spi.EL=org.jboss.weld.tck.ELImpl \ No newline at end of file diff --git a/microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/application.yaml b/microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/application.yaml new file mode 100644 index 00000000000..27189276ed8 --- /dev/null +++ b/microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/application.yaml @@ -0,0 +1,19 @@ +# +# Copyright (c) 2023 Oracle and/or its affiliates. +# +# 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. +# + +mp: + initializer: + allow: true diff --git a/microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/arquillian.xml b/microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/arquillian.xml new file mode 100644 index 00000000000..5320417c279 --- /dev/null +++ b/microprofile/tests/tck/tck-cdi-lang-model/src/test/resources/arquillian.xml @@ -0,0 +1,34 @@ + + + + + + target/deployments + 8080 + + + + true + + + \ No newline at end of file diff --git a/microprofile/tests/tck/tck-cdi/pom.xml b/microprofile/tests/tck/tck-cdi/pom.xml index 9b079fe2595..bc59b972362 100644 --- a/microprofile/tests/tck/tck-cdi/pom.xml +++ b/microprofile/tests/tck/tck-cdi/pom.xml @@ -73,39 +73,63 @@ org.apache.maven.plugins maven-surefire-plugin + + false + 1 false - cdi-full,se + + cdi-full,integration,javaee-full,se jakarta.enterprise:cdi-tck-core-impl - org/jboss/cdi/tck/tests/**/*Test.java - org/jboss/cdi/tck/interceptors/DependentContextTesttests/**/*Test.java + **/*Test.java - org/jboss/cdi/tck/tests/fulSyntheticBeanWithLookupTestl/extensions/lifecycle/bbd/broken/passivatingScope/AddingPassivatingScopeTest.java - - org/jboss/cdi/tck/tests/build/compatible/extensions/changeObserverQualifier/ChangeObserverQualifierTest.java - org/jboss/cdi/tck/tests/build/compatible/extensions/customStereotype/CustomStereotypeTest.java - org/jboss/cdi/tck/tests/build/compatible/extensions/syntheticBeanWithLookup/SyntheticBeanWithLookupTest.java - org/jboss/cdi/tck/tests/context/dependent/DependentContextTest.java + org/jboss/cdi/tck/tests/definition/bean/types/ManagedBeanTypesTest.java - org/jboss/cdi.tck/tests/event/EventTest.java - org/jboss/cdi/tck/tests/event/lifecycle/StartupShutdownTest.java - org/jboss/cdi/tck/tests/event/observer/broken/validation/unsatisfied/ObserverMethodParameterInjectionValidationTest.java - org/jboss/cdi/tck/tests/event/observer/broken/validation/ambiguous/ObserverMethodParameterInjectionValidationTest.java - org/jboss/cdi/tck/tests/event/observer/runtimeException/ObserverExceptionRethrownTest.java - org/jboss/cdi/tck/tests/event/observer/conditional/ConditionalObserverTest.java - org/jboss/cdi/tck/tests/event/observer/ObserverNotificationTest.java - org/jboss/cdi/tck/tests/event/observer/async/executor/FireAsyncWithCustomExecutorTest.java - org/jboss/cdi/tck/tests/inheritance/generics/MemberLevelInheritanceTest.java - org/jboss/cdi/tck/tests/lookup/clientProxy/unproxyable/privateConstructor/PrivateConstructorTest.java - org/jboss/cdi/tck/tests/lookup/clientProxy/unproxyable/beanConstructor/BeanConstructorWithParametersTest.java - org/jboss/cdi/tck/tests/implementation/simple/lifecycle/unproxyable/UnproxyableManagedBeanTest.java + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack-dependencies + package + + unpack-dependencies + + + true + true + target/classes + + + + + + org.netbeans.tools + sigtest-maven-plugin + ${version.lib.sigtest} + + + sigtest + verify + + check + + + + + ${project.build.directory}/classes/cdi-api-jdk11.sig + jakarta.decorator,jakarta.enterprise,jakarta.interceptor + ${project.build.directory}/classes + ${project.build.directory}/cdi-sig-report.txt + + diff --git a/microprofile/tests/tck/tck-cdi/src/test/resources/arquillian.xml b/microprofile/tests/tck/tck-cdi/src/test/resources/arquillian.xml index 5320417c279..8e8c9ca0132 100644 --- a/microprofile/tests/tck/tck-cdi/src/test/resources/arquillian.xml +++ b/microprofile/tests/tck/tck-cdi/src/test/resources/arquillian.xml @@ -29,6 +29,7 @@ true + false \ No newline at end of file diff --git a/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/pom.xml b/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/pom.xml index 0c8fa9bce52..15a2b139640 100644 --- a/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/pom.xml +++ b/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/pom.xml @@ -33,7 +33,7 @@ io.helidon.microprofile.bundles - helidon-microprofile-core + helidon-microprofile test @@ -77,12 +77,6 @@ *IT.java - - - ee/jakarta/tck/core/jsonb/JsonbApplicationIT.java - ee/jakarta/tck/core/json/ApplicationJsonpIT.java - ee/jakarta/tck/core/rest/jsonb/cdi/CustomJsonbSerializationIT.java - diff --git a/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/src/test/resources/arquillian.xml b/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/src/test/resources/arquillian.xml index f47555c4b3a..2ecdca68d32 100644 --- a/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/src/test/resources/arquillian.xml +++ b/microprofile/tests/tck/tck-core-profile/tck-core-profile-test/src/test/resources/arquillian.xml @@ -27,7 +27,7 @@ - true + true \ No newline at end of file diff --git a/microprofile/tests/tck/tck-inject/tck-inject-test/src/test/java/io/helidon/microprofile/tests/inject/TckInjectTest.java b/microprofile/tests/tck/tck-inject/tck-inject-test/src/test/java/io/helidon/microprofile/tests/inject/TckInjectTest.java index b6a9488aad0..c4c7a5d7fce 100644 --- a/microprofile/tests/tck/tck-inject/tck-inject-test/src/test/java/io/helidon/microprofile/tests/inject/TckInjectTest.java +++ b/microprofile/tests/tck/tck-inject/tck-inject-test/src/test/java/io/helidon/microprofile/tests/inject/TckInjectTest.java @@ -16,8 +16,11 @@ package io.helidon.microprofile.tests.inject; +import static org.junit.Assert.fail; + import jakarta.enterprise.inject.se.SeContainer; import jakarta.enterprise.inject.se.SeContainerInitializer; +import junit.framework.TestResult; import org.atinject.tck.Tck; import org.atinject.tck.auto.Car; import org.atinject.tck.auto.Convertible; @@ -44,7 +47,23 @@ void test() { SpareTire.class) .initialize(); Car tckCar = container.select(Car.class).get(); - Tck.testsFor(tckCar, false, true); + junit.framework.Test suite = Tck.testsFor(tckCar, false, true); + TestResult result = new TestResult(); + suite.run(result); + String results = printResults(result); + if (!result.wasSuccessful()) { + fail(results); + } else { + System.out.println(results); + } } + // Tests run: 1, Failures: 0, Errors: 1 + private String printResults(TestResult result) { + StringBuilder builder = new StringBuilder(); + builder.append("Tests run: ").append(result.runCount()); + builder.append(", Failures: ").append(result.failureCount()); + builder.append(", Errors: ").append(result.errorCount()); + return builder.toString(); + } } diff --git a/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml b/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml index efbd8b29c2b..6db6334d48b 100644 --- a/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml +++ b/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/pom.xml @@ -42,6 +42,10 @@ ${version.lib.jakarta.jsonb-api} test + + io.helidon.microprofile.cdi + helidon-microprofile-cdi + org.eclipse yasson @@ -58,6 +62,20 @@ true + + maven-dependency-plugin + + + compile + + copy-dependencies + + + ${project.build.directory}/lib + + + + org.apache.maven.plugins maven-surefire-plugin @@ -68,11 +86,11 @@ *Test.java - - *CDITest.java - *JSONBSigTest.java - NumberFormatCustomizationTest.java - + + COMPAT,CLDR + ${project.build.directory}/jdk11-bundle + ${project.build.directory}/lib/jakarta.json.bind-api-${version.lib.jakarta.jsonb-api}.jar:${project.build.directory}/jdk11-bundle/java.base:${project.build.directory}/jdk11-bundle/java.rmi:${project.build.directory}/jdk11-bundle/java.sql:${project.build.directory}/jdk11-bundle/java.naming + diff --git a/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/src/test/resources/META-INF/microprofile-config.properties b/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/src/test/resources/META-INF/microprofile-config.properties new file mode 100644 index 00000000000..41bf3da96ad --- /dev/null +++ b/microprofile/tests/tck/tck-jsonb/tck-jsonb-test/src/test/resources/META-INF/microprofile-config.properties @@ -0,0 +1,18 @@ +# +# Copyright (c) 2023 Oracle and/or its affiliates. +# +# 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. +# + +mp.initializer.allow=true +mp.initializer.no-warn=true diff --git a/microprofile/tests/tck/tck-jsonp/artifact-install.sh b/microprofile/tests/tck/tck-jsonp/artifact-install.sh deleted file mode 100755 index db282287a3a..00000000000 --- a/microprofile/tests/tck/tck-jsonp/artifact-install.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2023 Oracle and/or its affiliates. -# -# 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. -# - -##script to install the artifact directory contents into a local maven repository - -VERSION="$1" - -# Parent pom -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-"$VERSION".pom -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck -Dversion="$VERSION" -Dpackaging=pom - -# pom -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-common-"$VERSION".pom -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck-common -Dversion="$VERSION" -Dpackaging=pom - -# jar -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-common-"$VERSION".jar -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck-common -Dversion="$VERSION" -Dpackaging=jar - -# sources jar -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-common-"$VERSION"-sources.jar -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck-common-sources -Dversion="$VERSION" -Dpackaging=jar - -# pom -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-tests-"$VERSION".pom -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck-tests -Dversion="$VERSION" -Dpackaging=pom - -# jar -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-tests-"$VERSION".jar -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck-tests -Dversion="$VERSION" -Dpackaging=jar - -# sources jar -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-tests-"$VERSION"-sources.jar -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck-tests-sources -Dversion="$VERSION" -Dpackaging=jar - -# pom -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-tests-pluggability-"$VERSION".pom -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck-tests-pluggability -Dversion="$VERSION" -Dpackaging=pom - -# jar -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-tests-pluggability-"$VERSION".jar -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck-tests-pluggability -Dversion="$VERSION" -Dpackaging=jar - -# sources jar -mvn org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install-file \ --Dfile=jakarta.json-tck-tests-pluggability-"$VERSION"-sources.jar -DgroupId=jakarta.json \ --DartifactId=jakarta.json-tck-tests-pluggability-sources -Dversion="$VERSION" -Dpackaging=jar diff --git a/microprofile/tests/tck/tck-jsonp/pom.xml b/microprofile/tests/tck/tck-jsonp/pom.xml index ebafb5244e6..2d1e2850478 100644 --- a/microprofile/tests/tck/tck-jsonp/pom.xml +++ b/microprofile/tests/tck/tck-jsonp/pom.xml @@ -33,33 +33,6 @@ tck-jsonp-test + tck-jsonp-pluggability-test - - - - - maven-antrun-plugin - - - validate - - run - - - - - - - - - - - - - - - - - - diff --git a/microprofile/tests/tck/tck-jsonp/tck-jsonp-pluggability-test/pom.xml b/microprofile/tests/tck/tck-jsonp/tck-jsonp-pluggability-test/pom.xml new file mode 100644 index 00000000000..1266cfb9106 --- /dev/null +++ b/microprofile/tests/tck/tck-jsonp/tck-jsonp-pluggability-test/pom.xml @@ -0,0 +1,97 @@ + + + + + 4.0.0 + + io.helidon.microprofile.tests.tck + helidon-microprofile-tests-tck-jsonp + 4.0.0-SNAPSHOT + ../pom.xml + + helidon-microprofile-tests-tck-jsonp-pluggability-test + Helidon Microprofile Tests TCK JSONP + + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.netbeans.tools + sigtest-maven-plugin + + + + jakarta.json + jakarta.json-tck-tests-pluggability + ${version.lib.jakarta.jsonp-api} + test + + + org.eclipse.parsson + parsson + test + + + + + + + maven-antrun-plugin + + true + + + + maven-dependency-plugin + + + compile + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + jakarta.json:jakarta.json-tck-tests-pluggability + + + *Test*.java + + + ${project.build.directory}/jdk11-bundle + ${project.build.directory}/lib/jakarta.json-api-${version.lib.jakarta.jsonp-api}.jar:${project.build.directory}/jdk11-bundle/java.base:${project.build.directory}/jdk11-bundle/java.rmi:${project.build.directory}/jdk11-bundle/java.sql:${project.build.directory}/jdk11-bundle/java.naming + + + + + + diff --git a/microprofile/tests/tck/tck-jsonp/tck-jsonp-test/pom.xml b/microprofile/tests/tck/tck-jsonp/tck-jsonp-test/pom.xml index 29e435f249a..3019592df8c 100644 --- a/microprofile/tests/tck/tck-jsonp/tck-jsonp-test/pom.xml +++ b/microprofile/tests/tck/tck-jsonp/tck-jsonp-test/pom.xml @@ -36,6 +36,10 @@ junit-jupiter-engine test + + org.netbeans.tools + sigtest-maven-plugin + jakarta.json @@ -58,6 +62,20 @@ true + + maven-dependency-plugin + + + compile + + copy-dependencies + + + ${project.build.directory}/lib + + + + org.apache.maven.plugins maven-surefire-plugin @@ -66,8 +84,12 @@ jakarta.json:jakarta.json-tck-tests - *Tests.java + *Test*.java + + ${project.build.directory}/jdk11-bundle + ${project.build.directory}/lib/jakarta.json-api-${version.lib.jakarta.jsonp-api}.jar:${project.build.directory}/jdk11-bundle/java.base:${project.build.directory}/jdk11-bundle/java.rmi:${project.build.directory}/jdk11-bundle/java.sql:${project.build.directory}/jdk11-bundle/java.naming + diff --git a/microprofile/tests/tck/tck-metrics/src/test/java/io/helidon/microprofile/metrics/tck/MetricsTckCdiExtension.java b/microprofile/tests/tck/tck-metrics/src/test/java/io/helidon/microprofile/metrics/tck/MetricsTckCdiExtension.java index e8a06a368df..381c02b800c 100644 --- a/microprofile/tests/tck/tck-metrics/src/test/java/io/helidon/microprofile/metrics/tck/MetricsTckCdiExtension.java +++ b/microprofile/tests/tck/tck-metrics/src/test/java/io/helidon/microprofile/metrics/tck/MetricsTckCdiExtension.java @@ -15,6 +15,8 @@ */ package io.helidon.microprofile.metrics.tck; +import io.helidon.microprofile.server.CatchAllExceptionMapper; + import jakarta.enterprise.event.Observes; import jakarta.enterprise.inject.spi.BeforeBeanDiscovery; import jakarta.enterprise.inject.spi.Extension; @@ -23,5 +25,6 @@ public class MetricsTckCdiExtension implements Extension { void before(@Observes BeforeBeanDiscovery discovery) { discovery.addAnnotatedType(ArrayParamConverterProvider.class, ArrayParamConverterProvider.class.getSimpleName()); + discovery.addAnnotatedType(CatchAllExceptionMapper.class, CatchAllExceptionMapper.class.getSimpleName()); } } diff --git a/microprofile/tests/tck/tck-restful/pom.xml b/microprofile/tests/tck/tck-restful/pom.xml index 50a2e7f7a0b..28e3c8666b5 100644 --- a/microprofile/tests/tck/tck-restful/pom.xml +++ b/microprofile/tests/tck/tck-restful/pom.xml @@ -48,7 +48,7 @@ - + diff --git a/microprofile/tests/tck/tck-restful/tck-restful-test/pom.xml b/microprofile/tests/tck/tck-restful/tck-restful-test/pom.xml index c6a7472ac76..232555e5c95 100644 --- a/microprofile/tests/tck/tck-restful/tck-restful-test/pom.xml +++ b/microprofile/tests/tck/tck-restful/tck-restful-test/pom.xml @@ -59,9 +59,28 @@ test - io.helidon.microprofile.bundles - helidon-microprofile + io.helidon.microprofile.server + helidon-microprofile-server test + + + org.glassfish.jersey.ext.cdi + jersey-weld2-se + + + + + io.helidon.microprofile.rest-client + helidon-microprofile-rest-client + + + org.glassfish.jersey.media + jersey-media-json-binding + runtime + + + jakarta.json.bind + jakarta.json.bind-api com.sun.xml.bind @@ -81,6 +100,20 @@ true + + maven-dependency-plugin + + + compile + + copy-dependencies + + + ${project.build.directory}/lib + + + + org.apache.maven.plugins maven-surefire-plugin @@ -90,55 +123,26 @@ jakarta.ws.rs:jakarta-restful-ws-tck + xml_binding,servlet,security,se_bootstrap *IT.java - - ee/jakarta/tck/ws/rs/ee/rs/core/request/JAXRSClientIT.java - - ee.jakarta.tck.ws.rs.ee.resource.webappexception.mapper.JAXRSClientIT - ee/jakarta/tck/ws/rs/spec/client/exceptions/ClientExceptionsIT.java - ee/jakarta/tck/ws/rs/ee/rs/container/responsecontext/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/pathparam/sub/JAXRSSubClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/matrixparam/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/spec/resourceconstructor/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/pathparam/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/beanparam/plain/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/ext/providers/JAXRSProvidersClientIT.java - ee/jakarta/tck/ws/rs/jaxrs21/ee/sse/sseeventsink/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/spec/provider/sort/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/cookieparam/locator/JAXRSLocatorClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/headerparam/sub/JAXRSSubClientIT.java + ee/jakarta/tck/ws/rs/jaxrs21/ee/sse/sseeventsource/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/ext/paramconverter/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/beanparam/matrix/plain/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/beanparam/path/plain/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/pathparam/locator/JAXRSLocatorClientIT.java - ee/jakarta/tck/ws/rs/spec/provider/standard/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/signaturetest/jaxrs/JAXRSSigTestIT.java - ee/jakarta/tck/ws/rs/ee/rs/queryparam/sub/JAXRSSubClientIT.java - ee/jakarta/tck/ws/rs/jaxrs21/ee/client/executor/rx/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/spec/contextprovider/JsonbContextProviderIT.java - ee/jakarta/tck/ws/rs/spec/resource/locator/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/matrixparam/locator/JAXRSLocatorClientIT.java - ee/jakarta/tck/ws/rs/jaxrs21/ee/sse/ssebroadcaster/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/core/configurable/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/spec/resource/annotationprecedence/subclass/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/sebootstrap/SeBootstrapIT.java - ee/jakarta/tck/ws/rs/ee/rs/core/uriinfo/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/cookieparam/sub/JAXRSSubClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/matrixparam/sub/JAXRSSubClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/formparam/sub/JAXRSSubClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/formparam/locator/JAXRSLocatorClientIT.java - ee/jakarta/tck/ws/rs/servlet3/rs/applicationpath/JAXRSClientIT.java - ee/jakarta/tck/ws/rs/ee/rs/headerparam/locator/JAXRSLocatorClientIT.java - ee/jakarta/tck/ws/rs/spec/resource/valueofandfromstring/JAXRSClientIT.java + + ee/jakarta/tck/ws/rs/ee/rs/container/responsecontext/JAXRSClientIT.java - xml_binding,servlet,security localhost 8080 + false + true + false + false + SINGLE_THREAD + ${project.build.directory}/jdk11-bundle + ${project.build.directory}/lib/jakarta.xml.bind-api-${version.lib.jakarta.xml.bind-api}.jar:${project.build.directory}/lib/jakarta.ws.rs-api-${version.lib.jakarta.jaxrs-api}.jar:${project.build.directory}/jdk11-bundle/java.base:${project.build.directory}/jdk11-bundle/java.rmi:${project.build.directory}/jdk11-bundle/java.sql:${project.build.directory}/jdk11-bundle/java.naming diff --git a/microprofile/tests/tck/tck-restful/tck-restful-test/src/test/resources/META-INF/microprofile-config.properties b/microprofile/tests/tck/tck-restful/tck-restful-test/src/test/resources/META-INF/microprofile-config.properties new file mode 100644 index 00000000000..82d86a2bd88 --- /dev/null +++ b/microprofile/tests/tck/tck-restful/tck-restful-test/src/test/resources/META-INF/microprofile-config.properties @@ -0,0 +1,17 @@ +# +# Copyright (c) 2023 Oracle and/or its affiliates. +# +# 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. +# + +jersey.config.client.ignoreExceptionResponse=false diff --git a/microprofile/tests/tck/tck-restful/tck-restful-test/src/test/resources/arquillian.xml b/microprofile/tests/tck/tck-restful/tck-restful-test/src/test/resources/arquillian.xml index a04cc2bee39..023f94713f6 100644 --- a/microprofile/tests/tck/tck-restful/tck-restful-test/src/test/resources/arquillian.xml +++ b/microprofile/tests/tck/tck-restful/tck-restful-test/src/test/resources/arquillian.xml @@ -30,6 +30,10 @@ false true + + true + jaxrs_contextprovider_jsonb_web,jaxrs_client_exceptions + false \ No newline at end of file diff --git a/pom.xml b/pom.xml index caa0c6847cc..5d0f06fbf83 100644 --- a/pom.xml +++ b/pom.xml @@ -61,9 +61,10 @@ 9.1 2.11.0 2.4.14 - 10.0.1 - 4.0.10 - 3.1.3 + 10.0.2 + 1.4 + 4.0.12 + 3.1.4 2.2.1.Final 1.15.3 @@ -955,6 +956,11 @@ core-profile-tck-impl ${version.lib.microprofile-core-profile} + + org.netbeans.tools + sigtest-maven-plugin + ${version.lib.sigtest} + jakarta.enterprise cdi-tck-core-impl @@ -965,6 +971,11 @@ cdi-tck-api ${version.lib.microprofile-cdi-tck} + + jakarta.enterprise + cdi-tck-lang-model + ${version.lib.microprofile-cdi-tck} + jakarta.ws.rs jakarta-restful-ws-tck @@ -1139,6 +1150,11 @@ arquillian-junit-container ${version.lib.arquillian} + + org.jboss.arquillian.junit5 + arquillian-junit5-core + ${version.lib.arquillian} + org.jboss.arquillian.testenricher arquillian-testenricher-cdi-jakarta diff --git a/webclient/http1/src/main/java/io/helidon/webclient/http1/Http1CallChainBase.java b/webclient/http1/src/main/java/io/helidon/webclient/http1/Http1CallChainBase.java index dad118bd2ee..41c076d0ee3 100644 --- a/webclient/http1/src/main/java/io/helidon/webclient/http1/Http1CallChainBase.java +++ b/webclient/http1/src/main/java/io/helidon/webclient/http1/Http1CallChainBase.java @@ -272,6 +272,7 @@ private static boolean mayHaveEntity(Status responseStatus, ClientResponseHeader if (responseHeaders.contains(HeaderValues.CONTENT_LENGTH_ZERO)) { return false; } + // Why is NOT_MODIFIED_304 not added here too? if (responseStatus == Status.NO_CONTENT_204) { return false; } diff --git a/webserver/webserver/src/main/java/io/helidon/webserver/http/HttpRouting.java b/webserver/webserver/src/main/java/io/helidon/webserver/http/HttpRouting.java index 8b4350d4d94..c7a253e5fbf 100644 --- a/webserver/webserver/src/main/java/io/helidon/webserver/http/HttpRouting.java +++ b/webserver/webserver/src/main/java/io/helidon/webserver/http/HttpRouting.java @@ -631,7 +631,7 @@ public Void call() throws Exception { return null; } if (result == RoutingResult.NONE) { - throw new NotFoundException("Endpoint not found"); + throw new NotFoundException("Not Found"); } // rerouting, do the more heavyweight while loop @@ -653,7 +653,7 @@ public Void call() throws Exception { response.commit(); return null; } - throw new NotFoundException("Endpoint not found"); + throw new NotFoundException("Not Found"); } private RoutingResult doRoute(ConnectionContext ctx, RoutingRequest request, RoutingResponse response) throws Exception { diff --git a/webserver/webserver/src/main/java/io/helidon/webserver/http1/Http1ServerResponse.java b/webserver/webserver/src/main/java/io/helidon/webserver/http1/Http1ServerResponse.java index 4875d34c41b..00aad7d152a 100644 --- a/webserver/webserver/src/main/java/io/helidon/webserver/http1/Http1ServerResponse.java +++ b/webserver/webserver/src/main/java/io/helidon/webserver/http1/Http1ServerResponse.java @@ -111,7 +111,8 @@ static void nonEntityBytes(ServerResponseHeaders headers, buffer.write(OK_200); } else { buffer.write(HTTP_BYTES); - String reasonPhrase = status.reasonPhrase().isEmpty() ? status.codeText() : status.reasonPhrase(); + String reasonPhrase = status.reasonPhrase() == null || status.reasonPhrase().isEmpty() + ? status.codeText() : status.reasonPhrase(); buffer.write((status.code() + " " + reasonPhrase).getBytes(StandardCharsets.US_ASCII)); buffer.write('\r'); buffer.write('\n');