diff --git a/README.md b/README.md index f153347..e67695e 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ LocalS3 for Junit5 provides a Java annotation `@LocalS3` helps you easily launch ``` When you annotate it on test classes or test methods, the LocalS3 extension automatically inject instances with -the following parameter types of test methods. +the following parameter types of test methods or lifecycle methods. + `AmazonS3` + `S3Client` @@ -167,6 +167,29 @@ class AppTest { } ``` +Example 3: Inject instances to junit5 lifecycle methods. + +```java +@LocalS3 +class AppTest { + + @BeforeAll + static void beforeAll(S3Client client) { + client.createBucket(b -> b.bucket("my-bucket")); + } + + @Test + void test(S3Client client) { + client.headBucket(b -> b.bucket("my-bucket")); + } + + @AfterAll + static void afterAll(S3Client client) { + client.deleteBucket(b -> b.bucket("my-bucket")); + } +} +``` + #### Difference between `@LocalS3` on test classes and test methods If `@LocalS3` is on a test class, the Junit5 extension will create a shared service for all test methods in the class diff --git a/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/docker/LocalS3Container.java b/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/docker/LocalS3Container.java deleted file mode 100644 index 03b116e..0000000 --- a/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/docker/LocalS3Container.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.robothy.s3.jupiter.docker; - -import com.robothy.s3.rest.bootstrap.LocalS3Mode; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * When {@code @LocalS3Container} is present on a test method, the Junit5 extension starts a Docker - * container with specified options in this annotation and injects instances like - * {@linkplain com.amazonaws.services.s3.AmazonS3}, to the parameters of a test method. - * For example: - * - *
- * class HelloWorldTest{ - * @LocalS3Container - * void test(AmazonS3 s3) { - * s3.createBucket("my-bucket"); - * } - * } - *- * - * In the "after each" callback, the container will be stopped and deleted. - * - *
{@code @LocalS3Container} is similar to {@code @LocalS3}; if you don't know which to choose, - * {@code @LocalS3} is a better choice. - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@interface LocalS3Container { - - /** - * The Docker image tag. - * - * @return Docker image tag. - */ - String tag(); - - /** - * The host path bind to the container path "/data", which stores all - * data of LocalS3 if it is started in {@linkplain LocalS3Mode#PERSISTENCE} mode. - * - * @return host data path. - */ - String dataPath() default ""; - - /** - * The host TCP port that provides LocalS3 service. - * - * @return host TCP port. - */ - int port() default -1; - - /** - * LocalS3 running mode. - * - * @return LocalS3 running mode. - */ - LocalS3Mode mode() default LocalS3Mode.IN_MEMORY; - -} diff --git a/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/extensions/AbstractLocalS3ParameterResolver.java b/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/extensions/AbstractLocalS3ParameterResolver.java index 31f6b26..10d0583 100644 --- a/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/extensions/AbstractLocalS3ParameterResolver.java +++ b/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/extensions/AbstractLocalS3ParameterResolver.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.extension.ParameterResolver; +import java.lang.reflect.Method; import java.util.Objects; public abstract class AbstractLocalS3ParameterResolver implements ParameterResolver { @@ -18,8 +19,10 @@ public boolean supportsParameter(ParameterContext parameterContext, ExtensionCon @Override public Object resolveParameter(ParameterContext parameterContext, ExtensionContext context) throws ParameterResolutionException { + + String methodName = context.getTestMethod().map(Method::toString).orElse(""); String s3OnMethodKey = context.getRequiredTestClass() - + (context.getRequiredTestMethod() + LocalS3Extension.LOCAL_S3_PORT_STORE_SUFFIX); + + (methodName + LocalS3Extension.LOCAL_S3_PORT_STORE_SUFFIX); String s3OnClassKey = context.getRequiredTestClass() + LocalS3Extension.LOCAL_S3_PORT_STORE_SUFFIX; ExtensionContext.Store store = context.getStore(ExtensionContext.Namespace.GLOBAL); Integer port = store.getOrDefault(s3OnMethodKey, Integer.TYPE, store.getOrDefault(s3OnClassKey, Integer.TYPE, null)); diff --git a/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/extensions/S3ClientResolver.java b/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/extensions/S3ClientResolver.java index 16ef70d..4cdc057 100644 --- a/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/extensions/S3ClientResolver.java +++ b/local-s3-jupiter/src/main/java/com/robothy/s3/jupiter/extensions/S3ClientResolver.java @@ -1,9 +1,7 @@ package com.robothy.s3.jupiter.extensions; import lombok.SneakyThrows; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; @@ -25,8 +23,7 @@ protected Object resolve(int port) { .forcePathStyle(true) .endpointOverride(new URI(endpoint)) .region(Region.of("local")) - .credentialsProvider(StaticCredentialsProvider.create( - AwsBasicCredentials.create("local-s3-access-key", "local-s3-secret-key"))) + .credentialsProvider(AnonymousCredentialsProvider.create()) .build(); } diff --git a/local-s3-jupiter/src/test/java/com/robothy/s3/jupiter/extensions/ResolveBeforeAllParametersTest.java b/local-s3-jupiter/src/test/java/com/robothy/s3/jupiter/extensions/ResolveBeforeAllParametersTest.java new file mode 100644 index 0000000..5abc06d --- /dev/null +++ b/local-s3-jupiter/src/test/java/com/robothy/s3/jupiter/extensions/ResolveBeforeAllParametersTest.java @@ -0,0 +1,60 @@ +package com.robothy.s3.jupiter.extensions; + +import com.amazonaws.services.s3.AmazonS3; +import com.robothy.s3.jupiter.LocalS3; +import com.robothy.s3.jupiter.LocalS3Endpoint; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.HeadBucketRequest; + +import java.net.URI; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@LocalS3 +public class ResolveBeforeAllParametersTest { + + private static LocalS3Endpoint endpoint; + + private static AmazonS3 s3; + + private static S3Client s3Client; + + @BeforeAll + static void setup(LocalS3Endpoint endpoint, AmazonS3 s3, S3Client s3Client) throws Exception { + ResolveBeforeAllParametersTest.endpoint = endpoint; + ResolveBeforeAllParametersTest.s3 = s3; + ResolveBeforeAllParametersTest.s3Client = s3Client; + + s3.createBucket("my-bucket"); + assertDoesNotThrow(() -> s3Client.headBucket(HeadBucketRequest.builder().bucket("my-bucket").build())); + + S3Client clientWithInjectedEndpoint = S3Client.builder().region(Region.of("local")) + .endpointOverride(new URI(endpoint.endpoint())) + .forcePathStyle(true) + .credentialsProvider(AnonymousCredentialsProvider.create()) + .build(); + assertDoesNotThrow(() -> clientWithInjectedEndpoint.headBucket(HeadBucketRequest.builder().bucket("my-bucket").build())); + } + + @Test + void testInjectedInstancesShareTheSameEndpoint(LocalS3Endpoint endpoint, AmazonS3 s3, S3Client s3Client) { + assertEquals(ResolveBeforeAllParametersTest.endpoint, endpoint); + assertDoesNotThrow(() -> s3.headBucket(new com.amazonaws.services.s3.model.HeadBucketRequest("my-bucket"))); + assertDoesNotThrow(() -> s3Client.headBucket(b -> b.bucket("my-bucket"))); + } + + @AfterAll + static void cleanup(LocalS3Endpoint endpoint, AmazonS3 s3, S3Client s3Client) { + assertEquals(ResolveBeforeAllParametersTest.endpoint, endpoint); + assertDoesNotThrow(() -> s3.headBucket(new com.amazonaws.services.s3.model.HeadBucketRequest("my-bucket"))); + assertDoesNotThrow(() -> s3Client.headBucket(HeadBucketRequest.builder().bucket("my-bucket").build())); + assertDoesNotThrow(() -> s3Client.deleteBucket(builder -> builder.bucket("my-bucket"))); + } + +} diff --git a/local-s3-jupiter/src/test/java/com/robothy/s3/jupiter/extensions/ResolveBeforeEachParametersTest.java b/local-s3-jupiter/src/test/java/com/robothy/s3/jupiter/extensions/ResolveBeforeEachParametersTest.java new file mode 100644 index 0000000..9df21a1 --- /dev/null +++ b/local-s3-jupiter/src/test/java/com/robothy/s3/jupiter/extensions/ResolveBeforeEachParametersTest.java @@ -0,0 +1,52 @@ +package com.robothy.s3.jupiter.extensions; + +import com.amazonaws.services.s3.AmazonS3; +import com.robothy.s3.jupiter.LocalS3; +import com.robothy.s3.jupiter.LocalS3Endpoint; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.HeadBucketRequest; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@LocalS3 +public class ResolveBeforeEachParametersTest { + + private LocalS3Endpoint endpoint; + + @BeforeEach + void beforeEach(LocalS3Endpoint endpoint, AmazonS3 s3, S3Client s3Client) { + this.endpoint = endpoint; + assertDoesNotThrow(() -> s3.createBucket(new com.amazonaws.services.s3.model.CreateBucketRequest("my-bucket"))); + assertDoesNotThrow(() -> s3Client.headBucket(builder -> builder.bucket("my-bucket"))); + } + + @Order(1) + @Test + void testInjectedInstancesShareTheSameEndpoint(LocalS3Endpoint endpoint, AmazonS3 s3, S3Client s3Client) { + assertEquals(this.endpoint, endpoint); + assertDoesNotThrow(() -> s3.headBucket(new com.amazonaws.services.s3.model.HeadBucketRequest("my-bucket"))); + assertDoesNotThrow(() -> s3Client.headBucket(builder -> builder.bucket("my-bucket"))); + } + + @Order(2) + @Test + void testInjectedInstancesShareTheSameEndpoint2(LocalS3Endpoint endpoint, AmazonS3 s3, S3Client s3Client) { + assertEquals(this.endpoint, endpoint); + assertDoesNotThrow(() -> s3.headBucket(new com.amazonaws.services.s3.model.HeadBucketRequest("my-bucket"))); + assertDoesNotThrow(() -> s3Client.headBucket(builder -> builder.bucket("my-bucket"))); + } + + @AfterEach + void afterEach(LocalS3Endpoint endpoint, AmazonS3 s3, S3Client client) { + assertEquals(this.endpoint, endpoint); + assertDoesNotThrow(() -> s3.headBucket(new com.amazonaws.services.s3.model.HeadBucketRequest("my-bucket"))); + assertDoesNotThrow(() -> client.headBucket(HeadBucketRequest.builder().bucket("my-bucket").build())); + assertDoesNotThrow(() -> client.deleteBucket(builder -> builder.bucket("my-bucket"))); + } + +}