diff --git a/README.md b/README.md index 54efc37..099e33d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This is a test fixture, which provides a very basic servlet that registers expec Usage is pretty simple: -####For junit 4 Rule based +#### For junit 4 Rule based @Rule public ExpectationServerRule serverRule = new ExpectationServerRule( "repos" ); @@ -23,7 +23,7 @@ Usage is pretty simple: } -####For junit 5 Extension Based: +#### For junit 5 Extension Based: @ExtendWith(ExpectationServerExtension.class) public class ExpectaionTest{ @@ -62,4 +62,29 @@ or: // Do any assertions.... ....... } + } + +#### Quarkus Based Test + +There are some limitations to let junit5 @ExtendWith work together with @QuarkusTest, see https://github.com/quarkusio/quarkus/issues/24911#issuecomment-1098935690 +So to make it work, here brings the new annotation to make it work. + + + @QuarkusTest + public class ExpectaionTest{ + + @InjectExpected("repos") + ExpectationServer server; + + @Test + public void run() + throws Exception + { + final String pathParts = "/repos/pathParts/to/something.txt"; + final String content = "this is the content"; + final String url = server.formatUrl( pathParts ); + server.expect( url, 200, content ); + // Do any assertions.... + ....... + } } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 741ec28..ec6ce04 100644 --- a/pom.xml +++ b/pom.xml @@ -77,6 +77,7 @@ core junit4 junit5 + quarkus diff --git a/quarkus/pom.xml b/quarkus/pom.xml new file mode 100644 index 0000000..1dd66e1 --- /dev/null +++ b/quarkus/pom.xml @@ -0,0 +1,98 @@ + + + + + org.commonjava.util + http-testserver-parent + 2.1.1-SNAPSHOT + ../pom.xml + + 4.0.0 + + http-testserver-quarkus + + 2.16.11.Final + + + + + + io.quarkus + quarkus-bom + ${quarkus.version} + pom + import + + + + + + + org.commonjava.util + http-testserver-core + 2.1.1-SNAPSHOT + + + org.junit.jupiter + junit-jupiter + 5.9.2 + compile + + + io.quarkus + quarkus-arc-deployment + + + io.quarkus + quarkus-mutiny + + + io.quarkus + quarkus-junit5 + + + org.hamcrest + hamcrest + 2.2 + test + + + + + + + io.quarkus + quarkus-maven-plugin + ${quarkus.version} + + + + build + generate-code + generate-code-tests + + + + + + + + \ No newline at end of file diff --git a/quarkus/src/main/java/org/commonjava/test/http/quarkus/InjectExpected.java b/quarkus/src/main/java/org/commonjava/test/http/quarkus/InjectExpected.java new file mode 100644 index 0000000..6258425 --- /dev/null +++ b/quarkus/src/main/java/org/commonjava/test/http/quarkus/InjectExpected.java @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2011-2022 Red Hat, Inc. (https://github.com/Commonjava/http-testserver) + * + * 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 org.commonjava.test.http.quarkus; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * We use this new annotation to let the {@link org.commonjava.test.http.expect.ExpectationServer} have ability to be work like the + * old junit Rule based way under Quarkus Based Test. + * Note: This annotation should work with @QuarkusTest under a Quarkus based project, like below:
+ * + *
+ *   {@literal @}QuarkusTest
+ *    public class TestClass {
+ *        {@literal @}InjectExpected(base="base")
+ *         ExpectationServer server;
+ *         ......
+ *    }
+ * 
+ */ +@Target( ElementType.FIELD) +@Retention( RetentionPolicy.RUNTIME) +public @interface InjectExpected +{ + /** + * The base path of the server + * + * @return + */ + String base() default ""; + + /** + * The default port of the server. Note that if the port is occupied, the server will randomly find a new port to start + * @return + */ + int port() default 0; +} diff --git a/quarkus/src/main/java/org/commonjava/test/http/quarkus/InjectStream.java b/quarkus/src/main/java/org/commonjava/test/http/quarkus/InjectStream.java new file mode 100644 index 0000000..a8fa67d --- /dev/null +++ b/quarkus/src/main/java/org/commonjava/test/http/quarkus/InjectStream.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2011-2022 Red Hat, Inc. (https://github.com/Commonjava/http-testserver) + * + * 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 org.commonjava.test.http.quarkus; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * We use this new annotation to let the {@link org.commonjava.test.http.stream.StreamServer} have ability to be work like the + * old junit Rule based way under Quarkus Based Test. + * Note: This annotation should work with @QuarkusTest under a Quarkus based project + */ +@Target( ElementType.FIELD ) +@Retention( RetentionPolicy.RUNTIME ) +public @interface InjectStream +{ + /** + * The base path of the server + * + * @return + */ + String base() default ""; + +} diff --git a/quarkus/src/main/java/org/commonjava/test/http/quarkus/internal/ExpectationServerCallBack.java b/quarkus/src/main/java/org/commonjava/test/http/quarkus/internal/ExpectationServerCallBack.java new file mode 100644 index 0000000..f7c154b --- /dev/null +++ b/quarkus/src/main/java/org/commonjava/test/http/quarkus/internal/ExpectationServerCallBack.java @@ -0,0 +1,93 @@ +/** + * Copyright (C) 2011-2022 Red Hat, Inc. (https://github.com/Commonjava/http-testserver) + * + * 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 org.commonjava.test.http.quarkus.internal; + +import io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback; +import io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback; +import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback; +import io.quarkus.test.junit.callback.QuarkusTestMethodContext; +import org.commonjava.test.http.expect.ExpectationServer; +import org.commonjava.test.http.quarkus.InjectExpected; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ExpectationServerCallBack + implements QuarkusTestAfterConstructCallback, QuarkusTestAfterEachCallback, QuarkusTestBeforeEachCallback +{ + private final Logger logger = LoggerFactory.getLogger( this.getClass() ); + + private static final Map injectServers = new ConcurrentHashMap<>(); + + @Override + public void afterConstruct( Object testInstance ) + { + Class current = testInstance.getClass(); + while ( current.getSuperclass() != null ) + { + for ( Field field : current.getDeclaredFields() ) + { + InjectExpected injectMockAnnotation = field.getAnnotation( InjectExpected.class ); + if ( injectMockAnnotation != null && field.getType().equals( ExpectationServer.class ) ) + { + final String baseResource = injectMockAnnotation.base(); + final int port = injectMockAnnotation.port(); + logger.trace( "Found field with @InjectExpected annotation, base resource is {}, port is {}", + baseResource, port ); + + ExpectationServer server = new ExpectationServer( baseResource, port ); + try + { + logger.trace( "Injecting the field {} with server instance", field.getName() ); + field.setAccessible( true ); + field.set( testInstance, server ); + injectServers.put( testInstance, server ); + } + catch ( IllegalAccessException e ) + { + throw new RuntimeException( e ); + } + return; + } + } + current = current.getSuperclass(); + } + } + + @Override + public void beforeEach( QuarkusTestMethodContext context ) + { + ExpectationServer server = injectServers.get( context.getTestInstance() ); + if ( server != null ) + { + server.start(); + } + } + + @Override + public void afterEach( QuarkusTestMethodContext context ) + { + ExpectationServer server = injectServers.get( context.getTestInstance() ); + if ( server != null ) + { + server.stop(); + } + } + +} diff --git a/quarkus/src/main/java/org/commonjava/test/http/quarkus/internal/StreamServerCallBack.java b/quarkus/src/main/java/org/commonjava/test/http/quarkus/internal/StreamServerCallBack.java new file mode 100644 index 0000000..3dc8a05 --- /dev/null +++ b/quarkus/src/main/java/org/commonjava/test/http/quarkus/internal/StreamServerCallBack.java @@ -0,0 +1,91 @@ +/** + * Copyright (C) 2011-2022 Red Hat, Inc. (https://github.com/Commonjava/http-testserver) + * + * 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 org.commonjava.test.http.quarkus.internal; + +import io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback; +import io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback; +import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback; +import io.quarkus.test.junit.callback.QuarkusTestMethodContext; +import org.commonjava.test.http.quarkus.InjectStream; +import org.commonjava.test.http.stream.StreamServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class StreamServerCallBack + implements QuarkusTestAfterConstructCallback, QuarkusTestAfterEachCallback, QuarkusTestBeforeEachCallback +{ + private final Logger logger = LoggerFactory.getLogger( this.getClass() ); + + private static final Map injectStreamServers = new ConcurrentHashMap<>(); + + @Override + public void afterConstruct( Object testInstance ) + { + Class current = testInstance.getClass(); + while ( current.getSuperclass() != null ) + { + for ( Field field : current.getDeclaredFields() ) + { + InjectStream injectMockAnnotation = field.getAnnotation( InjectStream.class ); + if ( injectMockAnnotation != null && field.getType().equals( StreamServer.class ) ) + { + final String baseResource = injectMockAnnotation.base(); + logger.trace( "Found field with @InjectStream annotation, base resource is {}", baseResource ); + + StreamServer server = new StreamServer( baseResource ); + try + { + logger.trace( "Injecting the field {} with server instance", field.getName() ); + field.setAccessible( true ); + field.set( testInstance, server ); + injectStreamServers.putIfAbsent( testInstance, server ); + } + catch ( IllegalAccessException e ) + { + throw new RuntimeException( e ); + } + return; + } + } + current = current.getSuperclass(); + } + } + + @Override + public void beforeEach( QuarkusTestMethodContext context ) + { + final StreamServer server = injectStreamServers.get( context.getTestInstance() ); + if ( server != null ) + { + server.start(); + } + } + + @Override + public void afterEach( QuarkusTestMethodContext context ) + { + final StreamServer server = injectStreamServers.get( context.getTestInstance() ); + if ( server != null ) + { + server.stop(); + } + } + +} diff --git a/quarkus/src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback b/quarkus/src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback new file mode 100644 index 0000000..a0cc54a --- /dev/null +++ b/quarkus/src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback @@ -0,0 +1,2 @@ +org.commonjava.test.http.quarkus.internal.ExpectationServerCallBack +org.commonjava.test.http.quarkus.internal.StreamServerCallBack \ No newline at end of file diff --git a/quarkus/src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback b/quarkus/src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback new file mode 100644 index 0000000..a0cc54a --- /dev/null +++ b/quarkus/src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback @@ -0,0 +1,2 @@ +org.commonjava.test.http.quarkus.internal.ExpectationServerCallBack +org.commonjava.test.http.quarkus.internal.StreamServerCallBack \ No newline at end of file diff --git a/quarkus/src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback b/quarkus/src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback new file mode 100644 index 0000000..a0cc54a --- /dev/null +++ b/quarkus/src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback @@ -0,0 +1,2 @@ +org.commonjava.test.http.quarkus.internal.ExpectationServerCallBack +org.commonjava.test.http.quarkus.internal.StreamServerCallBack \ No newline at end of file diff --git a/quarkus/src/test/java/org/commonjava/test/http/quarkus/TestHttpServerWithQuarkus.java b/quarkus/src/test/java/org/commonjava/test/http/quarkus/TestHttpServerWithQuarkus.java new file mode 100644 index 0000000..ee1f319 --- /dev/null +++ b/quarkus/src/test/java/org/commonjava/test/http/quarkus/TestHttpServerWithQuarkus.java @@ -0,0 +1,126 @@ +/** + * Copyright (C) 2011-2022 Red Hat, Inc. (https://github.com/Commonjava/http-testserver) + * + * 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 org.commonjava.test.http.quarkus; + +import io.quarkus.test.junit.QuarkusTest; +import org.apache.commons.io.IOUtils; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.commonjava.test.http.common.CommonMethod; +import org.commonjava.test.http.expect.ExpectationServer; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +@QuarkusTest +public class TestHttpServerWithQuarkus +{ + @InjectExpected( base = "repos", port = 9090 ) + private ExpectationServer server; + + @Test + public void simpleStatus() + throws Exception + { + final String subPath = "/path/to/something.txt"; + final String url = server.formatUrl( subPath ); + server.expect( url, 200, "" ); + + final HttpGet request = new HttpGet( url ); + final CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = null; + + try + { + response = client.execute( request ); + assertThat( response.getStatusLine().getStatusCode(), is( 200 ) ); + } + finally + { + if ( response != null && response.getEntity() != null ) + { + EntityUtils.consumeQuietly( response.getEntity() ); + IOUtils.closeQuietly( response ); + } + + request.reset(); + + if ( client != null ) + { + IOUtils.closeQuietly( client ); + } + } + + } + + @Test + public void simpleDownload() + throws Exception + { + + final String subPath = "/path/to/something.txt"; + final String content = "this is the content"; + final String url = server.formatUrl( subPath ); + final String path = server.formatPath( subPath ); + server.expect( url, 200, content ); + + final HttpGet request = new HttpGet( url ); + final CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = null; + + InputStream stream = null; + try + { + response = client.execute( request ); + stream = response.getEntity().getContent(); + final String result = IOUtils.toString( stream ); + + assertThat( result, notNullValue() ); + assertThat( result, equalTo( content ) ); + } + finally + { + IOUtils.closeQuietly( stream ); + if ( response != null && response.getEntity() != null ) + { + EntityUtils.consumeQuietly( response.getEntity() ); + IOUtils.closeQuietly( response ); + } + + request.reset(); + + if ( client != null ) + { + IOUtils.closeQuietly( client ); + } + } + + System.out.println( server.getAccessesByPathKey() ); + + final String key = server.getAccessKey( CommonMethod.GET.name(), path ); + System.out.println( "Getting accesses for: '" + key + "'" ); + assertThat( server.getAccessesByPathKey().get( key ), equalTo( 1 ) ); + } + +} diff --git a/quarkus/src/test/resources/application.properties b/quarkus/src/test/resources/application.properties new file mode 100644 index 0000000..8af31a1 --- /dev/null +++ b/quarkus/src/test/resources/application.properties @@ -0,0 +1,6 @@ +#quarkus.http.port=8099 +#quarkus.http.read-timeout=30m +quarkus.log.level=INFO +#quarkus.log.category.org.commonjava.test.level=DEBUG +quarkus.log.console.level=DEBUG +quarkus.log.console.enable=true