diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 17097e06..43e7b530 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -4,7 +4,7 @@ This pull request closes # .
# Acceptance Test
-* [ ] Building the code with `mvn clean install -Pintegration-tests` still works.
+* [ ] Building the code with `mvn clean install -Punit-tests,it-minio,it-s3` still works.
# Questions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index cbb73ac9..1fd6ff84 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,13 +14,11 @@ on:
- '-**/*.md'
jobs:
- build-and-test:
+ build-matrix:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- # Commenting Windows out in order to preserve our free minutes.
- # We can re-enable it, if we get a sponsor.
os: [ubuntu-latest, windows-latest, macos-latest]
java: [ 8, 11.0.3 ]
env:
@@ -44,11 +42,15 @@ jobs:
uses: actions/cache@v2
with:
path: ~/.m2/repository
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ # https://github.com/actions/cache/issues/2#issuecomment-673493515
+ # Example: unix timestamp
+ key: ${{ runner.os }}-maven-${{ secrets.MVN_CACHE_VERSION }}-${{ hashFiles('**/pom.xml') }}
restore-keys: |
- ${{ runner.os }}-maven-
- - name: Build with Maven
- run: mvn clean install -Pjacoco-code-coverage
+ ${{ runner.os }}-maven-${{ secrets.MVN_CACHE_VERSION }}-
+ - name: Maven Version
+ run: mvn --version
+ - name: Build, unit test and coverage.
+ run: mvn clean install -Punit-tests -Pjacoco-code-coverage
- name: Publish code analysis to Sonarcloud
# [WARNING] The version of Java 1.8 you have used to run this analysis is deprecated and we will stop accepting
# it from October 2020. Please update to at least Java 11.
@@ -58,4 +60,101 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- run: mvn org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Pjacoco-code-coverage -DskipTests
+ run: mvn org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
+ continue-on-error: true
+
+ run-it-minio:
+ runs-on: ${{ matrix.os }}
+ needs: [build-matrix]
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest]
+ java: [ 8, 11.0.3 ]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ - name: Setup Java ${{ matrix.java }}
+ uses: actions/setup-java@v1
+ with:
+ java-version: ${{ matrix.java }}
+ - name: Cache local Maven repository
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2/repository
+ # https://github.com/actions/cache/issues/2#issuecomment-673493515
+ # Example: unix timestamp
+ key: ${{ runner.os }}-maven-${{ secrets.MVN_CACHE_VERSION }}-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-${{ secrets.MVN_CACHE_VERSION }}-
+ - name: Cache Docker images
+ id: docker-cache
+ uses: actions/cache@v2
+ with:
+ path: ${{ github.workspace }}/docker-image-cache.tar
+ # https://github.com/actions/cache/issues/2#issuecomment-673493515
+ # Example: unix timestamp
+ key: ${{ runner.os }}-docker-${{ secrets.DOCKER_CACHE_VERSION }}-${{ hashFiles('${{ github.workspace }}/docker-image-cache.tar') }}
+ restore-keys: |
+ ${{ runner.os }}-docker-${{ secrets.DOCKER_CACHE_VERSION }}-
+ - name: Load docker image cache
+ if: steps.docker-cache.outputs.cache-hit == 'true'
+ run: |
+ cat ${{ github.workspace }}/docker-image-cache.tar | docker load
+ docker images | grep -iE "minio|testcontainers"
+ - name: Docker info
+ run: docker info
+ - name: Maven Version
+ run: mvn --version
+ - name: MinIO integration tests.
+ run: mvn clean install -Pit-minio
+ env:
+ S3FS_BUCKET_NAME: ${{ secrets.S3FS_BUCKET_NAME }}
+ # access key must be >= 3 chars or authentication will fail.
+ S3FS_ACCESS_KEY: "access_key"
+ # secret key must be >= 8 chars or authentication will fail.
+ S3FS_SECRET_KEY: "secret_key"
+ S3FS_PROTOCOL: "http"
+ # TODO: These are necessary since the current logic in EnvironmentBuilder assumes we are using S3.
+ S3FS_REGION: "local"
+ # TODO: Adding this env var in advance, we might or might not need it after the test containers task is completed.
+ # https://github.com/carlspring/s3fs-nio/issues/60
+ S3FS_PORT: 9000
+ - name: Save docker images
+ run: docker save minio/minio testcontainers/ryuk > ${{ github.workspace }}/docker-image-cache.tar
+
+ run-it-s3:
+ needs: [run-it-minio]
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: true
+ matrix:
+ # TODO: We should, at some point, have the same matrix as `build-matrix`.
+ os: [ubuntu-latest, windows-latest]
+ java: [ 8 ]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ - name: Setup Java ${{ matrix.java }}
+ uses: actions/setup-java@v1
+ with:
+ java-version: ${{ matrix.java }}
+ - name: Cache local Maven repository
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2/repository
+ # https://github.com/actions/cache/issues/2#issuecomment-673493515
+ # Example: unix timestamp
+ key: ${{ runner.os }}-maven-${{ secrets.MVN_CACHE_VERSION }}-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-${{ secrets.MVN_CACHE_VERSION }}-
+ - name: Maven Version
+ run: mvn --version
+ - name: S3 integration tests.
+ run: mvn clean install -Pit-s3
+ env:
+ S3FS_BUCKET_NAME: ${{ secrets.S3FS_BUCKET_NAME }}
+ S3FS_ACCESS_KEY: ${{ secrets.S3FS_ACCESS_KEY }}
+ S3FS_SECRET_KEY: ${{ secrets.S3FS_SECRET_KEY }}
+ S3FS_REGION: ${{ secrets.S3FS_REGION }}
+ S3FS_PROTOCOL: "https"
\ No newline at end of file
diff --git a/docs/content/assets/resources/s3fs-nio-strict-policy.json b/docs/content/assets/resources/s3fs-nio-strict-policy.json
new file mode 100644
index 00000000..843dcb1d
--- /dev/null
+++ b/docs/content/assets/resources/s3fs-nio-strict-policy.json
@@ -0,0 +1,29 @@
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "VisualEditor0",
+ "Effect": "Allow",
+ "Action": [
+ "s3:PutObject",
+ "s3:GetObjectAcl",
+ "s3:GetObject",
+ "s3:DeleteObjectVersion",
+ "s3:PutReplicationConfiguration",
+ "s3:ListBucket",
+ "s3:DeleteObject",
+ "s3:GetBucketAcl"
+ ],
+ "Resource": [
+ "arn:aws:s3:::YOUR_BUCKET_NAME",
+ "arn:aws:s3:::YOUR_BUCKET_NAME/*"
+ ]
+ },
+ {
+ "Sid": "VisualEditor1",
+ "Effect": "Allow",
+ "Action": "s3:ListAllMyBuckets",
+ "Resource": "*"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docs/content/contributing/developer-guide/index.md b/docs/content/contributing/developer-guide/index.md
index b442cb21..2a1df46b 100644
--- a/docs/content/contributing/developer-guide/index.md
+++ b/docs/content/contributing/developer-guide/index.md
@@ -21,6 +21,49 @@ contributors to help with are marked with the following labels:
[![GitHub issues by-label help-wanted-link][help-wanted-badge]][help-wanted-link]
[![GitHub issues by-label hacktoberfest-link][hacktoberfest-badge]][hacktoberfest-link]
+## Preparing credentials
+
+### S3 - Easy
+
+!!! warning "Gives access to **all** buckets which could be dangerous!"
+
+The easiest way to get started would be to:
+
+1. Go to the [Identity and Access Management (IAM)][s3-iam]
+2. Go to `Users` -> `Add User`:
+ * Username: `my-s3fs-username` (or whatever)
+ * Access Type: `Programmatic access` must be selected!
+3. `Set Permissions`:
+ * Select `Attach existing policies directly`
+ * Search for `AmazonS3FullAccess` and select it.
+4. Continue with next steps (apply changes if necessary)
+5. At the final step you will receive an `Access Key` and `Secret Access Key` - copy those into your
+ `amazon-test.properties` or export them as `S3FS_**` env variable name (if running in a container).
+
+
+### S3 - Advanced
+
+!!! success "Allows access to a specific bucket and is safer if you have multiple buckets in your account."
+
+1. Go to the [Identity and Access Management (IAM)][s3-iam]
+2. Go to `Policies`:
+ * Create a new policy
+ * Switch to `JSON` editor and copy the policy below which will limit the access to only a specific bucket:
+ ```
+ --8<-- "./content/assets/resources/s3fs-nio-strict-policy.json"
+ ```
+ * Replace `YOUR_BUCKET_NAME` with your actual bucket name.
+ * Give a name and save (i.e. `s3fs-full-access-to-YOUR_BUCKET_NAME`)
+3. Go to `Users` -> `Add User`:
+ * Username: `my-s3fs-username` (or whatever)
+ * Access Type: `Programmatic access` must be selected!
+4. `Set Permissions`:
+ * Select `Attach existing policies directly`
+ * Search for `s3fs-full-access-to-YOUR_BUCKET_NAME` and select it
+ * Continue with next steps (apply changes if necessary)
+5. At the final step you will receive an `Access Key` and `Secret Access Key` - copy those into your
+ `amazon-test.properties` or export them as `S3FS_**` env variable name (if running in a container).
+
## Building the code
@@ -69,3 +112,6 @@ TODO: Add a guide to run tests with MinIO and docker-compose
[help-wanted-badge]: https://img.shields.io/github/issues-raw/carlspring/s3fs-nio/help%20wanted.svg?label=help%20wanted&color=%23856bf9&
[hacktoberfest-link]: {{ repo_url }}/issues?q=is%3Aissue+is%3Aopen+label%3A%22hacktoberfest%22
[hacktoberfest-badge]: https://img.shields.io/github/issues-raw/carlspring/s3fs-nio/hacktoberfest.svg?label=hacktoberfest&color=orange
+
+[<--# S3 -->]: #
+[s3-iam]: https://console.aws.amazon.com/iam/home
\ No newline at end of file
diff --git a/docs/content/index.md b/docs/content/index.md
index 6f517c71..13cd6da0 100644
--- a/docs/content/index.md
+++ b/docs/content/index.md
@@ -33,7 +33,7 @@
2. Open [IAM] and go to `Add User`
3. Set `Access Type` to `Programmatic Access` or you will get `403 Forbidden` errors.
4. Select `Attach an existing policies directly`
-5. Select `AmazonS3FullAccess` policy and `Create user`
+5. Select `AmazonS3FullAccess` policy and `Create user` (if you prefer more fine-grained access [click here](./contributing/developer-guide/index.md#s3-advanced))
6. Copy `Access key ID` and `Secret access key` - you will need them later!
### Example
diff --git a/pom.xml b/pom.xml
index dc26a209..3246d5cb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,9 +86,9 @@
1.25
3.0.2
5.7.0
- 1.7.0
3.7.7
2.1.0
+ 3.0.0-M5
@@ -103,15 +103,17 @@
UTF-8
+
org.apache.maven.plugins
maven-surefire-plugin
- 3.0.0-M5
-
-
- **/*ITTest*
-
-
+ ${version.surefire}
+
+
+ default-test
+ none
+
+
org.apache.maven.plugins
@@ -242,10 +244,11 @@
${version.junit}
test
+
- org.junit.platform
- junit-platform-runner
- ${version.junit.platform.runner}
+ org.apache.commons
+ commons-lang3
+ 3.11
test
@@ -286,9 +289,90 @@
+
+
+ unit-tests
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${version.surefire}
+
+
+ true
+
+ *
+
+
+
+ unit-tests
+
+ test
+
+
+
+
+
+
+
+
+
+
- integration-tests
+
+ it-minio
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 3.0.0-M5
+
+
+ true
+
+ **/*IT.java
+
+
+
+ minio
+
+
+
+
+ it-minio
+ integration-test
+
+ integration-test
+
+
+
+
+
+ it-minio
+ *
+
+
+
+ it-minio-verify
+ verify
+
+ verify
+
+
+
+
+
+
+
+
+ it-s3
@@ -296,23 +380,33 @@
maven-failsafe-plugin
3.0.0-M5
+
+ true
- **/*ITSuite.java
+ **/*IT.java
-
- **/**Test.java
-
+
+
+ s3
+
- integration-test
+ it-s3
integration-test
integration-test
+
+
+
+
+ it-s3
+ *
+
- verify
+ it-s3-verify
verify
verify
@@ -323,6 +417,7 @@
+
jacoco-code-coverage
diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileStore.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileStore.java
index 79d4de49..cf9324d9 100644
--- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileStore.java
+++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileStore.java
@@ -117,6 +117,12 @@ public Bucket getBucket()
return getBucket(name);
}
+ /**
+ * This code requires `s3:ListAllMyBuckets` permission.
+ *
+ * @param bucketName
+ * @return
+ */
private Bucket getBucket(final String bucketName)
{
for (Bucket buck : getClient().listBuckets().buckets())
diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3Path.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3Path.java
index 0b3315a9..a1ad2485 100644
--- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3Path.java
+++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3Path.java
@@ -64,8 +64,8 @@ public class S3Path
*/
public S3Path(S3FileSystem fileSystem, String first, String... more)
{
- Preconditions.checkArgument(first != null, "first path must be not null");
- Preconditions.checkArgument(!first.startsWith("//"), "first path doesnt start with '//'. Miss bucket");
+ Preconditions.checkArgument(first != null, "The first path must not be null. Perhaps you forgot to set the bucket name?");
+ Preconditions.checkArgument(!first.startsWith("//"), "The first path doesn't start with '//'. Missing bucket.");
// see tests org.carlspring.cloud.storage.s3fs.Path.EndsWithTest#endsWithRelativeBlankAbsolute()
boolean hasBucket = first.startsWith("/");
diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/util/S3Utils.java b/src/main/java/org/carlspring/cloud/storage/s3fs/util/S3Utils.java
index 06343fae..87376601 100644
--- a/src/main/java/org/carlspring/cloud/storage/s3fs/util/S3Utils.java
+++ b/src/main/java/org/carlspring/cloud/storage/s3fs/util/S3Utils.java
@@ -164,7 +164,8 @@ public S3BasicFileAttributes getS3FileAttributes(S3Path s3Path)
}
/**
- * get the S3PosixFileAttributes for a S3Path
+ * Get the S3PosixFileAttributes for a S3Path
+ * This requires `s3:GetBucketAcl` and `s3:GetObjectAcl`
*
* @param s3Path Path mandatory not null
* @return S3PosixFileAttributes never null
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/AmazonS3ITSuite.java b/src/test/java/org/carlspring/cloud/storage/s3fs/AmazonS3ITSuite.java
deleted file mode 100644
index 62ca5035..00000000
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/AmazonS3ITSuite.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.carlspring.cloud.storage.s3fs;
-
-import org.junit.platform.runner.JUnitPlatform;
-import org.junit.platform.suite.api.IncludeTags;
-import org.junit.platform.suite.api.SelectPackages;
-import org.junit.runner.RunWith;
-
-/**
- * @author carlspring
- */
-@RunWith(JUnitPlatform.class)
-@IncludeTags({ "s3-integration-test" })
-@SelectPackages({ "org.carlspring.cloud.storage.s3fs" })
-public class AmazonS3ITSuite
-{
-}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsIT.java
similarity index 94%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsIT.java
index f81216ef..440ef0f0 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsIT.java
@@ -1,5 +1,6 @@
package org.carlspring.cloud.storage.s3fs;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder;
import java.io.IOException;
@@ -9,14 +10,13 @@
import java.nio.file.FileSystems;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_IT;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;
-@Tag("s3-integration-test")
-class FileSystemsITTest
+@S3IntegrationTest
+class FileSystemsIT
{
private static final URI uriEurope = URI.create("s3://s3-eu-west-1.amazonaws.com/");
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FilesITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/FilesIT.java
similarity index 97%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/FilesITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/FilesIT.java
index a1f6be99..49c46ec1 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/FilesITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/FilesIT.java
@@ -1,5 +1,6 @@
package org.carlspring.cloud.storage.s3fs;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import org.carlspring.cloud.storage.s3fs.util.CopyDirVisitor;
import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder;
@@ -8,15 +9,7 @@
import java.io.OutputStream;
import java.net.URI;
import java.nio.channels.SeekableByteChannel;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystemNotFoundException;
-import java.nio.file.FileSystems;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.StandardOpenOption;
+import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;
import java.util.Map;
@@ -24,7 +17,6 @@
import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
@@ -32,14 +24,10 @@
import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_IT;
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-@Tag("s3-integration-test")
-class FilesITTest
+import static org.junit.jupiter.api.Assertions.*;
+
+@S3IntegrationTest
+class FilesIT
{
private static final String bucket = EnvironmentBuilder.getBucket();
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientIT.java
similarity index 97%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientIT.java
index f9bb2d7f..99e159ee 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientIT.java
@@ -1,5 +1,6 @@
package org.carlspring.cloud.storage.s3fs;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder;
import java.io.ByteArrayInputStream;
@@ -11,7 +12,6 @@
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
@@ -29,8 +29,8 @@
import static org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder.getRealEnv;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-@Tag("s3-integration-test")
-class S3ClientITTest
+@S3IntegrationTest
+class S3ClientIT
{
S3Client client;
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsIT.java
similarity index 99%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsIT.java
index 15247390..f59108e0 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsIT.java
@@ -2,6 +2,7 @@
import org.carlspring.cloud.storage.s3fs.attribute.S3BasicFileAttributes;
import org.carlspring.cloud.storage.s3fs.attribute.S3PosixFileAttributes;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import org.carlspring.cloud.storage.s3fs.util.CopyDirVisitor;
import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder;
import org.carlspring.cloud.storage.s3fs.util.S3Utils;
@@ -19,7 +20,6 @@
import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
@@ -34,8 +34,8 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
-@Tag("s3-integration-test")
-class S3UtilsITTest
+@S3IntegrationTest
+class S3UtilsIT
{
private static final String bucket = EnvironmentBuilder.getBucket();
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileSystemITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileSystemIT.java
similarity index 95%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileSystemITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileSystemIT.java
index a3963715..009cba86 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileSystemITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileSystemIT.java
@@ -1,6 +1,7 @@
package org.carlspring.cloud.storage.s3fs.fileSystemProvider;
import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import java.io.IOException;
import java.nio.file.FileSystem;
@@ -11,7 +12,6 @@
import com.google.common.collect.ImmutableMap;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY;
import static org.carlspring.cloud.storage.s3fs.S3Factory.REGION;
@@ -24,8 +24,8 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
-@Tag("s3-integration-test")
-class GetFileSystemITTest
+@S3IntegrationTest
+class GetFileSystemIT
{
private S3FileSystemProvider provider;
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewAsynchronousFileChannelITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewAsynchronousFileChannelTestIT.java
similarity index 98%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewAsynchronousFileChannelITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewAsynchronousFileChannelTestIT.java
index dcf706d6..d2c61e61 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewAsynchronousFileChannelITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewAsynchronousFileChannelTestIT.java
@@ -2,6 +2,7 @@
import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider;
import org.carlspring.cloud.storage.s3fs.S3UnitTestBase;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import org.carlspring.cloud.storage.s3fs.util.CopyDirVisitor;
import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder;
@@ -27,7 +28,6 @@
import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_IT;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
@@ -35,8 +35,8 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-@Tag("s3-integration-test")
-class NewAsynchronousFileChannelITTest
+@S3IntegrationTest
+class NewAsynchronousFileChannelTestIT
extends S3UnitTestBase
{
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelIT.java
similarity index 98%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelIT.java
index c4cd2cca..bfc14949 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelIT.java
@@ -2,6 +2,7 @@
import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider;
import org.carlspring.cloud.storage.s3fs.S3UnitTestBase;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import org.carlspring.cloud.storage.s3fs.util.CopyDirVisitor;
import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder;
@@ -22,7 +23,6 @@
import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_IT;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
@@ -30,8 +30,8 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-@Tag("s3-integration-test")
-class NewByteChannelITTest
+@S3IntegrationTest
+class NewByteChannelIT
extends S3UnitTestBase
{
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemIT.java
similarity index 97%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemIT.java
index d13eee58..8ebc1900 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemIT.java
@@ -1,6 +1,7 @@
package org.carlspring.cloud.storage.s3fs.fileSystemProvider;
import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import java.io.IOException;
import java.net.URI;
@@ -12,7 +13,6 @@
import com.google.common.collect.ImmutableMap;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY;
import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY;
@@ -28,8 +28,8 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-@Tag("s3-integration-test")
-class NewFileSystemITTest
+@S3IntegrationTest
+class NewFileSystemIT
{
private S3FileSystemProvider provider;
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/BaseAnnotationTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/BaseAnnotationTest.java
new file mode 100644
index 00000000..e8b5fd02
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/BaseAnnotationTest.java
@@ -0,0 +1,57 @@
+package org.carlspring.cloud.storage.s3fs.junit.annotations;
+
+public abstract class BaseAnnotationTest
+{
+
+ /**
+ * Check if there is an {@link S3IntegrationTest} annotation at a class level.
+ *
+ * @param clazz
+ * @return
+ */
+ protected static boolean hasS3Annotation(Class> clazz)
+ {
+ return clazz.getAnnotation(S3IntegrationTest.class) != null;
+ }
+
+ /**
+ * Check if there is an {@link S3IntegrationTest} annotation at a method level (and pick-up class level)
+ *
+ * @param clazz
+ * @param methodName
+ * @return
+ * @throws NoSuchMethodException
+ */
+ protected static boolean hasS3Annotation(Class> clazz,
+ String methodName)
+ throws NoSuchMethodException
+ {
+ return hasS3Annotation(clazz) || clazz.getMethod(methodName).getAnnotation(S3IntegrationTest.class) != null;
+ }
+
+ /**
+ * Check if there is an {@link MinioIntegrationTest} annotation at a class level.
+ *
+ * @param clazz
+ * @return
+ */
+ protected static boolean hasMinioAnnotation(Class> clazz)
+ {
+ return clazz.getAnnotation(MinioIntegrationTest.class) != null;
+ }
+
+ /**
+ * Check if there is an {@link MinioIntegrationTest} annotation at a method level (and pick-up class level)
+ *
+ * @param clazz
+ * @param methodName
+ * @return
+ * @throws NoSuchMethodException
+ */
+ protected static boolean hasMinioAnnotation(Class> clazz,
+ String methodName)
+ throws NoSuchMethodException
+ {
+ return hasMinioAnnotation(clazz) || clazz.getMethod(methodName).getAnnotation(MinioIntegrationTest.class) != null;
+ }
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/MinioIntegrationTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/MinioIntegrationTest.java
new file mode 100644
index 00000000..f168ba90
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/MinioIntegrationTest.java
@@ -0,0 +1,21 @@
+package org.carlspring.cloud.storage.s3fs.junit.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.jupiter.api.Tag;
+
+/**
+ * This annotation should be used for integration tests which are specific to MinIO.
+ * It is possible to combine it with {@link S3IntegrationTest} for test cases which are compatible with both (i.e. can
+ * run on S3 and MinIO)
+ */
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Tag("it-minio")
+public @interface MinioIntegrationTest
+{
+
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/MinioIntegrationTestAnnotationTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/MinioIntegrationTestAnnotationTest.java
new file mode 100644
index 00000000..14b5f70b
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/MinioIntegrationTestAnnotationTest.java
@@ -0,0 +1,41 @@
+package org.carlspring.cloud.storage.s3fs.junit.annotations;
+
+
+import org.carlspring.cloud.storage.s3fs.junit.examples.*;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class MinioIntegrationTestAnnotationTest
+ extends BaseAnnotationTest
+{
+
+ @Test
+ void testClassLevelAnnotation()
+ {
+ assertTrue(hasMinioAnnotation(MinioClassAnnotationIT.class));
+ assertTrue(hasMinioAnnotation(CombinedMinioS3IT.class));
+
+ assertFalse(hasMinioAnnotation(S3ClassAnnotationIT.class));
+ assertFalse(hasMinioAnnotation(CombinedS3MinioIT.class));
+
+ assertTrue(hasMinioAnnotation(CombinedIT.class));
+ }
+
+ @Test
+ void testMethodLevelAnnotation()
+ throws NoSuchMethodException
+ {
+ assertTrue(hasMinioAnnotation(MinioMethodAnnotationIT.class, "testShouldExecuteBecauseOfMethodAnnotation"));
+
+ assertTrue(hasMinioAnnotation(CombinedIT.class, "testMinioMethodShouldExecuteBecauseOfClassLevelAnnotation"));
+ assertTrue(hasMinioAnnotation(CombinedIT.class, "testMinioMethodShouldExecuteBecauseOfClassLevelAnnotation"));
+
+ assertTrue(hasMinioAnnotation(CombinedS3MinioIT.class, "testMinioMethodShouldExecuteBecauseOfMethodLevelAnnotation"));
+ assertTrue(hasMinioAnnotation(CombinedMinioS3IT.class, "testMinioMethodShouldExecuteBecauseOfClassLevelAnnotation"));
+
+ assertFalse(hasS3Annotation(MinioMethodAnnotationIT.class, "testShouldExecuteBecauseOfMethodAnnotation"));
+ }
+
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/S3IntegrationTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/S3IntegrationTest.java
new file mode 100644
index 00000000..b6ff4773
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/S3IntegrationTest.java
@@ -0,0 +1,21 @@
+package org.carlspring.cloud.storage.s3fs.junit.annotations;
+
+import org.junit.jupiter.api.Tag;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation should be used for integration tests which are specific to the official S3 API.
+ * It is possible to combine it with {@link MinioIntegrationTest} for test cases which are compatible with both (i.e. can
+ * run on S3 and MinIO)
+ */
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Tag("it-s3")
+public @interface S3IntegrationTest
+{
+
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/S3IntegrationTestAnnotationTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/S3IntegrationTestAnnotationTest.java
new file mode 100644
index 00000000..c1bda43c
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/annotations/S3IntegrationTestAnnotationTest.java
@@ -0,0 +1,38 @@
+package org.carlspring.cloud.storage.s3fs.junit.annotations;
+
+
+import org.carlspring.cloud.storage.s3fs.junit.examples.*;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+class S3IntegrationTestAnnotationTest
+ extends BaseAnnotationTest
+{
+
+ @Test
+ void testClassLevelAnnotation()
+ {
+ assertTrue(hasS3Annotation(S3ClassAnnotationIT.class));
+ assertTrue(hasS3Annotation(CombinedS3MinioIT.class));
+
+ assertFalse(hasS3Annotation(MinioClassAnnotationIT.class));
+ assertFalse(hasS3Annotation(CombinedMinioS3IT.class));
+
+ assertTrue(hasS3Annotation(CombinedIT.class));
+ }
+
+ @Test
+ void testMethodLevelAnnotation()
+ throws NoSuchMethodException
+ {
+ assertTrue(hasS3Annotation(S3MethodAnnotationIT.class, "testShouldExecuteBecauseOfMethodAnnotation"));
+ assertTrue(hasS3Annotation(CombinedIT.class, "testMinioMethodShouldExecuteBecauseOfClassLevelAnnotation"));
+ assertTrue(hasS3Annotation(CombinedIT.class, "testS3MethodShouldExecuteBecauseOfClassLevelAnnotation"));
+ assertTrue(hasS3Annotation(CombinedS3MinioIT.class, "testS3MethodShouldExecuteBecauseOfClassLevelAnnotation"));
+ assertTrue(hasS3Annotation(CombinedMinioS3IT.class, "testS3MethodShouldExecuteBecauseOfMethodLevelAnnotation"));
+
+ assertFalse(hasS3Annotation(MinioMethodAnnotationIT.class, "testShouldExecuteBecauseOfMethodAnnotation"));
+ }
+
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/CombinedIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/CombinedIT.java
new file mode 100644
index 00000000..4ad528fe
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/CombinedIT.java
@@ -0,0 +1,35 @@
+package org.carlspring.cloud.storage.s3fs.junit.examples;
+
+import org.carlspring.cloud.storage.s3fs.junit.annotations.MinioIntegrationTest;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Class level {@link MinioIntegrationTest} annotation and class level {@link S3IntegrationTest} annotation.
+ */
+@MinioIntegrationTest
+@S3IntegrationTest
+public class CombinedIT
+{
+
+ private static final Logger logger = LoggerFactory.getLogger(S3MethodAnnotationIT.class);
+
+ @Test
+ public void testS3MethodShouldExecuteBecauseOfClassLevelAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+
+ @Test
+ public void testMinioMethodShouldExecuteBecauseOfClassLevelAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/CombinedMinioS3IT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/CombinedMinioS3IT.java
new file mode 100644
index 00000000..5442e6df
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/CombinedMinioS3IT.java
@@ -0,0 +1,35 @@
+package org.carlspring.cloud.storage.s3fs.junit.examples;
+
+import org.carlspring.cloud.storage.s3fs.junit.annotations.MinioIntegrationTest;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Class level {@link MinioIntegrationTest} annotation and method level {@link S3IntegrationTest} annotation.
+ */
+@MinioIntegrationTest
+public class CombinedMinioS3IT
+{
+
+ private static final Logger logger = LoggerFactory.getLogger(S3MethodAnnotationIT.class);
+
+ @Test
+ @S3IntegrationTest
+ public void testS3MethodShouldExecuteBecauseOfMethodLevelAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+
+ @Test
+ public void testMinioMethodShouldExecuteBecauseOfClassLevelAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/CombinedS3MinioIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/CombinedS3MinioIT.java
new file mode 100644
index 00000000..ee953d34
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/CombinedS3MinioIT.java
@@ -0,0 +1,35 @@
+package org.carlspring.cloud.storage.s3fs.junit.examples;
+
+import org.carlspring.cloud.storage.s3fs.junit.annotations.MinioIntegrationTest;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Class level {@link S3IntegrationTest} annotation and method level {@link MinioIntegrationTest} annotation.
+ */
+@S3IntegrationTest
+public class CombinedS3MinioIT
+{
+
+ private static final Logger logger = LoggerFactory.getLogger(S3MethodAnnotationIT.class);
+
+ @Test
+ public void testS3MethodShouldExecuteBecauseOfClassLevelAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+
+ @Test
+ @MinioIntegrationTest
+ public void testMinioMethodShouldExecuteBecauseOfMethodLevelAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/MinioClassAnnotationIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/MinioClassAnnotationIT.java
new file mode 100644
index 00000000..f487013c
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/MinioClassAnnotationIT.java
@@ -0,0 +1,23 @@
+package org.carlspring.cloud.storage.s3fs.junit.examples;
+
+import org.carlspring.cloud.storage.s3fs.junit.annotations.MinioIntegrationTest;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@MinioIntegrationTest
+public class MinioClassAnnotationIT
+{
+
+ private static final Logger logger = LoggerFactory.getLogger(MinioClassAnnotationIT.class);
+
+ @Test
+ public void testShouldExecuteBecauseOfClassAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/MinioMethodAnnotationIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/MinioMethodAnnotationIT.java
new file mode 100644
index 00000000..4dc2f674
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/MinioMethodAnnotationIT.java
@@ -0,0 +1,22 @@
+package org.carlspring.cloud.storage.s3fs.junit.examples;
+
+import org.carlspring.cloud.storage.s3fs.junit.annotations.MinioIntegrationTest;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class MinioMethodAnnotationIT
+{
+
+ private static final Logger logger = LoggerFactory.getLogger(MinioMethodAnnotationIT.class);
+
+ @Test
+ @MinioIntegrationTest
+ public void testShouldExecuteBecauseOfMethodAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/S3ClassAnnotationIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/S3ClassAnnotationIT.java
new file mode 100644
index 00000000..990496de
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/S3ClassAnnotationIT.java
@@ -0,0 +1,23 @@
+package org.carlspring.cloud.storage.s3fs.junit.examples;
+
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@S3IntegrationTest
+public class S3ClassAnnotationIT
+{
+
+ private static final Logger logger = LoggerFactory.getLogger(S3ClassAnnotationIT.class);
+
+ @Test
+ public void testShouldExecuteBecauseOfClassAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/S3MethodAnnotationIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/S3MethodAnnotationIT.java
new file mode 100644
index 00000000..a24aba5c
--- /dev/null
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/junit/examples/S3MethodAnnotationIT.java
@@ -0,0 +1,22 @@
+package org.carlspring.cloud.storage.s3fs.junit.examples;
+
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class S3MethodAnnotationIT
+{
+
+ private static final Logger logger = LoggerFactory.getLogger(S3MethodAnnotationIT.class);
+
+ @Test
+ @S3IntegrationTest
+ public void testShouldExecuteBecauseOfMethodAnnotation()
+ {
+ logger.debug(new Exception().getStackTrace()[0].getMethodName());
+ assertTrue(true);
+ }
+}
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/path/ToURLITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ToURLIT.java
similarity index 97%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/path/ToURLITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/ToURLIT.java
index 5d8bd70e..b44d9ca2 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/path/ToURLITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ToURLIT.java
@@ -2,6 +2,7 @@
import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider;
import org.carlspring.cloud.storage.s3fs.S3Path;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder;
import java.io.IOException;
@@ -13,7 +14,6 @@
import java.util.HashMap;
import java.util.Map;
-import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.carlspring.cloud.storage.s3fs.S3Factory.PATH_STYLE_ACCESS;
import static org.carlspring.cloud.storage.s3fs.S3Factory.PROTOCOL;
@@ -23,8 +23,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
-@Tag("s3-integration-test")
-public class ToURLITTest
+@S3IntegrationTest
+class ToURLIT
{
private static final URI uriGlobal = EnvironmentBuilder.getS3URI(S3_GLOBAL_URI_IT);
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentITTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentIT.java
similarity index 73%
rename from src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentITTest.java
rename to src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentIT.java
index e3b4f4ab..ea4ea2b1 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentITTest.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentIT.java
@@ -1,5 +1,7 @@
package org.carlspring.cloud.storage.s3fs.spike;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.MinioIntegrationTest;
+import org.carlspring.cloud.storage.s3fs.junit.annotations.S3IntegrationTest;
import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder;
import java.util.Map;
@@ -9,7 +11,9 @@
import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-class EnvironmentITTest
+@S3IntegrationTest
+@MinioIntegrationTest
+class EnvironmentIT
{
@Test
void couldCreateFileSystem()
diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/EnvironmentBuilder.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/EnvironmentBuilder.java
index ef61b915..77794380 100644
--- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/EnvironmentBuilder.java
+++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/EnvironmentBuilder.java
@@ -7,7 +7,11 @@
import java.util.Properties;
import com.google.common.collect.ImmutableMap;
+import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;
+
+import javax.annotation.Nonnull;
+
import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY;
import static org.carlspring.cloud.storage.s3fs.S3Factory.PROTOCOL;
import static org.carlspring.cloud.storage.s3fs.S3Factory.REGION;
@@ -32,18 +36,20 @@ public static Map getRealEnv()
{
Map env;
- String accessKey = System.getenv(ACCESS_KEY);
- String secretKey = System.getenv(SECRET_KEY);
- String region = System.getenv(REGION);
- String protocol = System.getenv(PROTOCOL);
+ String accessKey = getEnvValue(ACCESS_KEY);
+ String secretKey = getEnvValue(SECRET_KEY);
+ String region = getEnvValue(REGION);
+ String protocol = getEnvValue(PROTOCOL);
+ String bucket = getEnvValue(BUCKET_NAME_KEY);
- if (accessKey != null && secretKey != null && region != null && protocol != null)
+ if (accessKey != null && secretKey != null && region != null && protocol != null && bucket != null)
{
env = ImmutableMap.builder().put(ACCESS_KEY, accessKey)
- .put(SECRET_KEY, secretKey)
- .put(REGION, region)
- .put(PROTOCOL, protocol)
- .build();
+ .put(SECRET_KEY, secretKey)
+ .put(REGION, region)
+ .put(PROTOCOL, protocol)
+ .put(BUCKET_NAME_KEY, bucket)
+ .build();
}
else
{
@@ -59,15 +65,51 @@ public static Map getRealEnv()
}
env = ImmutableMap.builder().put(ACCESS_KEY, props.getProperty(ACCESS_KEY))
- .put(SECRET_KEY, props.getProperty(SECRET_KEY))
- .put(REGION, props.getProperty(REGION))
- .put(PROTOCOL, props.getProperty(PROTOCOL))
- .build();
+ .put(SECRET_KEY, props.getProperty(SECRET_KEY))
+ .put(REGION, props.getProperty(REGION))
+ .put(PROTOCOL, props.getProperty(PROTOCOL))
+ .put(BUCKET_NAME_KEY, props.getProperty(BUCKET_NAME_KEY))
+ .build();
}
return env;
}
+ /**
+ * Attempt to retrieve OS Environment Variable
+ * @return
+ */
+ private static String getEnvValue(@Nonnull String key)
+ {
+ String envKeyName = getS3EnvName(key);
+ String value = System.getenv(envKeyName);
+
+ return value;
+ }
+
+ /**
+ * @param key Non-prefixed environment name (i.e. bucket.name)
+ * @return Prefixed uppercase environment name (i.e. S3FS_BUCKET_NAME || S3FS_MINIO_BUCKET_NAME)
+ */
+ private static String getS3EnvName(@Nonnull String key)
+ {
+ // Sometimes the key will contain `S3FS_` or `s3fs.property.name` which is why we need to sanitize the string
+ // to ensure consistency.
+ String sanitized = StringUtils.removeStartIgnoreCase(key, "S3FS.");
+ sanitized = StringUtils.removeStartIgnoreCase(sanitized, "S3FS_");
+ sanitized = sanitized.replaceAll("\\.", "_").toUpperCase();
+
+ String integrationSuite = System.getProperty("running.it");
+ if(integrationSuite != null && integrationSuite.equalsIgnoreCase("minio"))
+ {
+ sanitized = "MINIO_" + sanitized;
+ }
+
+ sanitized = "S3FS_" + sanitized;
+
+ return sanitized;
+ }
+
/**
* get default bucket name
*
@@ -75,7 +117,7 @@ public static Map getRealEnv()
*/
public static String getBucket()
{
- String bucketName = System.getenv(BUCKET_NAME_KEY);
+ String bucketName = getEnvValue(BUCKET_NAME_KEY);
if (bucketName != null)
{
if (!bucketName.endsWith("/"))