Injection of web target with correct endpoint. (#2380)

* Injection of web target with correct endpoint.
* Support for junit5 tests already in MP Config implementation
* Support for inherited repeating annotations.

Signed-off-by: Tomas Langer <tomas.langer@oracle.com>
This commit is contained in:
Tomas Langer
2020-09-23 13:40:01 +02:00
committed by GitHub
parent 62279c7b3c
commit 446afa7675
37 changed files with 600 additions and 347 deletions

View File

@@ -41,6 +41,11 @@ A test can be annotated with `io.helidon.microprofile.tests.junit5.HelidonTest`
CDI test. This annotation will start the CDI container before any test method is invoked, and stop it after
the last method is invoked. This annotation also enables injection into the test class itself.
The annotations described in this section are inherited (for the non-repeatable ones), and additive (for repeatable).
So if you declare `@DisableDiscovery` on abstract class, all implementations will have discovery disabled, unless you
annotate the implementation class with `@DisableDiscovery(false)`.
If you declare `@AddBean` on both abstract class and implementation class, both beans will be added.
In addition to this simplification, the following annotations are supported:
- `io.helidon.microprofile.tests.junit5.AddBean` - to add one or more beans to the container
@@ -49,6 +54,7 @@ In addition to this simplification, the following annotations are supported:
(if not added through service loader, or when discovery is disabled)
- `io.helidon.microprofile.tests.junit5.AddConfig` - to add one or more configuration properties to MicroProfile config
without the need of creating a `microprofile-config.properties` file
- `io.helidon.microprofile.tests.junit5.DisableDiscovery` - to disable automated discovery of beans and extensions
[source,java]
.Code sample
@@ -84,10 +90,23 @@ This will change the behavior as follows:
== Usage - configuration
In addition to the `@AddConfig` annotation, you can also use
`@Configuration`.
`@Configuration` to configure additional classpath properties config sources using `configSources`, and to
mark that a custom configuration is desired.
You can set up config in `@BeforeAll` method and register it with `ConfigProviderResolver` using MP Config APIs, and declare
`@Configuration(useExisting=true)`.
Note that this is not compatible with repeatable tests that use method sources that access CDI, as we must delay the CDI
startup to the test class instantiation (which is too late, as the method sources are already invoked by this time).
This allows you to do the following:
*If you want to use method sources that use CDI with repeatable tests, please do not use `@Configuration(useExisting=true)`*
- when `useExisting` is set to `true`, the configuration will not be changed
and current MP configuration will be used
- you can configure additional classpath properties config sources using `configSources`
== Usage - added parameters and injection types
The following types are available for injection (when a single CDI container is used per test class):
- `WebTarget` - a JAX-RS client's target configured for the current hostname and port when `helidon-micorprofile-server` is on
the classpath
The following types are available as method parameters (in any type of Helidon tests):
- `WebTarget` - a JAX-RS client's target configured for the current hostname and port when `helidon-micorprofile-server` is on
the classpath
- `SeContainer` - the current container instance

View File

@@ -36,9 +36,8 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.isOneOf;
import static org.hamcrest.Matchers.contains;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.hamcrest.Matchers.isOneOf;
class RetryTest {
@Test

View File

@@ -86,5 +86,10 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.tests</groupId>
<artifactId>helidon-microprofile-tests-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020 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.
@@ -18,30 +18,23 @@ package io.helidon.microprofile.config;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Map;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import javax.enterprise.inject.spi.CDI;
import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Inject;
import javax.inject.Qualifier;
import io.helidon.config.test.infra.RestoreSystemPropertiesExt;
import io.helidon.microprofile.config.Converters.Ctor;
import io.helidon.microprofile.config.Converters.Of;
import io.helidon.microprofile.config.Converters.Parse;
import io.helidon.microprofile.config.Converters.ValueOf;
import io.helidon.microprofile.tests.junit5.AddBean;
import io.helidon.microprofile.tests.junit5.AddConfig;
import io.helidon.microprofile.tests.junit5.HelidonTest;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -51,41 +44,23 @@ import static org.junit.jupiter.api.Assertions.assertAll;
/**
* Unit test for MP config injection.
*/
@ExtendWith(RestoreSystemPropertiesExt.class)
@HelidonTest
@AddConfig(key = "inject.of", value = "of")
@AddConfig(key = "inject.valueOf", value = "valueOf")
@AddConfig(key = "inject.parse", value = "parse")
@AddConfig(key = "inject.ctor", value = "ctor")
@AddBean(value = MpConfigInjectionTest.Bean.class, scope = Dependent.class)
@AddBean(value = MpConfigInjectionTest.SubBean.class, scope = Dependent.class)
class MpConfigInjectionTest {
private static SeContainer container;
@Inject
private Bean bean;
@BeforeAll
static void initClass() {
// Removed use of system properties, as those stay around after test is finished
ConfigProviderResolver configProvider = ConfigProviderResolver.instance();
configProvider.registerConfig(configProvider.getBuilder()
.addDefaultSources()
.withSources(new TestSource())
.build(),
Thread.currentThread().getContextClassLoader());
// CDI container
container = SeContainerInitializer.newInstance()
.addBeanClasses(Bean.class, SubBean.class)
.initialize();
}
@AfterAll
static void destroyClass() {
if (null != container) {
container.close();
}
}
@Inject
@Specific
private SubBean subBean;
@Test
public void testImplicitConversion() {
Bean bean = CDI.current().select(Bean.class).get();
assertAll("Implicit conversion injection",
() -> assertThat("of", bean.of, is(Of.of("of"))),
() -> assertThat("valueOf", bean.valueOf, is(ValueOf.valueOf("valueOf"))),
@@ -96,22 +71,15 @@ class MpConfigInjectionTest {
@Test
public void testImplicitConversionSubclass() {
Bean bean = CDI.current().select(SubBean.class,
new AnnotationLiteral<Specific>() {
}).get();
assertAll("Implicit conversion injection",
() -> assertThat("of", bean.of, is(Of.of("of"))),
() -> assertThat("valueOf", bean.valueOf, is(ValueOf.valueOf("valueOf"))),
() -> assertThat("parse", bean.parse, is(Parse.parse("parse"))),
() -> assertThat("ctor", bean.ctor, is(new Ctor("ctor")))
() -> assertThat("of", subBean.of, is(Of.of("of"))),
() -> assertThat("valueOf", subBean.valueOf, is(ValueOf.valueOf("valueOf"))),
() -> assertThat("parse", subBean.parse, is(Parse.parse("parse"))),
() -> assertThat("ctor", subBean.ctor, is(new Ctor("ctor")))
);
}
@Dependent
public static class Bean {
@Inject
@ConfigProperty(name = "inject.of")
public Of of;
@@ -131,36 +99,11 @@ class MpConfigInjectionTest {
@Qualifier
@Retention(RUNTIME)
@Target(TYPE)
@Target({TYPE, FIELD})
public @interface Specific {
}
@Dependent
@Specific
public static class SubBean extends Bean {
}
private static class TestSource implements ConfigSource {
private final Map<String, String> properties = Map.of(
"inject.of", "of",
"inject.valueOf", "valueOf",
"inject.parse", "parse",
"inject.ctor", "ctor"
);
@Override
public Map<String, String> getProperties() {
return properties;
}
@Override
public String getValue(String propertyName) {
return properties.get(propertyName);
}
@Override
public String getName() {
return getClass().getName();
}
}
}

View File

@@ -22,22 +22,25 @@ import java.util.function.BiConsumer;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import javax.enterprise.inject.spi.CDI;
import javax.inject.Inject;
import io.helidon.microprofile.tests.junit5.AddBean;
import io.helidon.microprofile.tests.junit5.Configuration;
import io.helidon.microprofile.tests.junit5.HelidonTest;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
public class MutableMpTest {
private static SeContainer container;
@HelidonTest
@Configuration(useExisting = true)
@AddBean(value = MutableMpTest.Bean.class, scope = Dependent.class)
class MutableMpTest {
private static MutableSource source;
@BeforeAll
@@ -50,35 +53,21 @@ public class MutableMpTest {
.withSources(source)
.build(),
Thread.currentThread().getContextClassLoader());
// CDI container
container = SeContainerInitializer.newInstance()
.addBeanClasses(Bean.class)
.initialize();
}
@AfterAll
static void destroyClass() {
if (null != container) {
container.close();
}
source = null;
}
@Test
public void testMutable() {
Bean bean = CDI.current().select(Bean.class).get();
public void testMutable(SeContainer cdi) {
Bean bean = cdi.select(Bean.class).get();
assertThat(bean.value, is("initial"));
source.setValue("updated");
bean = CDI.current().select(Bean.class).get();
bean = cdi.select(Bean.class).get();
assertThat(bean.value, is("updated"));
}
@Dependent
public static class Bean {
@Inject
@ConfigProperty(name = "value")

View File

@@ -71,5 +71,10 @@
<artifactId>helidon-microprofile-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.tests</groupId>
<artifactId>helidon-microprofile-tests-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -16,26 +16,23 @@
package io.helidon.microprofile.cors;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Set;
import io.helidon.microprofile.server.Server;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import io.helidon.microprofile.tests.junit5.AddBean;
import io.helidon.microprofile.tests.junit5.AddConfig;
import io.helidon.microprofile.tests.junit5.HelidonTest;
import org.junit.jupiter.api.Test;
import static io.helidon.common.http.Http.Header.ORIGIN;
@@ -54,42 +51,22 @@ import static org.hamcrest.MatcherAssert.assertThat;
/**
* Class CrossOriginTest.
*/
public class CrossOriginTest {
private static Client client;
private static Server server;
private static WebTarget target;
@HelidonTest
@AddBean(CrossOriginTest.CorsResource0.class)
@AddBean(CrossOriginTest.CorsResource1.class)
@AddBean(CrossOriginTest.CorsResource2.class)
@AddBean(CrossOriginTest.CorsResource3.class)
@AddConfig(key = "cors.paths.0.path-pattern", value = "/cors3")
@AddConfig(key = "cors.paths.0.allow-origins", value = "http://foo.bar, http://bar.foo")
@AddConfig(key = "cors.paths.0.allow-methods", value = "DELETE, PUT")
class CrossOriginTest {
@Inject
private WebTarget target;
static {
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
}
@BeforeAll
static void initClass() {
server = Server.builder()
.addApplication("/app", new CorsApplication())
.build();
server.start();
client = ClientBuilder.newClient();
target = client.target("http://localhost:" + server.port());
}
@AfterAll
static void destroyClass() {
server.stop();
client.close();
}
@ApplicationScoped
static public class CorsApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
return Set.of(CorsResource0.class, CorsResource1.class, CorsResource2.class, CorsResource3.class);
}
}
@RequestScoped
@Path("/cors1")
static public class CorsResource1 {
@@ -134,7 +111,7 @@ public class CrossOriginTest {
}
@RequestScoped
@Path("/cors3") // Configured in META-INF/microprofile-config.properties
@Path("/cors3")
static public class CorsResource3 {
@DELETE
@@ -178,7 +155,7 @@ public class CrossOriginTest {
@Test
void test1PreFlightAllowedOrigin() {
Response res = target.path("/app/cors1")
Response res = target.path("/cors1")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -192,7 +169,7 @@ public class CrossOriginTest {
@Test
void test1PreFlightAllowedHeaders1() {
Response res = target.path("/app/cors1")
Response res = target.path("/cors1")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -207,7 +184,7 @@ public class CrossOriginTest {
@Test
void test1PreFlightAllowedHeaders2() {
Response res = target.path("/app/cors1")
Response res = target.path("/cors1")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -225,7 +202,7 @@ public class CrossOriginTest {
@Test
void test2PreFlightForbiddenOrigin() {
Response res = target.path("/app/cors2")
Response res = target.path("/cors2")
.request()
.header(ORIGIN, "http://not.allowed")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -235,7 +212,7 @@ public class CrossOriginTest {
@Test
void test2PreFlightAllowedOrigin() {
Response res = target.path("/app/cors2")
Response res = target.path("/cors2")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -250,7 +227,7 @@ public class CrossOriginTest {
@Test
void test2PreFlightForbiddenMethod() {
Response res = target.path("/app/cors2")
Response res = target.path("/cors2")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "POST")
@@ -260,7 +237,7 @@ public class CrossOriginTest {
@Test
void test2PreFlightForbiddenHeader() {
Response res = target.path("/app/cors2")
Response res = target.path("/cors2")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -271,7 +248,7 @@ public class CrossOriginTest {
@Test
void test2PreFlightAllowedHeaders1() {
Response res = target.path("/app/cors2")
Response res = target.path("/cors2")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -288,7 +265,7 @@ public class CrossOriginTest {
@Test
void test2PreFlightAllowedHeaders2() {
Response res = target.path("/app/cors2")
Response res = target.path("/cors2")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -307,7 +284,7 @@ public class CrossOriginTest {
@Test
void test2PreFlightAllowedHeaders3() {
Response res = target.path("/app/cors2")
Response res = target.path("/cors2")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -327,7 +304,7 @@ public class CrossOriginTest {
@Test
void test1ActualAllowedOrigin() {
Response res = target.path("/app/cors1")
Response res = target.path("/cors1")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -338,7 +315,7 @@ public class CrossOriginTest {
@Test
void test2ActualAllowedOrigin() {
Response res = target.path("/app/cors2")
Response res = target.path("/cors2")
.request()
.header(ORIGIN, "http://foo.bar")
.put(Entity.entity("", MediaType.TEXT_PLAIN_TYPE));
@@ -349,7 +326,7 @@ public class CrossOriginTest {
@Test
void test3PreFlightAllowedOrigin() {
Response res = target.path("/app/cors3")
Response res = target.path("/cors3")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -363,7 +340,7 @@ public class CrossOriginTest {
@Test
void test3ActualAllowedOrigin() {
Response res = target.path("/app/cors3")
Response res = target.path("/cors3")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -374,7 +351,7 @@ public class CrossOriginTest {
@Test
void testErrorResponse() {
Response res = target.path("/app/notfound")
Response res = target.path("/notfound")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -385,7 +362,7 @@ public class CrossOriginTest {
@Test
void testMainPathInPresenceOfSubpath() {
Response res = target.path("/app/cors0")
Response res = target.path("/cors0")
.request()
.header(ORIGIN, "http://foo.bar")
.get();
@@ -396,7 +373,7 @@ public class CrossOriginTest {
@Test
void testSubPathPreflightAllowed() {
Response res = target.path("/app/cors0/subpath")
Response res = target.path("/cors0/subpath")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")
@@ -410,7 +387,7 @@ public class CrossOriginTest {
@Test
void testSubPathActualAllowed() {
Response res = target.path("/app/cors0/subpath")
Response res = target.path("/cors0/subpath")
.request()
.header(ORIGIN, "http://foo.bar")
.header(ACCESS_CONTROL_REQUEST_METHOD, "PUT")

View File

@@ -1,18 +0,0 @@
#
# Copyright (c) 2019, 2020 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.
#
cors.paths.0.path-pattern=/cors3
cors.paths.0.allow-origins=http://foo.bar, http://bar.foo
cors.paths.0.allow-methods=DELETE, PUT

View File

@@ -22,6 +22,7 @@ import java.util.concurrent.CompletionStage;
import java.util.stream.Stream;
import io.helidon.microprofile.tests.junit5.AddBean;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

View File

@@ -58,6 +58,10 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.helidon.health</groupId>
<artifactId>helidon-health-common</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
@@ -69,8 +73,9 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.health</groupId>
<artifactId>helidon-health-common</artifactId>
<groupId>io.helidon.microprofile.tests</groupId>
<artifactId>helidon-microprofile-tests-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

View File

@@ -19,59 +19,37 @@ package io.helidon.microprofile.health;
import java.io.StringReader;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import io.helidon.microprofile.server.Server;
import io.helidon.microprofile.tests.junit5.AddBean;
import io.helidon.microprofile.tests.junit5.HelidonTest;
import org.eclipse.microprofile.health.Health;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.logging.LoggingFeature;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.eclipse.microprofile.health.Liveness;
import org.eclipse.microprofile.health.Readiness;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
@HelidonTest
@AddBean(HealthMpServiceIT.HealthCheckOne.class)
@AddBean(HealthMpServiceIT.HealthCheckTwo.class)
@AddBean(HealthMpServiceIT.HealthCheckBad.class)
public class HealthMpServiceIT {
private static final Logger LOGGER = Logger.getLogger(HealthMpServiceIT.class.getName());
private static Server server;
private static Client client;
@BeforeAll
public static void startServer() throws Exception {
LogManager.getLogManager().readConfiguration(HealthMpServiceIT.class.getResourceAsStream("/logging.properties"));
server = Server.create().start();
client = ClientBuilder.newBuilder()
.register(new LoggingFeature(LOGGER, Level.WARNING, LoggingFeature.Verbosity.PAYLOAD_ANY, 500))
.property(ClientProperties.FOLLOW_REDIRECTS, true)
.build();
}
@AfterAll
public static void stopServer() {
if (server != null) {
server.stop();
}
}
@Inject
private WebTarget webTarget;
/**
* Verify that the {@link HealthCheck} CDI beans (inner classes below)
@@ -104,12 +82,14 @@ public class HealthMpServiceIT {
@Test
public void shouldAddProvidedHealthChecks() {
JsonObject json = getHealthJson();
assertThat(healthCheckExists(json, "Three"), is(true));
assertThat(healthCheckExists(json, "Four"), is(true));
assertThat(healthCheckExists(json, "Five"), is(true));
assertThat(healthCheckExists(json, "Six"), is(true));
}
Assertions.assertAll(
() -> assertThat("Three exists", healthCheckExists(json, "Three"), is(true)),
() -> assertThat("Four exists", healthCheckExists(json, "Four"), is(true)),
() -> assertThat("Five exists", healthCheckExists(json, "Five"), is(true)),
() -> assertThat("Six exists", healthCheckExists(json, "Six"), is(true))
);
}
private boolean healthCheckExists(JsonObject json, String name) {
return json.getJsonArray("checks")
@@ -120,7 +100,7 @@ public class HealthMpServiceIT {
private JsonObject getHealthJson() {
// request the application metrics in json format from the web server
String health = client.target("http://localhost:" + server.port())
String health = webTarget
.path("health")
.request()
.accept(MediaType.APPLICATION_JSON)
@@ -136,8 +116,7 @@ public class HealthMpServiceIT {
* A test {@link HealthCheck} bean that should be discovered
* by CDI and added to the health check endpoint.
*/
@Health
@ApplicationScoped
@Readiness
public static class HealthCheckOne
implements HealthCheck {
@@ -151,8 +130,7 @@ public class HealthMpServiceIT {
* A test {@link HealthCheck} bean that should be discovered
* by CDI and added to the health check endpoint.
*/
@Health
@ApplicationScoped
@Liveness
public static class HealthCheckTwo
implements HealthCheck {

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
version="2.0"
bean-discovery-mode="annotated">
</beans>

View File

@@ -92,5 +92,10 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.tests</groupId>
<artifactId>helidon-microprofile-tests-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020 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.
@@ -26,15 +26,14 @@ import javax.inject.Inject;
import javax.json.JsonString;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
import io.helidon.config.Config;
import io.helidon.microprofile.server.Server;
import io.helidon.microprofile.tests.junit5.AddBean;
import io.helidon.microprofile.tests.junit5.HelidonTest;
import io.helidon.security.EndpointConfig;
import io.helidon.security.OutboundSecurityResponse;
import io.helidon.security.Principal;
@@ -47,8 +46,6 @@ import org.eclipse.microprofile.jwt.Claim;
import org.eclipse.microprofile.jwt.ClaimValue;
import org.eclipse.microprofile.jwt.Claims;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -60,27 +57,13 @@ import static org.mockito.Mockito.when;
/**
* Unit test for {@link io.helidon.microprofile.jwt.auth.JsonWebTokenProducer}.
*/
@HelidonTest
@AddBean(JwtAuthTest.MyApp.class)
@AddBean(JwtAuthTest.MyResource.class)
@AddBean(JwtAuthTest.ResourceWithPublicMethod.class)
class JwtAuthTest {
private static Server server;
private static Client client;
@BeforeAll
static void startServer() {
server = Server.create(MyApp.class);
server.start();
client = ClientBuilder.newClient();
}
@AfterAll
static void stopServer() {
if (null != server) {
server.stop();
}
if (null != client) {
client.close();
}
}
@Inject
private WebTarget target;
@Test
void testRsa() {
@@ -126,8 +109,6 @@ class JwtAuthTest {
String signedToken = response.requestHeaders().get("Authorization").get(0);
WebTarget target = client.target("http://localhost:" + server.port());
// authenticated
String httpResponse = target.path("/hello")
.request()
@@ -147,8 +128,6 @@ class JwtAuthTest {
@Test
void testPublicEndpoint() {
WebTarget target = client.target("http://localhost:" + server.port());
// public
String httpResponse = target.path("/public")
.request()

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
version="2.0"
bean-discovery-mode="annotated">
</beans>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020 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.
@@ -51,6 +51,7 @@ class ServerImplTest {
client.close();
}
@Test
void testCustomExecutorService() {
Server server = Server.builder()
.addApplication("/app1", new TestApplication1())

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2020 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.helidon.microprofile.tests</groupId>
<artifactId>tests-project</artifactId>
<version>2.0.3-SNAPSHOT</version>
</parent>
<artifactId>helidon-microprofile-tests-junit5-tests</artifactId>
<name>Helidon Microprofile Tests Junit5 unit tests</name>
<description>
Test for JUnit5 integration to prevent cyclic dependendcies,
so the module can be used in MP config implementation
</description>
<dependencies>
<dependency>
<groupId>io.helidon.microprofile.server</groupId>
<artifactId>helidon-microprofile-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.tests</groupId>
<artifactId>helidon-microprofile-tests-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2020 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.tests.junit5;
import javax.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@HelidonTest
@AddConfig(key = "key", value = "value")
abstract class AbstractTest {
@Inject
@ConfigProperty(name = "key")
private String key;
@Test
void testKey() {
assertThat(key, is("value"));
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2020 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.tests.junit5;
import javax.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@AddConfig(key = "key1", value = "value1")
class TestChild1 extends AbstractTest {
@Inject
@ConfigProperty(name = "key1")
private String childKey;
@Test
void testChildKey() {
assertThat(childKey, is("value1"));
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2020 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.tests.junit5;
import javax.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@AddConfig(key = "key2", value = "value2")
class TestChild2 extends AbstractTest {
@Inject
@ConfigProperty(name = "key2")
private String childKey;
@Test
void testChildKey() {
assertThat(childKey, is("value2"));
}
}

View File

@@ -26,7 +26,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
@HelidonTest
@Configuration(configSources = "testConfigSources.properties")
public class TestConfigSources {
class TestConfigSources {
@Inject
@ConfigProperty(name = "some.key")
private String someKey;

View File

@@ -31,7 +31,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
@HelidonTest
@DisableDiscovery
@AddBean(TestConstructorInjection.MyBean.class)
public class TestConstructorInjection {
class TestConstructorInjection {
private final int currentPort;
@Inject

View File

@@ -54,7 +54,7 @@ class TestPerMethod {
@Test
@AddConfig(key = "key-1", value = "value-1")
@AddBean(TestPerMethod.MyBean.class)
@AddBean(MyBean.class)
void testWithAdditionalConfig() {
String configured = CDI.current()
.select(MyBean.class)
@@ -65,7 +65,7 @@ class TestPerMethod {
}
@Test
@AddExtension(TestPerMethod.MyExtension.class)
@AddExtension(MyExtension.class)
void testCustomExtension() {
assertThat("Extension should have been called, as it observes application scope", MyExtension.called, is(true));
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2020 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.tests.junit5;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.client.WebTarget;
import io.helidon.microprofile.server.JaxRsCdiExtension;
import io.helidon.microprofile.server.ServerCdiExtension;
import org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
@HelidonTest(resetPerTest = true)
@DisableDiscovery
@AddExtension(ServerCdiExtension.class)
@AddExtension(JaxRsCdiExtension.class)
@AddExtension(CdiComponentProvider.class)
@AddBean(TestWebTarget.ResourceClass.class)
class TestWebTarget {
@Test
void testFirst(WebTarget target) {
assertThat(target, notNullValue());
String response = target.path("/test")
.request()
.get(String.class);
assertThat(response, is("Hello from ResourceClass"));
}
@Test
void testSecond(WebTarget target) {
assertThat(target, notNullValue());
String response = target.path("/test")
.request()
.get(String.class);
assertThat(response, is("Hello from ResourceClass"));
}
@Path("/test")
public static class ResourceClass {
@GET
public String getIt() {
return "Hello from ResourceClass";
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2020 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.tests.junit5;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.client.WebTarget;
import io.helidon.microprofile.server.JaxRsCdiExtension;
import io.helidon.microprofile.server.ServerCdiExtension;
import org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
@HelidonTest
@DisableDiscovery
@AddExtension(ServerCdiExtension.class)
@AddExtension(JaxRsCdiExtension.class)
@AddExtension(CdiComponentProvider.class)
@AddBean(TestWebTargetPerMethod.ResourceClass.class)
class TestWebTargetPerMethod {
@Inject
private WebTarget injected;
@Test
void testIt() {
assertThat(injected, notNullValue());
String response = injected.path("/test")
.request()
.get(String.class);
assertThat(response, is("Hello from ResourceClass"));
}
@Test
void testInMethod(WebTarget method) {
assertThat(method, notNullValue());
String response = method.path("/test")
.request()
.get(String.class);
assertThat(response, is("Hello from ResourceClass"));
}
@Path("/test")
public static class ResourceClass {
@GET
public String getIt() {
return "Hello from ResourceClass";
}
}
}

View File

@@ -38,16 +38,15 @@
<artifactId>helidon-microprofile-cdi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.config</groupId>
<artifactId>helidon-microprofile-config</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.helidon.jersey</groupId>
<artifactId>helidon-jersey-client</artifactId>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>

View File

@@ -17,6 +17,7 @@
package io.helidon.microprofile.tests.junit5;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -26,11 +27,16 @@ import java.lang.annotation.Target;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
public @interface Configuration {
/**
* If set to {@code true}, the existing (or default) MicroProfile configuration would be used.
* By default uses a configuration constructed using all {@link io.helidon.microprofile.tests.junit5.AddConfig}
* annotations and {@link #configSources()}.
* When set to false and a {@link org.junit.jupiter.api.BeforeAll} method registers a custom configuration
* with {@link org.eclipse.microprofile.config.spi.ConfigProviderResolver}, the result is undefined, though
* tests have shown that the registered config may be used (as BeforeAll ordering is undefined by
* JUnit, it may be called after our extension)
*
* @return whether to use existing (or default) configuration, or customized one
*/

View File

@@ -17,6 +17,7 @@
package io.helidon.microprofile.tests.junit5;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -37,6 +38,7 @@ import java.lang.annotation.Target;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
public @interface DisableDiscovery {
/**
* By default if you annotate a class or a method, discovery gets disabled.

View File

@@ -32,14 +32,21 @@ import java.util.Map;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.BeforeBeanDiscovery;
import javax.enterprise.inject.spi.CDI;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import io.helidon.config.mp.MpConfigSources;
@@ -70,6 +77,14 @@ class HelidonJunitExtension implements BeforeAllCallback,
ParameterResolver {
private static final Set<Class<? extends Annotation>> HELIDON_TEST_ANNOTATIONS =
Set.of(AddBean.class, AddConfig.class, AddExtension.class, Configuration.class);
private static final Map<Class<? extends Annotation>, Annotation> BEAN_DEFINING = new HashMap<>();
static {
BEAN_DEFINING.put(ApplicationScoped.class, ApplicationScoped.Literal.INSTANCE);
BEAN_DEFINING.put(Singleton.class, ApplicationScoped.Literal.INSTANCE);
BEAN_DEFINING.put(RequestScoped.class, RequestScoped.Literal.INSTANCE);
BEAN_DEFINING.put(Dependent.class, Dependent.Literal.INSTANCE);
}
private final List<AddExtension> classLevelExtensions = new ArrayList<>();
private final List<AddBean> classLevelBeans = new ArrayList<>();
@@ -87,15 +102,15 @@ class HelidonJunitExtension implements BeforeAllCallback,
public void beforeAll(ExtensionContext context) {
testClass = context.getRequiredTestClass();
AddConfig[] configs = testClass.getAnnotationsByType(AddConfig.class);
AddConfig[] configs = getAnnotations(testClass, AddConfig.class);
classLevelConfigMeta.addConfig(configs);
classLevelConfigMeta.configuration(testClass.getAnnotation(Configuration.class));
configProviderResolver = ConfigProviderResolver.instance();
AddExtension[] extensions = testClass.getAnnotationsByType(AddExtension.class);
AddExtension[] extensions = getAnnotations(testClass, AddExtension.class);
classLevelExtensions.addAll(Arrays.asList(extensions));
AddBean[] beans = testClass.getAnnotationsByType(AddBean.class);
AddBean[] beans = getAnnotations(testClass, AddBean.class);
classLevelBeans.addAll(Arrays.asList(beans));
HelidonTest testAnnot = testClass.getAnnotation(HelidonTest.class);
@@ -117,7 +132,35 @@ class HelidonJunitExtension implements BeforeAllCallback,
configure(classLevelConfigMeta);
startContainer(classLevelBeans, classLevelExtensions, classLevelDisableDiscovery);
if (!classLevelConfigMeta.useExisting) {
// the container startup is delayed in case we `useExisting`, so the is first set up by the user
// when we do not need to `useExisting`, we want to start early, so parameterized test method sources that use CDI
// can work
startContainer(classLevelBeans, classLevelExtensions, classLevelDisableDiscovery);
}
}
@SuppressWarnings("unchecked")
private <T extends Annotation> T[] getAnnotations(Class<?> testClass, Class<T> annotClass) {
// inherited does not help, as it only returns annot from superclass if
// child has none
T[] directAnnotations = testClass.getAnnotationsByType(annotClass);
List<T> allAnnotations = new ArrayList<>(List.of(directAnnotations));
Class<?> superClass = testClass.getSuperclass();
while (superClass != null) {
directAnnotations = superClass.getAnnotationsByType(annotClass);
allAnnotations.addAll(List.of(directAnnotations));
superClass = superClass.getSuperclass();
}
Object result = Array.newInstance(annotClass, allAnnotations.size());
for (int i = 0; i < allAnnotations.size(); i++) {
Array.set(result, i, allAnnotations.get(i));
}
return (T[]) result;
}
@Override
@@ -310,6 +353,12 @@ class HelidonJunitExtension implements BeforeAllCallback,
return invocation.proceed();
}
// we need to start container before the test class is instantiated, to honor @BeforeAll that
// creates a custom MP config
if (container == null) {
startContainer(classLevelBeans, classLevelExtensions, classLevelDisableDiscovery);
}
// we need to replace instantiation with CDI lookup, to properly injection into fields (and constructors)
invocation.skip();
@@ -328,15 +377,26 @@ class HelidonJunitExtension implements BeforeAllCallback,
throw new ParameterResolutionException(
"When a test class is annotated with @HelidonTest(resetPerMethod=true), constructor must not have "
+ "parameters.");
} else if (executable instanceof Method) {
if (parameterContext.getParameter().getType().equals(SeContainer.class)) {
return true;
}
}
} else {
// we need to start container before the test class is instantiated, to honor @BeforeAll that
// creates a custom MP config
if (container == null) {
startContainer(classLevelBeans, classLevelExtensions, classLevelDisableDiscovery);
}
}
Class<?> paramType = parameterContext.getParameter().getType();
if (executable instanceof Constructor) {
return !container.select(parameterContext.getParameter().getType()).isUnsatisfied();
return !container.select(paramType).isUnsatisfied();
} else if (executable instanceof Method) {
if (paramType.equals(SeContainer.class)) {
return true;
}
if (paramType.equals(WebTarget.class)) {
return true;
}
}
return false;
@@ -345,16 +405,22 @@ class HelidonJunitExtension implements BeforeAllCallback,
@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
Executable executable = parameterContext.getParameter().getDeclaringExecutable();
Class<?> paramType = parameterContext.getParameter().getType();
if (parameterContext.getParameter().getType().equals(SeContainer.class)) {
return container;
if (executable instanceof Method) {
if (paramType.equals(SeContainer.class)) {
return container;
}
if (paramType.equals(WebTarget.class)) {
return container.select(WebTarget.class).get();
}
}
// we return null, as construction of the object is done by CDI
// for primitive types we must return appropriate primitive default
Class<?> type = parameterContext.getParameter().getType();
if (type.isPrimitive()) {
if (paramType.isPrimitive()) {
// a hack to get to default value of a primitive type
return Array.get(Array.newInstance(type, 1), 0);
return Array.get(Array.newInstance(paramType, 1), 0);
} else {
return null;
}
@@ -371,6 +437,28 @@ class HelidonJunitExtension implements BeforeAllCallback,
this.addBeans = addBeans;
}
@SuppressWarnings("unchecked")
void registerOtherBeans(@Observes AfterBeanDiscovery event) {
Client client = ClientBuilder.newClient();
event.addBean()
.addType(javax.ws.rs.client.WebTarget.class)
.scope(ApplicationScoped.class)
.createWith(context -> {
try {
Class<? extends Extension> extClass = (Class<? extends Extension>) Class
.forName("io.helidon.microprofile.server.ServerCdiExtension");
Extension extension = CDI.current().getBeanManager().getExtension(extClass);
Method m = extension.getClass().getMethod("port");
int port = (int) m.invoke(extension);
String uri = "http://localhost:" + port;
return client.target(uri);
} catch (Exception e) {
return client.target("http://localhost:7001");
}
});
}
void registerAddedBeans(@Observes BeforeBeanDiscovery event) {
event.addAnnotatedType(testClass, "junit-" + testClass.getName())
.add(ApplicationScoped.Literal.INSTANCE);
@@ -379,20 +467,32 @@ class HelidonJunitExtension implements BeforeAllCallback,
Annotation scope;
Class<? extends Annotation> definedScope = addBean.scope();
if (definedScope.equals(ApplicationScoped.class) || definedScope.equals(Singleton.class)) {
scope = ApplicationScoped.Literal.INSTANCE;
} else if (definedScope.equals(RequestScoped.class)) {
scope = RequestScoped.Literal.INSTANCE;
} else {
scope = BEAN_DEFINING.get(definedScope);
if (scope == null) {
throw new IllegalStateException(
"Only Singleton, ApplicationScoped and RequestScoped are allowed in tests. Scope " + definedScope
.getName() + " is not allowed for bean " + addBean.value().getName());
"Only on of " + BEAN_DEFINING.keySet() + " scopes are allowed in tests. Scope "
+ definedScope.getName() + " is not allowed for bean " + addBean.value().getName());
}
event.addAnnotatedType(addBean.value(), "junit-" + addBean.value().getName())
.add(scope);
AnnotatedTypeConfigurator<?> configurator = event
.addAnnotatedType(addBean.value(), "junit-" + addBean.value().getName());
if (!hasBda(addBean.value())) {
configurator.add(scope);
}
}
}
private boolean hasBda(Class<?> value) {
// does it have bean defining annotation?
for (Class<? extends Annotation> aClass : BEAN_DEFINING.keySet()) {
if (value.getAnnotation(aClass) != null) {
return true;
}
}
return false;
}
}
private static final class ConfigMeta {
@@ -401,8 +501,11 @@ class HelidonJunitExtension implements BeforeAllCallback,
private boolean useExisting;
private ConfigMeta() {
// to allow SeContainerInitializer (forbidden by default because of native image)
additionalKeys.put("mp.initializer.allow", "true");
additionalKeys.put("mp.initializer.no-warn", "true");
// to run on random port
additionalKeys.put("server.port", "0");
// higher ordinal then all the defaults, system props and environment variables
additionalKeys.putIfAbsent(ConfigSource.CONFIG_ORDINAL, "1000");
}
@@ -421,7 +524,7 @@ class HelidonJunitExtension implements BeforeAllCallback,
additionalSources.addAll(List.of(config.configSources()));
}
public ConfigMeta nextMethod() {
ConfigMeta nextMethod() {
ConfigMeta methodMeta = new ConfigMeta();
methodMeta.additionalKeys.putAll(this.additionalKeys);

View File

@@ -16,6 +16,7 @@
package io.helidon.microprofile.tests.junit5;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -36,6 +37,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ExtendWith(HelidonJunitExtension.class)
@Inherited
public @interface HelidonTest {
/**
* By default, CDI container is created once before the class is initialized and shut down

View File

@@ -41,6 +41,7 @@
<modules>
<module>arquillian</module>
<module>junit5</module>
<module>junit5-tests</module>
</modules>
<profiles>