diff --git a/pom.xml b/pom.xml index f7cb8f1a..f6b92114 100644 --- a/pom.xml +++ b/pom.xml @@ -81,7 +81,7 @@ 1.7.30 - 1.11.850 + 2.14.16 30.0-jre 1.24.1 3.0.2 @@ -166,11 +166,22 @@ + + + + software.amazon.awssdk + bom + ${version.software.amazon.awssdk} + pom + import + + + + - com.amazonaws - aws-java-sdk-s3 - ${version.aws-java-sdk-s3} + software.amazon.awssdk + s3 commons-logging @@ -178,6 +189,10 @@ + + software.amazon.awssdk + apache-client + com.google.guava guava diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/AmazonS3ClientFactory.java b/src/main/java/org/carlspring/cloud/storage/s3fs/AmazonS3ClientFactory.java deleted file mode 100644 index 52358705..00000000 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/AmazonS3ClientFactory.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.carlspring.cloud.storage.s3fs; - -import com.amazonaws.ClientConfiguration; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.metrics.RequestMetricCollector; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3Client; - -public class AmazonS3ClientFactory - extends AmazonS3Factory -{ - - @Override - protected AmazonS3 createAmazonS3(AWSCredentialsProvider credentialsProvider, - ClientConfiguration clientConfiguration, - RequestMetricCollector requestMetricsCollector) - { - return new AmazonS3Client(credentialsProvider, clientConfiguration, requestMetricsCollector); - } - -} diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/AmazonS3Factory.java b/src/main/java/org/carlspring/cloud/storage/s3fs/AmazonS3Factory.java deleted file mode 100644 index ed83c95f..00000000 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/AmazonS3Factory.java +++ /dev/null @@ -1,241 +0,0 @@ -package org.carlspring.cloud.storage.s3fs; - -import java.net.URI; -import java.util.Properties; - -import com.amazonaws.ClientConfiguration; -import com.amazonaws.Protocol; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; -import com.amazonaws.metrics.RequestMetricCollector; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.S3ClientOptions; - - -/** - * Factory base class to create a new AmazonS3 instance. - */ -public abstract class AmazonS3Factory -{ - - public static final String REGION = "s3fs_region"; - - public static final String ACCESS_KEY = "s3fs_access_key"; - - public static final String SECRET_KEY = "s3fs_secret_key"; - - public static final String REQUEST_METRIC_COLLECTOR_CLASS = "s3fs_request_metric_collector_class"; - - public static final String CONNECTION_TIMEOUT = "s3fs_connection_timeout"; - - public static final String MAX_CONNECTIONS = "s3fs_max_connections"; - - public static final String MAX_ERROR_RETRY = "s3fs_max_retry_error"; - - public static final String PROTOCOL = "s3fs_protocol"; - - public static final String PROXY_DOMAIN = "s3fs_proxy_domain"; - - public static final String PROXY_HOST = "s3fs_proxy_host"; - - public static final String PROXY_PASSWORD = "s3fs_proxy_password"; - - public static final String PROXY_PORT = "s3fs_proxy_port"; - - public static final String PROXY_USERNAME = "s3fs_proxy_username"; - - public static final String PROXY_WORKSTATION = "s3fs_proxy_workstation"; - - public static final String SOCKET_SEND_BUFFER_SIZE_HINT = "s3fs_socket_send_buffer_size_hint"; - - public static final String SOCKET_RECEIVE_BUFFER_SIZE_HINT = "s3fs_socket_receive_buffer_size_hint"; - - public static final String SOCKET_TIMEOUT = "s3fs_socket_timeout"; - - public static final String USER_AGENT = "s3fs_user_agent"; - - public static final String SIGNER_OVERRIDE = "s3fs_signer_override"; - - public static final String PATH_STYLE_ACCESS = "s3fs_path_style_access"; - - /** - * Build a new Amazon S3 instance with the URI and the properties provided - * - * @param uri URI mandatory - * @param props Properties with the credentials and others options - * @return AmazonS3 - */ - public AmazonS3 getAmazonS3(URI uri, Properties props) - { - AmazonS3 client = createAmazonS3(getCredentialsProvider(props), - getClientConfiguration(props), - getRequestMetricsCollector(props)); - if (uri.getHost() != null) - { - if (uri.getPort() != -1) - { - client.setEndpoint(uri.getHost() + ':' + uri.getPort()); - } - else - { - client.setEndpoint(uri.getHost()); - } - } - - client.setS3ClientOptions(getClientOptions(props)); - - return client; - } - - /** - * should return a new AmazonS3 - * - * @param credentialsProvider AWSCredentialsProvider mandatory - * @param clientConfiguration ClientConfiguration mandatory - * @param requestMetricsCollector RequestMetricCollector mandatory - * @return {@link com.amazonaws.services.s3.AmazonS3} - */ - protected abstract AmazonS3 createAmazonS3(AWSCredentialsProvider credentialsProvider, - ClientConfiguration clientConfiguration, - RequestMetricCollector requestMetricsCollector); - - protected AWSCredentialsProvider getCredentialsProvider(Properties props) - { - AWSCredentialsProvider credentialsProvider; - if (props.getProperty(ACCESS_KEY) == null && props.getProperty(SECRET_KEY) == null) - { - credentialsProvider = new DefaultAWSCredentialsProviderChain(); - } - else - { - credentialsProvider = new AWSStaticCredentialsProvider(getAWSCredentials(props)); - } - - return credentialsProvider; - } - - protected RequestMetricCollector getRequestMetricsCollector(Properties props) - { - RequestMetricCollector requestMetricCollector = null; - if (props.containsKey(REQUEST_METRIC_COLLECTOR_CLASS)) - { - try - { - requestMetricCollector = (RequestMetricCollector) Class.forName(props.getProperty( - REQUEST_METRIC_COLLECTOR_CLASS)).newInstance(); - } - catch (Throwable t) - { - throw new IllegalArgumentException("Can't instantiate REQUEST_METRIC_COLLECTOR_CLASS " + - props.getProperty(REQUEST_METRIC_COLLECTOR_CLASS), t); - } - } - - return requestMetricCollector; - } - - protected S3ClientOptions getClientOptions(Properties props) - { - S3ClientOptions.Builder builder = S3ClientOptions.builder(); - if (props.getProperty(PATH_STYLE_ACCESS) != null && Boolean.parseBoolean(props.getProperty(PATH_STYLE_ACCESS))) - { - builder.setPathStyleAccess(true); - } - - return builder.build(); - } - - protected ClientConfiguration getClientConfiguration(Properties props) - { - ClientConfiguration clientConfiguration = new ClientConfiguration(); - - if (props.getProperty(CONNECTION_TIMEOUT) != null) - { - clientConfiguration.setConnectionTimeout(Integer.parseInt(props.getProperty(CONNECTION_TIMEOUT))); - } - - if (props.getProperty(MAX_CONNECTIONS) != null) - { - clientConfiguration.setMaxConnections(Integer.parseInt(props.getProperty(MAX_CONNECTIONS))); - } - - if (props.getProperty(MAX_ERROR_RETRY) != null) - { - clientConfiguration.setMaxErrorRetry(Integer.parseInt(props.getProperty(MAX_ERROR_RETRY))); - } - - if (props.getProperty(PROTOCOL) != null) - { - clientConfiguration.setProtocol(Protocol.valueOf(props.getProperty(PROTOCOL))); - } - - if (props.getProperty(PROXY_DOMAIN) != null) - { - clientConfiguration.setProxyDomain(props.getProperty(PROXY_DOMAIN)); - } - - if (props.getProperty(PROXY_HOST) != null) - { - clientConfiguration.setProxyHost(props.getProperty(PROXY_HOST)); - } - - if (props.getProperty(PROXY_PASSWORD) != null) - { - clientConfiguration.setProxyPassword(props.getProperty(PROXY_PASSWORD)); - } - - if (props.getProperty(PROXY_PORT) != null) - { - clientConfiguration.setProxyPort(Integer.parseInt(props.getProperty(PROXY_PORT))); - } - - if (props.getProperty(PROXY_USERNAME) != null) - { - clientConfiguration.setProxyUsername(props.getProperty(PROXY_USERNAME)); - } - - if (props.getProperty(PROXY_WORKSTATION) != null) - { - clientConfiguration.setProxyWorkstation(props.getProperty(PROXY_WORKSTATION)); - } - - int socketSendBufferSizeHint = 0; - if (props.getProperty(SOCKET_SEND_BUFFER_SIZE_HINT) != null) - { - socketSendBufferSizeHint = Integer.parseInt(props.getProperty(SOCKET_SEND_BUFFER_SIZE_HINT)); - } - - int socketReceiveBufferSizeHint = 0; - if (props.getProperty(SOCKET_RECEIVE_BUFFER_SIZE_HINT) != null) - { - socketReceiveBufferSizeHint = Integer.parseInt(props.getProperty(SOCKET_RECEIVE_BUFFER_SIZE_HINT)); - } - - clientConfiguration.setSocketBufferSizeHints(socketSendBufferSizeHint, socketReceiveBufferSizeHint); - - if (props.getProperty(SOCKET_TIMEOUT) != null) - { - clientConfiguration.setSocketTimeout(Integer.parseInt(props.getProperty(SOCKET_TIMEOUT))); - } - - if (props.getProperty(USER_AGENT) != null) - { - clientConfiguration.setUserAgentPrefix(props.getProperty(USER_AGENT)); - } - - if (props.getProperty(SIGNER_OVERRIDE) != null) - { - clientConfiguration.setSignerOverride(props.getProperty(SIGNER_OVERRIDE)); - } - - return clientConfiguration; - } - - protected BasicAWSCredentials getAWSCredentials(Properties props) - { - return new BasicAWSCredentials(props.getProperty(ACCESS_KEY), props.getProperty(SECRET_KEY)); - } - -} diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3AccessControlList.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3AccessControlList.java index 6420d51d..c30fd9cb 100644 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3AccessControlList.java +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3AccessControlList.java @@ -3,29 +3,32 @@ import java.nio.file.AccessDeniedException; import java.nio.file.AccessMode; import java.util.EnumSet; +import java.util.stream.StreamSupport; -import com.amazonaws.services.s3.model.AccessControlList; -import com.amazonaws.services.s3.model.Grant; -import com.amazonaws.services.s3.model.Owner; -import com.amazonaws.services.s3.model.Permission; +import software.amazon.awssdk.services.s3.model.Grant; +import software.amazon.awssdk.services.s3.model.Owner; +import software.amazon.awssdk.services.s3.model.Permission; +import software.amazon.awssdk.utils.StringUtils; import static java.lang.String.format; public class S3AccessControlList { - private String fileStoreName; + private final String fileStoreName; - private String key; + private final String key; - private AccessControlList acl; + private final Iterable grants; - private Owner owner; + private final Owner owner; - - public S3AccessControlList(String fileStoreName, String key, AccessControlList acl, Owner owner) + public S3AccessControlList(final String fileStoreName, + final String key, + final Iterable grants, + final Owner owner) { this.fileStoreName = fileStoreName; - this.acl = acl; + this.grants = grants; this.key = key; this.owner = owner; } @@ -41,20 +44,14 @@ public String getKey() * @param permissions almost one * @return */ - private boolean hasPermission(EnumSet permissions) + private boolean hasPermission(final EnumSet permissions) { - for (Grant grant : acl.getGrantsAsList()) - { - if (grant.getGrantee().getIdentifier().equals(owner.getId()) && permissions.contains(grant.getPermission())) - { - return true; - } - } - - return false; + return StreamSupport.stream(grants.spliterator(), false) + .anyMatch(grant -> StringUtils.equals(grant.grantee().id(), owner.id()) && + permissions.contains(grant.permission())); } - public void checkAccess(AccessMode[] modes) + public void checkAccess(final AccessMode[] modes) throws AccessDeniedException { for (AccessMode accessMode : modes) @@ -64,20 +61,17 @@ public void checkAccess(AccessMode[] modes) case EXECUTE: throw new AccessDeniedException(fileName(), null, "file is not executable"); case READ: - if (!hasPermission(EnumSet.of(Permission.FullControl, Permission.Read))) + if (!hasPermission(EnumSet.of(Permission.FULL_CONTROL, Permission.READ))) { throw new AccessDeniedException(fileName(), null, "file is not readable"); } - break; case WRITE: - if (!hasPermission(EnumSet.of(Permission.FullControl, Permission.Write))) + if (!hasPermission(EnumSet.of(Permission.FULL_CONTROL, Permission.WRITE))) { - throw new AccessDeniedException(fileName(), - null, + throw new AccessDeniedException(fileName(), null, format("bucket '%s' is not writable", fileStoreName)); } - break; } } @@ -87,5 +81,4 @@ private String fileName() { return fileStoreName + S3Path.PATH_SEPARATOR + key; } - } diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3ClientFactory.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3ClientFactory.java new file mode 100644 index 00000000..63ae8b38 --- /dev/null +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3ClientFactory.java @@ -0,0 +1,16 @@ +package org.carlspring.cloud.storage.s3fs; + +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3ClientBuilder; + +public class S3ClientFactory + extends S3Factory +{ + + @Override + protected S3Client createS3Client(final S3ClientBuilder builder) + { + return builder.build(); + } + +} diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3Factory.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3Factory.java new file mode 100644 index 00000000..6734329b --- /dev/null +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3Factory.java @@ -0,0 +1,360 @@ +package org.carlspring.cloud.storage.s3fs; + +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.time.Duration; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.retry.RetryPolicy; +import software.amazon.awssdk.core.signer.Signer; +import software.amazon.awssdk.http.SdkHttpClient; +import software.amazon.awssdk.http.apache.ApacheHttpClient; +import software.amazon.awssdk.http.apache.ProxyConfiguration; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3ClientBuilder; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.Protocol; +import static software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.SIGNER; +import static software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.USER_AGENT_PREFIX; + + +/** + * Factory base class to create a new S3Client instance. + */ +public abstract class S3Factory +{ + + public static final String REGION = "s3fs_region"; + + public static final String ACCESS_KEY = "s3fs_access_key"; + + public static final String SECRET_KEY = "s3fs_secret_key"; + + public static final String REQUEST_METRIC_COLLECTOR_CLASS = "s3fs_request_metric_collector_class"; + + public static final String CONNECTION_TIMEOUT = "s3fs_connection_timeout"; + + public static final String MAX_CONNECTIONS = "s3fs_max_connections"; + + public static final String MAX_ERROR_RETRY = "s3fs_max_retry_error"; + + public static final String PROTOCOL = "s3fs_protocol"; + + public static final String PROXY_DOMAIN = "s3fs_proxy_domain"; + + public static final String PROXY_HOST = "s3fs_proxy_host"; + + public static final String PROXY_PASSWORD = "s3fs_proxy_password"; + + public static final String PROXY_PORT = "s3fs_proxy_port"; + + public static final String PROXY_USERNAME = "s3fs_proxy_username"; + + public static final String PROXY_WORKSTATION = "s3fs_proxy_workstation"; + + /** + * @deprecated Not supported according to https://github.com/aws/aws-sdk-java-v2/blob/master/docs/LaunchChangelog.md#133-client-override-configuration + */ + @Deprecated + public static final String SOCKET_SEND_BUFFER_SIZE_HINT = "s3fs_socket_send_buffer_size_hint"; + + /** + * @deprecated Not supported according to https://github.com/aws/aws-sdk-java-v2/blob/master/docs/LaunchChangelog.md#133-client-override-configuration + */ + @Deprecated + public static final String SOCKET_RECEIVE_BUFFER_SIZE_HINT = "s3fs_socket_receive_buffer_size_hint"; + + public static final String SOCKET_TIMEOUT = "s3fs_socket_timeout"; + + public static final String USER_AGENT = "s3fs_user_agent"; + + public static final String SIGNER_OVERRIDE = "s3fs_signer_override"; + + public static final String PATH_STYLE_ACCESS = "s3fs_path_style_access"; + + private static final Logger LOGGER = LoggerFactory.getLogger(S3Factory.class); + + private static final String DEFAULT_PROTOCOL = Protocol.HTTPS.toString(); + + private static final Region DEFAULT_REGION = Region.US_EAST_1; + + private static final int RADIX = 10; + + /** + * Build a new Amazon S3 instance with the URI and the properties provided + * + * @param uri URI mandatory + * @param props Properties with the credentials and others options + * @return {@link software.amazon.awssdk.services.s3.S3Client} + */ + public S3Client getS3Client(final URI uri, + final Properties props) + { + S3ClientBuilder builder = getS3ClientBuilder(); + + if (uri.getHost() != null) + { + final URI endpoint = getEndpointUri(uri.getHost(), uri.getPort(), props); + builder.endpointOverride(endpoint); + } + + builder.region(getRegion(props)) + .credentialsProvider(getCredentialsProvider(props)) + .httpClient(getHttpClient(props)) + .overrideConfiguration(getOverrideConfiguration(props)) + .serviceConfiguration(getServiceConfiguration(props)); + + return createS3Client(builder); + } + + private URI getEndpointUri(final String host, + final int port, + final Properties props) + { + final String scheme = getProtocol(props); + + String endpointStr; + if (port != -1) + { + endpointStr = String.format("%s://%s:%d", scheme, host, port); + } + else + { + endpointStr = String.format("%s://%s", scheme, host); + } + + return URI.create(endpointStr); + } + + protected S3ClientBuilder getS3ClientBuilder() + { + return S3Client.builder(); + } + + private String getProtocol(final Properties props) + { + if (props.getProperty(PROTOCOL) != null) + { + return Protocol.fromValue(props.getProperty(PROTOCOL)).toString(); + } + + return DEFAULT_PROTOCOL; + } + + private Region getRegion(final Properties props) + { + if (props.getProperty(REGION) != null) + { + return Region.of(props.getProperty(REGION)); + } + + try + { + return new DefaultAwsRegionProviderChain().getRegion(); + } + catch (final SdkClientException e) + { + LOGGER.warn("Unable to load region from any of the providers in the chain"); + } + + return DEFAULT_REGION; + } + + protected SdkHttpClient getHttpClient(final Properties props) + { + final ApacheHttpClient.Builder builder = getApacheHttpClientBuilder(props); + return builder.build(); + } + + private ApacheHttpClient.Builder getApacheHttpClientBuilder(final Properties props) + { + final ApacheHttpClient.Builder builder = ApacheHttpClient.builder(); + + if (props.getProperty(CONNECTION_TIMEOUT) != null) + { + try + { + final Duration duration = Duration.ofMillis( + Long.parseLong(props.getProperty(CONNECTION_TIMEOUT), RADIX)); + builder.connectionTimeout(duration); + } + catch (final NumberFormatException e) + { + printWarningMessage(props, CONNECTION_TIMEOUT); + } + } + + if (props.getProperty(MAX_CONNECTIONS) != null) + { + try + { + final int maxConnections = Integer.parseInt(props.getProperty(MAX_CONNECTIONS), RADIX); + builder.maxConnections(maxConnections); + } + catch (final NumberFormatException e) + { + printWarningMessage(props, MAX_CONNECTIONS); + } + } + + if (props.getProperty(SOCKET_TIMEOUT) != null) + { + try + { + final Duration duration = Duration.ofMillis(Long.parseLong(props.getProperty(SOCKET_TIMEOUT), RADIX)); + builder.socketTimeout(duration); + } + catch (final NumberFormatException e) + { + printWarningMessage(props, SOCKET_TIMEOUT); + } + } + + return builder.proxyConfiguration(getProxyConfiguration(props)); + } + + /** + * should return a new S3Client + * + * @param builder S3ClientBuilder mandatory. + * @return {@link software.amazon.awssdk.services.s3.S3Client} + */ + protected abstract S3Client createS3Client(final S3ClientBuilder builder); + + protected AwsCredentialsProvider getCredentialsProvider(final Properties props) + { + AwsCredentialsProvider credentialsProvider; + if (props.getProperty(ACCESS_KEY) == null && props.getProperty(SECRET_KEY) == null) + { + credentialsProvider = DefaultCredentialsProvider.create(); + } + else + { + final AwsCredentials awsCredentials = getAwsCredentials(props); + credentialsProvider = StaticCredentialsProvider.create(awsCredentials); + } + return credentialsProvider; + } + + protected AwsCredentials getAwsCredentials(final Properties props) + { + return AwsBasicCredentials.create(props.getProperty(ACCESS_KEY), props.getProperty(SECRET_KEY)); + } + + protected S3Configuration getServiceConfiguration(final Properties props) + { + S3Configuration.Builder builder = S3Configuration.builder(); + if (props.getProperty(PATH_STYLE_ACCESS) != null && Boolean.parseBoolean(props.getProperty(PATH_STYLE_ACCESS))) + { + builder.pathStyleAccessEnabled(true); + } + + return builder.build(); + } + + protected ClientOverrideConfiguration getOverrideConfiguration(final Properties props) + { + final ClientOverrideConfiguration.Builder builder = ClientOverrideConfiguration.builder(); + + if (props.getProperty(MAX_ERROR_RETRY) != null) + { + try + { + final Integer numRetries = Integer.parseInt(props.getProperty(MAX_ERROR_RETRY), RADIX); + final RetryPolicy retryPolicy = RetryPolicy.builder().numRetries(numRetries).build(); + builder.retryPolicy(retryPolicy); + } + catch (final NumberFormatException e) + { + printWarningMessage(props, MAX_ERROR_RETRY); + } + } + + if (props.getProperty(USER_AGENT) != null) + { + builder.putAdvancedOption(USER_AGENT_PREFIX, props.getProperty(USER_AGENT)); + } + + if (props.getProperty(SIGNER_OVERRIDE) != null) + { + try + { + final Class clazz = Class.forName(props.getProperty(SIGNER_OVERRIDE)); + final Signer signer = (Signer) clazz.getDeclaredConstructor().newInstance(); + builder.putAdvancedOption(SIGNER, signer); + } + catch (final ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) + { + printWarningMessage(props, SIGNER_OVERRIDE); + } + } + + return builder.build(); + } + + + protected ProxyConfiguration getProxyConfiguration(final Properties props) + { + final ProxyConfiguration.Builder builder = ProxyConfiguration.builder(); + + if (props.getProperty(PROXY_HOST) != null) + { + final String host = props.getProperty(PROXY_HOST); + final String portStr = props.getProperty(PROXY_PORT); + int port = -1; + try + { + port = portStr != null ? Integer.parseInt(portStr, RADIX) : -1; + } + catch (final NumberFormatException e) + { + printWarningMessage(props, PROXY_PORT); + } + + final URI uri = getEndpointUri(host, port, props); + builder.endpoint(uri); + } + + if (props.getProperty(PROXY_USERNAME) != null) + { + builder.username(props.getProperty(PROXY_USERNAME)); + } + + if (props.getProperty(PROXY_PASSWORD) != null) + { + builder.password(props.getProperty(PROXY_PASSWORD)); + } + + if (props.getProperty(PROXY_DOMAIN) != null) + { + builder.ntlmDomain(props.getProperty(PROXY_DOMAIN)); + } + + if (props.getProperty(PROXY_WORKSTATION) != null) + { + builder.ntlmWorkstation(props.getProperty(PROXY_WORKSTATION)); + } + + return builder.build(); + } + + private void printWarningMessage(final Properties props, + final String propertyName) + { + LOGGER.warn("The '{}' property could not be loaded with this value: {}", + propertyName, + props.getProperty(propertyName)); + } + +} diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileChannel.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileChannel.java index 7024ce67..a7898e80 100644 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileChannel.java +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileChannel.java @@ -9,105 +9,133 @@ import java.nio.channels.FileLock; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; -import java.nio.file.*; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.S3Object; import org.apache.tika.Tika; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; import static java.lang.String.format; public class S3FileChannel extends FileChannel { - private S3Path path; + private final S3Path path; - private Set options; + private final Set options; - private FileChannel filechannel; + private final FileChannel filechannel; - private Path tempFile; + private final Path tempFile; - - public S3FileChannel(S3Path path, Set options) + /** + * Open or creates a file, returning a file channel. + * + * @param path the path open or create. + * @param options options specifying how the file is opened. + * @param tempFileRequired true if a temp file wanted, false in case of a in-memory solution option. + * @throws IOException if an I/O error occurs + */ + public S3FileChannel(final S3Path path, + final Set options, + final boolean tempFileRequired) throws IOException { this.path = path; this.options = Collections.unmodifiableSet(new HashSet<>(options)); - - String key = path.getKey(); - boolean exists = path.getFileSystem().provider().exists(path); if (exists && this.options.contains(StandardOpenOption.CREATE_NEW)) { throw new FileAlreadyExistsException(format("target already exists: %s", path)); } - else if (!exists && !this.options.contains(StandardOpenOption.CREATE_NEW) && !this.options.contains( - StandardOpenOption.CREATE)) + else if (!exists && !this.options.contains(StandardOpenOption.CREATE_NEW) && + !this.options.contains(StandardOpenOption.CREATE)) { throw new NoSuchFileException(format("target not exists: %s", path)); } - tempFile = Files.createTempFile("temp-s3-", key.replaceAll("/", "_")); - boolean removeTempFile = true; + final Set fileChannelOptions = new HashSet<>(this.options); + fileChannelOptions.remove(StandardOpenOption.CREATE_NEW); - try + if(tempFileRequired) { - if (exists) + final String key = path.getKey(); + this.tempFile = Files.createTempFile("temp-s3-", key.replaceAll("/", "_")); + boolean removeTempFile = true; + try { - try (S3Object object = path.getFileSystem().getClient().getObject(path.getFileStore() - .getBucket() - .getName(), - key)) + if (exists) { - Files.copy(object.getObjectContent(), tempFile, StandardCopyOption.REPLACE_EXISTING); + final S3Client client = path.getFileSystem().getClient(); + final GetObjectRequest request = GetObjectRequest.builder() + .bucket(path.getFileStore().name()) + .key(key) + .build(); + try (ResponseInputStream byteStream = client.getObject(request)) + { + Files.copy(byteStream, tempFile, StandardCopyOption.REPLACE_EXISTING); + } } - } - Set fileChannelOptions = new HashSet<>(this.options); - - fileChannelOptions.remove(StandardOpenOption.CREATE_NEW); - - filechannel = FileChannel.open(tempFile, fileChannelOptions); - - removeTempFile = false; - } - finally - { - if (removeTempFile) + this.filechannel = FileChannel.open(tempFile, fileChannelOptions); + removeTempFile = false; + } + finally { - Files.deleteIfExists(tempFile); + if (removeTempFile) + { + Files.deleteIfExists(tempFile); + } } } + else + { + this.tempFile = null; + this.filechannel = FileChannel.open(path, fileChannelOptions); + } } @Override - public int read(ByteBuffer dst) + public int read(final ByteBuffer dst) throws IOException { return filechannel.read(dst); } @Override - public long read(ByteBuffer[] dsts, int offset, int length) + public long read(final ByteBuffer[] dsts, + final int offset, + final int length) throws IOException { return filechannel.read(dsts, offset, length); } @Override - public int write(ByteBuffer src) + public int write(final ByteBuffer src) throws IOException { return filechannel.write(src); } @Override - public long write(ByteBuffer[] srcs, int offset, int length) + public long write(final ByteBuffer[] srcs, + final int offset, + final int length) throws IOException { return filechannel.write(srcs, offset, length); @@ -121,7 +149,7 @@ public long position() } @Override - public FileChannel position(long newPosition) + public FileChannel position(final long newPosition) throws IOException { return filechannel.position(newPosition); @@ -135,63 +163,75 @@ public long size() } @Override - public FileChannel truncate(long size) + public FileChannel truncate(final long size) throws IOException { return filechannel.truncate(size); } @Override - public void force(boolean metaData) + public void force(final boolean metaData) throws IOException { filechannel.force(metaData); } @Override - public long transferTo(long position, long count, WritableByteChannel target) + public long transferTo(final long position, + final long count, + WritableByteChannel target) throws IOException { return filechannel.transferTo(position, count, target); } @Override - public long transferFrom(ReadableByteChannel src, long position, long count) + public long transferFrom(final ReadableByteChannel src, + final long position, + final long count) throws IOException { return filechannel.transferFrom(src, position, count); } @Override - public int read(ByteBuffer dst, long position) + public int read(final ByteBuffer dst, + final long position) throws IOException { return filechannel.read(dst, position); } @Override - public int write(ByteBuffer src, long position) + public int write(final ByteBuffer src, + final long position) throws IOException { return filechannel.write(src, position); } @Override - public MappedByteBuffer map(MapMode mode, long position, long size) + public MappedByteBuffer map(final MapMode mode, + final long position, + final long size) throws IOException { return filechannel.map(mode, position, size); } @Override - public FileLock lock(long position, long size, boolean shared) + public FileLock lock(final long position, + final long size, + final boolean shared) throws IOException { return filechannel.lock(position, size, shared); } @Override - public FileLock tryLock(long position, long size, boolean shared) + public FileLock tryLock(final long position, + final long size, + final boolean shared) throws IOException { return filechannel.tryLock(position, size, shared); @@ -202,14 +242,16 @@ protected void implCloseChannel() throws IOException { super.close(); - filechannel.close(); - - if (!this.options.contains(StandardOpenOption.READ)) + this.filechannel.close(); + if(this.tempFile != null) { - sync(); - } + if (!this.options.contains(StandardOpenOption.READ)) + { + sync(); + } - Files.deleteIfExists(tempFile); + Files.deleteIfExists(tempFile); + } } /** @@ -222,15 +264,16 @@ protected void sync() { try (InputStream stream = new BufferedInputStream(Files.newInputStream(tempFile))) { - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(Files.size(tempFile)); - metadata.setContentType(new Tika().detect(stream, path.getFileName().toString())); - - String bucket = path.getFileStore().name(); - String key = path.getKey(); - - path.getFileSystem().getClient().putObject(bucket, key, stream, metadata); + //TODO: If the temp file is larger than 5 GB then, instead of a putObject, a multi-part upload is needed. + final PutObjectRequest.Builder builder = PutObjectRequest.builder(); + final long length = Files.size(tempFile); + builder.bucket(path.getFileStore().name()) + .key(path.getKey()) + .contentLength(length) + .contentType(new Tika().detect(stream, path.getFileName().toString())); + + final S3Client client = path.getFileSystem().getClient(); + client.putObject(builder.build(), RequestBody.fromInputStream(stream, length)); } } - } 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 7ad8c221..79d4de49 100644 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileStore.java +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileStore.java @@ -3,22 +3,27 @@ import java.nio.file.FileStore; import java.nio.file.attribute.FileAttributeView; import java.nio.file.attribute.FileStoreAttributeView; +import java.util.Date; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.Bucket; -import com.amazonaws.services.s3.model.Owner; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.Bucket; +import software.amazon.awssdk.services.s3.model.GetBucketAclRequest; +import software.amazon.awssdk.services.s3.model.HeadBucketRequest; +import software.amazon.awssdk.services.s3.model.ListBucketsRequest; +import software.amazon.awssdk.services.s3.model.NoSuchBucketException; +import software.amazon.awssdk.services.s3.model.Owner; public class S3FileStore extends FileStore implements Comparable { - private S3FileSystem fileSystem; + private final S3FileSystem fileSystem; - private String name; + private final String name; - - public S3FileStore(S3FileSystem s3FileSystem, String name) + public S3FileStore(final S3FileSystem s3FileSystem, + final String name) { this.fileSystem = s3FileSystem; this.name = name; @@ -61,13 +66,13 @@ public long getUnallocatedSpace() } @Override - public boolean supportsFileAttributeView(Class type) + public boolean supportsFileAttributeView(final Class type) { return false; } @Override - public boolean supportsFileAttributeView(String attributeViewName) + public boolean supportsFileAttributeView(final String attributeViewName) { return false; } @@ -78,21 +83,26 @@ public V getFileStoreAttributeView(Class t { if (type != S3FileStoreAttributeView.class) { - throw new IllegalArgumentException("FileStoreAttributeView of type '" + type.getName() + - "' is not supported."); + throw new IllegalArgumentException( + "FileStoreAttributeView of type '" + type.getName() + "' is not supported."); } - Bucket buck = getBucket(); - Owner owner = buck.getOwner(); + final Bucket buck = getBucket(name); + if (buck != null) + { + final Owner owner = getClient().getBucketAcl(GetBucketAclRequest.builder().bucket(name).build()).owner(); - return (V) new S3FileStoreAttributeView(buck.getCreationDate(), - buck.getName(), - owner.getId(), - owner.getDisplayName()); + return (V) new S3FileStoreAttributeView(Date.from(buck.creationDate()), buck.name(), owner.id(), + owner.displayName()); + } + else + { + throw NoSuchBucketException.builder().message("Bucket not found: " + name).build(); + } } @Override - public Object getAttribute(String attribute) + public Object getAttribute(final String attribute) { return getFileStoreAttributeView(S3FileStoreAttributeView.class).getAttribute(attribute); } @@ -107,38 +117,68 @@ public Bucket getBucket() return getBucket(name); } - private Bucket getBucket(String bucketName) + private Bucket getBucket(final String bucketName) { - for (Bucket buck : getClient().listBuckets()) + for (Bucket buck : getClient().listBuckets().buckets()) { - if (buck.getName().equals(bucketName)) + if (buck.name().equals(bucketName)) { return buck; } } - return null; } + private boolean hasBucket(final String bucketName) + { + // Originally getBucket was being used to determine presence of a bucket + // + // This is incorrect for two reasons: + // 1. The list bucket operation provides buckets for which you are the owner + // It would not, therefore, allow you to work with buckets for which you + // have access but are not the owner. + // 2. The way this information is being used later is to determine the + // bucket owner, which by definition, is now "you". + // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTServiceGET.html + // + // However, note that the revised code below now has a different permissions + // model as HeadBucket is now required + boolean bucket = false; + try + { + getClient().headBucket(HeadBucketRequest.builder().bucket(bucketName).build()); + bucket = true; + } + catch (NoSuchBucketException ignored) + { + //Do nothing + } + return bucket; + } + public S3Path getRootDirectory() { return new S3Path(fileSystem, "/" + this.name()); } - private AmazonS3 getClient() + private S3Client getClient() { return fileSystem.getClient(); } public Owner getOwner() { - Bucket bucket = getBucket(); - if (bucket != null) + if (hasBucket(name)) { - return bucket.getOwner(); + return getClient().getBucketAcl(GetBucketAclRequest.builder().bucket(name).build()).owner(); } - - return fileSystem.getClient().getS3AccountOwner(); + // SDK v1 getS3AccountOwner uses the list buckets call, then extracts + // the owner field (see: https://github.com/aws/aws-sdk-java/blob/4734de6fb0f80fe5768a6587aad3b9d0eaec388f/aws-java-sdk-s3/src/main/java/com/amazonaws/services/s3/model/transform/Unmarshallers.java#L48 + // and https://github.com/aws/aws-sdk-java/blob/2d15a603a96f98076f5458db49d659f296eab313/aws-java-sdk-s3/src/main/java/com/amazonaws/services/s3/AmazonS3Client.java#L926 + // + // SDK v2 does not have that, as the SDK is mostly auto-generated based on the model files from the service, so much less custom code and helpers + // More transparency, but we have to unwind this manually. So, here we go... + return getClient().listBuckets(ListBucketsRequest.builder().build()).owner(); } @Override @@ -148,7 +188,6 @@ public int compareTo(S3FileStore o) { return 0; } - return o.name().compareTo(name); } @@ -156,12 +195,9 @@ public int compareTo(S3FileStore o) public int hashCode() { final int prime = 31; - int result = 1; - result = prime * result + ((fileSystem == null) ? 0 : fileSystem.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; } @@ -173,17 +209,14 @@ public boolean equals(Object obj) { return true; } - if (obj == null) { return false; } - if (!(obj instanceof S3FileStore)) { return false; } - S3FileStore other = (S3FileStore) obj; if (fileSystem == null) @@ -197,7 +230,6 @@ else if (!fileSystem.equals(other.fileSystem)) { return false; } - if (name == null) { return other.name == null; @@ -207,5 +239,4 @@ else if (!fileSystem.equals(other.fileSystem)) return name.equals(other.name); } } - } diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileSystem.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileSystem.java index a4799a4f..940940d4 100644 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileSystem.java +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileSystem.java @@ -1,19 +1,24 @@ package org.carlspring.cloud.storage.s3fs; -import java.nio.file.*; +import java.io.IOException; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.WatchService; import java.nio.file.attribute.UserPrincipalLookupService; import java.util.Set; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.Bucket; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.Bucket; import static org.carlspring.cloud.storage.s3fs.S3Path.PATH_SEPARATOR; /** * S3FileSystem with a concrete client configured and ready to use. * - * @see AmazonS3 configured by {@link AmazonS3Factory} + * @see S3Client configured by {@link S3Factory} */ public class S3FileSystem extends FileSystem @@ -24,14 +29,16 @@ public class S3FileSystem private final String key; - private final AmazonS3 client; + private final S3Client client; private final String endpoint; - private int cache; + private final int cache; - - public S3FileSystem(S3FileSystemProvider provider, String key, AmazonS3 client, String endpoint) + public S3FileSystem(final S3FileSystemProvider provider, + final String key, + final S3Client client, + final String endpoint) { this.provider = provider; this.key = key; @@ -53,6 +60,7 @@ public String getKey() @Override public void close() + throws IOException { this.provider.close(this); } @@ -72,19 +80,17 @@ public boolean isReadOnly() @Override public String getSeparator() { - return S3Path.PATH_SEPARATOR; + return PATH_SEPARATOR; } @Override public Iterable getRootDirectories() { ImmutableList.Builder builder = ImmutableList.builder(); - for (FileStore fileStore : getFileStores()) { builder.add(((S3FileStore) fileStore).getRootDirectory()); } - return builder.build(); } @@ -92,10 +98,9 @@ public Iterable getRootDirectories() public Iterable getFileStores() { ImmutableList.Builder builder = ImmutableList.builder(); - - for (Bucket bucket : client.listBuckets()) + for (Bucket bucket : client.listBuckets().buckets()) { - builder.add(new S3FileStore(this, bucket.getName())); + builder.add(new S3FileStore(this, bucket.name())); } return builder.build(); @@ -108,7 +113,8 @@ public Set supportedFileAttributeViews() } @Override - public S3Path getPath(String first, String... more) + public S3Path getPath(final String first, + final String... more) { if (more.length == 0) { @@ -119,7 +125,7 @@ public S3Path getPath(String first, String... more) } @Override - public PathMatcher getPathMatcher(String syntaxAndPattern) + public PathMatcher getPathMatcher(final String syntaxAndPattern) { throw new UnsupportedOperationException(); } @@ -136,7 +142,7 @@ public WatchService newWatchService() throw new UnsupportedOperationException(); } - public AmazonS3 getClient() + public S3Client getClient() { return client; } @@ -219,7 +225,7 @@ else if (!endpoint.equals(other.endpoint)) } @Override - public int compareTo(S3FileSystem o) + public int compareTo(final S3FileSystem o) { return key.compareTo(o.getKey()); } @@ -228,5 +234,4 @@ public int getCache() { return cache; } - } diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileSystemProvider.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileSystemProvider.java index 38aa7ae9..bb15e4b5 100644 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileSystemProvider.java +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3FileSystemProvider.java @@ -6,34 +6,94 @@ import org.carlspring.cloud.storage.s3fs.attribute.S3PosixFileAttributes; import org.carlspring.cloud.storage.s3fs.util.AttributesUtils; import org.carlspring.cloud.storage.s3fs.util.Cache; +import org.carlspring.cloud.storage.s3fs.util.Constants; import org.carlspring.cloud.storage.s3fs.util.S3Utils; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; import java.net.URI; +import java.net.URLEncoder; import java.nio.channels.FileChannel; import java.nio.channels.SeekableByteChannel; -import java.nio.file.*; -import java.nio.file.attribute.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.AccessMode; +import java.nio.file.AtomicMoveNotSupportedException; +import java.nio.file.CopyOption; +import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemAlreadyExistsException; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.NoSuchFileException; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributeView; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.PosixFileAttributeView; +import java.nio.file.attribute.PosixFileAttributes; import java.nio.file.spi.FileSystemProvider; -import java.util.*; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.internal.Constants; -import com.amazonaws.services.s3.model.AmazonS3Exception; -import com.amazonaws.services.s3.model.Bucket; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.S3Object; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.Bucket; +import software.amazon.awssdk.services.s3.model.CopyObjectRequest; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectAclRequest; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.Grant; +import software.amazon.awssdk.services.s3.model.Owner; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.model.S3Exception; +import software.amazon.awssdk.services.s3.model.S3Object; import static com.google.common.collect.Sets.difference; import static java.lang.String.format; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.*; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.CONNECTION_TIMEOUT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.MAX_CONNECTIONS; +import static org.carlspring.cloud.storage.s3fs.S3Factory.MAX_ERROR_RETRY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PATH_STYLE_ACCESS; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROTOCOL; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_DOMAIN; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_HOST; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_PASSWORD; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_PORT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_USERNAME; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_WORKSTATION; +import static org.carlspring.cloud.storage.s3fs.S3Factory.REGION; +import static org.carlspring.cloud.storage.s3fs.S3Factory.REQUEST_METRIC_COLLECTOR_CLASS; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SIGNER_OVERRIDE; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SOCKET_RECEIVE_BUFFER_SIZE_HINT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SOCKET_SEND_BUFFER_SIZE_HINT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SOCKET_TIMEOUT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.USER_AGENT; +import static software.amazon.awssdk.http.HttpStatusCode.NOT_FOUND; /** * Spec: @@ -69,7 +129,7 @@ public class S3FileSystemProvider public static final String CHARSET_KEY = "s3fs_charset"; - public static final String AMAZON_S3_FACTORY_CLASS = "s3fs_amazon_s3_factory"; + public static final String S3_FACTORY_CLASS = "s3fs_amazon_s3_factory"; private static final ConcurrentMap fileSystems = new ConcurrentHashMap<>(); @@ -86,15 +146,16 @@ public class S3FileSystemProvider PROXY_PORT, PROXY_USERNAME, PROXY_WORKSTATION, + REGION, SOCKET_SEND_BUFFER_SIZE_HINT, SOCKET_RECEIVE_BUFFER_SIZE_HINT, SOCKET_TIMEOUT, USER_AGENT, - AMAZON_S3_FACTORY_CLASS, + S3_FACTORY_CLASS, SIGNER_OVERRIDE, PATH_STYLE_ACCESS); - private S3Utils s3Utils = new S3Utils(); + private final S3Utils s3Utils = new S3Utils(); private Cache cache = new Cache(); @@ -181,7 +242,7 @@ protected String getFileSystemKey(URI uri, Properties props) { // we don`t use uri.getUserInfo and uri.getHost because secret key and access key have special chars // and dont return the correct strings - String uriString = uri.toString().replace("s3://", ""); + String uriString = uri.toString().replaceAll("s3://", ""); String authority = null; int authoritySeparator = uriString.indexOf("@"); @@ -236,9 +297,10 @@ protected void addEnvProperties(Properties props, Map env) overloadProperty(props, env, key); } - for (String key : env.keySet()) + for (Map.Entry entry : env.entrySet()) { - Object value = env.get(key); + final String key = entry.getKey(); + final Object value = entry.getValue(); if (!PROPS_TO_OVERLOAD.contains(key)) { @@ -279,7 +341,7 @@ private void overloadProperty(Properties props, Map env, String key) */ protected boolean overloadPropertiesWithEnv(Properties props, Map env, String key) { - if (env.get(key) != null && env.get(key) instanceof String) + if (env.get(key) instanceof String) { props.setProperty(key, (String) env.get(key)); @@ -426,8 +488,9 @@ public InputStream newInputStream(Path path, OpenOption... options) throws IOException { - S3Path s3Path = toS3Path(path); - String key = s3Path.getKey(); + final S3Path s3Path = toS3Path(path); + final String key = s3Path.getKey(); + final String bucketName = s3Path.getFileStore().name(); Preconditions.checkArgument(options.length == 0, "OpenOptions not yet supported: %s", @@ -436,25 +499,31 @@ public InputStream newInputStream(Path path, try { - S3Object object = s3Path.getFileSystem().getClient().getObject(s3Path.getFileStore().name(), key); - InputStream res = object.getObjectContent(); + final S3Client client = s3Path.getFileSystem().getClient(); + final GetObjectRequest request = GetObjectRequest.builder() + .bucket(bucketName) + .key(key) + .build(); + final ResponseInputStream res = client.getObject(request); if (res == null) { - throw new IOException(String.format("The specified path is a directory: %s", path)); + final String message = format("The specified path is a directory: %s", path); + throw new IOException(message); } return res; } - catch (AmazonS3Exception e) + catch (final S3Exception e) { - if (e.getStatusCode() == 404) + if (e.statusCode() == NOT_FOUND) { throw new NoSuchFileException(path.toString()); } // otherwise throws a generic IO exception - throw new IOException(String.format("Cannot access file: %s", path), e); + final String message = format("Cannot access file: %s", path); + throw new IOException(message, e); } } @@ -466,7 +535,7 @@ public SeekableByteChannel newByteChannel(Path path, { S3Path s3Path = toS3Path(path); - return new S3SeekableByteChannel(s3Path, options); + return new S3SeekableByteChannel(s3Path, options, true); } @Override @@ -477,7 +546,7 @@ public FileChannel newFileChannel(Path path, { S3Path s3Path = toS3Path(path); - return new S3FileChannel(s3Path, options); + return new S3FileChannel(s3Path, options, true); } /** @@ -490,7 +559,8 @@ public void createDirectory(Path dir, FileAttribute... attrs) throws IOException { - S3Path s3Path = toS3Path(dir); + final S3Path s3Path = toS3Path(dir); + final S3Client client = s3Path.getFileSystem().getClient(); Preconditions.checkArgument(attrs.length == 0, "attrs not yet supported: %s", @@ -502,23 +572,27 @@ public void createDirectory(Path dir, } // create bucket if necessary - Bucket bucket = s3Path.getFileStore().getBucket(); - String bucketName = s3Path.getFileStore().name(); + final Bucket bucket = s3Path.getFileStore().getBucket(); + final String bucketName = s3Path.getFileStore().name(); + if (bucket == null) { - s3Path.getFileSystem().getClient().createBucket(bucketName); + final CreateBucketRequest request = CreateBucketRequest.builder() + .bucket(bucketName) + .build(); + client.createBucket(request); } // create the object as directory - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(0); + final String directoryKey = s3Path.getKey().endsWith("/") ? s3Path.getKey() : s3Path.getKey() + "/"; + //TODO: If the temp file is larger than 5 GB then, instead of a putObject, a multi-part upload is needed. + final PutObjectRequest request = PutObjectRequest.builder() + .bucket(bucketName) + .key(directoryKey) + .contentLength(0L) + .build(); - String directoryKey = s3Path.getKey().endsWith("/") ? s3Path.getKey() : s3Path.getKey() + "/"; - - s3Path.getFileSystem().getClient().putObject(bucketName, - directoryKey, - new ByteArrayInputStream(new byte[0]), - metadata); + client.putObject(request, RequestBody.fromBytes(new byte[0])); } @Override @@ -530,18 +604,27 @@ public void delete(Path path) { throw new NoSuchFileException("the path: " + this + " not exists"); } - if (Files.isDirectory(s3Path) && Files.newDirectoryStream(s3Path).iterator().hasNext()) + if (Files.isDirectory(s3Path)) { - throw new DirectoryNotEmptyException("the path: " + this + " is a directory and is not empty"); + try (final DirectoryStream stream = Files.newDirectoryStream(s3Path)) + { + if (stream.iterator().hasNext()) + { + throw new DirectoryNotEmptyException("the path: " + this + " is a directory and is not empty"); + } + } } String key = s3Path.getKey(); String bucketName = s3Path.getFileStore().name(); + final S3Client client = s3Path.getFileSystem().getClient(); - s3Path.getFileSystem().getClient().deleteObject(bucketName, key); + DeleteObjectRequest request = DeleteObjectRequest.builder().bucket(bucketName).key(key).build(); + client.deleteObject(request); // we delete the two objects (sometimes exists the key '/' and sometimes not) - s3Path.getFileSystem().getClient().deleteObject(bucketName, key + "/"); + request = DeleteObjectRequest.builder().bucket(bucketName).key(key + "/").build(); + client.deleteObject(request); } @Override @@ -572,8 +655,34 @@ public void copy(Path source, Path target, CopyOption... options) String keySource = s3Source.getKey(); String bucketNameTarget = s3Target.getFileStore().name(); String keyTarget = s3Target.getKey(); + final S3Client client = s3Source.getFileSystem().getClient(); + + final String encodedUrl = encodeUrl(bucketNameOrigin, keySource); - s3Source.getFileSystem().getClient().copyObject(bucketNameOrigin, keySource, bucketNameTarget, keyTarget); + //TODO: If the temp file is larger than 5 GB then, instead of a copyObject, a multi-part copy is needed. + final CopyObjectRequest request = CopyObjectRequest.builder() + .copySource(encodedUrl) + .destinationBucket(bucketNameTarget) + .destinationKey(keyTarget) + .build(); + + client.copyObject(request); + } + + private String encodeUrl(final String bucketNameOrigin, + final String keySource) + throws UnsupportedEncodingException + { + String encodedUrl; + try + { + encodedUrl = URLEncoder.encode(bucketNameOrigin + "/" + keySource, StandardCharsets.UTF_8.toString()); + } + catch (final UnsupportedEncodingException e) + { + throw new UnsupportedEncodingException("URL could not be encoded: " + e.getMessage()); + } + return encodedUrl; } @Override @@ -625,21 +734,21 @@ public void checkAccess(Path path, AccessMode... modes) throw new NoSuchFileException(toString()); } - String key = s3Utils.getS3ObjectSummary(s3Path).getKey(); - S3AccessControlList accessControlList = new S3AccessControlList(s3Path.getFileStore().name(), - key, - s3Path.getFileSystem() - .getClient() - .getObjectAcl(s3Path.getFileStore() - .name(), - key), - s3Path.getFileStore().getOwner()); + final S3Object s3Object = s3Utils.getS3Object(s3Path); + final String key = s3Object.key(); + final String bucket = s3Path.getFileStore().name(); + final GetObjectAclRequest request = GetObjectAclRequest.builder().bucket(bucket).key(key).build(); + final S3Client client = s3Path.getFileSystem().getClient(); + final List grants = client.getObjectAcl(request).grants(); + final Owner owner = s3Path.getFileStore().getOwner(); + final S3AccessControlList accessControlList = new S3AccessControlList(bucket, key, grants, owner); accessControlList.checkAccess(modes); } @Override + @SuppressWarnings("unchecked") public V getFileAttributeView(Path path, Class type, LinkOption... options) @@ -772,33 +881,37 @@ public void setAttribute(Path path, String attribute, Object value, LinkOption.. */ public S3FileSystem createFileSystem(URI uri, Properties props) { - return new S3FileSystem(this, getFileSystemKey(uri, props), getAmazonS3(uri, props), uri.getHost()); + final String key = getFileSystemKey(uri, props); + final S3Client client = getS3Client(uri, props); + final String host = uri.getHost(); + return new S3FileSystem(this, key, client, host); } - protected AmazonS3 getAmazonS3(URI uri, Properties props) + protected S3Client getS3Client(URI uri, Properties props) { - return getAmazonS3Factory(props).getAmazonS3(uri, props); + final S3Factory factory = getS3Factory(props); + return factory.getS3Client(uri, props); } - protected AmazonS3Factory getAmazonS3Factory(Properties props) + protected S3Factory getS3Factory(final Properties props) { - if (props.containsKey(AMAZON_S3_FACTORY_CLASS)) + if (props.containsKey(S3_FACTORY_CLASS)) { - String amazonS3FactoryClass = props.getProperty(AMAZON_S3_FACTORY_CLASS); + String s3FactoryClass = props.getProperty(S3_FACTORY_CLASS); try { - return (AmazonS3Factory) Class.forName(amazonS3FactoryClass).newInstance(); + return (S3Factory) Class.forName(s3FactoryClass).getDeclaredConstructor().newInstance(); } - catch (InstantiationException | IllegalAccessException | ClassNotFoundException | ClassCastException e) + catch (InstantiationException | IllegalAccessException | ClassNotFoundException | ClassCastException | NoSuchMethodException | InvocationTargetException e) { throw new S3FileSystemConfigurationException("Configuration problem, couldn't instantiate " + - "AmazonS3Factory (" + amazonS3FactoryClass + "): ", + "S3Factory (" + s3FactoryClass + "): ", e); } } - return new AmazonS3ClientFactory(); + return new S3ClientFactory(); } /** @@ -847,7 +960,7 @@ boolean exists(S3Path path) S3Path s3Path = toS3Path(path); try { - s3Utils.getS3ObjectSummary(s3Path); + s3Utils.getS3Object(s3Path); return true; } diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3Iterator.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3Iterator.java index b3b6741f..60948ec7 100644 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3Iterator.java +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3Iterator.java @@ -3,13 +3,21 @@ import org.carlspring.cloud.storage.s3fs.util.S3Utils; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; -import com.amazonaws.services.s3.model.ListObjectsRequest; -import com.amazonaws.services.s3.model.ObjectListing; -import com.amazonaws.services.s3.model.S3ObjectSummary; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.CommonPrefix; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; +import software.amazon.awssdk.services.s3.model.S3Object; /** * S3 iterator over folders at first level. @@ -20,25 +28,27 @@ public class S3Iterator implements Iterator { - private S3FileSystem fileSystem; + public static final String ROOT_PATH = "/"; - private S3FileStore fileStore; + private final S3FileSystem fileSystem; - private String key; + private final S3FileStore fileStore; - private List items = Lists.newArrayList(); + private final String key; - private Set addedVirtualDirectories = Sets.newHashSet(); + private final List items = Lists.newArrayList(); - private ObjectListing current; + private final Set addedVirtualDirectories = Sets.newHashSet(); + + private ListObjectsV2Response current; private int cursor; // index of next element to return private int size; - private boolean incremental; + private final boolean incremental; - private S3Utils s3Utils = new S3Utils(); + private final S3Utils s3Utils = new S3Utils(); public S3Iterator(S3Path path) @@ -55,12 +65,12 @@ public S3Iterator(S3Path path, boolean incremental) public S3Iterator(S3FileStore fileStore, String key, boolean incremental) { - ListObjectsRequest listObjectsRequest = buildRequest(fileStore.name(), key, incremental); + final ListObjectsV2Request listObjectsV2Request = buildRequest(fileStore.name(), key, incremental); this.fileStore = fileStore; this.fileSystem = fileStore.getFileSystem(); this.key = key; - this.current = fileSystem.getClient().listObjects(listObjectsRequest); + this.current = fileSystem.getClient().listObjectsV2(listObjectsV2Request); this.incremental = incremental; loadObjects(); @@ -77,7 +87,14 @@ public S3Path next() { if (cursor == size && current.isTruncated()) { - this.current = fileSystem.getClient().listNextBatchOfObjects(current); + ListObjectsV2Request request = ListObjectsV2Request.builder() + .bucket(fileStore.name()) + .prefix(key) + .continuationToken(current.nextContinuationToken()) + .build(); + + final S3Client client = fileSystem.getClient(); + this.current = client.listObjectsV2(request); loadObjects(); } @@ -115,15 +132,15 @@ private void loadObjects() private void parseObjects() { - for (final S3ObjectSummary objectSummary : current.getObjectSummaries()) + for (final S3Object object : current.contents()) { - final String objectSummaryKey = objectSummary.getKey(); + final String objectKey = object.key(); - String[] keyParts = fileSystem.key2Parts(objectSummaryKey); + String[] keyParts = fileSystem.key2Parts(objectKey); addParentPaths(keyParts); - S3Path path = new S3Path(fileSystem, "/" + fileStore.name(), keyParts); + S3Path path = new S3Path(fileSystem, ROOT_PATH + fileStore.name(), keyParts); if (!items.contains(path)) { @@ -145,8 +162,8 @@ private void addParentPaths(String[] keyParts) while (subParts.length > 0) { - S3Path path = new S3Path(fileSystem, "/" + fileStore.name(), subParts); - String prefix = current.getPrefix(); + S3Path path = new S3Path(fileSystem, ROOT_PATH + fileStore.name(), subParts); + String prefix = current.prefix(); String parentKey = path.getKey(); if (prefix.length() > parentKey.length() && prefix.contains(parentKey)) @@ -177,32 +194,33 @@ private void addParentPaths(String[] keyParts) * * @param key the uri to parse * @param listPath List not null list to add - * @param current ObjectListing to walk + * @param current List to walk */ - private void parseObjectListing(String key, List listPath, ObjectListing current) + private void parseObjectListing(String key, List listPath, ListObjectsV2Response current) { - for (String commonPrefix : current.getCommonPrefixes()) + for (CommonPrefix commonPrefix : current.commonPrefixes()) { - if (!commonPrefix.equals("/")) + if (!commonPrefix.prefix().equals("/")) { - listPath.add(new S3Path(fileSystem, "/" + fileStore.name(), fileSystem.key2Parts(commonPrefix))); + listPath.add(new S3Path(fileSystem, "/" + fileStore.name(), + fileSystem.key2Parts(commonPrefix.prefix()))); } } // TODO: figure our a way to efficiently preprocess commonPrefix basicFileAttributes - for (final S3ObjectSummary objectSummary : current.getObjectSummaries()) + for (final S3Object object : current.contents()) { - final String objectSummaryKey = objectSummary.getKey(); + final String objectKey = object.key(); // we only want the first level - String immediateDescendantKey = getImmediateDescendant(key, objectSummaryKey); + String immediateDescendantKey = getImmediateDescendant(key, objectKey); if (immediateDescendantKey != null) { S3Path descendentPart = new S3Path(fileSystem, "/" + fileStore.name(), fileSystem.key2Parts(immediateDescendantKey)); - descendentPart.setFileAttributes(s3Utils.toS3FileAttributes(objectSummary, descendentPart.getKey())); + descendentPart.setFileAttributes(s3Utils.toS3FileAttributes(object, descendentPart.getKey())); if (!listPath.contains(descendentPart)) { listPath.add(descendentPart); @@ -253,19 +271,23 @@ private String deleteExtraPath(String keyChild) return keyChild; } - ListObjectsRequest buildRequest(String bucketName, String key, boolean incremental) + ListObjectsV2Request buildRequest(String bucketName, String key, boolean incremental) { return buildRequest(bucketName, key, incremental, null); } - ListObjectsRequest buildRequest(String bucketName, String key, boolean incremental, Integer maxKeys) + ListObjectsV2Request buildRequest(String bucketName, String key, boolean incremental, Integer maxKeys) { - if (incremental) + ListObjectsV2Request.Builder builder = ListObjectsV2Request.builder(); + builder.bucket(bucketName) + .prefix(key) + .maxKeys(maxKeys); + + if (!incremental) { - return new ListObjectsRequest(bucketName, key, null, null, maxKeys); + builder.delimiter("/"); } - - return new ListObjectsRequest(bucketName, key, key, "/", maxKeys); + return builder.build(); } } 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 5544aba6..decb32b0 100644 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3Path.java +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3Path.java @@ -7,7 +7,11 @@ import java.net.URI; import java.net.URL; import java.net.URLDecoder; -import java.nio.file.*; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; import java.util.Iterator; import java.util.List; @@ -15,6 +19,10 @@ import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import software.amazon.awssdk.core.Protocol; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Utilities; +import software.amazon.awssdk.services.s3.model.GetUrlRequest; import static com.google.common.collect.Iterables.concat; import static java.lang.String.format; @@ -23,6 +31,7 @@ public class S3Path { public static final String PATH_SEPARATOR = "/"; + public static final String PATH_OTHER_INSTANCE_MESSAGE = "other must be an instance of %s"; /** * S3FileStore which represents the Bucket this path resides in. @@ -31,7 +40,7 @@ public class S3Path /** * URI not encoded - * Is the key for AmazonS3 + * Is the key for S3Client */ private String uri; @@ -58,7 +67,6 @@ 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"); // see tests org.carlspring.cloud.storage.s3fs.Path.EndsWithTest#endsWithRelativeBlankAbsolute() - // Preconditions.checkArgument(!first.isEmpty(), "first path must be not empty"); boolean hasBucket = first.startsWith("/"); @@ -67,7 +75,7 @@ public S3Path(S3FileSystem fileSystem, String first, String... more) if (hasBucket) { // absolute path - Preconditions.checkArgument(pathsURI.size() >= 1, "path must start with bucket name"); + Preconditions.checkArgument(!pathsURI.isEmpty(), "path must start with bucket name"); Preconditions.checkArgument(!pathsURI.get(0).isEmpty(), "bucket name must be not empty"); String bucket = pathsURI.get(0); @@ -129,11 +137,21 @@ public S3FileStore getFileStore() return fileStore; } + /** + * bucket name for amazon. + * + * @return the bucketName for S3Client + */ + public String getBucketName() + { + return fileStore.name(); + } + /** * key for amazon without final slash. * note: the final slash need to be added to save a directory (Amazon s3 spec) * - * @return the key for AmazonS3Client + * @return the key for S3Client */ public String getKey() { @@ -164,7 +182,7 @@ public Path getRoot() { if (isAbsolute()) { - return new S3Path(fileSystem, PATH_SEPARATOR + fileStore.name() + PATH_SEPARATOR); + return new S3Path(fileSystem, PATH_SEPARATOR + getBucketName() + PATH_SEPARATOR); } return null; @@ -215,7 +233,7 @@ public Path getParent() return null; } - String filestore = isAbsolute() ? PATH_SEPARATOR + fileStore.name() + PATH_SEPARATOR : ""; + String filestore = isAbsolute() ? PATH_SEPARATOR + getBucketName() + PATH_SEPARATOR : ""; return new S3Path(fileSystem, filestore + newUri); } @@ -242,7 +260,7 @@ public Path getName(int index) if (isAbsolute() && index == 0) { - pathsBuilder.append(PATH_SEPARATOR + fileStore.name() + PATH_SEPARATOR); + pathsBuilder.append(PATH_SEPARATOR + getBucketName() + PATH_SEPARATOR); } pathsBuilder.append(path); @@ -285,7 +303,7 @@ public Path subpath(int beginIndex, int endIndex) // build path string if (this.isAbsolute() && beginIndex == 0) { - pathsStringBuilder.append(PATH_SEPARATOR + fileStore.name() + PATH_SEPARATOR); + pathsStringBuilder.append(PATH_SEPARATOR + getBucketName() + PATH_SEPARATOR); } for (String path : pathSubList) @@ -324,7 +342,7 @@ public boolean startsWith(Path other) S3Path path = (S3Path) other; - if (this.isAbsolute() && other.isAbsolute() && !this.fileStore.name().equals(path.fileStore.name())) + if (this.isAbsolute() && other.isAbsolute() && !getBucketName().equals(path.getBucketName())) { return false; } @@ -389,7 +407,7 @@ public boolean endsWith(Path other) int i = pathsOther.size() - 1; int j = paths.size() - 1; - for (; i >= 0 && j >= 0; ) + while (i >= 0 && j >= 0) { if (!pathsOther.get(i).equals(paths.get(j))) { @@ -421,7 +439,7 @@ public Path resolve(Path other) if (other.isAbsolute()) { Preconditions.checkArgument(other instanceof S3Path, - "other must be an instance of %s", + PATH_OTHER_INSTANCE_MESSAGE, S3Path.class.getName()); return other; @@ -432,7 +450,7 @@ public Path resolve(Path other) if (this.isAbsolute()) { - pathBuilder.append(PATH_SEPARATOR + this.fileStore.name() + PATH_SEPARATOR); + pathBuilder.append(PATH_SEPARATOR + getBucketName() + PATH_SEPARATOR); } pathBuilder.append(this.uri); @@ -454,7 +472,7 @@ public Path resolve(String other) @Override public Path resolveSibling(Path other) { - Preconditions.checkArgument(other instanceof S3Path, "other must be an instance of %s", S3Path.class.getName()); + Preconditions.checkArgument(other instanceof S3Path, PATH_OTHER_INSTANCE_MESSAGE, S3Path.class.getName()); S3Path s3Path = (S3Path) other; @@ -479,7 +497,7 @@ public Path resolveSibling(Path other) if (isAbsolute()) { - pathBuilder.append(PATH_SEPARATOR + fileStore.name() + PATH_SEPARATOR); + pathBuilder.append(PATH_SEPARATOR + getBucketName() + PATH_SEPARATOR); } for (String path : concat(paths.subList(0, paths.size() - 1), othersPaths)) { @@ -502,7 +520,7 @@ public Path resolveSibling(String other) @Override public Path relativize(Path other) { - Preconditions.checkArgument(other instanceof S3Path, "other must be an instance of %s", S3Path.class.getName()); + Preconditions.checkArgument(other instanceof S3Path, PATH_OTHER_INSTANCE_MESSAGE, S3Path.class.getName()); S3Path s3Path = (S3Path) other; if (this.equals(other)) @@ -516,7 +534,6 @@ public Path relativize(Path other) "Cannot relativize paths with different buckets: '%s', '%s'", this, other); - // Preconditions.checkArgument(parts.size() <= s3Path.parts.size(), "Cannot relativize against a parent path: '%s', '%s'", this, other); String uriPath = decode(URI.create(encode(this.uri)).relativize(URI.create(encode(s3Path.uri)))); @@ -544,18 +561,18 @@ public Path relativize(Path other) @Override public URI toUri() { - String uri = encode(this.uri); + String encodedUri = encode(this.uri); // absolute if (this.isAbsolute()) { - String builder = fileSystem.getKey() + PATH_SEPARATOR + fileStore.name() + PATH_SEPARATOR + uri; + String builder = fileSystem.getKey() + PATH_SEPARATOR + getBucketName() + PATH_SEPARATOR + encodedUri; return URI.create("s3://" + normalizeURI(builder)); } else { - return URI.create(uri); + return URI.create(encodedUri); } } @@ -569,7 +586,6 @@ public URI toUri() * All S3Path has a URL if is absolute * * @return URL or null if is not absoulte - * @see com.amazonaws.services.s3.AmazonS3#getUrl(String, String) * @see S3Path#toUri() for unique resource identifier */ public URL toURL() @@ -579,7 +595,16 @@ public URL toURL() return null; } - return this.getFileSystem().getClient().getUrl(this.fileStore.name(), this.getKey()); + final S3Client s3client = this.getFileSystem().getClient(); + //TODO: How to get s3fs_protocol property value? + final String protocol = Protocol.HTTPS.name(); + final String endpointStr = String.format("%s://%s", protocol, this.getFileSystem().getEndpoint()); + final URI endpoint = URI.create(endpointStr); + final S3Utilities utilities = s3client.utilities(); + final String bucketName = this.getBucketName(); + final String key = this.getKey(); + final GetUrlRequest request = GetUrlRequest.builder().bucket(bucketName).key(key).endpoint(endpoint).build(); + return utilities.getUrl(request); } @Override @@ -624,7 +649,7 @@ public Iterator iterator() if (isAbsolute()) { - builder.add(new S3Path(fileSystem, PATH_SEPARATOR + fileStore.name() + PATH_SEPARATOR)); + builder.add(new S3Path(fileSystem, PATH_SEPARATOR + getBucketName() + PATH_SEPARATOR)); } List paths = uriToList(); diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/S3SeekableByteChannel.java b/src/main/java/org/carlspring/cloud/storage/s3fs/S3SeekableByteChannel.java index 987db5bd..035dff9c 100644 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/S3SeekableByteChannel.java +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/S3SeekableByteChannel.java @@ -5,37 +5,48 @@ import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.SeekableByteChannel; -import java.nio.file.*; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.S3Object; import org.apache.tika.Tika; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; import static java.lang.String.format; public class S3SeekableByteChannel implements SeekableByteChannel { - private S3Path path; + private final S3Path path; - private Set options; + private final Set options; - private SeekableByteChannel seekable; + private final SeekableByteChannel seekable; - private Path tempFile; + private final Path tempFile; /** * Open or creates a file, returning a seekable byte channel * - * @param path the path open or create - * @param options options specifying how the file is opened + * @param path the path open or create + * @param options options specifying how the file is opened + * @param tempFileRequired true if a temp file wanted, false in case of a in-memory solution option. * @throws IOException if an I/O error occurs */ - public S3SeekableByteChannel(S3Path path, Set options) + public S3SeekableByteChannel(final S3Path path, + final Set options, + final boolean tempFileRequired) throws IOException { this.path = path; @@ -55,36 +66,48 @@ else if (!exists && !this.options.contains(StandardOpenOption.CREATE_NEW) && !th throw new NoSuchFileException(format("target not exists: %s", path)); } - tempFile = Files.createTempFile("temp-s3-", key.replaceAll("/", "_")); + final Set seekOptions = new HashSet<>(this.options); + seekOptions.remove(StandardOpenOption.CREATE_NEW); - boolean removeTempFile = true; - - try + if(tempFileRequired) { - if (exists) + tempFile = Files.createTempFile("temp-s3-", key.replaceAll("/", "_")); + + boolean removeTempFile = true; + + try { - try (S3Object object = path.getFileSystem().getClient().getObject(path.getFileStore() - .getBucket() - .getName(), - key)) + if (exists) { - Files.copy(object.getObjectContent(), tempFile, StandardCopyOption.REPLACE_EXISTING); - } - } + final S3Client client = path.getFileSystem().getClient(); + final String bucketName = path.getFileStore().getBucket().name(); + final GetObjectRequest request = GetObjectRequest.builder() + .bucket(bucketName) + .key(key) + .build(); + + try (InputStream byteStream = client.getObject(request)) + { + Files.copy(byteStream, tempFile, StandardCopyOption.REPLACE_EXISTING); + } - Set seekOptions = new HashSet<>(this.options); - seekOptions.remove(StandardOpenOption.CREATE_NEW); + } - seekable = Files.newByteChannel(tempFile, seekOptions); + seekable = Files.newByteChannel(tempFile, seekOptions); - removeTempFile = false; - } - finally - { - if (removeTempFile) + removeTempFile = false; + } + finally { - Files.deleteIfExists(tempFile); + if (removeTempFile) + { + Files.deleteIfExists(tempFile); + } } + }else + { + this.tempFile = null; + this.seekable = Files.newByteChannel(path, seekOptions); } } @@ -119,11 +142,17 @@ public void close() return; } - sync(); + if(this.tempFile != null) + { + sync(); + } } finally { - Files.deleteIfExists(tempFile); + if(tempFile != null) + { + Files.deleteIfExists(tempFile); + } } } @@ -137,18 +166,22 @@ protected void sync() { try (InputStream stream = new BufferedInputStream(Files.newInputStream(tempFile))) { - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(Files.size(tempFile)); + //TODO: If the temp file is larger than 5 GB then, instead of a putObject, a multi-part upload is needed. + PutObjectRequest.Builder builder = PutObjectRequest.builder(); + long length = Files.size(tempFile); + builder.contentLength(length); if (path.getFileName() != null) { - metadata.setContentType(new Tika().detect(stream, path.getFileName().toString())); + builder.contentType(new Tika().detect(stream, path.getFileName().toString())); } - String bucket = path.getFileStore().name(); - String key = path.getKey(); + builder.bucket(path.getFileStore().name()); + builder.key(path.getKey()); + + S3Client client = path.getFileSystem().getClient(); - path.getFileSystem().getClient().putObject(bucket, key, stream, metadata); + client.putObject(builder.build(), RequestBody.fromInputStream(stream, length)); } } diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/attribute/S3BasicFileAttributes.java b/src/main/java/org/carlspring/cloud/storage/s3fs/attribute/S3BasicFileAttributes.java index 84a48cbb..1403d01d 100644 --- a/src/main/java/org/carlspring/cloud/storage/s3fs/attribute/S3BasicFileAttributes.java +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/attribute/S3BasicFileAttributes.java @@ -22,11 +22,11 @@ public class S3BasicFileAttributes private long cacheCreated; - public S3BasicFileAttributes(String key, - FileTime lastModifiedTime, - long size, - boolean isDirectory, - boolean isRegularFile) + public S3BasicFileAttributes(final String key, + final FileTime lastModifiedTime, + final long size, + final boolean isDirectory, + final boolean isRegularFile) { this.key = key; this.lastModifiedTime = lastModifiedTime; diff --git a/src/main/java/org/carlspring/cloud/storage/s3fs/util/Constants.java b/src/main/java/org/carlspring/cloud/storage/s3fs/util/Constants.java new file mode 100644 index 00000000..c2c2213f --- /dev/null +++ b/src/main/java/org/carlspring/cloud/storage/s3fs/util/Constants.java @@ -0,0 +1,12 @@ +package org.carlspring.cloud.storage.s3fs.util; + +public final class Constants +{ + + private Constants() + { + throw new IllegalStateException("Utility class"); + } + + public static final String S3_HOSTNAME = "s3.amazonaws.com"; +} 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 2e76983e..6791541a 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 @@ -11,11 +11,24 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.TimeUnit; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.*; import com.google.common.collect.Sets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.GetObjectAclRequest; +import software.amazon.awssdk.services.s3.model.GetObjectAclResponse; +import software.amazon.awssdk.services.s3.model.Grant; +import software.amazon.awssdk.services.s3.model.HeadObjectRequest; +import software.amazon.awssdk.services.s3.model.HeadObjectResponse; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; +import software.amazon.awssdk.services.s3.model.Owner; +import software.amazon.awssdk.services.s3.model.Permission; +import software.amazon.awssdk.services.s3.model.S3Exception; +import software.amazon.awssdk.services.s3.model.S3Object; +import static software.amazon.awssdk.http.HttpStatusCode.NOT_FOUND; /** * Utilities to work with Amazon S3 Objects. @@ -23,45 +36,60 @@ public class S3Utils { + private static final Logger LOGGER = LoggerFactory.getLogger(S3Utils.class); + /** - * Get the {@link S3ObjectSummary} that represent this Path or her first child if this path not exists + * Get the {@link S3Object} that represent this Path or her first child if this path not exists * * @param s3Path {@link S3Path} - * @return {@link S3ObjectSummary} + * @return {@link S3Object} * @throws NoSuchFileException if not found the path and any child */ - public S3ObjectSummary getS3ObjectSummary(S3Path s3Path) + public S3Object getS3Object(S3Path s3Path) throws NoSuchFileException { - String key = s3Path.getKey(); - String bucketName = s3Path.getFileStore().name(); + final String key = s3Path.getKey(); + final String bucketName = s3Path.getFileStore().name(); - AmazonS3 client = s3Path.getFileSystem().getClient(); + final S3Client client = s3Path.getFileSystem().getClient(); // try to find the element with the current key (maybe with end slash or maybe not.) try { - ObjectMetadata metadata = client.getObjectMetadata(bucketName, key); - - AccessControlList objectAcl = client.getObjectAcl(bucketName, key); - - S3ObjectSummary result = new S3ObjectSummary(); - result.setBucketName(bucketName); - result.setETag(metadata.getETag()); - result.setKey(key); - result.setLastModified(metadata.getLastModified()); - result.setSize(metadata.getContentLength()); - result.setOwner(objectAcl.getOwner()); - - return result; + final HeadObjectRequest headObjectRequest = HeadObjectRequest.builder() + .bucket(bucketName) + .key(key) + .build(); + final HeadObjectResponse metadata = client.headObject(headObjectRequest); + + final GetObjectAclRequest getObjectAclRequest = GetObjectAclRequest.builder() + .bucket(bucketName) + .key(key) + .build(); + final GetObjectAclResponse acl = client.getObjectAcl(getObjectAclRequest); + + final S3Object.Builder builder = S3Object.builder(); + + builder.key(key) + .lastModified(metadata.lastModified()) + .eTag(metadata.eTag()) + .owner(acl.owner()) + .size(metadata.contentLength()) + .storageClass(metadata.storageClassAsString()); + + return builder.build(); } - catch (AmazonS3Exception e) + catch (final S3Exception e) { - if (e.getStatusCode() != 404) + if (e.statusCode() != NOT_FOUND) { throw e; } } + catch (final SdkClientException e) + { + LOGGER.warn("Object could not be retrieved as a file with the given key"); + } // if not found (404 err) with the original key. // try to find the element as a directory. @@ -74,15 +102,16 @@ public S3ObjectSummary getS3ObjectSummary(S3Path s3Path) keyFolder += "/"; } - ListObjectsRequest request = new ListObjectsRequest(); - request.setBucketName(bucketName); - request.setPrefix(keyFolder); - request.setMaxKeys(1); + final ListObjectsV2Request request = ListObjectsV2Request.builder() + .bucket(bucketName) + .prefix(keyFolder) + .maxKeys(1) + .build(); - ObjectListing current = client.listObjects(request); - if (!current.getObjectSummaries().isEmpty()) + final ListObjectsV2Response current = client.listObjectsV2(request); + if (!current.contents().isEmpty()) { - return current.getObjectSummaries().get(0); + return current.contents().get(0); } } catch (Exception e) @@ -102,9 +131,9 @@ public S3ObjectSummary getS3ObjectSummary(S3Path s3Path) public S3BasicFileAttributes getS3FileAttributes(S3Path s3Path) throws NoSuchFileException { - S3ObjectSummary objectSummary = getS3ObjectSummary(s3Path); + S3Object object = getS3Object(s3Path); - return toS3FileAttributes(objectSummary, s3Path.getKey()); + return toS3FileAttributes(object, s3Path.getKey()); } /** @@ -117,23 +146,23 @@ public S3BasicFileAttributes getS3FileAttributes(S3Path s3Path) public S3PosixFileAttributes getS3PosixFileAttributes(S3Path s3Path) throws NoSuchFileException { - S3ObjectSummary objectSummary = getS3ObjectSummary(s3Path); + S3Object object = getS3Object(s3Path); String key = s3Path.getKey(); String bucketName = s3Path.getFileStore().name(); - S3BasicFileAttributes attrs = toS3FileAttributes(objectSummary, key); + S3BasicFileAttributes attrs = toS3FileAttributes(object, key); S3UserPrincipal userPrincipal = null; Set permissions = null; if (!attrs.isDirectory()) { - AmazonS3 client = s3Path.getFileSystem().getClient(); - AccessControlList acl = client.getObjectAcl(bucketName, key); - Owner owner = acl.getOwner(); + S3Client client = s3Path.getFileSystem().getClient(); + GetObjectAclResponse acl = client.getObjectAcl(GetObjectAclRequest.builder().bucket(bucketName).key(key).build()); + Owner owner = acl.owner(); - userPrincipal = new S3UserPrincipal(owner.getId() + ":" + owner.getDisplayName()); - permissions = toPosixFilePermissions(acl.getGrantsAsList()); + userPrincipal = new S3UserPrincipal(owner.id() + ":" + owner.displayName()); + permissions = toPosixFilePermissions(acl.grants()); } return new S3PosixFileAttributes((String) attrs.fileKey(), @@ -147,7 +176,7 @@ public S3PosixFileAttributes getS3PosixFileAttributes(S3Path s3Path) } /** - * transform com.amazonaws.services.s3.model.Grant to java.nio.file.attribute.PosixFilePermission + * transform software.amazon.awssdk.services.s3.model.Grant to java.nio.file.attribute.PosixFilePermission * * @param grants Set grants mandatory, must be not null * @return Set PosixFilePermission never null @@ -158,14 +187,14 @@ public Set toPosixFilePermissions(List grants) Set filePermissions = new HashSet<>(); for (Grant grant : grants) { - filePermissions.addAll(toPosixFilePermission(grant.getPermission())); + filePermissions.addAll(toPosixFilePermission(grant.permission())); } return filePermissions; } /** - * transform a com.amazonaws.services.s3.model.Permission to a java.nio.file.attribute.PosixFilePermission + * transform a software.amazon.awssdk.services.s3.model.Permission to a java.nio.file.attribute.PosixFilePermission * We use the follow rules: * - transform only to the Owner permission, S3 doesnt have concepts like owner, group or other so we map only to owner. * - ACP is a special permission: WriteAcp are mapped to Owner execute permission and ReadAcp are mapped to owner read @@ -177,47 +206,46 @@ public Set toPosixFilePermission(Permission permission) { switch (permission) { - case FullControl: + case FULL_CONTROL: return Sets.newHashSet(PosixFilePermission.OWNER_EXECUTE, PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE); - case Write: + case WRITE: return Sets.newHashSet(PosixFilePermission.OWNER_WRITE); - case Read: - return Sets.newHashSet(PosixFilePermission.OWNER_READ); - case ReadAcp: + case READ: + case READ_ACP: return Sets.newHashSet(PosixFilePermission.OWNER_READ); - case WriteAcp: + case WRITE_ACP: return Sets.newHashSet(PosixFilePermission.OWNER_EXECUTE); + default: + throw new IllegalStateException("Unknown Permission: " + permission); } - throw new IllegalStateException("Unknown Permission: " + permission); } /** - * transform S3ObjectSummary to S3FileAttributes + * transform S3Object to S3FileAttributes * - * @param objectSummary S3ObjectSummary mandatory not null, the real objectSummary with - * exactly the same key than the key param or the immediate descendant - * if it is a virtual directory - * @param key String the real key that can be exactly equal than the objectSummary or + * @param object S3Object mandatory not null, the real object with exactly the same key than the key param + * or the immediate descendant if it is a virtual directory + * @param key String the real key that can be exactly equal than the object * @return S3FileAttributes */ - public S3BasicFileAttributes toS3FileAttributes(S3ObjectSummary objectSummary, String key) + public S3BasicFileAttributes toS3FileAttributes(S3Object object, String key) { // parse the data to BasicFileAttributes. FileTime lastModifiedTime = null; - if (objectSummary.getLastModified() != null) + if (object.lastModified() != null) { - lastModifiedTime = FileTime.from(objectSummary.getLastModified().getTime(), TimeUnit.MILLISECONDS); + lastModifiedTime = FileTime.from(object.lastModified()); } - long size = objectSummary.getSize(); + long size = object.size() != null ? object.size() : 0; boolean directory = false; boolean regularFile = false; - String resolvedKey = objectSummary.getKey(); + String resolvedKey = object.key(); // check if is a directory and exists the key of this directory at amazon s3 if (key.endsWith("/") && resolvedKey.equals(key) || resolvedKey.equals(key + "/")) diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/AmazonS3ClientFactoryTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/AmazonS3ClientFactoryTest.java deleted file mode 100644 index 75faf004..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/AmazonS3ClientFactoryTest.java +++ /dev/null @@ -1,234 +0,0 @@ -package org.carlspring.cloud.storage.s3fs; - -import org.carlspring.cloud.storage.s3fs.util.ExposingAmazonS3Client; -import org.carlspring.cloud.storage.s3fs.util.ExposingAmazonS3ClientFactory; -import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; - -import java.net.URI; -import java.util.Properties; - -import com.amazonaws.ClientConfiguration; -import com.amazonaws.Protocol; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSCredentialsProvider; -import org.junit.jupiter.api.Test; -import static com.amazonaws.SDKGlobalConfiguration.ACCESS_KEY_SYSTEM_PROPERTY; -import static com.amazonaws.SDKGlobalConfiguration.SECRET_KEY_SYSTEM_PROPERTY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.*; -import static org.junit.jupiter.api.Assertions.*; - -public class AmazonS3ClientFactoryTest -{ - - - @Test - public void neverTrustTheDefaults() - { - AmazonS3ClientFactory clientFactory = new ExposingAmazonS3ClientFactory(); - - Properties props = new Properties(); - props.setProperty(ACCESS_KEY, "some_access_key"); - props.setProperty(SECRET_KEY, "super_secret_key"); - props.setProperty(REQUEST_METRIC_COLLECTOR_CLASS, - "org.carlspring.cloud.storage.s3fs.util.NoOpRequestMetricCollector"); - props.setProperty(CONNECTION_TIMEOUT, "10"); - props.setProperty(MAX_CONNECTIONS, "50"); - props.setProperty(MAX_ERROR_RETRY, "3"); - props.setProperty(PROTOCOL, "HTTP"); - props.setProperty(PROXY_DOMAIN, "localhost"); - props.setProperty(PROXY_HOST, "127.0.0.1"); - props.setProperty(PROXY_PASSWORD, "proxy_password"); - props.setProperty(PROXY_PORT, "12345"); - props.setProperty(PROXY_USERNAME, "proxy_username"); - props.setProperty(PROXY_WORKSTATION, "what.does.this.do.localhost"); - props.setProperty(SOCKET_SEND_BUFFER_SIZE_HINT, "48000"); - props.setProperty(SOCKET_RECEIVE_BUFFER_SIZE_HINT, "49000"); - props.setProperty(SOCKET_TIMEOUT, "30"); - props.setProperty(USER_AGENT, "I-am-Groot"); - props.setProperty(SIGNER_OVERRIDE, "S3SignerType"); - props.setProperty(PATH_STYLE_ACCESS, "true"); - - ExposingAmazonS3Client client = - (ExposingAmazonS3Client) clientFactory.getAmazonS3(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); - - AWSCredentialsProvider credentialsProvider = client.getAWSCredentialsProvider(); - AWSCredentials credentials = credentialsProvider.getCredentials(); - - assertEquals("some_access_key", credentials.getAWSAccessKeyId()); - assertEquals("super_secret_key", credentials.getAWSSecretKey()); - assertEquals("class org.carlspring.cloud.storage.s3fs.util.NoOpRequestMetricCollector", - client.getRequestMetricsCollector().getClass().toString()); - - ClientConfiguration clientConfiguration = client.getClientConfiguration(); - - assertEquals(10, clientConfiguration.getConnectionTimeout()); - assertEquals(50, clientConfiguration.getMaxConnections()); - assertEquals(3, clientConfiguration.getMaxErrorRetry()); - assertEquals(Protocol.HTTP, clientConfiguration.getProtocol()); - assertEquals("localhost", clientConfiguration.getProxyDomain()); - assertEquals("127.0.0.1", clientConfiguration.getProxyHost()); - assertEquals("proxy_password", clientConfiguration.getProxyPassword()); - assertEquals(12345, clientConfiguration.getProxyPort()); - assertEquals("proxy_username", clientConfiguration.getProxyUsername()); - assertEquals("what.does.this.do.localhost", clientConfiguration.getProxyWorkstation()); - assertEquals(48000, clientConfiguration.getSocketBufferSizeHints()[0]); - assertEquals(49000, clientConfiguration.getSocketBufferSizeHints()[1]); - assertEquals(30, clientConfiguration.getSocketTimeout()); - assertEquals("I-am-Groot", clientConfiguration.getUserAgent()); - assertEquals("S3SignerType", clientConfiguration.getSignerOverride()); - assertTrue(client.getClientOptions().isPathStyleAccess()); - } - - @Test - public void theDefaults() - { - AmazonS3ClientFactory clientFactory = new ExposingAmazonS3ClientFactory(); - - System.setProperty(ACCESS_KEY_SYSTEM_PROPERTY, "giev.ma.access!"); - System.setProperty(SECRET_KEY_SYSTEM_PROPERTY, "I'll never teeeeeellllll!"); - - Properties props = new Properties(); - - ExposingAmazonS3Client client = - (ExposingAmazonS3Client) clientFactory.getAmazonS3(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); - - AWSCredentialsProvider credentialsProvider = client.getAWSCredentialsProvider(); - AWSCredentials credentials = credentialsProvider.getCredentials(); - - assertEquals("giev.ma.access!", credentials.getAWSAccessKeyId()); - assertEquals("I'll never teeeeeellllll!", credentials.getAWSSecretKey()); - assertNull(client.getRequestMetricsCollector()); - - ClientConfiguration clientConfiguration = client.getClientConfiguration(); - - assertEquals(ClientConfiguration.DEFAULT_CONNECTION_TIMEOUT, clientConfiguration.getConnectionTimeout()); - assertEquals(ClientConfiguration.DEFAULT_MAX_CONNECTIONS, clientConfiguration.getMaxConnections()); - assertEquals(-1, clientConfiguration.getMaxErrorRetry()); - assertEquals(Protocol.HTTPS, clientConfiguration.getProtocol()); - assertNull(clientConfiguration.getProxyDomain()); - assertNull(clientConfiguration.getProxyHost()); - assertNull(clientConfiguration.getProxyPassword()); - assertEquals(-1, clientConfiguration.getProxyPort()); - assertNull(clientConfiguration.getProxyUsername()); - assertNull(clientConfiguration.getProxyWorkstation()); - assertEquals(0, clientConfiguration.getSocketBufferSizeHints()[0]); - assertEquals(0, clientConfiguration.getSocketBufferSizeHints()[1]); - assertEquals(50000, clientConfiguration.getSocketTimeout()); - assertTrue(clientConfiguration.getUserAgent().startsWith("aws-sdk-java")); - assertNull(clientConfiguration.getSignerOverride()); - assertFalse(client.getClientOptions().isPathStyleAccess()); - } - - @Test - public void halfTheCredentials() - { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - AmazonS3ClientFactory clientFactory = new ExposingAmazonS3ClientFactory(); - - System.setProperty(SECRET_KEY_SYSTEM_PROPERTY, "I'll never teeeeeellllll!"); - - Properties props = new Properties(); - props.setProperty(ACCESS_KEY, "I want access"); - - clientFactory.getAmazonS3(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); - }); - - assertNotNull(exception); - } - - @Test - public void theOtherHalf() - { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - AmazonS3ClientFactory clientFactory = new ExposingAmazonS3ClientFactory(); - - System.setProperty(ACCESS_KEY_SYSTEM_PROPERTY, "I want access"); - - Properties props = new Properties(); - props.setProperty(SECRET_KEY, "I'll never teeeeeellllll!"); - - clientFactory.getAmazonS3(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); - }); - - assertNotNull(exception); - } - - @Test - public void wrongMetricsCollector() - { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - AmazonS3ClientFactory clientFactory = new ExposingAmazonS3ClientFactory(); - - Properties props = new Properties(); - props.setProperty(ACCESS_KEY, "I want access"); - props.setProperty(SECRET_KEY, "I'll never teeeeeellllll!"); - props.setProperty(REQUEST_METRIC_COLLECTOR_CLASS, "org.carlspring.cloud.storage.s3fs.util.WrongRequestMetricCollector"); - - clientFactory.getAmazonS3(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); - }); - - assertNotNull(exception); - } - - @Test - public void defaultSendBufferHint() - { - AmazonS3ClientFactory clientFactory = new ExposingAmazonS3ClientFactory(); - - System.setProperty(ACCESS_KEY_SYSTEM_PROPERTY, "giev.ma.access!"); - System.setProperty(SECRET_KEY_SYSTEM_PROPERTY, "I'll never teeeeeellllll!"); - - Properties props = new Properties(); - props.setProperty(SOCKET_SEND_BUFFER_SIZE_HINT, "12345"); - - ExposingAmazonS3Client client = - (ExposingAmazonS3Client) clientFactory.getAmazonS3(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); - - ClientConfiguration clientConfiguration = client.getClientConfiguration(); - - assertEquals(12345, clientConfiguration.getSocketBufferSizeHints()[0]); - assertEquals(0, clientConfiguration.getSocketBufferSizeHints()[1]); - } - - @Test - public void defaultReceiveBufferHint() - { - AmazonS3ClientFactory clientFactory = new ExposingAmazonS3ClientFactory(); - - System.setProperty(ACCESS_KEY_SYSTEM_PROPERTY, "giev.ma.access!"); - System.setProperty(SECRET_KEY_SYSTEM_PROPERTY, "I'll never teeeeeellllll!"); - - Properties props = new Properties(); - props.setProperty(SOCKET_RECEIVE_BUFFER_SIZE_HINT, "54321"); - - ExposingAmazonS3Client client = - (ExposingAmazonS3Client) clientFactory.getAmazonS3(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); - - ClientConfiguration clientConfiguration = client.getClientConfiguration(); - - assertEquals(0, clientConfiguration.getSocketBufferSizeHints()[0]); - assertEquals(54321, clientConfiguration.getSocketBufferSizeHints()[1]); - } - - @Test - public void overrideHostAndPort() - { - AmazonS3ClientFactory clientFactory = new ExposingAmazonS3ClientFactory(); - - System.setProperty(ACCESS_KEY_SYSTEM_PROPERTY, "test"); - System.setProperty(SECRET_KEY_SYSTEM_PROPERTY, "test"); - - ExposingAmazonS3Client client = (ExposingAmazonS3Client) clientFactory.getAmazonS3(URI.create( - "s3://localhost:8001/"), new Properties()); - - URI endpoint = client.getEndpoint(); - - assertEquals("https", endpoint.getScheme()); - assertEquals("localhost", endpoint.getHost()); - assertEquals(8001, endpoint.getPort()); - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/AmazonS3ClientIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/AmazonS3ClientIT.java deleted file mode 100644 index ffbc6c22..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/AmazonS3ClientIT.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.carlspring.cloud.storage.s3fs; - -import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.Map; - -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.PutObjectResult; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import static java.util.UUID.randomUUID; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; -import static org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder.getRealEnv; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -public class AmazonS3ClientIT -{ - - AmazonS3 client; - - - @BeforeEach - public void setup() - { - // s3client - final Map credentials = getRealEnv(); - - BasicAWSCredentials credentialsS3 = new BasicAWSCredentials(credentials.get(ACCESS_KEY).toString(), - credentials.get(SECRET_KEY).toString()); - - client = new com.amazonaws.services.s3.AmazonS3Client(credentialsS3); - } - - @Test - public void putObject() - throws IOException - { - Path file = Files.createTempFile("file-se", "file"); - - Files.write(file, "content".getBytes(), StandardOpenOption.APPEND); - - PutObjectResult result = client.putObject(getBucket(), randomUUID().toString(), file.toFile()); - - assertNotNull(result); - } - - @Test - public void putObjectWithEndSlash() - throws IOException - { - Path file = Files.createTempFile("file-se", "file"); - - Files.write(file, "content".getBytes(), StandardOpenOption.APPEND); - - PutObjectResult result = client.putObject(getBucket(), randomUUID().toString() + "/", file.toFile()); - - assertNotNull(result); - } - - @Test - public void putObjectWithStartSlash() - throws IOException - { - Path file = Files.createTempFile("file-se", "file"); - - Files.write(file, "content".getBytes(), StandardOpenOption.APPEND); - - client.putObject(getBucket(), "/" + randomUUID().toString(), file.toFile()); - } - - @Test - public void putObjectWithBothSlash() - throws IOException - { - Path file = Files.createTempFile("file-se", "file"); - - Files.write(file, "content".getBytes(), StandardOpenOption.APPEND); - - PutObjectResult result = client.putObject(getBucket(), "/" + randomUUID().toString() + "/", file.toFile()); - - assertNotNull(result); - } - - @Test - public void putObjectByteArray() - { - PutObjectResult result = client.putObject(getBucket(), - randomUUID().toString(), - new ByteArrayInputStream("content1".getBytes()), - new ObjectMetadata()); - - assertNotNull(result); - } - - private String getBucket() - { - return EnvironmentBuilder.getBucket().replace("/", ""); - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/ExampleClass.java b/src/test/java/org/carlspring/cloud/storage/s3fs/ExampleClass.java index 60a7a78f..678954ea 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/ExampleClass.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/ExampleClass.java @@ -2,33 +2,36 @@ import java.util.Map; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.*; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.REGION; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; import static org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder.getRealEnv; // TODO: Write a fully-working example class with a simple integration test for it. public class ExampleClass { - private AmazonS3 client; + private S3Client client; public ExampleClass() { final Map env = getRealEnv(); - BasicAWSCredentials credentialsS3 = new BasicAWSCredentials(env.get(ACCESS_KEY).toString(), - env.get(SECRET_KEY).toString()); + final AwsCredentials credentialsS3 = AwsBasicCredentials.create(env.get(ACCESS_KEY).toString(), + env.get(SECRET_KEY).toString()); - AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentialsS3); + final AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(credentialsS3); - client = AmazonS3ClientBuilder.standard() - .withCredentials(credentialsProvider) - .withRegion(env.get(REGION).toString()) - .build(); + client = S3Client.builder() + .credentialsProvider(credentialsProvider) + .region(Region.of(env.get(REGION).toString())) + .build(); } public void upload() diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/CheckAccessTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/CheckAccessTest.java deleted file mode 100644 index befd0423..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/CheckAccessTest.java +++ /dev/null @@ -1,174 +0,0 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; - -import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; -import org.carlspring.cloud.storage.s3fs.S3Path; -import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; -import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; - -import java.io.IOException; -import java.nio.file.*; - -import com.amazonaws.services.s3.model.AccessControlList; -import com.amazonaws.services.s3.model.Owner; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.doReturn; - -public class CheckAccessTest - extends S3UnitTestBase -{ - - - @BeforeEach - public void setup() - throws IOException - { - s3fsProvider = getS3fsProvider(); - fileSystem = s3fsProvider.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, null); - } - - @AfterEach - public void tearDown() - throws IOException - { -//! super.tearDown(); - - s3fsProvider.close((S3FileSystem) fileSystem); - fileSystem.close(); - } - - // check access - @Test - public void checkAccessRead() - throws IOException - { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir").file("dir/file"); - - FileSystem fs = createNewS3FileSystem(); - Path file1 = fs.getPath("/bucketA/dir/file"); - - s3fsProvider.checkAccess(file1, AccessMode.READ); - } - - @Test - public void checkAccessReadWithoutPermission() - throws IOException - { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir"); - - FileSystem fs = createNewS3FileSystem(); - Path file1 = fs.getPath("/bucketA/dir"); - - // We're expecting an exception here to be thrown - Exception exception = assertThrows(AccessDeniedException.class, () -> { - s3fsProvider.checkAccess(file1, AccessMode.READ); - }); - - // TODO: Assert that the exception message is as expected - assertNotNull(exception); - } - - @Test - public void checkAccessWrite() - throws IOException - { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir").file("dir/file"); - - S3FileSystem fs = createNewS3FileSystem(); - S3Path file1 = fs.getPath("/bucketA/dir/file"); - - s3fsProvider.checkAccess(file1, AccessMode.WRITE); - } - - @Test - public void checkAccessWriteDifferentUser() - { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(AccessDeniedException.class, () -> { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir").file("dir/readOnly"); - - // return empty list - doReturn(client.createReadOnly(new Owner("2", "Read Only"))).when(client).getObjectAcl("bucketA", - "dir/readOnly"); - - S3FileSystem fs = createNewS3FileSystem(); - S3Path file1 = fs.getPath("/bucketA/dir/readOnly"); - - s3fsProvider.checkAccess(file1, AccessMode.WRITE); - }); - - assertNotNull(exception); - } - - @Test - public void checkAccessWriteWithoutPermission() - { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(AccessDeniedException.class, () -> { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir"); - - // return empty list - doReturn(new AccessControlList()).when(client).getObjectAcl("bucketA", "dir/"); - - Path file1 = createNewS3FileSystem().getPath("/bucketA/dir"); - - s3fsProvider.checkAccess(file1, AccessMode.WRITE); - }); - - assertNotNull(exception); - } - - @Test - public void checkAccessExecute() - { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(AccessDeniedException.class, () -> { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir").file("dir/file"); - - Path file1 = createNewS3FileSystem().getPath("/bucketA/dir/file"); - - s3fsProvider.checkAccess(file1, AccessMode.EXECUTE); - }); - - assertNotNull(exception); - } - - /** - * create a new file system for s3 scheme with fake credentials - * and global endpoint - * - * @return FileSystem - * @throws IOException - */ - private S3FileSystem createNewS3FileSystem() - throws IOException - { - try - { - return s3fsProvider.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); - } - catch (FileSystemNotFoundException e) - { - return (S3FileSystem) FileSystems.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, null); - } - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsIT.java index 559e06b2..9074c90b 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsIT.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemsIT.java @@ -14,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertSame; -public class FileSystemsIT +class FileSystemsIT { private static final URI uriEurope = URI.create("s3://s3-eu-west-1.amazonaws.com/"); @@ -28,7 +28,7 @@ public class FileSystemsIT public void setup() throws IOException { - System.clearProperty(S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS); + System.clearProperty(S3FileSystemProvider.S3_FACTORY_CLASS); fileSystemAmazon = build(); } @@ -55,7 +55,7 @@ private static FileSystem createNewFileSystem() } @Test - public void buildEnv() + void buildEnv() { FileSystem fileSystem = FileSystems.getFileSystem(uriGlobal); @@ -63,10 +63,10 @@ public void buildEnv() } @Test - public void buildEnvAnotherURIReturnDifferent() + void buildEnvAnotherURIReturnDifferent() throws IOException { - FileSystem fileSystem = FileSystems.newFileSystem(uriEurope, null); + FileSystem fileSystem = FileSystems.newFileSystem(uriEurope, EnvironmentBuilder.getRealEnv()); assertNotSame(fileSystemAmazon, fileSystem); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FilesIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/FilesIT.java index 30e7ee9f..00f29034 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FilesIT.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/FilesIT.java @@ -8,20 +8,36 @@ import java.io.OutputStream; import java.net.URI; import java.nio.channels.SeekableByteChannel; -import java.nio.file.*; +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.attribute.BasicFileAttributes; import java.util.EnumSet; import java.util.Map; import java.util.UUID; -import com.amazonaws.services.s3.model.ObjectMetadata; import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.HeadObjectRequest; +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.*; +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; -public class FilesIT +class FilesIT { private static final String bucket = EnvironmentBuilder.getBucket(); @@ -35,7 +51,7 @@ public class FilesIT public void setup() throws IOException { - System.clearProperty(S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS); + System.clearProperty(S3FileSystemProvider.S3_FACTORY_CLASS); fileSystemAmazon = build(); } @@ -62,7 +78,7 @@ private static FileSystem createNewFileSystem() } @Test - public void notExistsDir() + void notExistsDir() { Path dir = fileSystemAmazon.getPath(bucket, UUID.randomUUID().toString() + "/"); @@ -70,7 +86,7 @@ public void notExistsDir() } @Test - public void notExistsFile() + void notExistsFile() { Path file = fileSystemAmazon.getPath(bucket, UUID.randomUUID().toString()); @@ -78,7 +94,7 @@ public void notExistsFile() } @Test - public void existsFile() + void existsFile() throws IOException { Path file = fileSystemAmazon.getPath(bucket, UUID.randomUUID().toString()); @@ -91,7 +107,7 @@ public void existsFile() } @Test - public void existsFileWithSpace() + void existsFileWithSpace() throws IOException { Path file = fileSystemAmazon.getPath(bucket, UUID.randomUUID().toString(), "space folder"); @@ -105,7 +121,7 @@ public void existsFileWithSpace() } @Test - public void createEmptyDirTest() + void createEmptyDirTest() throws IOException { Path dir = createEmptyDir(); @@ -115,7 +131,7 @@ public void createEmptyDirTest() } @Test - public void createEmptyFileTest() + void createEmptyFileTest() throws IOException { Path file = createEmptyFile(); @@ -125,7 +141,7 @@ public void createEmptyFileTest() } @Test - public void createTempFile() + void createTempFile() throws IOException { Path dir = createEmptyDir(); @@ -136,7 +152,7 @@ public void createTempFile() } @Test - public void createTempFileAndWrite() + void createTempFileAndWrite() throws IOException { Path dir = createEmptyDir(); @@ -152,7 +168,7 @@ public void createTempFileAndWrite() } @Test - public void createTempDir() + void createTempDir() throws IOException { Path dir = createEmptyDir(); @@ -163,27 +179,29 @@ public void createTempDir() } @Test - public void deleteFile() + void deleteFile() throws IOException { Path file = createEmptyFile(); Files.delete(file); - Files.notExists(file); + + assertTrue(Files.notExists(file)); } @Test - public void deleteDir() + void deleteDir() throws IOException { Path dir = createEmptyDir(); Files.delete(dir); - Files.notExists(dir); + + assertTrue(Files.notExists(dir)); } @Test - public void copyDir() + void copyDir() throws IOException { Path dir = uploadDir(); @@ -195,7 +213,7 @@ public void copyDir() } @Test - public void directoryStreamBaseBucketFindDirectoryTest() + void directoryStreamBaseBucketFindDirectoryTest() throws IOException { Path bucketPath = fileSystemAmazon.getPath(bucket); @@ -210,7 +228,7 @@ public void directoryStreamBaseBucketFindDirectoryTest() } @Test - public void directoryStreamBaseBucketFindFileTest() + void directoryStreamBaseBucketFindFileTest() throws IOException { Path bucketPath = fileSystemAmazon.getPath(bucket); @@ -225,7 +243,7 @@ public void directoryStreamBaseBucketFindFileTest() } @Test - public void directoryStreamFirstDirTest() + void directoryStreamFirstDirTest() throws IOException { Path dir = uploadDir(); @@ -248,7 +266,7 @@ public void directoryStreamFirstDirTest() } @Test - public void virtualDirectoryStreamTest() + void virtualDirectoryStreamTest() throws IOException { String folder = UUID.randomUUID().toString() + "/"; @@ -259,24 +277,19 @@ public void virtualDirectoryStreamTest() Path dir = fileSystemAmazon.getPath(bucket, folder); S3Path s3Path = (S3Path) dir; + final S3Client client = s3Path.getFileSystem().getClient(); // upload file without paths - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(0); + final ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[0]); + final RequestBody requestBody = RequestBody.fromInputStream(inputStream, inputStream.available()); + String bucketName = s3Path.getFileStore().name(); + PutObjectRequest request = PutObjectRequest.builder().bucket(bucketName).key(file1).build(); + client.putObject(request, requestBody); - s3Path.getFileSystem().getClient().putObject(s3Path.getFileStore().name(), - file1, - new ByteArrayInputStream(new byte[0]), - metadata); // another file without paths - ObjectMetadata metadata2 = new ObjectMetadata(); - metadata.setContentLength(0); - - s3Path.getFileSystem().getClient().putObject(s3Path.getFileStore().name(), - file2, - new ByteArrayInputStream(new byte[0]), - metadata2); + request = PutObjectRequest.builder().bucket(bucketName).key(file2).build(); + client.putObject(request, requestBody); try (DirectoryStream dirStream = Files.newDirectoryStream(dir)) { @@ -313,7 +326,7 @@ public void virtualDirectoryStreamTest() } @Test - public void virtualDirectoryStreamWithVirtualSubFolderTest() + void virtualDirectoryStreamWithVirtualSubFolderTest() throws IOException { String folder = UUID.randomUUID().toString() + "/"; @@ -324,23 +337,18 @@ public void virtualDirectoryStreamWithVirtualSubFolderTest() Path dir = fileSystemAmazon.getPath(bucket, folder); S3Path s3Path = (S3Path) dir; + final S3Client client = s3Path.getFileSystem().getClient(); // upload without paths - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(0); + final ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[0]); + final RequestBody requestBody = RequestBody.fromInputStream(inputStream, inputStream.available()); + String bucketName = s3Path.getFileStore().name(); + PutObjectRequest request = PutObjectRequest.builder().bucket(bucketName).key(subFolder).build(); + client.putObject(request, requestBody); - s3Path.getFileSystem().getClient().putObject(s3Path.getFileStore().name(), - subFolder, - new ByteArrayInputStream(new byte[0]), - metadata); // upload another file without paths - ObjectMetadata metadata2 = new ObjectMetadata(); - metadata.setContentLength(0); - - s3Path.getFileSystem().getClient().putObject(s3Path.getFileStore().name(), - file2, - new ByteArrayInputStream(new byte[0]), - metadata2); + request = PutObjectRequest.builder().bucket(bucketName).key(file2).build(); + client.putObject(request, requestBody); try (DirectoryStream dirStream = Files.newDirectoryStream(dir)) { @@ -377,7 +385,7 @@ public void virtualDirectoryStreamWithVirtualSubFolderTest() } @Test - public void deleteFullDirTest() + void deleteFullDirTest() throws IOException { Path dir = uploadDir(); @@ -410,7 +418,7 @@ public FileVisitResult postVisitDirectory(Path directory, IOException exc) } @Test - public void copyUpload() + void copyUpload() throws IOException { final String content = "sample content"; @@ -422,7 +430,7 @@ public void copyUpload() } @Test - public void copyDownload() + void copyDownload() throws IOException { Path result = uploadSingleFile(null); @@ -436,7 +444,7 @@ public void copyDownload() } @Test - public void moveFromDifferentProviders() + void moveFromDifferentProviders() throws IOException { final String content = "sample content"; @@ -456,7 +464,7 @@ public void moveFromDifferentProviders() } @Test - public void move() + void move() throws IOException { final String content = "sample content"; @@ -473,52 +481,54 @@ public void move() } @Test - public void createFileWithFolderAndNotExistsFolders() + void createFileWithFolderAndNotExistsFolders() { String fileWithFolders = UUID.randomUUID().toString() + "/folder2/file.html"; Path path = fileSystemAmazon.getPath(bucket, fileWithFolders.split("/")); S3Path s3Path = (S3Path) path; + final S3Client client = s3Path.getFileSystem().getClient(); - // upload file without paths - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(0); - - s3Path.getFileSystem().getClient().putObject(s3Path.getFileStore().name(), - fileWithFolders, - new ByteArrayInputStream(new byte[0]), - metadata); + // upload without paths + final ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[0]); + final RequestBody requestBody = RequestBody.fromInputStream(inputStream, inputStream.available()); + String bucketName = s3Path.getFileStore().name(); + PutObjectRequest request = PutObjectRequest.builder().bucket(bucketName).key(fileWithFolders).build(); + client.putObject(request, requestBody); assertTrue(Files.exists(path)); assertTrue(Files.exists(path.getParent())); } @Test - public void amazonCopyDetectContentType() + void amazonCopyDetectContentType() throws IOException { - try (FileSystem linux = MemoryFileSystemBuilder.newLinux().build("linux")) + try (final FileSystem linux = MemoryFileSystemBuilder.newLinux().build("linux")) { - Path htmlFile = Files.write(linux.getPath("/index.html"), "html file".getBytes()); + final Path htmlFile = Files.write(linux.getPath("/index.html"), + "html file".getBytes()); - Path result = fileSystemAmazon.getPath(bucket, - UUID.randomUUID().toString() + htmlFile.getFileName().toString()); + final String fileName = UUID.randomUUID().toString() + htmlFile.getFileName().toString(); + final Path result = fileSystemAmazon.getPath(bucket, fileName); Files.copy(htmlFile, result); - S3Path resultS3 = (S3Path) result; - ObjectMetadata metadata = resultS3.getFileSystem() - .getClient() - .getObjectMetadata(resultS3.getFileStore().name(), - resultS3.getKey()); + final S3Path resultS3 = (S3Path) result; + final String bucketName = resultS3.getFileStore().name(); + final String key = resultS3.getKey(); + final HeadObjectRequest request = HeadObjectRequest.builder().bucket(bucketName).key(key).build(); + final HeadObjectResponse response = resultS3.getFileSystem() + .getClient() + .headObject(request); - assertEquals("text/html", metadata.getContentType()); + assertEquals("text/html", response.contentType()); } } @Test - public void amazonCopyNotDetectContentTypeSetDefault() + void amazonCopyNotDetectContentTypeSetDefault() throws IOException { final byte[] data = new byte[]{ (byte) 0xe0, @@ -538,47 +548,49 @@ public void amazonCopyNotDetectContentTypeSetDefault() 0x30, (byte) 0x9d }; - try (FileSystem linux = MemoryFileSystemBuilder.newLinux().build("linux")) + try (final FileSystem linux = MemoryFileSystemBuilder.newLinux().build("linux")) { - Path htmlFile = Files.write(linux.getPath("/index.adsadas"), data); + final Path htmlFile = Files.write(linux.getPath("/index.adsadas"), data); - Path result = fileSystemAmazon.getPath(bucket, - UUID.randomUUID().toString() + htmlFile.getFileName().toString()); + final String fileName = UUID.randomUUID().toString() + htmlFile.getFileName().toString(); + final Path result = fileSystemAmazon.getPath(bucket, fileName); Files.copy(htmlFile, result); - S3Path resultS3 = (S3Path) result; - - ObjectMetadata metadata = resultS3.getFileSystem() - .getClient() - .getObjectMetadata(resultS3.getFileStore().name(), resultS3.getKey()); + final S3Path resultS3 = (S3Path) result; + final String bucketName = resultS3.getFileStore().name(); + final String key = resultS3.getKey(); + final HeadObjectRequest request = HeadObjectRequest.builder().bucket(bucketName).key(key).build(); + final HeadObjectResponse response = resultS3.getFileSystem() + .getClient() + .headObject(request); - assertEquals("application/octet-stream", metadata.getContentType()); + assertEquals("application/octet-stream", response.contentType()); } } @Test - public void amazonOutpuStreamDetectContentType() + void amazonOutpuStreamDetectContentType() throws IOException { - try (FileSystem linux = MemoryFileSystemBuilder.newLinux().build("linux")) + try (final FileSystem linux = MemoryFileSystemBuilder.newLinux().build("linux")) { - Path htmlFile = Files.write(linux.getPath("/index.html"), "html file".getBytes()); + final Path htmlFile = Files.write(linux.getPath("/index.html"), "html file".getBytes()); - Path result = fileSystemAmazon.getPath(bucket, - UUID.randomUUID().toString() + htmlFile.getFileName().toString()); + final String fileName = UUID.randomUUID().toString() + htmlFile.getFileName().toString(); + final Path result = fileSystemAmazon.getPath(bucket, fileName); - try (OutputStream out = Files.newOutputStream(result)) + try (final OutputStream out = Files.newOutputStream(result)) { // copied from Files.write - byte[] bytes = Files.readAllBytes(htmlFile); + final byte[] bytes = Files.readAllBytes(htmlFile); - int len = bytes.length; + final int len = bytes.length; int rem = len; while (rem > 0) { - int n = Math.min(rem, 8192); + final int n = Math.min(rem, 8192); out.write(bytes, (len - rem), n); @@ -586,18 +598,20 @@ public void amazonOutpuStreamDetectContentType() } } - S3Path resultS3 = (S3Path) result; - ObjectMetadata metadata = resultS3.getFileSystem() - .getClient() - .getObjectMetadata(resultS3.getFileStore().name(), - resultS3.getKey()); + final S3Path resultS3 = (S3Path) result; + final String bucketName = resultS3.getFileStore().name(); + final String key = resultS3.getKey(); + final HeadObjectRequest request = HeadObjectRequest.builder().bucket(bucketName).key(key).build(); + final HeadObjectResponse response = resultS3.getFileSystem() + .getClient() + .headObject(request); - assertEquals("text/html", metadata.getContentType()); + assertEquals("text/html", response.contentType()); } } @Test - public void readAttributesFile() + void readAttributesFile() throws IOException { final String content = "sample content"; @@ -615,7 +629,7 @@ public void readAttributesFile() } @Test - public void readAttributesString() + void readAttributesString() throws IOException { final String content = "sample content"; @@ -636,7 +650,7 @@ public void readAttributesString() } @Test - public void readAttributesDirectory() + void readAttributesDirectory() throws IOException { Path dir; @@ -659,8 +673,6 @@ public void readAttributesDirectory() Files.walkFileTree(assets.getParent(), new CopyDirVisitor(assets.getParent().getParent(), dir)); } - //dir = fileSystemAmazon.getPath("/upp-sources", "DES", "skeleton"); - BasicFileAttributes fileAttributes = Files.readAttributes(dir.resolve("lib").resolve("angular"), BasicFileAttributes.class); assertNotNull(fileAttributes); @@ -669,7 +681,7 @@ public void readAttributesDirectory() } @Test - public void seekableCloseTwice() + void seekableCloseTwice() throws IOException { Path file = createEmptyFile(); @@ -682,22 +694,22 @@ public void seekableCloseTwice() } @Test - public void bucketIsDirectory() + void bucketIsDirectory() throws IOException { - Path path = fileSystemAmazon.getPath(bucket); + Path path = fileSystemAmazon.getPath(bucket, "/"); BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); assertEquals(0, attrs.size()); - assertNull(attrs.creationTime()); - assertNull(attrs.lastAccessTime()); - assertNull(attrs.lastModifiedTime()); + assertNotNull(attrs.creationTime()); + assertNotNull(attrs.lastAccessTime()); + assertNotNull(attrs.lastModifiedTime()); assertTrue(attrs.isDirectory()); } @Test - public void fileIsReadableBucket() + void fileIsReadableBucket() { Path path = fileSystemAmazon.getPath(bucket, "/"); @@ -707,7 +719,7 @@ public void fileIsReadableBucket() } @Test - public void fileIsReadableBucketFile() + void fileIsReadableBucketFile() throws IOException { Path file = createEmptyFile(); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/ToURLIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/Path/ToURLIT.java deleted file mode 100644 index 110eb69f..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/ToURLIT.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.carlspring.cloud.storage.s3fs.Path; - -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; -import org.carlspring.cloud.storage.s3fs.S3Path; -import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder; - -import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.nio.file.FileSystem; -import java.nio.file.FileSystemAlreadyExistsException; -import java.nio.file.FileSystems; -import java.util.HashMap; -import java.util.Map; - -import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.PATH_STYLE_ACCESS; -import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_IT; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -public class ToURLIT -{ - - private static final URI uriGlobal = EnvironmentBuilder.getS3URI(S3_GLOBAL_URI_IT); - - public FileSystem getS3FileSystem(Entry... props) - throws IOException - { - System.clearProperty(S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS); - - Map env = new HashMap<>(EnvironmentBuilder.getRealEnv()); - if (props != null) - { - for (Entry entry : props) - { - env.put(entry.getKey(), entry.getValue()); - } - } - - try - { - return FileSystems.newFileSystem(uriGlobal, env); - } - catch (FileSystemAlreadyExistsException e) - { - FileSystems.getFileSystem(uriGlobal).close(); - - return FileSystems.newFileSystem(uriGlobal, env); - } - } - - @Test - public void toURLDefault() - throws IOException - { - FileSystem fs = getS3FileSystem(); - - S3Path s3Path = (S3Path) fs.getPath("/bucket.with.dots").resolve("index.html"); - - assertEquals(new URL("https://bucket.with.dots." + S3_GLOBAL_URI_IT.toString().replace("s3://", "") + - "index.html"), - s3Path.toURL()); - } - - @Test - public void toURLWithPathStyle() - throws IOException - { - FileSystem fs = getS3FileSystem(new Entry(PATH_STYLE_ACCESS, "true")); - - S3Path s3Path = (S3Path) fs.getPath("/bucket.with.dots").resolve("index.html"); - - assertEquals(new URL("https://" + S3_GLOBAL_URI_IT.toString().replace("s3://", "") + - "bucket.with.dots/index.html"), - s3Path.toURL()); - } - - @Test - public void toURLNull() - throws IOException - { - FileSystem fs = getS3FileSystem(new Entry(PATH_STYLE_ACCESS, "true")); - - S3Path s3Path = (S3Path) fs.getPath("directory").resolve("index.html"); - - assertNull(s3Path.toURL()); - } - - public static class Entry - { - - private String key; - - private String value; - - - public Entry(String key, String value) - { - this.key = key; - this.value = value; - } - - public String getKey() - { - return key; - } - - public void setKey(String key) - { - this.key = key; - } - - public String getValue() - { - return value; - } - - public void setValue(String value) - { - this.value = value; - } - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientFactoryTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientFactoryTest.java new file mode 100644 index 00000000..8cf6a00b --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientFactoryTest.java @@ -0,0 +1,221 @@ +package org.carlspring.cloud.storage.s3fs; + +import org.carlspring.cloud.storage.s3fs.util.ExposingS3Client; +import org.carlspring.cloud.storage.s3fs.util.ExposingS3ClientFactory; +import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; + +import java.net.URI; +import java.util.Properties; + +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.core.Protocol; +import software.amazon.awssdk.core.SdkSystemSetting; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.http.apache.ProxyConfiguration; +import software.amazon.awssdk.services.s3.S3Configuration; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.CONNECTION_TIMEOUT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.MAX_CONNECTIONS; +import static org.carlspring.cloud.storage.s3fs.S3Factory.MAX_ERROR_RETRY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PATH_STYLE_ACCESS; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROTOCOL; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_DOMAIN; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_HOST; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_PASSWORD; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_PORT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_USERNAME; +import static org.carlspring.cloud.storage.s3fs.S3Factory.PROXY_WORKSTATION; +import static org.carlspring.cloud.storage.s3fs.S3Factory.REGION; +import static org.carlspring.cloud.storage.s3fs.S3Factory.REQUEST_METRIC_COLLECTOR_CLASS; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SIGNER_OVERRIDE; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SOCKET_RECEIVE_BUFFER_SIZE_HINT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SOCKET_SEND_BUFFER_SIZE_HINT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SOCKET_TIMEOUT; +import static org.carlspring.cloud.storage.s3fs.S3Factory.USER_AGENT; +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.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.SIGNER; +import static software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.USER_AGENT_PREFIX; +import static software.amazon.awssdk.core.client.config.SdkClientOption.ENDPOINT; + +class S3ClientFactoryTest +{ + @Test + void neverTrustTheDefaults() + { + S3ClientFactory clientFactory = new ExposingS3ClientFactory(); + + Properties props = new Properties(); + props.setProperty(ACCESS_KEY, "some_access_key"); + props.setProperty(SECRET_KEY, "super_secret_key"); + props.setProperty(REQUEST_METRIC_COLLECTOR_CLASS, + "org.carlspring.cloud.storage.s3fs.util.NoOpRequestMetricCollector"); + props.setProperty(CONNECTION_TIMEOUT, "10"); + props.setProperty(MAX_CONNECTIONS, "50"); + props.setProperty(MAX_ERROR_RETRY, "3"); + props.setProperty(PROTOCOL, "http"); + props.setProperty(PROXY_DOMAIN, "localhost"); + props.setProperty(PROXY_HOST, "127.0.0.1"); + props.setProperty(PROXY_PASSWORD, "proxy_password"); + props.setProperty(PROXY_PORT, "12345"); + props.setProperty(PROXY_USERNAME, "proxy_username"); + props.setProperty(PROXY_WORKSTATION, "what.does.this.do.localhost"); + props.setProperty(SOCKET_SEND_BUFFER_SIZE_HINT, "48000"); + props.setProperty(SOCKET_RECEIVE_BUFFER_SIZE_HINT, "49000"); + props.setProperty(SOCKET_TIMEOUT, "30"); + props.setProperty(USER_AGENT, "I-am-Groot"); + props.setProperty(SIGNER_OVERRIDE, "software.amazon.awssdk.core.signer.NoOpSigner"); + props.setProperty(PATH_STYLE_ACCESS, "true"); + props.setProperty(REGION, "eu-central-1"); + + ExposingS3Client client = + (ExposingS3Client) clientFactory.getS3Client(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); + + final AwsCredentialsProvider credentialsProvider = clientFactory.getCredentialsProvider(props); + final AwsCredentials credentials = credentialsProvider.resolveCredentials(); + + assertEquals("some_access_key", credentials.accessKeyId()); + assertEquals("super_secret_key", credentials.secretAccessKey()); + + ClientOverrideConfiguration overrideConfiguration = clientFactory.getOverrideConfiguration(props); + + assertTrue(overrideConfiguration.retryPolicy().isPresent()); + assertEquals(3, overrideConfiguration.retryPolicy().get().numRetries()); + assertEquals("I-am-Groot", overrideConfiguration.toBuilder().advancedOptions().get(USER_AGENT_PREFIX)); + assertEquals("class software.amazon.awssdk.core.signer.NoOpSigner", + overrideConfiguration.toBuilder().advancedOptions().get(SIGNER).getClass().toString()); + + final SdkClientConfiguration clientConfiguration = client.getClientConfiguration(); + final URI endpoint = clientConfiguration.option(ENDPOINT); + assertEquals("http", endpoint.getScheme()); + + ProxyConfiguration proxyConfiguration = clientFactory.getProxyConfiguration(props); + + assertEquals("127.0.0.1", proxyConfiguration.host()); + assertEquals(12345, proxyConfiguration.port()); + assertEquals("proxy_username", proxyConfiguration.username()); + assertEquals("proxy_password", proxyConfiguration.password()); + assertEquals("localhost", proxyConfiguration.ntlmDomain()); + assertEquals("what.does.this.do.localhost", proxyConfiguration.ntlmWorkstation()); + + S3Configuration serviceConfiguration = clientFactory.getServiceConfiguration(props); + assertTrue(serviceConfiguration.pathStyleAccessEnabled()); + } + + @Test + void theDefaults() + { + S3ClientFactory clientFactory = new ExposingS3ClientFactory(); + + System.setProperty(SdkSystemSetting.AWS_ACCESS_KEY_ID.property(), "giev.ma.access!"); + System.setProperty(SdkSystemSetting.AWS_SECRET_ACCESS_KEY.property(), "I'll never teeeeeellllll!"); + + Properties props = new Properties(); + props.setProperty(REGION, "eu-central-1"); + props.setProperty(PROTOCOL, Protocol.HTTPS.toString()); + + ExposingS3Client client = + (ExposingS3Client) clientFactory.getS3Client(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); + + final AwsCredentialsProvider credentialsProvider = clientFactory.getCredentialsProvider(props); + final AwsCredentials credentials = credentialsProvider.resolveCredentials(); + + assertEquals("giev.ma.access!", credentials.accessKeyId()); + assertEquals("I'll never teeeeeellllll!", credentials.secretAccessKey()); + + ClientOverrideConfiguration overrideConfiguration = clientFactory.getOverrideConfiguration(props); + + assertFalse(overrideConfiguration.retryPolicy().isPresent()); + assertNull(overrideConfiguration.toBuilder().advancedOptions().get(USER_AGENT_PREFIX)); + assertNull(overrideConfiguration.toBuilder().advancedOptions().get(SIGNER)); + + final SdkClientConfiguration clientConfiguration = client.getClientConfiguration(); + final URI endpoint = clientConfiguration.option(ENDPOINT); + assertEquals("https", endpoint.getScheme()); + + ProxyConfiguration proxyConfiguration = clientFactory.getProxyConfiguration(props); + + assertNull(proxyConfiguration.host()); + assertEquals(0, proxyConfiguration.port()); + assertNull(proxyConfiguration.username()); + assertNull(proxyConfiguration.password()); + assertNull(proxyConfiguration.ntlmDomain()); + assertNull(proxyConfiguration.ntlmWorkstation()); + + S3Configuration serviceConfiguration = clientFactory.getServiceConfiguration(props); + assertFalse(serviceConfiguration.pathStyleAccessEnabled()); + } + + @Test + void halfTheCredentials() + { + S3ClientFactory clientFactory = new ExposingS3ClientFactory(); + + System.setProperty(SdkSystemSetting.AWS_SECRET_ACCESS_KEY.property(), "I'll never teeeeeellllll!"); + + Properties props = new Properties(); + props.setProperty(ACCESS_KEY, "I want access"); + props.setProperty(REGION, "eu-central-1"); + + // We're expecting an exception here to be thrown + Exception exception = assertThrows(NullPointerException.class, + () -> clientFactory.getS3Client(S3EndpointConstant.S3_GLOBAL_URI_TEST, + props)); + + assertNotNull(exception); + } + + @Test + void theOtherHalf() + { + S3ClientFactory clientFactory = new ExposingS3ClientFactory(); + + System.setProperty(SdkSystemSetting.AWS_ACCESS_KEY_ID.property(), "I want access"); + + Properties props = new Properties(); + props.setProperty(SECRET_KEY, "I'll never teeeeeellllll!"); + props.setProperty(REGION, "eu-central-1"); + + // We're expecting an exception here to be thrown + Exception exception = assertThrows(NullPointerException.class, + () -> clientFactory.getS3Client(S3EndpointConstant.S3_GLOBAL_URI_TEST, + props)); + + assertNotNull(exception); + } + + @Test + void overrideHostAndPort() + { + S3ClientFactory clientFactory = new ExposingS3ClientFactory(); + + System.setProperty(SdkSystemSetting.AWS_ACCESS_KEY_ID.property(), "test"); + System.setProperty(SdkSystemSetting.AWS_SECRET_ACCESS_KEY.property(), "test"); + + URI uri = URI.create("s3://localhost:8001/"); + Properties props = new Properties(); + final String regionName = "eu-central-1"; + props.setProperty(REGION, regionName); + final String protocol = "https"; + props.setProperty(PROTOCOL, protocol); + ExposingS3Client client = (ExposingS3Client) clientFactory.getS3Client(uri, props); + + assertNotNull(client); + + final SdkClientConfiguration sdkClientConfiguration = client.getClientConfiguration(); + final URI endpoint = sdkClientConfiguration.option(ENDPOINT); + + assertEquals("https", endpoint.getScheme()); + assertEquals("localhost", endpoint.getHost()); + assertEquals(8001, endpoint.getPort()); + } + +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientIT.java new file mode 100644 index 00000000..413a0e4f --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3ClientIT.java @@ -0,0 +1,126 @@ +package org.carlspring.cloud.storage.s3fs; + +import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectResponse; +import static java.util.UUID.randomUUID; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.REGION; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder.getRealEnv; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class S3ClientIT +{ + + S3Client client; + + + @BeforeEach + public void setup() + { + // s3client + final Map credentials = getRealEnv(); + + final AwsCredentials credentialsS3 = AwsBasicCredentials.create(credentials.get(ACCESS_KEY).toString(), + credentials.get(SECRET_KEY).toString()); + final AwsCredentialsProvider credentialsProviderS3 = StaticCredentialsProvider.create(credentialsS3); + + final String regionStr = credentials.get(REGION).toString(); + final Region region = Region.of(regionStr); + client = S3Client.builder().region(region).credentialsProvider(credentialsProviderS3).build(); + } + + @Test + void putObject() + throws IOException + { + Path file = Files.createTempFile("file-se", "file"); + + Files.write(file, "content".getBytes(), StandardOpenOption.APPEND); + + PutObjectRequest request = PutObjectRequest.builder().bucket(getBucket()).key(randomUUID().toString()).build(); + PutObjectResponse result = client.putObject(request, file); + + assertNotNull(result); + } + + @Test + void putObjectWithEndSlash() + throws IOException + { + Path file = Files.createTempFile("file-se", "file"); + + Files.write(file, "content".getBytes(), StandardOpenOption.APPEND); + + PutObjectRequest request = PutObjectRequest.builder().bucket(getBucket()).key( + randomUUID().toString() + "/").build(); + PutObjectResponse result = client.putObject(request, file); + + assertNotNull(result); + } + + @Test + void putObjectWithStartSlash() + throws IOException + { + Path file = Files.createTempFile("file-se", "file"); + + Files.write(file, "content".getBytes(), StandardOpenOption.APPEND); + + PutObjectRequest request = PutObjectRequest.builder().bucket(getBucket()).key("/" + randomUUID().toString()).build(); + PutObjectResponse result = client.putObject(request, file); + + assertNotNull(result); + } + + @Test + void putObjectWithBothSlash() + throws IOException + { + Path file = Files.createTempFile("file-se", "file"); + + Files.write(file, "content".getBytes(), StandardOpenOption.APPEND); + + PutObjectRequest request = PutObjectRequest.builder().bucket(getBucket()).key("/" + randomUUID().toString() + "/").build(); + PutObjectResponse result = client.putObject(request, file); + + assertNotNull(result); + } + + @Test + void putObjectByteArray() + throws IOException + { + final InputStream inputStream = new ByteArrayInputStream("contents1".getBytes()); + final RequestBody requestBody = RequestBody.fromInputStream(inputStream, inputStream.available()); + PutObjectRequest request = PutObjectRequest.builder().bucket(getBucket()).key(randomUUID().toString()).build(); + PutObjectResponse result = client.putObject(request, requestBody); + + assertNotNull(result); + } + + private String getBucket() + { + return EnvironmentBuilder.getBucket().replace("/", ""); + } + +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileChannelTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileChannelTest.java index f1e040d5..f87995da 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileChannelTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileChannelTest.java @@ -1,34 +1,43 @@ package org.carlspring.cloud.storage.s3fs; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.channels.NonReadableChannelException; import java.nio.channels.NonWritableChannelException; -import java.nio.file.*; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.NoSuchFileException; +import java.nio.file.StandardOpenOption; import java.util.EnumSet; -import com.amazonaws.services.s3.model.ObjectMetadata; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; - -public class S3FileChannelTest +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +class S3FileChannelTest extends S3UnitTestBase { - private final AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + private final S3ClientMock client = S3MockFactory.getS3ClientMock(); @BeforeEach @@ -48,13 +57,14 @@ public void tearDown() } @Test - public void constructorRead() + void constructorRead() throws IOException { client.bucket("buck").file("file1"); - S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); - S3FileChannel channel = new S3FileChannel(file1, EnumSet.of(StandardOpenOption.READ)); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file1 = (S3Path) fileSystem.getPath("/buck/file1"); + final S3FileChannel channel = new S3FileChannel(file1, EnumSet.of(StandardOpenOption.READ), true); assertNotNull(channel); @@ -63,32 +73,37 @@ public void constructorRead() } @Test - public void constructorReadButTryToWrite() + void constructorReadButTryToWrite() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(NonWritableChannelException.class, () -> { - client.bucket("buck").file("file1"); + client.bucket("buck").file("file1"); - S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); - S3FileChannel channel = new S3FileChannel(file1, EnumSet.of(StandardOpenOption.READ)); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file1 = (S3Path) fileSystem.getPath( + "/buck/file1"); + final S3FileChannel channel = new S3FileChannel(file1, EnumSet.of(StandardOpenOption.READ), true); - assertNotNull(channel); + assertNotNull(channel); + + final ByteBuffer wrap = ByteBuffer.wrap("hoi".getBytes()); - channel.write(ByteBuffer.wrap("hoi".getBytes())); - channel.close(); - }); + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(NonWritableChannelException.class, () -> channel.write(wrap)); assertNotNull(exception); } @Test - public void constructorWrite() + void constructorWrite() throws IOException { client.bucket("buck").file("file1"); - S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); - S3FileChannel channel = new S3FileChannel(file1, EnumSet.of(StandardOpenOption.WRITE)); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file1 = (S3Path) fileSystem.getPath("/buck/file1"); + final S3FileChannel channel = new S3FileChannel(file1, + EnumSet.of(StandardOpenOption.WRITE), + true); assertNotNull(channel); @@ -97,107 +112,114 @@ public void constructorWrite() } @Test - public void constructorWriteButTryToRead() + void constructorWriteButTryToRead() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(NonReadableChannelException.class, () -> { - client.bucket("buck").file("file1"); + client.bucket("buck").file("file1"); - S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); - S3FileChannel channel = new S3FileChannel(file1, EnumSet.of(StandardOpenOption.WRITE)); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file1 = (S3Path) fileSystem.getPath("/buck/file1"); + final S3FileChannel channel = new S3FileChannel(file1, EnumSet.of(StandardOpenOption.WRITE), true); - assertNotNull(channel); + assertNotNull(channel); + + final ByteBuffer byteBuffer = ByteBuffer.allocate(10); - channel.read(ByteBuffer.allocate(10)); - channel.close(); - }); + // We're expecting an exception here to be thrown + Exception exception = assertThrows(NonReadableChannelException.class, () -> channel.read(byteBuffer)); assertNotNull(exception); } - @Test - public void readNeedsToCloseChannel() + @ParameterizedTest + @ValueSource(booleans = { true, + false }) + void readNeedsToCloseChannel(final boolean tempFileRequired) throws IOException { client.bucket("buck").file("file1"); - S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); - S3FileChannel channel = spy(new S3FileChannel(file1, EnumSet.of(StandardOpenOption.READ))); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file1 = (S3Path) fileSystem.getPath("/buck/file1"); + final S3FileChannel channel = spy(new S3FileChannel(file1, + EnumSet.of(StandardOpenOption.READ), + tempFileRequired)); assertNotNull(channel); channel.close(); verify(channel, times(1)).implCloseChannel(); - verify(client, never()).putObject(anyString(), anyString(), any(InputStream.class), any(ObjectMetadata.class)); + verify(client, never()).putObject(isA(PutObjectRequest.class), isA(RequestBody.class)); } - @Test - public void writeNeedsToCloseChannel() + @ParameterizedTest + @ValueSource(booleans = { true, + false }) + void writeNeedsToCloseChannel(final boolean tempFileRequired) throws IOException { client.bucket("buck").file("file1"); - S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file1 = (S3Path) fileSystem.getPath("/buck/file1"); - S3FileChannel channel = spy(new S3FileChannel(file1, EnumSet.of(StandardOpenOption.WRITE))); + final S3FileChannel channel = spy( + new S3FileChannel(file1, EnumSet.of(StandardOpenOption.WRITE), tempFileRequired)); channel.write(ByteBuffer.wrap("hoi".getBytes())); channel.close(); verify(channel, times(1)).implCloseChannel(); - verify(client, times(1)).putObject(eq("buck"), eq("file1"), any(InputStream.class), any(ObjectMetadata.class)); + verify(client, times(1)).putObject(isA(PutObjectRequest.class), isA(RequestBody.class)); } @Test - public void alreadyExists() + void alreadyExists() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(FileAlreadyExistsException.class, () -> { - client.bucket("buck").file("file1"); + client.bucket("buck").file("file1"); - S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file1 = (S3Path) fileSystem.getPath("/buck/file1"); + final EnumSet options = EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW); - new S3FileChannel(file1, EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)); - }); + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(FileAlreadyExistsException.class, + () -> new S3FileChannel(file1, options, true)); assertNotNull(exception); } @Test - public void brokenNetwork() + void brokenNetwork() { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(RuntimeException.class, () -> { - doThrow(new RuntimeException("network broken")).when(client).getObject("buck", "file2"); + final GetObjectRequest request = GetObjectRequest.builder().bucket("buck").key("file2").build(); + doThrow(new RuntimeException("network broken")).when(client).getObject(request); - S3Path file2 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file2"); - S3FileChannel channel = new S3FileChannel(file2, EnumSet.of(StandardOpenOption.READ)); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file2 = (S3Path) fileSystem.getPath("/buck/file2"); - channel.close(); - }); + final EnumSet readOption = EnumSet.of(StandardOpenOption.READ); + + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(RuntimeException.class, + () -> new S3FileChannel(file2, readOption, true)); assertNotNull(exception); } @Test - public void tempFileDisappeared() - throws SecurityException, - IllegalArgumentException + void shouldNotCreateChannelWithWriteWhenTargetDoesNotExist() + throws SecurityException, IllegalArgumentException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(NoSuchFileException.class, () -> { - S3Path file2 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file2"); - S3FileChannel channel = new S3FileChannel(file2, EnumSet.of(StandardOpenOption.WRITE)); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file2 = (S3Path) fileSystem.getPath("/buck/file2"); + final EnumSet writeOption = EnumSet.of(StandardOpenOption.WRITE); - Field f = channel.getClass().getDeclaredField("tempFile"); - f.setAccessible(true); - - Path tempFile = (Path) f.get(channel); - Files.delete(tempFile); - - channel.close(); - }); + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(NoSuchFileException.class, + () -> new S3FileChannel(file2, writeOption, true)); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileStoreTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileStoreTest.java index c1640fe0..fc14f9a7 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileStoreTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileStoreTest.java @@ -1,9 +1,9 @@ package org.carlspring.cloud.storage.s3fs; import org.carlspring.cloud.storage.s3fs.S3FileStoreAttributeView.AttrID; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import org.carlspring.cloud.storage.s3fs.util.UnsupportedFileStoreAttributeView; import java.io.IOException; @@ -14,16 +14,22 @@ import java.nio.file.Path; import java.util.Map; -import com.amazonaws.services.s3.model.Owner; import com.github.marschall.com.sun.nio.zipfs.ZipFileAttributeView; import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; -import static org.junit.jupiter.api.Assertions.*; - -public class S3FileStoreTest +import software.amazon.awssdk.services.s3.model.Owner; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class S3FileStoreTest extends S3UnitTestBase { @@ -41,7 +47,7 @@ public void prepareFileStore() fileSystem = FileSystems.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, env); - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucket").file("placeholder"); client.bucket("bucket2").file("placeholder"); @@ -51,25 +57,25 @@ public void prepareFileStore() } @Test - public void bucketConstructor() + void bucketConstructor() { S3FileStore s3FileStore = new S3FileStore((S3FileSystem) fileSystem, "name"); assertEquals("name", s3FileStore.name()); - assertEquals("Mock", s3FileStore.getOwner().getDisplayName()); + assertEquals("Mock", s3FileStore.getOwner().displayName()); } @Test - public void nameConstructorAlreadyExists() + void nameConstructorAlreadyExists() { S3FileStore s3FileStore = new S3FileStore((S3FileSystem) fileSystem, "bucket2"); assertEquals("bucket2", s3FileStore.name()); - assertEquals("Mock", s3FileStore.getOwner().getDisplayName()); + assertEquals("Mock", s3FileStore.getOwner().displayName()); } @Test - public void getFileStoreAttributeView() + void getFileStoreAttributeView() { S3FileStoreAttributeView fileStoreAttributeView = fileStore.getFileStoreAttributeView(S3FileStoreAttributeView.class); @@ -82,18 +88,17 @@ public void getFileStoreAttributeView() } @Test - public void getUnsupportedFileStoreAttributeView() + void getUnsupportedFileStoreAttributeView() { - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - fileStore.getFileStoreAttributeView(UnsupportedFileStoreAttributeView.class); - }); + final Class attributeViewClass = UnsupportedFileStoreAttributeView.class; + final Exception exception = assertThrows(IllegalArgumentException.class, + () -> fileStore.getFileStoreAttributeView(attributeViewClass)); assertNotNull(exception); } @Test - public void getAttributes() - throws IOException + void getAttributes() { assertEquals("bucket", fileStore.getAttribute(AttrID.name.name())); assertNotNull(fileStore.getAttribute(AttrID.creationDate.name())); @@ -102,16 +107,16 @@ public void getAttributes() } @Test - public void getOwner() + void getOwner() { Owner owner = fileStore.getOwner(); - assertEquals("Mock", owner.getDisplayName()); - assertEquals("1", owner.getId()); + assertEquals("Mock", owner.displayName()); + assertEquals("1", owner.id()); } @Test - public void getRootDirectory() + void getRootDirectory() { S3Path rootDirectory = fileStore.getRootDirectory(); @@ -122,7 +127,7 @@ public void getRootDirectory() } @Test - public void getSpaces() + void getSpaces() throws IOException { Path root = fileSystem.getPath("/newbucket"); @@ -140,7 +145,7 @@ public void getSpaces() } @Test - public void comparable() + void comparable() throws IOException { S3FileStore store = ((S3Path) fileSystem.getPath("/bucket")).getFileStore(); @@ -167,16 +172,16 @@ public void comparable() assertEquals(0, noFs1.compareTo(noFsSameAs1)); assertEquals(0, s3FileStore.compareTo(noFsSameAs1)); - assertFalse(store.equals(other)); - assertFalse(store.equals(differentHost)); - assertTrue(store.equals(shouldBeTheSame)); - assertFalse(store.equals(shouldBeTheSame.getOwner())); - assertFalse(store.equals(noFs1)); - assertFalse(noFs1.equals(store)); - assertFalse(noFs1.equals(noFs2)); - assertTrue(noFs1.equals(noFsSameAs1)); - assertFalse(noFsNoName1.equals(noFs1)); - assertTrue(noFsNoName1.equals(noFsNoName2)); + assertNotEquals(other, store); + assertNotEquals(differentHost, store); + assertEquals(shouldBeTheSame, store); + assertNotEquals(shouldBeTheSame.getOwner(), store); + assertNotEquals(noFs1, store); + assertNotEquals(store, noFs1); + assertNotEquals(noFs2, noFs1); + assertEquals(noFsSameAs1, noFs1); + assertNotEquals(noFs1, noFsNoName1); + assertEquals(noFsNoName2, noFsNoName1); } private Map buildFakeEnv() diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileSystemTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileSystemTest.java index 9511bac5..3921b764 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileSystemTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3FileSystemTest.java @@ -1,30 +1,41 @@ package org.carlspring.cloud.storage.s3fs; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.net.URI; -import java.nio.file.*; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; import java.util.Iterator; import java.util.Map; import java.util.Set; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; -import static org.junit.jupiter.api.Assertions.*; - -public class S3FileSystemTest +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Utilities; +import software.amazon.awssdk.services.s3.model.GetUrlRequest; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class S3FileSystemTest extends S3UnitTestBase { @@ -35,33 +46,31 @@ public class S3FileSystemTest public void setup() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA"); client.bucket("bucketB"); - fs = FileSystems.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, null); + final URI s3GlobalUriTest = S3EndpointConstant.S3_GLOBAL_URI_TEST; + fs = FileSystems.newFileSystem(s3GlobalUriTest, null); } @AfterEach public void tearDown() throws IOException { -//! super.tearDown(); - - // s3fsProvider.close((S3FileSystem) fs); fs.close(); } @Test - public void getPathFirst() + void getPathFirst() { assertEquals(fs.getPath("/bucket"), fs.getPath("/bucket")); assertEquals(fs.getPath("file"), fs.getPath("file")); } @Test - public void getPathFirstWithMultiplesPaths() + void getPathFirstWithMultiplesPaths() { assertEquals(fs.getPath("/bucket/path/to/file"), fs.getPath("/bucket/path/to/file")); assertNotEquals(fs.getPath("/bucket/path/other/file"), fs.getPath("/bucket/path/to/file")); @@ -71,7 +80,7 @@ public void getPathFirstWithMultiplesPaths() } @Test - public void getPathFirstAndMore() + void getPathFirstAndMore() { Path actualAbsolute = fs.getPath("/bucket", "dir", "file"); @@ -85,7 +94,7 @@ public void getPathFirstAndMore() } @Test - public void getPathFirstAndMoreWithMultiplesPaths() + void getPathFirstAndMoreWithMultiplesPaths() { Path actual = fs.getPath("/bucket", "dir/file"); @@ -95,7 +104,7 @@ public void getPathFirstAndMoreWithMultiplesPaths() } @Test - public void getPathFirstWithMultiplesPathsAndMoreWithMultiplesPaths() + void getPathFirstWithMultiplesPathsAndMoreWithMultiplesPaths() { Path actual = fs.getPath("/bucket/dir", "dir/file"); @@ -106,7 +115,7 @@ public void getPathFirstWithMultiplesPathsAndMoreWithMultiplesPaths() } @Test - public void getPathRelativeAndAbsoulte() + void getPathRelativeAndAbsoulte() { assertNotEquals(fs.getPath("/bucket"), fs.getPath("bucket")); assertNotEquals(fs.getPath("/bucket/dir"), fs.getPath("bucket/dir")); @@ -117,7 +126,7 @@ public void getPathRelativeAndAbsoulte() } @Test - public void duplicatedSlashesAreDeleted() + void duplicatedSlashesAreDeleted() { Path actualFirst = fs.getPath("/bucket//file"); @@ -133,20 +142,20 @@ public void duplicatedSlashesAreDeleted() } @Test - public void readOnlyAlwaysFalse() + void readOnlyAlwaysFalse() { assertFalse(fs.isReadOnly()); } @Test - public void getSeparatorSlash() + void getSeparatorSlash() { assertEquals("/", fs.getSeparator()); assertEquals("/", S3Path.PATH_SEPARATOR); } @Test - public void getPathMatcherThrowException() + void getPathMatcherThrowException() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { @@ -157,7 +166,7 @@ public void getPathMatcherThrowException() } @Test - public void getUserPrincipalLookupServiceThrowException() + void getUserPrincipalLookupServiceThrowException() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { @@ -168,7 +177,7 @@ public void getUserPrincipalLookupServiceThrowException() } @Test - public void newWatchServiceThrowException() + void newWatchServiceThrowException() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { @@ -179,7 +188,7 @@ public void newWatchServiceThrowException() } @Test - public void getPathWithoutBucket() + void getPathWithoutBucket() { // We're expecting an exception here to be thrown Exception exception = assertThrows(IllegalArgumentException.class, () -> { @@ -190,7 +199,7 @@ public void getPathWithoutBucket() } @Test - public void getFileStores() + void getFileStores() { Iterable result = fs.getFileStores(); @@ -204,7 +213,7 @@ public void getFileStores() } @Test - public void getRootDirectories() + void getRootDirectories() { Iterable paths = fs.getRootDirectories(); @@ -241,7 +250,7 @@ else if (fileStore.equals("bucketB") && fileName == null) } @Test - public void supportedFileAttributeViewsReturnBasic() + void supportedFileAttributeViewsReturnBasic() { Set operations = fs.supportedFileAttributeViews(); @@ -253,7 +262,7 @@ public void supportedFileAttributeViewsReturnBasic() } @Test - public void close() + void close() throws IOException { assertTrue(fs.isOpen()); @@ -264,7 +273,8 @@ public void close() } @Test - public void comparables() + void comparables() + throws IOException { // create other vars @@ -281,25 +291,17 @@ public void comparables() S3FileSystem s3fs6 = (S3FileSystem) provider.newFileSystem(URI.create( "s3://access_key:secret_key@mirror1.amazon.test/"), null); - AmazonS3ClientMock amazonClientMock = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock s3ClientMock = S3MockFactory.getS3ClientMock(); - S3FileSystem s3fs7 = new S3FileSystem(provider, null, amazonClientMock, "mirror1.amazon.test"); - S3FileSystem s3fs8 = new S3FileSystem(provider, null, amazonClientMock, null); - S3FileSystem s3fs9 = new S3FileSystem(provider, null, amazonClientMock, null); - S3FileSystem s3fs10 = new S3FileSystem(provider, "somekey", amazonClientMock, null); + S3FileSystem s3fs7 = new S3FileSystem(provider, null, s3ClientMock, "mirror1.amazon.test"); + S3FileSystem s3fs8 = new S3FileSystem(provider, null, s3ClientMock, null); + S3FileSystem s3fs9 = new S3FileSystem(provider, null, s3ClientMock, null); + S3FileSystem s3fs10 = new S3FileSystem(provider, "somekey", s3ClientMock, null); S3FileSystem s3fs11 = new S3FileSystem(provider, "access-key@mirror2.amazon.test", - amazonClientMock, + s3ClientMock, "mirror2.amazon.test"); - // FIXME: review the hashcode creation. - assertEquals(1483378423, s3fs1.hashCode()); - assertEquals(684416791, s3fs2.hashCode()); - assertEquals(182977201, s3fs3.hashCode()); - assertEquals(-615984431, s3fs4.hashCode()); - assertEquals(-498271993, s3fs6.hashCode()); - assertEquals(-82123487, s3fs7.hashCode()); - assertNotEquals(s3fs1, s3fs2); assertNotEquals(s3fs1, s3fs3); assertNotEquals(s3fs1, s3fs4); @@ -307,9 +309,7 @@ public void comparables() assertNotEquals(s3fs3, s3fs4); assertNotEquals(s3fs3, s3fs6); assertNotEquals(s3fs1, s3fs6); - assertNotEquals(s3fs1, new S3FileStore(s3fs1, "emmer")); assertNotEquals(s3fs7, s3fs8); - assertEquals(s3fs8, s3fs8); assertNotEquals(s3fs8, s3fs1); assertEquals(s3fs8, s3fs9); assertNotEquals(s3fs9, s3fs10); @@ -327,13 +327,14 @@ public void comparables() } @Test - public void key2Parts() + void key2Parts() + throws IOException { S3FileSystemProvider provider = new S3FileSystemProvider(); - AmazonS3ClientMock amazonClientMock = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock amazonClientMock = S3MockFactory.getS3ClientMock(); - try (S3FileSystem s3fs = new S3FileSystem(provider, null, amazonClientMock, "mirror1.amazon.test");) + try (S3FileSystem s3fs = new S3FileSystem(provider, null, amazonClientMock, "mirror1.amazon.test")) { String[] parts = s3fs.key2Parts("/bucket/folder with spaces/file"); @@ -345,11 +346,11 @@ public void key2Parts() } @Test - public void parts2Key() + void parts2Key() { S3FileSystemProvider provider = new S3FileSystemProvider(); - AmazonS3ClientMock amazonClientMock = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock amazonClientMock = S3MockFactory.getS3ClientMock(); S3FileSystem s3fs = new S3FileSystem(provider, null, amazonClientMock, "mirror1.amazon.test"); @@ -359,43 +360,49 @@ public void parts2Key() } @Test - public void urlWithSpecialCharacters() + void urlWithSpecialCharacters() { String fileName = "βeta.png"; String expected = "https://bucket.s3.eu-west-1.amazonaws.com/%CE%B2eta.png"; - AmazonS3 amazonS3Client = AmazonS3ClientBuilder.standard().withRegion(Regions.EU_WEST_1).build(); + Region region = Region.EU_WEST_1; + S3Client s3Client = S3Client.builder().region(region).build(); + S3Utilities utilities = S3Utilities.builder().region(region).build(); - S3FileSystem s3FileSystem = new S3FileSystem(null, null, amazonS3Client, "mirror"); + S3FileSystem s3FileSystem = new S3FileSystem(null, null, s3Client, "mirror"); S3Path path = new S3Path(s3FileSystem, fileName); - String url = amazonS3Client.getUrl("bucket", path.getKey()).toString(); + GetUrlRequest request = GetUrlRequest.builder().bucket("bucket").key(path.getKey()).build(); + String url = utilities.getUrl(request).toString(); assertEquals(expected, url); } @Test - public void urlWithSpaceCharacters() + void urlWithSpaceCharacters() { String fileName = "beta gaming.png"; String expected = "https://bucket.s3.eu-west-1.amazonaws.com/beta%20gaming.png"; - AmazonS3 amazonS3Client = AmazonS3ClientBuilder.standard().withRegion(Regions.EU_WEST_1).build(); + Region region = Region.EU_WEST_1; + S3Client s3Client = S3Client.builder().region(region).build(); + S3Utilities utilities = S3Utilities.builder().region(region).build(); - S3FileSystem s3FileSystem = new S3FileSystem(null, null, amazonS3Client, "mirror"); + S3FileSystem s3FileSystem = new S3FileSystem(null, null, s3Client, "mirror"); S3Path path = new S3Path(s3FileSystem, fileName); - String url = amazonS3Client.getUrl("bucket", path.getKey()).toString(); + GetUrlRequest request = GetUrlRequest.builder().bucket("bucket").key(path.getKey()).build(); + String url = utilities.getUrl(request).toString(); assertEquals(expected, url); } @Test - public void createDirectory() + void createDirectory() throws IOException { S3FileSystemProvider provider = new S3FileSystemProvider(); - AmazonS3ClientMock amazonClientMock = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock amazonClientMock = S3MockFactory.getS3ClientMock(); try (S3FileSystem s3fs = new S3FileSystem(provider, null, amazonClientMock, "mirror1.amazon.test");) { @@ -406,29 +413,33 @@ public void createDirectory() } @Test - public void createDirectoryWithAttributes() + void createDirectoryWithAttributes() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - S3FileSystemProvider provider = new S3FileSystemProvider(); - AmazonS3ClientMock amazonClientMock = AmazonS3MockFactory.getAmazonClientMock(); + S3FileSystemProvider provider = new S3FileSystemProvider(); + S3ClientMock amazonClientMock = S3MockFactory.getS3ClientMock(); - try (S3FileSystem s3fs = new S3FileSystem(provider, null, amazonClientMock, "mirror1.amazon.test");) - { - S3Path folder = s3fs.getPath("/bucket", "folder"); - provider.createDirectory(folder, - PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwxrwxrw"))); - } - }); + try (S3FileSystem s3fs = new S3FileSystem(provider, null, amazonClientMock, "mirror1.amazon.test")) + { + S3Path folder = s3fs.getPath("/bucket", "folder"); + Set posixFilePermissions = PosixFilePermissions.fromString("rwxrwxrw-"); + FileAttribute> fileAttribute = PosixFilePermissions.asFileAttribute( + posixFilePermissions); - assertNotNull(exception); + // We're expecting an exception here to be thrown + Exception exception = assertThrows(IllegalArgumentException.class, + () -> provider.createDirectory(folder, fileAttribute)); + + assertNotNull(exception); + } } @Test - public void isSameFile() + void isSameFile() + throws IOException { S3FileSystemProvider provider = new S3FileSystemProvider(); - AmazonS3ClientMock amazonClientMock = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock amazonClientMock = S3MockFactory.getS3ClientMock(); try (S3FileSystem s3fs = new S3FileSystem(provider, null, amazonClientMock, "mirror1.amazon.test");) { diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3IteratorTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3IteratorTest.java index f545b316..801f2567 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3IteratorTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3IteratorTest.java @@ -1,24 +1,37 @@ package org.carlspring.cloud.storage.s3fs; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; import org.carlspring.cloud.storage.s3fs.util.MockBucket; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.net.URI; import java.nio.file.FileSystems; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Properties; -import com.amazonaws.services.s3.model.ObjectListing; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.*; - -public class S3IteratorTest +import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; +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.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +class S3IteratorTest extends S3UnitTestBase { @@ -38,14 +51,14 @@ public void prepare() FileSystems.newFileSystem(endpoint, null); - reset(AmazonS3MockFactory.getAmazonClientMock()); + reset(S3MockFactory.getS3ClientMock()); } @Test - public void iteratorDirectory() + void iteratorDirectory() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1"); S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); @@ -56,10 +69,10 @@ public void iteratorDirectory() } @Test - public void iteratorAnotherDirectory() + void iteratorAnotherDirectory() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir2").file("dir2/file1", "dir2/file2"); S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); @@ -70,10 +83,10 @@ public void iteratorAnotherDirectory() } @Test - public void iteratorWithFileContainsDirectoryName() + void iteratorWithFileContainsDirectoryName() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir2").file("dir2/dir2-file", "dir2-file2"); S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); @@ -84,10 +97,10 @@ public void iteratorWithFileContainsDirectoryName() } @Test - public void iteratorWithSubFolderAndSubFiles() + void iteratorWithSubFolderAndSubFiles() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir", "dir/dir", "dir/dir2", "dir/dir2/dir3").file("dir/file", "dir/file2", "dir/dir/file", @@ -102,10 +115,10 @@ public void iteratorWithSubFolderAndSubFiles() } @Test - public void iteratorWithSubFolderAndSubFilesAtBucketLevel() + void iteratorWithSubFolderAndSubFilesAtBucketLevel() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("file", "file2", "dir/file3", "dir2/file4", "dir2/dir3/file3").dir("dir", "dir2", "dir2/dir3", @@ -119,10 +132,10 @@ public void iteratorWithSubFolderAndSubFilesAtBucketLevel() } @Test - public void iteratorFileReturnEmpty() + void iteratorFileReturnEmpty() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("file1"); S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); @@ -133,10 +146,10 @@ public void iteratorFileReturnEmpty() } @Test - public void iteratorEmptyDirectory() + void iteratorEmptyDirectory() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); @@ -147,10 +160,10 @@ public void iteratorEmptyDirectory() } @Test - public void iteratorBucket() + void iteratorBucket() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("file1", "file2", "file3"); S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); @@ -161,33 +174,32 @@ public void iteratorBucket() } @Test - public void iteratorExhausted() + void iteratorExhausted() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(NoSuchElementException.class, () -> { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").file("file1", "file2", "file3"); - - S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); - S3Path path = s3FileSystem.getPath("/bucketA"); + S3ClientMock client = S3MockFactory.getS3ClientMock(); + client.bucket("bucketA").file("file1", "file2", "file3"); - S3Iterator iterator = new S3Iterator(path); - while (iterator.hasNext()) - { - iterator.next(); - } + S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); + S3Path path = s3FileSystem.getPath("/bucketA"); + S3Iterator iterator = new S3Iterator(path); + while (iterator.hasNext()) + { iterator.next(); - }); + } + + // We're expecting an exception here to be thrown + Exception exception = assertThrows(NoSuchElementException.class, iterator::next); assertNotNull(exception); } @Test - public void iteratorDirs() + void iteratorDirs() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("file1", "file2", "file3", @@ -203,10 +215,10 @@ public void iteratorDirs() } @Test - public void virtualDirs() + void virtualDirs() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("directory1/file1.1", "directory1/file1.2", "directory1/file1.3"); S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); @@ -222,10 +234,10 @@ public void virtualDirs() } @Test - public void incrementalVirtualDirs() + void incrementalVirtualDirs() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("dir/subdir/subberdir/file1.1", "dir/subdir/subberdir/file1.2", "dir/subdir/subberdir/file1.3"); @@ -238,10 +250,10 @@ public void incrementalVirtualDirs() } @Test - public void iteratorMoreThanAmazonS3ClientLimit() + void iteratorMoreThanS3ClientLimit() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); MockBucket mockBucket = client.bucket("bucketD"); String[] filesNameExpected = new String[1050]; @@ -275,22 +287,23 @@ public void iteratorMoreThanAmazonS3ClientLimit() assertIterator(iterator, filesNameExpected); - verify(client, times(1)).listNextBatchOfObjects(any(ObjectListing.class)); + verify(client, times(2)).listObjectsV2(any(ListObjectsV2Request.class)); } @Test - public void remove() + void remove() + throws IOException { + S3ClientMock client = S3MockFactory.getS3ClientMock(); + client.bucket("bucketA").dir("dir").file("dir/file1"); + + S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); + S3Path path = s3FileSystem.getPath("/bucketA", "dir"); + + S3Iterator iterator = new S3Iterator(path); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(UnsupportedOperationException.class, () -> { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir").file("dir/file1"); - - S3FileSystem s3FileSystem = (S3FileSystem) FileSystems.getFileSystem(endpoint); - S3Path path = s3FileSystem.getPath("/bucketA", "dir"); - S3Iterator iterator = new S3Iterator(path); - iterator.remove(); - }); + Exception exception = assertThrows(UnsupportedOperationException.class, iterator::remove); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3SeekableByteChannelTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3SeekableByteChannelTest.java index e0b1f735..9560bc3b 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3SeekableByteChannelTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3SeekableByteChannelTest.java @@ -1,22 +1,35 @@ package org.carlspring.cloud.storage.s3fs; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.lang.reflect.Field; import java.nio.ByteBuffer; -import java.nio.file.*; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.EnumSet; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; -public class S3SeekableByteChannelTest +class S3SeekableByteChannelTest extends S3UnitTestBase { @@ -28,17 +41,19 @@ public void setup() fileSystem = FileSystems.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, null); } - @Test - public void constructor() + @ParameterizedTest + @ValueSource(booleans = { true, + false }) + void constructor(final boolean tempFileRequired) throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("buck").file("file1"); S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); S3SeekableByteChannel channel = new S3SeekableByteChannel(file1, EnumSet.of(StandardOpenOption.WRITE, - StandardOpenOption.READ)); + StandardOpenOption.READ), tempFileRequired); assertNotNull(channel); @@ -47,14 +62,14 @@ public void constructor() } @Test - public void readDontNeedToSyncTempFile() + void readDontNeedToSyncTempFile() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("buck").file("file1"); S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); - S3SeekableByteChannel channel = spy(new S3SeekableByteChannel(file1, EnumSet.of(StandardOpenOption.READ))); + S3SeekableByteChannel channel = spy(new S3SeekableByteChannel(file1, EnumSet.of(StandardOpenOption.READ), true)); assertNotNull(channel); @@ -64,15 +79,32 @@ public void readDontNeedToSyncTempFile() } @Test - public void writeNeedToSyncTempFile() + void tempFileRequiredFlagToFalseDontNeedToSyncTempFile() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("buck").file("file1"); S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); + S3SeekableByteChannel channel = spy(new S3SeekableByteChannel(file1, EnumSet.of(StandardOpenOption.READ), false)); + + assertNotNull(channel); - S3SeekableByteChannel channel = spy(new S3SeekableByteChannel(file1, EnumSet.of(StandardOpenOption.WRITE))); + channel.close(); + + verify(channel, never()).sync(); + } + + @Test + void writeNeedToSyncTempFile() + throws IOException + { + S3ClientMock client = S3MockFactory.getS3ClientMock(); + client.bucket("buck").file("file1"); + + S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST).getPath("/buck/file1"); + + S3SeekableByteChannel channel = spy(new S3SeekableByteChannel(file1, EnumSet.of(StandardOpenOption.WRITE), true)); channel.write(ByteBuffer.wrap("hoi".getBytes())); channel.close(); @@ -81,42 +113,41 @@ public void writeNeedToSyncTempFile() } @Test - public void alreadyExists() + void alreadyExists() { // We're expecting an exception here to be thrown Exception exception = assertThrows(FileAlreadyExistsException.class, () -> { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("buck").file("file1"); S3Path file1 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST) .getPath("/buck/file1"); - new S3SeekableByteChannel(file1, EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)); + new S3SeekableByteChannel(file1, EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW), true); }); assertNotNull(exception); } @Test - public void brokenNetwork() + void brokenNetwork() { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(RuntimeException.class, () -> { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - doThrow(new RuntimeException("network broken")).when(client).getObject("buck", "file2"); + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + final GetObjectRequest request = GetObjectRequest.builder().bucket("buck").key("file2").build(); + doThrow(new RuntimeException("network broken")).when(client).getObject(request); - S3Path file2 = (S3Path) FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST) - .getPath("/buck/file2"); - S3SeekableByteChannel channel = new S3SeekableByteChannel(file2, - EnumSet.of(StandardOpenOption.WRITE, - StandardOpenOption.READ)); - channel.close(); - }); + final FileSystem fileSystem = FileSystems.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + final S3Path file2 = (S3Path) fileSystem.getPath("/buck/file2"); + + final EnumSet options = EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.READ); + + // We're expecting an exception here to be thrown + Exception exception = assertThrows(RuntimeException.class, () -> new S3SeekableByteChannel(file2, options, true)); assertNotNull(exception); } @Test - public void tempFileDisappeared() + void tempFileDisappeared() throws SecurityException, IllegalArgumentException { @@ -126,7 +157,7 @@ public void tempFileDisappeared() .getPath("/buck/file2"); S3SeekableByteChannel channel = new S3SeekableByteChannel(file2, EnumSet.of(StandardOpenOption.WRITE, - StandardOpenOption.READ)); + StandardOpenOption.READ), true); Field f = channel.getClass().getDeclaredField("tempFile"); f.setAccessible(true); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3UnitTestBase.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3UnitTestBase.java index 88c23cb7..9db2e88a 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3UnitTestBase.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3UnitTestBase.java @@ -1,7 +1,7 @@ package org.carlspring.cloud.storage.s3fs; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.nio.file.FileSystem; @@ -9,11 +9,11 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; -import static org.carlspring.cloud.storage.s3fs.S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.carlspring.cloud.storage.s3fs.S3FileSystemProvider.S3_FACTORY_CLASS; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -28,11 +28,11 @@ public class S3UnitTestBase @BeforeEach public void setProperties() { - System.clearProperty(S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS); + System.clearProperty(S3FileSystemProvider.S3_FACTORY_CLASS); System.clearProperty(ACCESS_KEY); System.clearProperty(SECRET_KEY); - System.setProperty(AMAZON_S3_FACTORY_CLASS, "org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory"); + System.setProperty(S3_FACTORY_CLASS, "org.carlspring.cloud.storage.s3fs.util.S3MockFactory"); } @BeforeEach @@ -48,8 +48,8 @@ public void setupS3fsProvider() @AfterEach public void closeMemory() { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.clear(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); + client.close(); for (S3FileSystem s3FileSystem : S3FileSystemProvider.getFilesystems().values()) { @@ -79,12 +79,9 @@ public void tearDown() { fileSystem.close(); } - - com.amazonaws.http.IdleConnectionReaper.shutdown(); } - catch (Throwable t) + catch (Throwable ignored) { - // e.printStackTrace(); } } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsIT.java index 586122a4..986203a2 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsIT.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsIT.java @@ -9,22 +9,31 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URI; -import java.nio.file.*; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import java.util.UUID; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.PutObjectRequest; -import com.amazonaws.services.s3.model.S3ObjectSummary; import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.model.S3Object; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_IT; -import static org.junit.jupiter.api.Assertions.*; +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.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class S3UtilsIT +class S3UtilsIT { private static final String bucket = EnvironmentBuilder.getBucket(); @@ -44,7 +53,7 @@ public void setup() private static FileSystem build() throws IOException { - System.clearProperty(S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS); + System.clearProperty(S3FileSystemProvider.S3_FACTORY_CLASS); System.clearProperty(ACCESS_KEY); System.clearProperty(SECRET_KEY); @@ -67,19 +76,19 @@ private static FileSystem createNewFileSystem() } @Test - public void lookupS3ObjectWhenS3PathIsFile() + void lookupS3ObjectWhenS3PathIsFile() throws IOException { Path path = getPathFile(); S3Path s3Path = (S3Path) path.resolve("file"); - S3ObjectSummary result = getS3ObjectSummary(s3Path); + S3Object result = getS3ObjectSummary(s3Path); - assertEquals(s3Path.getKey(), result.getKey()); + assertEquals(s3Path.getKey(), result.key()); } @Test - public void lookupS3ObjectWhenS3PathIsFileAndExistsOtherStartsWithSameName() + void lookupS3ObjectWhenS3PathIsFileAndExistsOtherStartsWithSameName() throws IOException { Path path; @@ -99,13 +108,13 @@ public void lookupS3ObjectWhenS3PathIsFileAndExistsOtherStartsWithSameName() } S3Path s3Path = (S3Path) path.resolve("file"); - S3ObjectSummary result = getS3ObjectSummary(s3Path); + S3Object result = getS3ObjectSummary(s3Path); - assertEquals(s3Path.getKey(), result.getKey()); + assertEquals(s3Path.getKey(), result.key()); } @Test - public void lookupS3ObjectWhenS3PathIsADirectory() + void lookupS3ObjectWhenS3PathIsADirectory() throws IOException { Path path; @@ -122,58 +131,60 @@ public void lookupS3ObjectWhenS3PathIsADirectory() S3Path s3Path = (S3Path) path.resolve("dir"); - S3ObjectSummary result = getS3ObjectSummary(s3Path); + S3Object result = getS3ObjectSummary(s3Path); - assertEquals(s3Path.getKey() + "/", result.getKey()); + assertEquals(s3Path.getKey() + "/", result.key()); } @Test - public void lookupS3ObjectWhenS3PathIsADirectoryAndExistsOtherDirectoryStartsSameName() + void lookupS3ObjectWhenS3PathIsADirectoryAndExistsOtherDirectoryStartsSameName() throws IOException { final String startPath = "0000example" + UUID.randomUUID().toString() + "/"; S3FileSystem s3FileSystem = (S3FileSystem) fileSystemAmazon; - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentLength(0L); + final RequestBody requestBody = RequestBody.fromInputStream(new ByteArrayInputStream("".getBytes()), 0L); - s3FileSystem.getClient().putObject(bucket.replace("/", ""), - startPath + "lib/angular/", - new ByteArrayInputStream("".getBytes()), - metadata); - s3FileSystem.getClient().putObject(bucket.replace("/", ""), - startPath + "lib/angular-dynamic-locale/", - new ByteArrayInputStream("".getBytes()), - metadata); + String bucketName = bucket.replace("/", ""); + String key1 = startPath + "lib/angular/"; + PutObjectRequest request = PutObjectRequest.builder().bucket(bucketName).key(key1).build(); + s3FileSystem.getClient().putObject(request, requestBody); + + String key2 = startPath + "lib/angular-dynamic-locale/"; + request = PutObjectRequest.builder().bucket(bucketName).key(key2).build(); + s3FileSystem.getClient().putObject(request, requestBody); S3Path s3Path = s3FileSystem.getPath(bucket, startPath, "lib", "angular"); - S3ObjectSummary result = getS3ObjectSummary(s3Path); + S3Object result = getS3ObjectSummary(s3Path); - assertEquals(startPath + "lib/angular/", result.getKey()); + assertEquals(startPath + "lib/angular/", result.key()); } @Test - public void lookupS3ObjectWhenS3PathIsADirectoryAndIsVirtual() + void lookupS3ObjectWhenS3PathIsADirectoryAndIsVirtual() throws IOException { String folder = "angular" + UUID.randomUUID().toString(); String key = folder + "/content.js"; + final ByteArrayInputStream inputStream = new ByteArrayInputStream("content1".getBytes()); + final RequestBody requestBody = RequestBody.fromInputStream(inputStream, inputStream.available()); + S3FileSystem s3FileSystem = (S3FileSystem) fileSystemAmazon; - s3FileSystem.getClient().putObject(bucket.replace("/", ""), - key, - new ByteArrayInputStream("content1".getBytes()), - new ObjectMetadata()); + + String bucketName = bucket.replace("/", ""); + PutObjectRequest request = PutObjectRequest.builder().bucket(bucketName).key(key).build(); + s3FileSystem.getClient().putObject(request, requestBody); S3Path s3Path = (S3Path) fileSystemAmazon.getPath(bucket, folder); - S3ObjectSummary result = getS3ObjectSummary(s3Path); + S3Object result = getS3ObjectSummary(s3Path); - assertEquals(key, result.getKey()); + assertEquals(key, result.key()); } @Test - public void lookupS3BasicFileAttributesWhenS3PathIsFile() + void lookupS3BasicFileAttributesWhenS3PathIsFile() throws IOException { Path path = getPathFile(); @@ -194,17 +205,19 @@ public void lookupS3BasicFileAttributesWhenS3PathIsFile() } @Test - public void lookupS3BasicFileAttributesWhenS3PathIsADirectoryAndIsVirtual() + void lookupS3BasicFileAttributesWhenS3PathIsADirectoryAndIsVirtual() throws IOException { String folder = "angular" + UUID.randomUUID().toString(); String key = folder + "/content.js"; S3FileSystem s3FileSystem = (S3FileSystem) fileSystemAmazon; - s3FileSystem.getClient().putObject(bucket.replace("/", ""), - key, - new ByteArrayInputStream("content1".getBytes()), - new ObjectMetadata()); + + ByteArrayInputStream inputStream = new ByteArrayInputStream("content1".getBytes()); + final RequestBody requestBody = RequestBody.fromInputStream(inputStream, inputStream.available()); + String bucketName = bucket.replace("/", ""); + PutObjectRequest request = PutObjectRequest.builder().bucket(bucketName).key(key).build(); + s3FileSystem.getClient().putObject(request, requestBody); S3Path s3Path = (S3Path) fileSystemAmazon.getPath(bucket, folder); S3BasicFileAttributes result = new S3Utils().getS3FileAttributes(s3Path); @@ -222,22 +235,20 @@ public void lookupS3BasicFileAttributesWhenS3PathIsADirectoryAndIsVirtual() } @Test - public void lookupS3BasicFileAttributesWhenS3PathIsADirectoryAndIsNotVirtualAndNoContent() + void lookupS3BasicFileAttributesWhenS3PathIsADirectoryAndIsNotVirtualAndNoContent() throws IOException { String folder = "folder" + UUID.randomUUID().toString(); String key = folder + "/"; - final ObjectMetadata om = new ObjectMetadata(); - om.setContentLength(0L); - - PutObjectRequest putObjectRequest = new PutObjectRequest(bucket.replace("/", ""), - key, - new ByteArrayInputStream("".getBytes()), - om); + ByteArrayInputStream inputStream = new ByteArrayInputStream("contenido1".getBytes()); + final RequestBody requestBody = RequestBody.fromInputStream(inputStream, inputStream.available()); + String bucketName = bucket.replace("/", ""); + PutObjectRequest request = PutObjectRequest.builder().bucket(bucketName).key(key).build(); S3FileSystem s3FileSystem = (S3FileSystem) fileSystemAmazon; - s3FileSystem.getClient().putObject(putObjectRequest); + + s3FileSystem.getClient().putObject(request, requestBody); S3Path s3Path = (S3Path) fileSystemAmazon.getPath(bucket, folder); @@ -256,7 +267,7 @@ public void lookupS3BasicFileAttributesWhenS3PathIsADirectoryAndIsNotVirtualAndN } @Test - public void lookupS3PosixFileAttributesWhenS3PathIsFile() + void lookupS3PosixFileAttributesWhenS3PathIsFile() throws IOException { Path path = getPathFile(); @@ -282,17 +293,21 @@ public void lookupS3PosixFileAttributesWhenS3PathIsFile() } @Test - public void lookupS3PosixFileAttributesWhenS3PathIsADirectoryAndIsVirtual() + void lookupS3PosixFileAttributesWhenS3PathIsADirectoryAndIsVirtual() throws IOException { String folder = "angular" + UUID.randomUUID().toString(); String key = folder + "/content.js"; + + ByteArrayInputStream inputStream = new ByteArrayInputStream("content1".getBytes()); + final RequestBody requestBody = RequestBody.fromInputStream(inputStream, inputStream.available()); + String bucketName = bucket.replace("/", ""); + PutObjectRequest request = PutObjectRequest.builder().bucket(bucketName).key(key).build(); + S3FileSystem s3FileSystem = (S3FileSystem) fileSystemAmazon; - s3FileSystem.getClient().putObject(bucket.replace("/", ""), - key, - new ByteArrayInputStream("content1".getBytes()), - new ObjectMetadata()); + + s3FileSystem.getClient().putObject(request, requestBody); S3Path s3Path = (S3Path) fileSystemAmazon.getPath(bucket, folder); S3PosixFileAttributes result = new S3Utils().getS3PosixFileAttributes(s3Path); @@ -315,22 +330,20 @@ public void lookupS3PosixFileAttributesWhenS3PathIsADirectoryAndIsVirtual() } @Test - public void lookupS3PosixFileAttributesWhenS3PathIsADirectoryAndIsNotVirtualAndNoContent() + void lookupS3PosixFileAttributesWhenS3PathIsADirectoryAndIsNotVirtualAndNoContent() throws IOException { String folder = "folder" + UUID.randomUUID().toString(); String key = folder + "/"; - final ObjectMetadata om = new ObjectMetadata(); - om.setContentLength(0L); - - PutObjectRequest putObjectRequest = new PutObjectRequest(bucket.replace("/", ""), - key, - new ByteArrayInputStream("".getBytes()), - om); + final RequestBody requestBody = RequestBody.fromInputStream(new ByteArrayInputStream("".getBytes()), + 0L); + String bucketName = bucket.replace("/", ""); + PutObjectRequest request = PutObjectRequest.builder().bucket(bucketName).key(key).build(); S3FileSystem s3FileSystem = (S3FileSystem) fileSystemAmazon; - s3FileSystem.getClient().putObject(putObjectRequest); + + s3FileSystem.getClient().putObject(request, requestBody); S3Path s3Path = (S3Path) fileSystemAmazon.getPath(bucket, folder); S3PosixFileAttributes result = new S3Utils().getS3PosixFileAttributes(s3Path); @@ -352,10 +365,10 @@ public void lookupS3PosixFileAttributesWhenS3PathIsADirectoryAndIsNotVirtualAndN assertNull(result.permissions()); } - public S3ObjectSummary getS3ObjectSummary(S3Path s3Path) + public S3Object getS3ObjectSummary(final S3Path s3Path) throws NoSuchFileException { - return new S3Utils().getS3ObjectSummary(s3Path); + return new S3Utils().getS3Object(s3Path); } private Path getPathFile() diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsTest.java index e239a6d0..8c4cfef5 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3UtilsTest.java @@ -1,8 +1,8 @@ package org.carlspring.cloud.storage.s3fs; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import org.carlspring.cloud.storage.s3fs.util.S3Utils; import java.io.IOException; @@ -12,15 +12,21 @@ import java.nio.file.NoSuchFileException; import java.nio.file.StandardOpenOption; -import com.amazonaws.services.s3.model.AmazonS3Exception; -import com.amazonaws.services.s3.model.Owner; -import com.amazonaws.services.s3.model.S3ObjectSummary; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.services.s3.model.GetObjectAclRequest; +import software.amazon.awssdk.services.s3.model.Owner; +import software.amazon.awssdk.services.s3.model.S3Exception; +import software.amazon.awssdk.services.s3.model.S3Object; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.doThrow; +import static software.amazon.awssdk.http.HttpStatusCode.INTERNAL_SERVER_ERROR; -public class S3UtilsTest +class S3UtilsTest extends S3UnitTestBase { @@ -31,79 +37,76 @@ public void setup() { fileSystem = FileSystems.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, null); - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + final S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucket"); } @Test - public void getS3ObjectSummary() + void getS3Object() throws IOException { - S3Path root = (S3Path) fileSystem.getPath("/bucket"); - S3Path file1 = (S3Path) root.resolve("file1"); + final S3Path root = (S3Path) fileSystem.getPath("/bucket"); + final S3Path file1 = (S3Path) root.resolve("file1"); - String contentString = "Some content String"; + final String contentString = "Some content String"; - OutputStream outputStream = Files.newOutputStream(file1, StandardOpenOption.CREATE, StandardOpenOption.WRITE); + final OutputStream outputStream = Files.newOutputStream(file1, StandardOpenOption.CREATE, StandardOpenOption.WRITE); outputStream.write(contentString.getBytes()); outputStream.close(); - S3ObjectSummary file1ObjectSummary = getS3ObjectSummary(file1); + final S3Object file1Object = getS3Object(file1); - assertEquals("bucket", file1ObjectSummary.getBucketName()); - assertNull(file1ObjectSummary.getETag()); - assertEquals("file1", file1ObjectSummary.getKey()); - assertNotNull(file1ObjectSummary.getLastModified()); + assertNull(file1Object.eTag()); + assertEquals("file1", file1Object.key()); + assertNotNull(file1Object.lastModified()); - Owner owner = file1ObjectSummary.getOwner(); + final Owner owner = file1Object.owner(); assertNotNull(owner); - assertEquals("Mock", owner.getDisplayName()); - assertEquals("1", owner.getId()); - assertEquals(19, file1ObjectSummary.getSize()); + assertEquals("Mock", owner.displayName()); + assertEquals("1", owner.id()); + assertEquals(19, file1Object.size()); } @Test - public void getS3ObjectSummary404() + void getS3Object404() { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(NoSuchFileException.class, () -> { - S3Path root = (S3Path) fileSystem.getPath("/bucket"); - S3Path file1 = (S3Path) root.resolve("file1"); + final S3Path root = (S3Path) fileSystem.getPath("/bucket"); + final S3Path file1 = (S3Path) root.resolve("file1"); - getS3ObjectSummary(file1); - }); + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(NoSuchFileException.class, () -> getS3Object(file1)); assertNotNull(exception); } @Test - public void getS3ObjectSummary500() + void getS3Object500() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(AmazonS3Exception.class, () -> { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - AmazonS3Exception toBeThrown = new AmazonS3Exception("We messed up"); + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + final AwsServiceException toBeThrown = S3Exception.builder().message("We messed up").statusCode( + INTERNAL_SERVER_ERROR).build(); - toBeThrown.setStatusCode(500); - doThrow(toBeThrown).when(client).getObjectAcl("bucket", "file2"); + GetObjectAclRequest request = GetObjectAclRequest.builder().bucket("bucket").key("file2").build(); + doThrow(toBeThrown).when(client).getObjectAcl(request); - S3Path root = (S3Path) fileSystem.getPath("/bucket"); - S3Path file2 = (S3Path) root.resolve("file2"); + final S3Path root = (S3Path) fileSystem.getPath("/bucket"); + final S3Path file2 = (S3Path) root.resolve("file2"); - Files.createFile(file2); + Files.createFile(file2); - getS3ObjectSummary(file2); - }); + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(S3Exception.class, () -> getS3Object(file2)); assertNotNull(exception); } - public S3ObjectSummary getS3ObjectSummary(S3Path s3Path) + public S3Object getS3Object(S3Path s3Path) throws NoSuchFileException { - return new S3Utils().getS3ObjectSummary(s3Path); + return new S3Utils().getS3Object(s3Path); } } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/S3WalkerTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/S3WalkerTest.java index 3becce7f..64e4d7ff 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/S3WalkerTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/S3WalkerTest.java @@ -1,22 +1,33 @@ package org.carlspring.cloud.storage.s3fs; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; import org.carlspring.cloud.storage.s3fs.util.MockBucket; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.net.URI; -import java.nio.file.*; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.reset; -public class S3WalkerTest +class S3WalkerTest extends S3UnitTestBase { @@ -119,17 +130,17 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) } @BeforeEach - public void setup() + void setup() throws IOException { FileSystems.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, null); } @Test - public void walkFileTree() + void walkFileTree() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); MockBucket mockBucket = client.bucket("/tree"); mockBucket.dir("folder", "folder/subfolder1"); @@ -165,16 +176,16 @@ public void walkFileTree() Iterator iter = registrar.getVisitOrder().iterator(); - Files.walkFileTree(folder, Collections.emptySet(), 20, new CheckVisitor(iter)); + Files.walkFileTree(folder, Collections.emptySet(), 20, new CheckVisitor(iter)); assertFalse(iter.hasNext(), "Iterator should have been exhausted."); } @Test - public void walkEmptyFileTree() + void walkEmptyFileTree() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("tree").dir("folder"); S3Path folder = (S3Path) Paths.get(URI.create(S3EndpointConstant.S3_GLOBAL_URI_TEST + "tree/folder")); @@ -196,10 +207,10 @@ public void walkEmptyFileTree() } @Test - public void walkLargeFileTree() + void walkLargeFileTree() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); MockBucket mockBucket = client.bucket("/tree"); @@ -248,10 +259,10 @@ public void walkLargeFileTree() } @Test - public void noSuchElementTreeWalk() + void noSuchElementTreeWalk() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("/tree"); S3Path folder = (S3Path) Paths.get(URI.create(S3EndpointConstant.S3_GLOBAL_URI_TEST + "tree/folder")); @@ -274,10 +285,10 @@ public void noSuchElementTreeWalk() } @Test - public void skippingWalk() + void skippingWalk() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); MockBucket mockBucket = client.bucket("/tree"); mockBucket.dir("folder", "folder/subfolder1"); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/CheckAccessTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/CheckAccessTest.java new file mode 100644 index 00000000..cc17696e --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/CheckAccessTest.java @@ -0,0 +1,202 @@ +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; + +import org.carlspring.cloud.storage.s3fs.S3FileSystem; +import org.carlspring.cloud.storage.s3fs.S3Path; +import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; +import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; + +import java.io.IOException; +import java.nio.file.AccessDeniedException; +import java.nio.file.AccessMode; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Path; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.services.s3.model.GetObjectAclRequest; +import software.amazon.awssdk.services.s3.model.GetObjectAclResponse; +import software.amazon.awssdk.services.s3.model.Owner; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doReturn; + +class CheckAccessTest + extends S3UnitTestBase +{ + + @BeforeEach + public void setup() + throws IOException + { + s3fsProvider = getS3fsProvider(); + fileSystem = s3fsProvider.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, null); + } + + @AfterEach + public void tearDown() + throws IOException + { + s3fsProvider.close((S3FileSystem) fileSystem); + fileSystem.close(); + } + + // check access + @Test + void checkAccessRead() + throws IOException + { + // fixtures + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + final String bucketName = "bucketA"; + final String directory = "dir"; + final String filePath = directory + "/file"; + client.bucket(bucketName).dir(directory).file(filePath); + + final FileSystem fs = createNewS3FileSystem(); + final String path = String.format("/%s/%s", bucketName, filePath); + final Path file1 = fs.getPath(path); + + s3fsProvider.checkAccess(file1, AccessMode.READ); + } + + @Test + void checkAccessReadWithoutPermission() + throws IOException + { + // fixtures + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + final String bucketName = "bucketA"; + final String directory = "dir"; + client.bucket(bucketName).dir(directory); + + final FileSystem fs = createNewS3FileSystem(); + final String path = String.format("/%s/%s", bucketName, directory); + final Path file1 = fs.getPath(path); + + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(AccessDeniedException.class, + () -> s3fsProvider.checkAccess(file1, AccessMode.READ)); + + // TODO: Assert that the exception message is as expected + assertNotNull(exception); + } + + @Test + void checkAccessWrite() + throws IOException + { + // fixtures + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + final String bucketName = "bucketA"; + final String directory = "dir"; + final String filePath = directory + "/file"; + client.bucket(bucketName).dir(directory).file(filePath); + + final S3FileSystem fs = createNewS3FileSystem(); + final String path = String.format("/%s/%s", bucketName, filePath); + final S3Path file1 = fs.getPath(path); + + s3fsProvider.checkAccess(file1, AccessMode.WRITE); + } + + @Test + void checkAccessWriteDifferentUser() + throws IOException + { + // fixtures + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + final String bucketName = "bucketA"; + final String directory = "dir"; + final String filePath = directory + "/readOnly"; + client.bucket(bucketName).dir(directory).file(filePath); + + // return empty list + final Owner owner = Owner.builder().id("2").displayName("Read Only").build(); + final GetObjectAclRequest request = GetObjectAclRequest.builder().bucket(bucketName).key(filePath).build(); + final GetObjectAclResponse response = GetObjectAclResponse.builder().owner(owner).build(); + doReturn(response).when(client).getObjectAcl(request); + + final S3FileSystem fs = createNewS3FileSystem(); + final String path = String.format("/%s/%s", bucketName, filePath); + final S3Path file1 = fs.getPath(path); + + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(AccessDeniedException.class, + () -> s3fsProvider.checkAccess(file1, AccessMode.WRITE)); + + assertNotNull(exception); + } + + @Test + void checkAccessWriteWithoutPermission() + throws IOException + { + // fixtures + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + final String bucketName = "bucketA"; + final String directory = "dir"; + client.bucket("bucketA").dir(directory); + + // return empty list + final GetObjectAclResponse response = GetObjectAclResponse.builder().build(); + final GetObjectAclRequest request = GetObjectAclRequest.builder().bucket(bucketName).key( + directory + "/").build(); + doReturn(response).when(client).getObjectAcl(request); + + final String path = String.format("/%s/%s", bucketName, directory); + final Path file1 = createNewS3FileSystem().getPath(path); + + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(AccessDeniedException.class, + () -> s3fsProvider.checkAccess(file1, AccessMode.WRITE)); + + assertNotNull(exception); + } + + @Test + void checkAccessExecute() + throws IOException + { + // fixtures + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + final String bucketName = "bucketA"; + final String directory = "dir"; + final String filePath = directory + "/file"; + client.bucket(bucketName).dir(directory).file(filePath); + + final String path = String.format("/%s/%s", bucketName, filePath); + final Path file1 = createNewS3FileSystem().getPath(path); + + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(AccessDeniedException.class, + () -> s3fsProvider.checkAccess(file1, AccessMode.EXECUTE)); + + assertNotNull(exception); + } + + /** + * create a new file system for s3 scheme with fake credentials + * and global endpoint + * + * @return FileSystem + * @throws IOException + */ + private S3FileSystem createNewS3FileSystem() + throws IOException + { + try + { + return s3fsProvider.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); + } + catch (final FileSystemNotFoundException e) + { + return (S3FileSystem) FileSystems.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, null); + } + } + +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/CopyTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/CopyTest.java similarity index 74% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/CopyTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/CopyTest.java index f84f9291..fa6520f2 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/CopyTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/CopyTest.java @@ -1,20 +1,29 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; -import java.nio.file.*; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class CopyTest +class CopyTest extends S3UnitTestBase { @@ -28,13 +37,13 @@ public void setup() } @Test - public void copy() + void copy() throws IOException { final String content = "content-file-1"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir", "dir2").file("dir/file1", content.getBytes()); // act @@ -51,13 +60,13 @@ public void copy() } @Test - public void copySameFile() + void copySameFile() throws IOException { final String content = "sample-content"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1", content.getBytes()); // act @@ -75,13 +84,13 @@ public void copySameFile() } @Test - public void copyAlreadyExistsWithReplace() + void copyAlreadyExistsWithReplace() throws IOException { final String content = "sample-content"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1", content.getBytes()).file("dir/file2"); // act @@ -98,13 +107,13 @@ public void copyAlreadyExistsWithReplace() } @Test - public void copyAlreadyExists() + void copyAlreadyExists() throws IOException { final String content = "sample-content"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1", content.getBytes()).file("dir/file2", content.getBytes()); // act @@ -112,9 +121,7 @@ public void copyAlreadyExists() Path file = fs.getPath("/bucketA", "dir", "file1"); Path fileDest = fs.getPath("/bucketA", "dir", "file2"); - Exception exception = assertThrows(FileAlreadyExistsException.class, () -> { - s3fsProvider.copy(file, fileDest); - }); + Exception exception = assertThrows(FileAlreadyExistsException.class, () -> s3fsProvider.copy(file, fileDest)); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/CreateDirectoryTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/CreateDirectoryTest.java similarity index 76% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/CreateDirectoryTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/CreateDirectoryTest.java index 6ae5dabd..47ca20e1 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/CreateDirectoryTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/CreateDirectoryTest.java @@ -1,12 +1,10 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; -import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.nio.file.FileSystemNotFoundException; @@ -18,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -public class CreateDirectoryTest +class CreateDirectoryTest extends S3UnitTestBase { @@ -32,11 +30,11 @@ public void setup() } @Test - public void createDirectory() + void createDirectory() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA"); // act @@ -51,10 +49,10 @@ public void createDirectory() @Test - public void createDirectoryInNewBucket() + void createDirectoryInNewBucket() throws IOException { - S3Path root = createNewS3FileSystem().getPath("/newer-bucket"); + Path root = createNewS3FileSystem().getPath("/newer-bucket"); Path resolve = root.resolve("folder"); Path path = Files.createDirectories(resolve); @@ -63,18 +61,18 @@ public void createDirectoryInNewBucket() assertEquals("s3://s3.test.amazonaws.com/newer-bucket/folder", path.toAbsolutePath().toString()); assertTrue(Files.exists(root)); assertTrue(Files.isDirectory(root)); - assertTrue(Files.exists(root)); assertTrue(Files.exists(resolve)); assertTrue(Files.isDirectory(resolve)); - assertTrue(Files.exists(resolve)); + assertTrue(Files.exists(path)); + assertTrue(Files.isDirectory(path)); } @Test - public void createDirectoryWithSpace() + void createDirectoryWithSpace() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA"); // act @@ -95,7 +93,6 @@ public void createDirectoryWithSpace() * and global endpoint * * @return FileSystem - * @throws IOException */ private S3FileSystem createNewS3FileSystem() { diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/DeleteTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/DeleteTest.java similarity index 72% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/DeleteTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/DeleteTest.java index 092e8faa..44939335 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/DeleteTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/DeleteTest.java @@ -1,24 +1,30 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.net.URI; -import java.nio.file.*; +import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; -import static org.junit.jupiter.api.Assertions.*; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class DeleteTest +class DeleteTest extends S3UnitTestBase { @@ -32,11 +38,11 @@ public void setup() } @Test - public void deleteFile() + void deleteFile() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file"); // act @@ -48,11 +54,11 @@ public void deleteFile() } @Test - public void deleteEmptyDirectory() + void deleteEmptyDirectory() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); Path base = s3fsProvider.newFileSystem(URI.create("s3://endpoint1/"), ImmutableMap.builder().put(ACCESS_KEY, "access_key") @@ -67,11 +73,11 @@ public void deleteEmptyDirectory() } @Test - public void deleteDirectoryWithEntries() + void deleteDirectoryWithEntries() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file"); Path file = createNewS3FileSystem().getPath("/bucketA/dir/file"); @@ -84,11 +90,11 @@ public void deleteDirectoryWithEntries() } @Test - public void deleteFileNotExists() + void deleteFileNotExists() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); Path file = createNewS3FileSystem().getPath("/bucketA/dir/file"); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetFileAttributeViewTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileAttributeViewTest.java similarity index 80% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetFileAttributeViewTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileAttributeViewTest.java index 26c10b4c..ad910f6c 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetFileAttributeViewTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileAttributeViewTest.java @@ -1,13 +1,12 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.attribute.S3BasicFileAttributes; import org.carlspring.cloud.storage.s3fs.attribute.S3PosixFileAttributes; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.nio.file.FileSystemNotFoundException; @@ -18,9 +17,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class GetFileAttributeViewTest +class GetFileAttributeViewTest extends S3UnitTestBase { @@ -34,10 +35,10 @@ public void setup() } @Test - public void getBasicFileAttributeView() + void getBasicFileAttributeView() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file"); Path file = createNewS3FileSystem().getPath("/bucketA/dir/file"); @@ -49,10 +50,10 @@ public void getBasicFileAttributeView() } @Test - public void getPosixFileAttributeView() + void getPosixFileAttributeView() throws IOException { - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file"); Path file = createNewS3FileSystem().getPath("/bucketA/dir/file"); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetFileStoreTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileStoreTest.java similarity index 68% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetFileStoreTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileStoreTest.java index cb90475e..3298b664 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetFileStoreTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileStoreTest.java @@ -1,11 +1,10 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.nio.file.FileSystemNotFoundException; @@ -17,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -public class GetFileStoreTest +class GetFileStoreTest extends S3UnitTestBase { @@ -31,20 +30,18 @@ public void setup() } @Test - public void getFileStore() + void getFileStore() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(UnsupportedOperationException.class, () -> { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir").file("dir/file1"); + // fixtures + S3ClientMock client = S3MockFactory.getS3ClientMock(); + client.bucket("bucketA").dir("dir").file("dir/file1"); - // act - Path file1 = createNewS3FileSystem().getPath("/bucketA/dir/file1"); + // act + Path file1 = createNewS3FileSystem().getPath("/bucketA/dir/file1"); - // assert - s3fsProvider.getFileStore(file1); - }); + // We're expecting an exception here to be thrown + Exception exception = assertThrows(UnsupportedOperationException.class, () -> s3fsProvider.getFileStore(file1)); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetFileSystemIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileSystemIT.java similarity index 73% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetFileSystemIT.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileSystemIT.java index 44b5211e..8bd5c6a1 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetFileSystemIT.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetFileSystemIT.java @@ -1,4 +1,4 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; @@ -12,17 +12,18 @@ import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.REGION; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_IT; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; -public class GetFileSystemIT +class GetFileSystemIT { private S3FileSystemProvider provider; @@ -32,7 +33,7 @@ public class GetFileSystemIT public void setup() throws IOException { - System.clearProperty(S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS); + System.clearProperty(S3FileSystemProvider.S3_FACTORY_CLASS); System.clearProperty(ACCESS_KEY); System.clearProperty(SECRET_KEY); @@ -53,9 +54,9 @@ public void setup() } @Test - public void getFileSystemWithSameEnvReturnSameFileSystem() + void getFileSystemWithSameEnvReturnSameFileSystem() { - Map env = ImmutableMap.of("s3fs_access_key", "a", "s3fs_secret_key", "b"); + Map env = ImmutableMap.of(ACCESS_KEY, "a", SECRET_KEY, "b", REGION, "c"); FileSystem fileSystem = provider.getFileSystem(S3_GLOBAL_URI_IT, env); assertNotNull(fileSystem); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetPathTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetPathTest.java similarity index 62% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetPathTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetPathTest.java index bed2f3e7..99e7bacd 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/GetPathTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/GetPathTest.java @@ -1,6 +1,5 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; @@ -9,13 +8,17 @@ import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Path; +import java.nio.file.spi.FileSystemProvider; import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; -public class GetPathTest +class GetPathTest extends S3UnitTestBase { @@ -29,7 +32,7 @@ public void setup() } @Test - public void getPathWithEmptyEndpoint() + void getPathWithEmptyEndpoint() throws IOException { FileSystem fs = FileSystems.newFileSystem(URI.create("s3:///"), ImmutableMap.of()); @@ -40,7 +43,7 @@ public void getPathWithEmptyEndpoint() } @Test - public void getPath() + void getPath() throws IOException { FileSystem fs = FileSystems.newFileSystem(URI.create("s3://endpoint1/"), null); @@ -51,7 +54,7 @@ public void getPath() } @Test - public void getAnotherPath() + void getAnotherPath() throws IOException { FileSystem fs = FileSystems.newFileSystem(URI.create("s3://endpoint1/"), ImmutableMap.of()); @@ -62,23 +65,29 @@ public void getAnotherPath() } @Test - public void getPathWithEndpointAndWithoutBucket() + void getPathWithEndpointAndWithoutBucket() + throws IOException { - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - FileSystem fs = FileSystems.newFileSystem(URI.create("s3://endpoint1/"), null); - fs.provider().getPath(URI.create("s3://endpoint1//missed-bucket")); - }); + FileSystem fs = FileSystems.newFileSystem(URI.create("s3://endpoint1/"), null); + URI uri = URI.create("s3://endpoint1//missed-bucket"); + FileSystemProvider provider = fs.provider(); + + Exception exception = assertThrows(IllegalArgumentException.class, + () -> provider.getPath(uri)); assertNotNull(exception); } @Test - public void getPathWithDefaultEndpointAndWithoutBucket() + void getPathWithDefaultEndpointAndWithoutBucket() + throws IOException { - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - FileSystem fs = FileSystems.newFileSystem(URI.create("s3:///"), ImmutableMap.of()); - fs.provider().getPath(URI.create("s3:////missed-bucket")); - }); + FileSystem fs = FileSystems.newFileSystem(URI.create("s3:///"), ImmutableMap.of()); + FileSystemProvider provider = fs.provider(); + URI uri = URI.create("s3:////missed-bucket"); + + Exception exception = assertThrows(IllegalArgumentException.class, + () -> provider.getPath(uri)); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/IsHiddenTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/IsHiddenTest.java similarity index 80% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/IsHiddenTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/IsHiddenTest.java index bab852c5..b5dafe88 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/IsHiddenTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/IsHiddenTest.java @@ -1,11 +1,10 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.nio.file.FileSystemNotFoundException; @@ -16,7 +15,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertFalse; -public class IsHiddenTest +class IsHiddenTest extends S3UnitTestBase { @@ -30,11 +29,11 @@ public void setup() } @Test - public void isHidden() + void isHidden() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1"); // act diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/IsSameFileTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/IsSameFileTest.java similarity index 78% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/IsSameFileTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/IsSameFileTest.java index d839dd57..6c0b8fa4 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/IsSameFileTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/IsSameFileTest.java @@ -1,11 +1,10 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.nio.file.FileSystem; @@ -15,9 +14,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -public class IsSameFileTest +class IsSameFileTest extends S3UnitTestBase { @@ -31,11 +31,11 @@ public void setup() } @Test - public void isSameFileTrue() + void isSameFileTrue() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1"); // act @@ -48,11 +48,11 @@ public void isSameFileTrue() } @Test - public void isSameFileFalse() + void isSameFileFalse() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir", "dir2").file("dir/file1", "dir2/file13"); // act @@ -61,7 +61,7 @@ public void isSameFileFalse() Path fileCopy = fs.getPath("/bucketA/dir2/file2"); // assert - assertTrue(!s3fsProvider.isSameFile(file1, fileCopy)); + assertFalse(s3fsProvider.isSameFile(file1, fileCopy)); } /** diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/MoveTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/MoveTest.java similarity index 77% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/MoveTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/MoveTest.java index a04077de..afd04eba 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/MoveTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/MoveTest.java @@ -1,20 +1,29 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; -import java.nio.file.*; +import java.nio.file.AtomicMoveNotSupportedException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class MoveTest +class MoveTest extends S3UnitTestBase { @@ -28,12 +37,12 @@ public void setup() } @Test - public void move() + void move() throws IOException { // fixtures final String content = "sample-content"; - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir", "dir2").file("dir/file1", content.getBytes()); // act @@ -51,12 +60,12 @@ public void move() } @Test - public void moveWithReplaceExisting() + void moveWithReplaceExisting() throws IOException { // fixtures final String content = "sample-content"; - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1", content.getBytes()).file("dir/file2", "different-content".getBytes()); @@ -75,12 +84,12 @@ public void moveWithReplaceExisting() } @Test - public void moveWithoutReplaceExisting() + void moveWithoutReplaceExisting() throws IOException { // fixtures final String content = "sample-content"; - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1", content.getBytes()).file("dir/file2", "different-content".getBytes()); @@ -98,13 +107,13 @@ public void moveWithoutReplaceExisting() } @Test - public void moveWithAtomicOption() + void moveWithAtomicOption() throws IOException { // fixtures final String content = "sample-content"; - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir", "dir2").file("dir/file1", content.getBytes()); // act diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewByteChannelIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelIT.java similarity index 80% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewByteChannelIT.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelIT.java index f8b3cd2a..0ebfd892 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewByteChannelIT.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelIT.java @@ -1,4 +1,4 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; @@ -11,7 +11,12 @@ import java.nio.channels.NonReadableChannelException; import java.nio.channels.NonWritableChannelException; import java.nio.channels.SeekableByteChannel; -import java.nio.file.*; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.EnumSet; import java.util.UUID; @@ -19,9 +24,12 @@ import org.junit.jupiter.api.BeforeEach; 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.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class NewByteChannelIT +class NewByteChannelIT extends S3UnitTestBase { @@ -36,7 +44,7 @@ public class NewByteChannelIT public void setup() throws IOException { - System.clearProperty(S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS); + System.clearProperty(S3FileSystemProvider.S3_FACTORY_CLASS); fileSystemAmazon = build(); } @@ -63,7 +71,7 @@ private static FileSystem createNewFileSystem() } @Test - public void newByteChannelCreateAndWrite() + void newByteChannelCreateAndWrite() throws IOException { final String content = "sample content"; @@ -83,7 +91,7 @@ public void newByteChannelCreateAndWrite() } @Test - public void newByteChannelWrite() + void newByteChannelWrite() throws IOException { final String content = "sample content"; @@ -100,7 +108,7 @@ public void newByteChannelWrite() } @Test - public void newByteChannelWriteWithoutPermission() + void newByteChannelWriteWithoutPermission() throws IOException { final String content = "sample content"; @@ -110,16 +118,17 @@ public void newByteChannelWriteWithoutPermission() try (SeekableByteChannel seek = fileSystemAmazon.provider().newByteChannel(file, EnumSet.of(StandardOpenOption.READ))) { - Exception exception = assertThrows(NonWritableChannelException.class, () -> { - seek.write(ByteBuffer.wrap(content.getBytes())); - }); + byte[] bytes = content.getBytes(); + ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + Exception exception = assertThrows(NonWritableChannelException.class, + () -> seek.write(byteBuffer)); assertNotNull(exception); } } @Test - public void newByteChannelRead() + void newByteChannelRead() throws IOException { final String content = "sample content"; @@ -140,18 +149,20 @@ public void newByteChannelRead() } @Test - public void newByteChannelReadWithoutPermission() + void newByteChannelReadWithoutPermission() throws IOException { final String content = "sample content"; Path file = uploadSingleFile(content); try (SeekableByteChannel seek = fileSystemAmazon.provider().newByteChannel(file, - EnumSet.of(StandardOpenOption.WRITE))) + EnumSet.of( + StandardOpenOption.WRITE))) { - Exception exception = assertThrows(NonReadableChannelException.class, () -> { - seek.read(ByteBuffer.allocate(content.length())); - }); + int length = content.length(); + ByteBuffer byteBuffer = ByteBuffer.allocate(length); + Exception exception = assertThrows(NonReadableChannelException.class, + () -> seek.read(byteBuffer)); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewByteChannelTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelTest.java similarity index 81% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewByteChannelTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelTest.java index df3f36d3..ff3081ee 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewByteChannelTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewByteChannelTest.java @@ -1,23 +1,32 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SeekableByteChannel; -import java.nio.file.*; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.EnumSet; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -public class NewByteChannelTest +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.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class NewByteChannelTest extends S3UnitTestBase { @@ -31,18 +40,18 @@ public void setup() } @Test - public void seekable() + void seekable() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + final S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", "".getBytes()); - Path base = createNewS3FileSystem().getPath("/bucketA", "dir"); - + final Path base = createNewS3FileSystem().getPath("/bucketA", "dir"); final String content = "content"; + final Path filePath = base.resolve("file"); - try (SeekableByteChannel seekable = s3fsProvider.newByteChannel(base.resolve("file"), + try (SeekableByteChannel seekable = s3fsProvider.newByteChannel(filePath, EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.READ))) { @@ -54,20 +63,19 @@ public void seekable() seekable.read(bufferRead); assertArrayEquals(bufferRead.array(), buffer.array()); - seekable.close(); } - assertArrayEquals(content.getBytes(), Files.readAllBytes(base.resolve("file"))); + assertArrayEquals(content.getBytes(), Files.readAllBytes(filePath)); } @Test - public void seekableSize() + void seekableSize() throws IOException { final String content = "content"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", content.getBytes()); Path base = createNewS3FileSystem().getPath("/bucketA/dir"); @@ -83,12 +91,12 @@ public void seekableSize() } @Test - public void seekableAnotherSize() + void seekableAnotherSize() throws IOException { final String content = "content-more-large"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", content.getBytes()); Path base = createNewS3FileSystem().getPath("/bucketA/dir"); @@ -103,13 +111,13 @@ public void seekableAnotherSize() } @Test - public void seekablePosition() + void seekablePosition() throws IOException { final String content = "content"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", content.getBytes()); Path base = createNewS3FileSystem().getPath("/bucketA/dir"); @@ -130,13 +138,13 @@ public void seekablePosition() } @Test - public void seekablePositionRead() + void seekablePositionRead() throws IOException { final String content = "content-more-larger"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", content.getBytes()); Path base = createNewS3FileSystem().getPath("/bucketA/dir"); @@ -158,12 +166,12 @@ public void seekablePositionRead() } @Test - public void seekablePositionWrite() + void seekablePositionWrite() throws IOException { final String content = "content-more-larger"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", content.getBytes()); Path base = createNewS3FileSystem().getPath("/bucketA/dir"); @@ -186,11 +194,11 @@ public void seekablePositionWrite() } @Test - public void seekableIsOpen() + void seekableIsOpen() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file"); Path base = createNewS3FileSystem().getPath("/bucketA/dir"); @@ -210,11 +218,11 @@ public void seekableIsOpen() } @Test - public void seekableRead() + void seekableRead() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); final String content = "content"; @@ -235,13 +243,13 @@ public void seekableRead() } @Test - public void seekableReadPartialContent() + void seekableReadPartialContent() throws IOException { // fixtures final String content = "content"; - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", content.getBytes()); Path file = createNewS3FileSystem().getPath("/bucketA/dir/file"); @@ -259,13 +267,13 @@ public void seekableReadPartialContent() } @Test - public void seekableTruncate() + void seekableTruncate() throws IOException { final String content = "content"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", content.getBytes()); Path file = createNewS3FileSystem().getPath("/bucketA/dir/file"); @@ -281,13 +289,13 @@ public void seekableTruncate() } @Test - public void seekableAnotherTruncate() + void seekableAnotherTruncate() throws IOException { final String content = "content"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", content.getBytes()); Path file = createNewS3FileSystem().getPath("/bucketA/dir/file"); @@ -303,13 +311,13 @@ public void seekableAnotherTruncate() } @Test - public void seekableruncateGreatherThanSize() + void seekableruncateGreatherThanSize() throws IOException { final String content = "content"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file", content.getBytes()); Path file = createNewS3FileSystem().getPath("/bucketA/dir/file"); @@ -324,17 +332,17 @@ public void seekableruncateGreatherThanSize() } @Test - public void seekableCreateEmpty() + void seekableCreateEmpty() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); Path base = createNewS3FileSystem().getPath("/bucketA/dir"); Path file = base.resolve("file"); - try (SeekableByteChannel seekable = s3fsProvider.newByteChannel(file, EnumSet.of(StandardOpenOption.CREATE))) + try (SeekableByteChannel ignored = s3fsProvider.newByteChannel(file, EnumSet.of(StandardOpenOption.CREATE))) { // } @@ -344,18 +352,18 @@ public void seekableCreateEmpty() } @Test - public void seekableDeleteOnClose() + void seekableDeleteOnClose() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); Path base = createNewS3FileSystem().getPath("/bucketA/dir"); Path file = Files.createFile(base.resolve("file")); - try (SeekableByteChannel seekable = s3fsProvider.newByteChannel(file, - EnumSet.of(StandardOpenOption.DELETE_ON_CLOSE))) + try (SeekableByteChannel ignored = s3fsProvider.newByteChannel(file, + EnumSet.of(StandardOpenOption.DELETE_ON_CLOSE))) { } @@ -363,11 +371,11 @@ public void seekableDeleteOnClose() } @Test - public void seekableCloseTwice() + void seekableCloseTwice() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); Path base = createNewS3FileSystem().getPath("/bucketA/dir"); @@ -381,12 +389,12 @@ public void seekableCloseTwice() } @Test - public void seekableNotExists() + void seekableNotExists() { // We're expecting an exception here to be thrown Exception exception = assertThrows(NoSuchFileException.class, () -> { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); Path base = createNewS3FileSystem().getPath("/bucketA", "dir"); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewDirectoryStreamTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewDirectoryStreamTest.java similarity index 67% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewDirectoryStreamTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewDirectoryStreamTest.java index 1f5a1eb4..8671bcbd 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewDirectoryStreamTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewDirectoryStreamTest.java @@ -1,15 +1,18 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; import org.carlspring.cloud.storage.s3fs.util.MockBucket; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; -import java.nio.file.*; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; @@ -17,9 +20,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class NewDirectoryStreamTest +class NewDirectoryStreamTest extends S3UnitTestBase { @@ -33,11 +39,11 @@ public void setup() } @Test - public void createStreamDirectoryReader() + void createStreamDirectoryReader() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("file1"); // act @@ -48,11 +54,11 @@ public void createStreamDirectoryReader() } @Test - public void createAnotherStreamDirectoryReader() + void createAnotherStreamDirectoryReader() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("file1", "file2"); // act @@ -63,11 +69,11 @@ public void createAnotherStreamDirectoryReader() } @Test - public void createAnotherWithDirStreamDirectoryReader() + void createAnotherWithDirStreamDirectoryReader() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir1").file("file1"); // act @@ -78,11 +84,11 @@ public void createAnotherWithDirStreamDirectoryReader() } @Test - public void createStreamDirectoryFromDirectoryReader() + void createStreamDirectoryFromDirectoryReader() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir", "dir/file2").file("dir/file1"); // act @@ -93,33 +99,32 @@ public void createStreamDirectoryFromDirectoryReader() } @Test - public void removeIteratorStreamDirectoryReader() + void removeIteratorStreamDirectoryReader() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(UnsupportedOperationException.class, () -> { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir1").file("dir1/file1", "content".getBytes()); + // fixtures + S3ClientMock client = S3MockFactory.getS3ClientMock(); + client.bucket("bucketA").dir("dir1").file("dir1/file1", "content".getBytes()); - // act - Path bucket = createNewS3FileSystem().getPath("/bucketA"); + // act + Path bucket = createNewS3FileSystem().getPath("/bucketA"); - // act - try (DirectoryStream dir = Files.newDirectoryStream(bucket)) - { - dir.iterator().remove(); - } - }); + try (DirectoryStream dir = Files.newDirectoryStream(bucket)) + { + Iterator iterator = dir.iterator(); - assertNotNull(exception); + // We're expecting an exception here to be thrown + Exception exception = assertThrows(UnsupportedOperationException.class, iterator::remove); + assertNotNull(exception); + } } @Test - public void list999Paths() + void list999Paths() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); MockBucket bucketA = client.bucket("bucketA"); @@ -134,10 +139,8 @@ public void list999Paths() int count = 0; try (DirectoryStream files = Files.newDirectoryStream(bucket)) { - Iterator iterator = files.iterator(); - while (iterator.hasNext()) + for (Path ignored : files) { - iterator.next(); count++; } } @@ -146,11 +149,11 @@ public void list999Paths() } @Test - public void list1050Paths() + void list1050Paths() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); MockBucket bucketA = client.bucket("bucketA"); final int count1050 = 1050; @@ -164,10 +167,8 @@ public void list1050Paths() int count = 0; try (DirectoryStream files = Files.newDirectoryStream(bucket)) { - Iterator iterator = files.iterator(); - while (iterator.hasNext()) + for (Path ignored : files) { - iterator.next(); count++; } } @@ -182,7 +183,8 @@ public void list1050Paths() * @param files String array of file names * @throws IOException */ - private void assertNewDirectoryStream(Path base, final String... files) + private void assertNewDirectoryStream(Path base, + final String... files) throws IOException { try (DirectoryStream dir = Files.newDirectoryStream(base)) diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewFileSystemIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemIT.java similarity index 83% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewFileSystemIT.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemIT.java index 8373e2dd..71fa15b0 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewFileSystemIT.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemIT.java @@ -1,4 +1,4 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; @@ -13,18 +13,21 @@ import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_IT; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; - -public class NewFileSystemIT +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +class NewFileSystemIT { private S3FileSystemProvider provider; @@ -34,7 +37,7 @@ public class NewFileSystemIT public void setup() throws IOException { - System.clearProperty(S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS); + System.clearProperty(S3FileSystemProvider.S3_FACTORY_CLASS); System.clearProperty(ACCESS_KEY); System.clearProperty(SECRET_KEY); @@ -57,7 +60,7 @@ public void setup() } @Test - public void createAuthenticatedByProperties() + void createAuthenticatedByProperties() { URI uri = URI.create("s3://yadi/"); @@ -69,7 +72,7 @@ public void createAuthenticatedByProperties() } @Test - public void createsAuthenticatedByEnvOverridesProps() + void createsAuthenticatedByEnvOverridesProps() { final Map env = buildFakeEnv(); @@ -79,7 +82,7 @@ public void createsAuthenticatedByEnvOverridesProps() } @Test - public void createsAuthenticatedBySystemProps() + void createsAuthenticatedBySystemProps() { doCallRealMethod().when(provider).overloadPropertiesWithSystemEnv(any(Properties.class), anyString()); @@ -97,7 +100,7 @@ public void createsAuthenticatedBySystemProps() } @Test - public void createsAuthenticatedBySystemEnv() + void createsAuthenticatedBySystemEnv() { doCallRealMethod().when(provider).overloadPropertiesWithSystemProps(any(Properties.class), anyString()); @@ -115,7 +118,7 @@ public void createsAuthenticatedBySystemEnv() } @Test - public void createsAuthenticatedByUri() + void createsAuthenticatedByUri() { final String accessKeyUri = "access-key-uri"; final String secretKeyUri = "secret-key-uri"; @@ -129,9 +132,9 @@ public void createsAuthenticatedByUri() @Test - public void createsAnonymousNotPossible() + void createsAnonymousNotPossible() { - FileSystem fileSystem = provider.newFileSystem(S3_GLOBAL_URI_IT, ImmutableMap.of()); + FileSystem fileSystem = provider.newFileSystem(S3_GLOBAL_URI_IT, ImmutableMap.of()); assertNotNull(fileSystem); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewFileSystemTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemTest.java similarity index 61% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewFileSystemTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemTest.java index 43acd6b9..6e0cb3e9 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewFileSystemTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewFileSystemTest.java @@ -1,36 +1,42 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; import org.carlspring.cloud.storage.s3fs.S3FileSystemConfigurationException; import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; +import org.carlspring.cloud.storage.s3fs.util.Constants; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; import java.io.IOException; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; import java.nio.file.FileSystemAlreadyExistsException; import java.util.Map; import java.util.Properties; import java.util.UUID; -import com.amazonaws.services.s3.internal.Constants; import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; -import static org.carlspring.cloud.storage.s3fs.S3FileSystemProvider.AMAZON_S3_FACTORY_CLASS; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; import static org.carlspring.cloud.storage.s3fs.S3FileSystemProvider.CHARSET_KEY; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; - -public class NewFileSystemTest +import static org.carlspring.cloud.storage.s3fs.S3FileSystemProvider.S3_FACTORY_CLASS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +class NewFileSystemTest extends S3UnitTestBase { @@ -44,57 +50,57 @@ public void setup() } @Test - public void misconfigure() + void misconfigure() { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(S3FileSystemConfigurationException.class, () -> { - Properties props = new Properties(); - props.setProperty(AMAZON_S3_FACTORY_CLASS, "org.carlspring.cloud.storage.s3fs.util.BrokenAmazonS3Factory"); + Properties props = new Properties(); + props.setProperty(S3_FACTORY_CLASS, "org.carlspring.cloud.storage.s3fs.util.BrokenS3Factory"); - s3fsProvider.createFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, props); - }); + // We're expecting an exception here to be thrown + Exception exception = assertThrows(S3FileSystemConfigurationException.class, + () -> s3fsProvider.createFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, + props)); assertNotNull(exception); } @Test - public void newS3FileSystemWithEmptyHostAndUserInfo() + void newS3FileSystemWithEmptyHostAndUserInfo() { FileSystem s3fs = s3fsProvider.newFileSystem(URI.create("s3:///bucket/file"), - ImmutableMap.of()); + ImmutableMap.of()); assertEquals(Constants.S3_HOSTNAME, ((S3FileSystem) s3fs).getKey()); } @Test - public void newS3FileSystemWithEmptyHost() + void newS3FileSystemWithEmptyHost() { FileSystem s3fs = s3fsProvider.newFileSystem(URI.create("s3://access-key:secret-key@/bucket/file"), - ImmutableMap.of()); + ImmutableMap.of()); assertEquals("access-key:secret-key@" + Constants.S3_HOSTNAME, ((S3FileSystem) s3fs).getKey()); } @Test - public void newS3FileSystemWithCustomHost() + void newS3FileSystemWithCustomHost() { FileSystem s3fs = s3fsProvider.newFileSystem(URI.create("s3://access-key:secret-key@my.ceph.storage"), - ImmutableMap.of()); + ImmutableMap.of()); assertEquals("access-key:secret-key@my.ceph.storage", ((S3FileSystem) s3fs).getKey()); } @Test - public void newS3FileSystemWithCustomHostAndBucket() + void newS3FileSystemWithCustomHostAndBucket() { FileSystem s3fs = s3fsProvider.newFileSystem(URI.create("s3://access-key:secret-key@my.ceph.storage/bucket"), - ImmutableMap.of()); + ImmutableMap.of()); assertEquals("access-key:secret-key@my.ceph.storage", ((S3FileSystem) s3fs).getKey()); } @Test - public void createsAuthenticatedByEnv() + void createsAuthenticatedByEnv() { Map env = buildFakeEnv(); @@ -110,7 +116,7 @@ public void createsAuthenticatedByEnv() } @Test - public void setEncodingByProperties() + void setEncodingByProperties() { Properties props = new Properties(); props.setProperty(SECRET_KEY, "better_secret_key"); @@ -121,16 +127,17 @@ public void setEncodingByProperties() URI uri = URI.create("s3://" + UUID.randomUUID().toString()); - FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); + FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); assertNotNull(fileSystem); verify(s3fsProvider).createFileSystem(eq(uri), - eq(buildFakeProps("better_access_key", "better_secret_key", "UTF-8"))); + eq(buildFakeProps("better_access_key", "better_secret_key", + StandardCharsets.UTF_8.toString()))); } @Test - public void createAuthenticatedByProperties() + void createAuthenticatedByProperties() { Properties props = new Properties(); props.setProperty(SECRET_KEY, "better_secret_key"); @@ -140,7 +147,7 @@ public void createAuthenticatedByProperties() URI uri = URI.create("s3://" + UUID.randomUUID().toString()); - FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); + FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); assertNotNull(fileSystem); @@ -148,7 +155,7 @@ public void createAuthenticatedByProperties() } @Test - public void createAuthenticatedBySystemEnvironment() + void createAuthenticatedBySystemEnvironment() { final String accessKey = "better-access-key"; final String secretKey = "better-secret-key"; @@ -159,27 +166,22 @@ public void createAuthenticatedBySystemEnvironment() doReturn(secretKey).when(s3fsProvider).systemGetEnv(SECRET_KEY); doCallRealMethod().when(s3fsProvider).overloadPropertiesWithSystemEnv(any(Properties.class), anyString()); - s3fsProvider.newFileSystem(uri, ImmutableMap.of()); + s3fsProvider.newFileSystem(uri, ImmutableMap.of()); - verify(s3fsProvider).createFileSystem(eq(uri), argThat(new ArgumentMatcher() - { - @Override - public boolean matches(Properties properties) - { - assertEquals(accessKey, properties.getProperty(ACCESS_KEY)); - assertEquals(secretKey, properties.getProperty(SECRET_KEY)); - - return true; - } + verify(s3fsProvider).createFileSystem(eq(uri), argThat(properties -> { + assertEquals(accessKey, properties.getProperty(ACCESS_KEY)); + assertEquals(secretKey, properties.getProperty(SECRET_KEY)); + + return true; })); } @Test - public void createsAnonymous() + void createsAnonymous() { URI uri = URI.create("s3://" + UUID.randomUUID().toString()); - FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); + FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); assertNotNull(fileSystem); @@ -187,7 +189,7 @@ public void createsAnonymous() } @Test - public void createWithDefaultEndpoint() + void createWithDefaultEndpoint() { Properties props = new Properties(); props.setProperty(SECRET_KEY, "better_secret_key"); @@ -198,7 +200,7 @@ public void createWithDefaultEndpoint() URI uri = URI.create("s3:///"); - FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); + FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); assertNotNull(fileSystem); @@ -207,92 +209,97 @@ public void createWithDefaultEndpoint() } @Test - public void createWithOnlyAccessKey() + void createWithOnlyAccessKey() { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - Properties props = new Properties(); + Properties props = new Properties(); - URI uri = URI.create("s3://" + UUID.randomUUID().toString()); + URI uri = URI.create("s3://" + UUID.randomUUID().toString()); - props.setProperty(ACCESS_KEY, "better_access_key"); + props.setProperty(ACCESS_KEY, "better_access_key"); - doReturn(props).when(s3fsProvider).loadAmazonProperties(); + doReturn(props).when(s3fsProvider).loadAmazonProperties(); - s3fsProvider.newFileSystem(uri, ImmutableMap.of()); - }); + final ImmutableMap env = ImmutableMap.of(); + + // We're expecting an exception here to be thrown + Exception exception = assertThrows(IllegalArgumentException.class, + () -> s3fsProvider.newFileSystem(uri, env)); assertNotNull(exception); } @Test - public void createWithOnlySecretKey() + void createWithOnlySecretKey() { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - Properties props = new Properties(); - props.setProperty(SECRET_KEY, "better_secret_key"); + Properties props = new Properties(); + props.setProperty(SECRET_KEY, "better_secret_key"); + + doReturn(props).when(s3fsProvider).loadAmazonProperties(); - doReturn(props).when(s3fsProvider).loadAmazonProperties(); + URI uri = URI.create("s3://" + UUID.randomUUID().toString()); - URI uri = URI.create("s3://" + UUID.randomUUID().toString()); + final ImmutableMap env = ImmutableMap.of(); - s3fsProvider.newFileSystem(uri, ImmutableMap.of()); - }); + // We're expecting an exception here to be thrown + Exception exception = assertThrows(IllegalArgumentException.class, + () -> s3fsProvider.newFileSystem(uri, env)); assertNotNull(exception); } @Test - public void createFailsIfAlreadyCreated() + void createFailsIfAlreadyCreated() { + final URI uri = URI.create("s3://" + UUID.randomUUID().toString()); + final ImmutableMap env = ImmutableMap.of(); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(FileSystemAlreadyExistsException.class, () -> { - FileSystem fileSystem = s3fsProvider.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, - ImmutableMap.of()); + final Exception exception = assertThrows(FileSystemAlreadyExistsException.class, () -> { - assertNotNull(fileSystem); + final FileSystem fileSystem = s3fsProvider.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, env); - URI uri = URI.create("s3://" + UUID.randomUUID().toString()); + assertNotNull(fileSystem); - s3fsProvider.newFileSystem(uri, ImmutableMap.of()); + s3fsProvider.newFileSystem(uri, env); }); assertNotNull(exception); } @Test - public void createWithWrongEnv() + void createWithWrongEnv() { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - Map env = ImmutableMap.builder().put(ACCESS_KEY, 1234) - .put(SECRET_KEY, - "secret key") - .build(); + final Map env = ImmutableMap.builder().put(ACCESS_KEY, 1234) + .put(SECRET_KEY, "secret key") + .build(); - URI uri = URI.create("s3://" + UUID.randomUUID().toString()); + final URI uri = URI.create("s3://" + UUID.randomUUID().toString()); - FileSystem fileSystem = s3fsProvider.newFileSystem(uri, env); + final ImmutableMap emptyEnv = ImmutableMap.of(); + + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(IllegalArgumentException.class, () -> { + + final FileSystem fileSystem = s3fsProvider.newFileSystem(uri, env); assertNotNull(fileSystem); - s3fsProvider.newFileSystem(uri, ImmutableMap.of()); + s3fsProvider.newFileSystem(uri, emptyEnv); }); assertNotNull(exception); } @Test - public void getFileSystem() + void getFileSystem() { URI uri = URI.create("s3://" + UUID.randomUUID().toString()); - FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); + FileSystem fileSystem = s3fsProvider.newFileSystem(uri, ImmutableMap.of()); assertNotNull(fileSystem); - fileSystem = s3fsProvider.getFileSystem(uri, ImmutableMap.of()); + fileSystem = s3fsProvider.getFileSystem(uri, ImmutableMap.of()); assertNotNull(fileSystem); @@ -302,16 +309,16 @@ public void getFileSystem() } @Test - public void getUnknownFileSystem() + void getUnknownFileSystem() { FileSystem fileSystem = s3fsProvider.getFileSystem(URI.create("s3://endpoint20/bucket/path/to/file"), - ImmutableMap.of()); + ImmutableMap.of()); assertNotNull(fileSystem); } @Test - public void closeFileSystemReturnNewFileSystem() + void closeFileSystemReturnNewFileSystem() throws IOException { S3FileSystemProvider provider = new S3FileSystemProvider(); @@ -330,20 +337,19 @@ public void closeFileSystemReturnNewFileSystem() } @Test - public void createTwoFileSystemThrowError() + void createTwoFileSystemThrowError() { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(FileSystemAlreadyExistsException.class, () -> { - S3FileSystemProvider provider = new S3FileSystemProvider(); + S3FileSystemProvider provider = new S3FileSystemProvider(); - Map env = buildFakeEnv(); + Map env = buildFakeEnv(); - FileSystem fileSystem = provider.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, env); + FileSystem fileSystem = provider.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, env); - assertNotNull(fileSystem); + assertNotNull(fileSystem); - provider.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, env); - }); + // We're expecting an exception here to be thrown + Exception exception = assertThrows(FileSystemAlreadyExistsException.class, + () -> provider.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, env)); assertNotNull(exception); } @@ -356,7 +362,9 @@ public void createTwoFileSystemThrowError() .build(); } - private Properties buildFakeProps(String access_key, String secret_key, String encoding) + private Properties buildFakeProps(String access_key, + String secret_key, + String encoding) { Properties props = buildFakeProps(access_key, secret_key); props.setProperty(CHARSET_KEY, encoding); @@ -365,10 +373,11 @@ private Properties buildFakeProps(String access_key, String secret_key, String e } - private Properties buildFakeProps(String access_key, String secret_key) + private Properties buildFakeProps(String access_key, + String secret_key) { Properties props = new Properties(); - props.setProperty(AMAZON_S3_FACTORY_CLASS, "org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory"); + props.setProperty(S3_FACTORY_CLASS, "org.carlspring.cloud.storage.s3fs.util.S3MockFactory"); if (access_key != null) { diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewInputStreamTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewInputStreamTest.java similarity index 59% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewInputStreamTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewInputStreamTest.java index 0355cce9..b245c328 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewInputStreamTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewInputStreamTest.java @@ -1,16 +1,16 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; import org.carlspring.cloud.storage.s3fs.util.IOUtils; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.nio.file.FileSystem; import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.NoSuchFileException; @@ -20,11 +20,14 @@ import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; -import static org.junit.jupiter.api.Assertions.*; - -public class NewInputStreamTest +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +class NewInputStreamTest extends S3UnitTestBase { @@ -38,11 +41,11 @@ public void setup() } @Test - public void inputStreamFile() + void inputStreamFile() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("file1", "content".getBytes()); Path file = createNewS3FileSystem().getPath("/bucketA/file1"); @@ -56,13 +59,13 @@ public void inputStreamFile() } @Test - public void anotherInputStreamFile() + void anotherInputStreamFile() throws IOException { String res = "another content"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1", res.getBytes()); // act @@ -78,20 +81,21 @@ public void anotherInputStreamFile() } @Test - public void newInputStreamFileNotExists() + void newInputStreamFileNotExists() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(NoSuchFileException.class, () -> { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir"); + // fixtures + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + client.bucket("bucketA").dir("dir"); - // act - S3FileSystem fileSystem = createNewS3FileSystem(); + // act + final S3FileSystem fileSystem = createNewS3FileSystem(); - Path file = fileSystem.getPath("/bucketA/dir/file1"); + final Path file = fileSystem.getPath("/bucketA/dir/file1"); - try (InputStream inputStream = s3fsProvider.newInputStream(file)) + // We're expecting an exception here to be thrown + final Exception exception = assertThrows(NoSuchFileException.class, () -> { + try (InputStream ignored = s3fsProvider.newInputStream(file)) { fail("The file does not exist"); } @@ -101,26 +105,29 @@ public void newInputStreamFileNotExists() } @Test - public void inputStreamDirectory() + void inputStreamDirectory() + throws IOException { - // We're expecting an exception here to be thrown - Exception exception = assertThrows(IOException.class, () -> { - // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); - client.bucket("bucketA").dir("dir"); + // fixtures + final S3ClientMock client = S3MockFactory.getS3ClientMock(); + client.bucket("bucketA").dir("dir"); - Path result = s3fsProvider.newFileSystem(URI.create("s3://endpoint1/"), buildFakeEnv()).getPath("/bucketA/dir"); + final URI uri = URI.create("s3://endpoint1/"); + final Map envMap = buildFakeEnv(); + final FileSystem fileSystem = s3fsProvider.newFileSystem(uri, envMap); + Path result = fileSystem.getPath("/bucketA/dir"); - // act - s3fsProvider.newInputStream(result); - }); + // We're expecting an exception here to be thrown + Exception exception = assertThrows(IOException.class, () -> s3fsProvider.newInputStream(result)); assertNotNull(exception); } private Map buildFakeEnv() { - return ImmutableMap.builder().put(ACCESS_KEY, "accesskey").put(SECRET_KEY, "secretkey").build(); + return ImmutableMap.builder().put(ACCESS_KEY, "access-key") + .put(SECRET_KEY, "secret-key") + .build(); } /** diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewOutputStreamTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewOutputStreamTest.java similarity index 75% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewOutputStreamTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewOutputStreamTest.java index 1e49f4aa..7eb48d66 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/NewOutputStreamTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/NewOutputStreamTest.java @@ -1,26 +1,34 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; import java.io.OutputStream; import java.net.URI; -import java.nio.file.*; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Map; import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; -import static org.junit.jupiter.api.Assertions.*; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; -public class NewOutputStreamTest +class NewOutputStreamTest extends S3UnitTestBase { @@ -42,7 +50,7 @@ public void tearDown() } @Test - public void outputStreamWithCreateNew() + void outputStreamWithCreateNew() throws IOException { Path base = getS3Directory(); @@ -64,13 +72,13 @@ public void outputStreamWithCreateNew() } @Test - public void outputStreamWithTruncate() + void outputStreamWithTruncate() throws IOException { String initialContent = "Content line 1\n" + "Content line 2\n" + "Content line 3\n" + "Content line 4"; // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").file("file1", initialContent.getBytes()); Path file = createNewS3FileSystem().getPath("/bucketA/file1"); @@ -91,7 +99,7 @@ public void outputStreamWithTruncate() } @Test - public void outputStreamWithCreateNewAndFileExists() + void outputStreamWithCreateNewAndFileExists() { // We're expecting an exception here to be thrown Exception exception = assertThrows(FileAlreadyExistsException.class, () -> { @@ -105,7 +113,7 @@ public void outputStreamWithCreateNewAndFileExists() } @Test - public void outputStreamWithCreateAndFileExists() + void outputStreamWithCreateAndFileExists() throws IOException { Path base = getS3Directory(); @@ -129,7 +137,7 @@ public void outputStreamWithCreateAndFileExists() } @Test - public void outputStreamWithCreateAndFileNotExists() + void outputStreamWithCreateAndFileNotExists() throws IOException { Path base = getS3Directory(); @@ -150,7 +158,7 @@ public void outputStreamWithCreateAndFileNotExists() } @Test - public void anotherOutputStream() + void anotherOutputStream() throws IOException { Path base = getS3Directory(); @@ -175,14 +183,15 @@ private Path getS3Directory() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); - return s3fsProvider.newFileSystem(URI.create("s3://endpoint1/"), - ImmutableMap.builder().put(ACCESS_KEY, "access_key") - .put(SECRET_KEY, "secret_key") - .build()) - .getPath("/bucketA/dir"); + final URI uri = URI.create("s3://endpoint1/"); + final Map envMap = ImmutableMap.builder().put(ACCESS_KEY, "access_key") + .put(SECRET_KEY, "secret_key") + .build(); + final FileSystem fileSystem = s3fsProvider.newFileSystem(uri, envMap); + return fileSystem.getPath("/bucketA/dir"); } /** diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/ReadAttributesTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/ReadAttributesTest.java similarity index 83% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/ReadAttributesTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/ReadAttributesTest.java index 8f136e79..01b43f59 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/ReadAttributesTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/ReadAttributesTest.java @@ -1,16 +1,20 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3ClientMock; -import org.carlspring.cloud.storage.s3fs.util.AmazonS3MockFactory; import org.carlspring.cloud.storage.s3fs.util.MockBucket; +import org.carlspring.cloud.storage.s3fs.util.S3ClientMock; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; +import org.carlspring.cloud.storage.s3fs.util.S3MockFactory; import java.io.IOException; -import java.nio.file.*; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.DosFileAttributes; import java.nio.file.attribute.PosixFileAttributes; @@ -22,9 +26,15 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.carlspring.cloud.storage.s3fs.util.FileAttributeBuilder.build; -import static org.junit.jupiter.api.Assertions.*; - -public class ReadAttributesTest +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.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ReadAttributesTest extends S3UnitTestBase { @@ -37,16 +47,14 @@ public void setup() fileSystem = s3fsProvider.newFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST, null); } - // readAttributes BasicFileAttributes.class - @Test - public void readAttributesFileEmpty() + void readAttributesFileEmpty() throws IOException { // fixtures final String content = ""; - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1", content.getBytes()); Path file1 = createNewS3FileSystem().getPath("/bucketA/dir/file1"); @@ -62,11 +70,11 @@ public void readAttributesFileEmpty() } @Test - public void readAttributesFile() + void readAttributesFile() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); MockBucket mockBucket = client.bucket("bucketA").dir("dir"); final String content = "sample"; @@ -93,11 +101,11 @@ public void readAttributesFile() } @Test - public void readAttributesDirectory() + void readAttributesDirectory() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); MockBucket mocket = client.bucket("bucketA").dir("dir"); Path memoryDir = mocket.resolve("dir/"); @@ -129,11 +137,11 @@ public void readAttributesDirectory() } @Test - public void readAnotherAttributesDirectory() + void readAnotherAttributesDirectory() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/dir", "content".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -146,11 +154,11 @@ public void readAnotherAttributesDirectory() } @Test - public void readAttributesDirectoryNotExistsAtAmazon() + void readAttributesDirectoryNotExistsAtAmazon() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); MockBucket mockBucket = client.bucket("bucketA").dir("dir", "dir/dir2"); Path memoryDir = mockBucket.resolve("dir/dir2/"); @@ -182,11 +190,11 @@ public void readAttributesDirectoryNotExistsAtAmazon() } @Test - public void readAttributesRegenerateCacheWhenNotExists() + void readAttributesRegenerateCacheWhenNotExists() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1", "".getBytes()); S3Path file1 = createNewS3FileSystem().getPath("/bucketA/dir/file1"); @@ -206,11 +214,11 @@ public void readAttributesRegenerateCacheWhenNotExists() } @Test - public void readAttributesPosixRegenerateCacheWhenNotExists() + void readAttributesPosixRegenerateCacheWhenNotExists() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1", "".getBytes()); S3Path file1 = createNewS3FileSystem().getPath("/bucketA/dir/file1"); @@ -230,12 +238,12 @@ public void readAttributesPosixRegenerateCacheWhenNotExists() } @Test - public void readAttributesFileNotExists() + void readAttributesFileNotExists() { // We're expecting an exception here to be thrown Exception exception = assertThrows(NoSuchFileException.class, () -> { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); FileSystem fs = createNewS3FileSystem(); @@ -248,12 +256,12 @@ public void readAttributesFileNotExists() } @Test - public void readAttributesFileNotExistsButExistsAnotherThatContainsTheKey() + void readAttributesFileNotExistsButExistsAnotherThatContainsTheKey() { // We're expecting an exception here to be thrown Exception exception = assertThrows(NoSuchFileException.class, () -> { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir").file("dir/file1hello", "content".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -266,12 +274,12 @@ public void readAttributesFileNotExistsButExistsAnotherThatContainsTheKey() } @Test - public void readAttributesNotAcceptedSubclass() + void readAttributesNotAcceptedSubclass() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); client.bucket("bucketA").dir("dir"); FileSystem fs = createNewS3FileSystem(); @@ -286,13 +294,13 @@ public void readAttributesNotAcceptedSubclass() // readAttributes permission PosixFileAttributes.class @Test - public void readPosixPermissionOwnerWriteAttributes() + void readPosixPermissionOwnerWriteAttributes() throws IOException { // fixtures - AmazonS3MockFactory.getAmazonClientMock() - .bucket("bucketA") - .file("file", + S3MockFactory.getS3ClientMock() + .bucket("bucketA") + .file("file", "content".getBytes(), build("posix:permissions", Sets.newHashSet(PosixFilePermission.OWNER_READ, @@ -308,13 +316,13 @@ public void readPosixPermissionOwnerWriteAttributes() } @Test - public void readPosixPermissionOwnerExecuteAttributes() + void readPosixPermissionOwnerExecuteAttributes() throws IOException { // fixtures - AmazonS3MockFactory.getAmazonClientMock() - .bucket("bucketA") - .file("file", + S3MockFactory.getS3ClientMock() + .bucket("bucketA") + .file("file", "content".getBytes(), build("posix:permissions", Sets.newHashSet(PosixFilePermission.OWNER_READ, @@ -330,13 +338,13 @@ public void readPosixPermissionOwnerExecuteAttributes() } @Test - public void readPosixPermissionGroupWriteAttributes() + void readPosixPermissionGroupWriteAttributes() throws IOException { // fixtures - AmazonS3MockFactory.getAmazonClientMock() - .bucket("bucketA") - .file("file", + S3MockFactory.getS3ClientMock() + .bucket("bucketA") + .file("file", "content".getBytes(), build("posix:permissions", Sets.newHashSet(PosixFilePermission.OWNER_READ, @@ -352,13 +360,13 @@ public void readPosixPermissionGroupWriteAttributes() } @Test - public void readPosixPermissionGroupExecuteAttributes() + void readPosixPermissionGroupExecuteAttributes() throws IOException { // fixtures - AmazonS3MockFactory.getAmazonClientMock() - .bucket("bucketA") - .file("file", + S3MockFactory.getS3ClientMock() + .bucket("bucketA") + .file("file", "content".getBytes(), build("posix:permissions", Sets.newHashSet(PosixFilePermission.OWNER_READ, @@ -374,13 +382,13 @@ public void readPosixPermissionGroupExecuteAttributes() } @Test - public void readPosixPermissionOtherWriteAttributes() + void readPosixPermissionOtherWriteAttributes() throws IOException { // fixtures - AmazonS3MockFactory.getAmazonClientMock() - .bucket("bucketA") - .file("file", + S3MockFactory.getS3ClientMock() + .bucket("bucketA") + .file("file", "content".getBytes(), build("posix:permissions", Sets.newHashSet(PosixFilePermission.OWNER_READ, @@ -396,13 +404,13 @@ public void readPosixPermissionOtherWriteAttributes() } @Test - public void readPosixPermissionOtherExecuteAttributes() + void readPosixPermissionOtherExecuteAttributes() throws IOException { // fixtures - AmazonS3MockFactory.getAmazonClientMock() - .bucket("bucketA") - .file("file", + S3MockFactory.getS3ClientMock() + .bucket("bucketA") + .file("file", "content".getBytes(), build("posix:permissions", Sets.newHashSet(PosixFilePermission.OWNER_READ, @@ -420,13 +428,13 @@ public void readPosixPermissionOtherExecuteAttributes() // readAttributes owner and group PosixFileAttributes @Test - public void readPosixPermissionOwnerAndGroupAttributes() + void readPosixPermissionOwnerAndGroupAttributes() throws IOException { // fixtures - AmazonS3MockFactory.getAmazonClientMock() - .bucket("bucketA") - .file("file", + S3MockFactory.getS3ClientMock() + .bucket("bucketA") + .file("file", "content".getBytes(), build("posix:permissions", Sets.newHashSet(PosixFilePermission.OWNER_READ))); @@ -443,11 +451,11 @@ public void readPosixPermissionOwnerAndGroupAttributes() // readAttributes String all @Test - public void readAttributesAll() + void readAttributesAll() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); final String content = "sample"; @@ -473,11 +481,11 @@ public void readAttributesAll() } @Test - public void readAttributesAllBasic() + void readAttributesAllBasic() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); Files.write(client.bucket("bucketA").dir("dir").resolve("dir/file"), "sample".getBytes()); @@ -494,11 +502,11 @@ public void readAttributesAllBasic() } @Test - public void readAttributesOnlyOne() + void readAttributesOnlyOne() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); Files.write(client.bucket("bucketA").dir("dir").resolve("dir/file"), "sample".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -512,11 +520,11 @@ public void readAttributesOnlyOne() } @Test - public void readAttributesPartial() + void readAttributesPartial() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); Files.write(client.bucket("bucketA").dir("dir").resolve("dir/file"), "sample".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -531,11 +539,11 @@ public void readAttributesPartial() } @Test - public void readAttributesPartialBasic() + void readAttributesPartialBasic() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); Files.write(client.bucket("bucketA").dir("dir").resolve("dir/file"), "sample".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -551,11 +559,11 @@ public void readAttributesPartialBasic() } @Test - public void readAttributesAllPosix() + void readAttributesAllPosix() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); Files.write(client.bucket("bucketA").dir("dir").resolve("dir/file"), "sample".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -567,11 +575,11 @@ public void readAttributesAllPosix() } @Test - public void readAttributesPartialPosix() + void readAttributesPartialPosix() throws IOException { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); Files.write(client.bucket("bucketA").dir("dir").resolve("dir/file"), "sample".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -583,12 +591,12 @@ public void readAttributesPartialPosix() } @Test - public void readAttributesNullAttrs() + void readAttributesNullAttrs() { // We're expecting an exception here to be thrown Exception exception = assertThrows(IllegalArgumentException.class, () -> { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); Files.write(client.bucket("bucketA").dir("dir").resolve("dir/file"), "sample".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -601,12 +609,12 @@ public void readAttributesNullAttrs() } @Test - public void readAttributesDosNotSupported() + void readAttributesDosNotSupported() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); Files.write(client.bucket("bucketA").dir("dir").resolve("dir/file"), "sample".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -619,12 +627,12 @@ public void readAttributesDosNotSupported() } @Test - public void readAttributesUnknownNotSupported() + void readAttributesUnknownNotSupported() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { // fixtures - AmazonS3ClientMock client = AmazonS3MockFactory.getAmazonClientMock(); + S3ClientMock client = S3MockFactory.getS3ClientMock(); Files.write(client.bucket("bucketA").dir("dir").resolve("dir/file"), "sample".getBytes()); FileSystem fs = createNewS3FileSystem(); @@ -638,7 +646,7 @@ public void readAttributesUnknownNotSupported() // setAttribute @Test - public void readAttributesObject() + void readAttributesObject() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/SetAttributeTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/SetAttributeTest.java similarity index 83% rename from src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/SetAttributeTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/SetAttributeTest.java index f0217558..93ad7620 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/FileSystemProvider/SetAttributeTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/fileSystemProvider/SetAttributeTest.java @@ -1,7 +1,6 @@ -package org.carlspring.cloud.storage.s3fs.FileSystemProvider; +package org.carlspring.cloud.storage.s3fs.fileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; @@ -14,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -public class SetAttributeTest +class SetAttributeTest extends S3UnitTestBase { @@ -28,12 +27,13 @@ public void setup() } @Test - public void readAttributesObject() + void readAttributesObject() { + Object value = new Object(); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(UnsupportedOperationException.class, () -> { - s3fsProvider.setAttribute(null, "", new Object()); - }); + Exception exception = assertThrows(UnsupportedOperationException.class, + () -> s3fsProvider.setAttribute(null, "", value)); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/EndsWithTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/EndsWithTest.java similarity index 83% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/EndsWithTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/EndsWithTest.java index b68265a9..d9235222 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/EndsWithTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/EndsWithTest.java @@ -1,7 +1,6 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; @@ -18,7 +17,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -public class EndsWithTest +class EndsWithTest extends S3UnitTestBase { @@ -43,67 +42,67 @@ private S3Path getPath(String path) } @Test - public void endsWithAbsoluteRelative() + void endsWithAbsoluteRelative() { assertTrue(getPath("/bucket/file1").endsWith(getPath("file1"))); } @Test - public void endsWithAbsoluteAbsolute() + void endsWithAbsoluteAbsolute() { assertTrue(getPath("/bucket/file1").endsWith(getPath("/bucket/file1"))); } @Test - public void endsWithRelativeRelative() + void endsWithRelativeRelative() { assertTrue(getPath("file/file1").endsWith(getPath("file1"))); } @Test - public void endsWithRelativeAbsolute() + void endsWithRelativeAbsolute() { assertFalse(getPath("file/file1").endsWith(getPath("/bucket"))); } @Test - public void endsWithDifferentFileSystem() + void endsWithDifferentFileSystem() { assertFalse(getPath("/bucket/file1").endsWith(Paths.get("/bucket/file1"))); } @Test - public void endsWithBlankRelativeAbsolute() + void endsWithBlankRelativeAbsolute() { assertFalse(getPath("").endsWith(getPath("/bucket"))); } @Test - public void endsWithBlankBlank() + void endsWithBlankBlank() { assertTrue(getPath("").endsWith(getPath(""))); } @Test - public void endsWithRelativeBlankAbsolute() + void endsWithRelativeBlankAbsolute() { assertFalse(getPath("/bucket/file1").endsWith(getPath(""))); } @Test - public void endsWithRelativeBlankRelative() + void endsWithRelativeBlankRelative() { assertFalse(getPath("file1").endsWith(getPath(""))); } @Test - public void endsWithDifferent() + void endsWithDifferent() { assertFalse(getPath("/bucket/dir/dir/file1").endsWith(getPath("fail/dir/file1"))); } @Test - public void endsWithDifferentProvider() + void endsWithDifferentProvider() throws IOException { try (FileSystem linux = MemoryFileSystemBuilder.newLinux().build("linux")) @@ -122,7 +121,7 @@ public void endsWithDifferentProvider() } @Test - public void endsWithString() + void endsWithString() { // endsWithAbsoluteRelative(){ assertTrue(getPath("/bucket/file1").endsWith("file1")); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/EqualsTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/EqualsTest.java similarity index 87% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/EqualsTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/EqualsTest.java index bf22d49d..8d4c3f3f 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/EqualsTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/EqualsTest.java @@ -1,7 +1,6 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; @@ -19,8 +18,9 @@ import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_TEST; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; -public class EqualsTest +class EqualsTest extends S3UnitTestBase { @@ -47,7 +47,7 @@ private S3Path getPath(String path) } @Test - public void equals() + void equals() { Path path = getPath("/bucketA/dir/file"); Path path2 = getPath("/bucketA/dir/file"); @@ -56,7 +56,7 @@ public void equals() } @Test - public void equalsDir() + void equalsDir() { Path path = getPath("/bucketA/dir/"); Path path2 = getPath("/bucketA/dir/"); @@ -65,7 +65,7 @@ public void equalsDir() } @Test - public void equalsBucket() + void equalsBucket() { Path path = getPath("/bucketA/"); Path path2 = getPath("/bucketA/"); @@ -74,7 +74,7 @@ public void equalsBucket() } @Test - public void equalsBucketWithoutEndSlash() + void equalsBucketWithoutEndSlash() { Path path = getPath("/bucketA/"); Path path2 = getPath("/bucketA"); @@ -83,7 +83,7 @@ public void equalsBucketWithoutEndSlash() } @Test - public void notEquals() + void notEquals() { Path path = getPath("/bucketA/dir/file"); Path path2 = getPath("/bucketA/dir/file2"); @@ -92,7 +92,7 @@ public void notEquals() } @Test - public void notEqualsDirFile() + void notEqualsDirFile() { Path path = getPath("/bucketA/dir/asd/"); Path path2 = getPath("/bucketA/dir/asd"); @@ -101,15 +101,15 @@ public void notEqualsDirFile() } @Test - public void notEqualsNull() + void notEqualsNull() { Path path = getPath("/bucketA/dir/file"); - assertNotEquals(path, null); + assertNotNull(path); } @Test - public void notEqualsDifferentProvider() + void notEqualsDifferentProvider() throws IOException { Path path = getPath("/c/dir/file"); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetFileNameTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/GetFileNameTest.java similarity index 85% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetFileNameTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/GetFileNameTest.java index b85dee9f..e525ec4d 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetFileNameTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/GetFileNameTest.java @@ -1,12 +1,10 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import java.io.IOException; -import java.nio.file.FileSystem; import java.nio.file.Path; import org.junit.jupiter.api.AfterEach; @@ -16,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -public class GetFileNameTest +class GetFileNameTest extends S3UnitTestBase { @@ -41,7 +39,7 @@ private S3Path getPath(String path) } @Test - public void getFileName() + void getFileName() { Path path = getPath("/bucketA/file"); Path name = path.getFileName(); @@ -50,7 +48,7 @@ public void getFileName() } @Test - public void getAnotherFileName() + void getAnotherFileName() { Path path = getPath("/bucketA/dir/another-file"); Path fileName = path.getFileName(); @@ -61,7 +59,7 @@ public void getAnotherFileName() } @Test - public void getFileNameBucket() + void getFileNameBucket() { Path path = getPath("/bucket"); Path name = path.getFileName(); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetKeyTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/GetKeyTest.java similarity index 76% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetKeyTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/GetKeyTest.java index 777261b0..479d3448 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetKeyTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/GetKeyTest.java @@ -1,4 +1,4 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; @@ -11,7 +11,7 @@ import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_TEST; import static org.junit.jupiter.api.Assertions.assertEquals; -public class GetKeyTest +class GetKeyTest extends S3UnitTestBase { @@ -30,7 +30,7 @@ private S3Path getPath(String path) } @Test - public void getKeyBucket() + void getKeyBucket() { S3Path path = getPath("/bucket"); @@ -38,39 +38,39 @@ public void getKeyBucket() } @Test - public void getKeyFile() + void getKeyFile() { S3Path path = getPath("/bucket/file"); - assertEquals(path.getKey(), "file"); + assertEquals("file", path.getKey()); } @Test - public void getKeyFolder() + void getKeyFolder() { S3Path path = getPath("/bucket/folder/"); - assertEquals(path.getKey(), "folder/"); + assertEquals("folder/", path.getKey()); } @Test - public void getKeyParent() + void getKeyParent() { S3Path path = (S3Path) getPath("/bucket/folder/file").getParent(); - assertEquals(path.getKey(), "folder/"); + assertEquals("folder/", path.getKey()); } @Test - public void getKeyRoot() + void getKeyRoot() { S3Path path = (S3Path) getPath("/bucket/folder/file").getRoot(); - assertEquals(path.getKey(), ""); + assertEquals("", path.getKey()); } @Test - public void getKeyEncodingPath() + void getKeyEncodingPath() { S3Path path = getPath("/bucket/path with spaces/to/β ϐ"); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetNameTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/GetNameTest.java similarity index 74% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetNameTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/GetNameTest.java index e451efc2..60e4860d 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetNameTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/GetNameTest.java @@ -1,21 +1,21 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; import java.io.IOException; -import java.nio.file.FileSystem; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_TEST; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; -public class GetNameTest +class GetNameTest extends S3UnitTestBase { @@ -42,20 +42,18 @@ private S3Path getPath(String path) } @Test - public void getNameBucket() + void getNameBucket() { + S3Path path = getPath("/bucket"); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - // TODO: this is ok? - S3Path path = getPath("/bucket"); - path.getName(0); - }); + Exception exception = assertThrows(IllegalArgumentException.class, () -> path.getName(0)); assertNotNull(exception); } @Test - public void getName0() + void getName0() { S3Path path = getPath("/bucket/file"); @@ -63,7 +61,7 @@ public void getName0() } @Test - public void getNames() + void getNames() { S3Path path = getPath("/bucket/path/to/file"); @@ -73,13 +71,12 @@ public void getNames() } @Test - public void getNameOutOfIndex() + void getNameOutOfIndex() { + S3Path path = getPath("/bucket/path/to/file"); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - S3Path path = getPath("/bucket/path/to/file"); - path.getName(3); - }); + Exception exception = assertThrows(IllegalArgumentException.class, () -> path.getName(3)); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetRootTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/GetRootTest.java similarity index 83% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetRootTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/GetRootTest.java index d818a390..aaf1f8de 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/GetRootTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/GetRootTest.java @@ -1,12 +1,10 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import java.io.IOException; -import java.nio.file.FileSystem; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -15,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -public class GetRootTest +class GetRootTest extends S3UnitTestBase { @@ -37,13 +35,13 @@ public void tearDown() } @Test - public void getRootReturnBucket() + void getRootReturnBucket() { assertEquals(getPath("/bucketA/"), getPath("/bucketA/dir/file").getRoot()); } @Test - public void getRootRelativeReturnNull() + void getRootRelativeReturnNull() { assertNull(getPath("dir/file").getRoot()); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/IteratorTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/IteratorTest.java similarity index 91% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/IteratorTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/IteratorTest.java index bdb2630d..569e95f9 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/IteratorTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/IteratorTest.java @@ -1,4 +1,4 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; @@ -14,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -public class IteratorTest +class IteratorTest extends S3UnitTestBase { @@ -33,7 +33,7 @@ private S3Path getPath(String path) } @Test - public void iterator() + void iterator() { Iterator iterator = getPath("/bucket/path/to/file").iterator(); @@ -44,7 +44,7 @@ public void iterator() } @Test - public void iteratorEmtpy() + void iteratorEmtpy() { Iterator iterator = getPath("").iterator(); assertFalse(iterator.hasNext()); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/ResolveSiblingTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ResolveSiblingTest.java similarity index 94% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/ResolveSiblingTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/ResolveSiblingTest.java index 38576e11..3c12d37f 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/ResolveSiblingTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ResolveSiblingTest.java @@ -1,13 +1,11 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; import java.io.IOException; -import java.nio.file.FileSystem; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -15,7 +13,7 @@ import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_TEST; import static org.junit.jupiter.api.Assertions.assertEquals; -public class ResolveSiblingTest +class ResolveSiblingTest extends S3UnitTestBase { @@ -42,7 +40,7 @@ private S3Path getPath(String path) } @Test - public void resolveSibling() + void resolveSibling() { // absolute (non-root) vs... assertEquals(getPath("/bucket/path/to/file").resolveSibling(getPath("other/child")), @@ -70,7 +68,7 @@ public void resolveSibling() } @Test - public void resolveSiblingString() + void resolveSiblingString() { // absolute (non-root) vs... assertEquals(getPath("/bucket/path/to/file").resolveSibling("other/child"), diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/ResolveTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ResolveTest.java similarity index 92% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/ResolveTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/ResolveTest.java index 99cc161f..64dc15f1 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/ResolveTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ResolveTest.java @@ -1,13 +1,11 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; import java.io.IOException; -import java.nio.file.FileSystem; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -15,7 +13,7 @@ import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_TEST; import static org.junit.jupiter.api.Assertions.assertEquals; -public class ResolveTest +class ResolveTest extends S3UnitTestBase { @@ -42,7 +40,7 @@ private S3Path getPath(String path) } @Test - public void resolve() + void resolve() { assertEquals(getPath("/bucket/path/to/dir/child/xyz"), getPath("/bucket/path/to/dir/").resolve(getPath("child/xyz"))); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/S3PathTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/S3PathTest.java similarity index 86% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/S3PathTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/S3PathTest.java index 405d99f2..5a7f9fc8 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/S3PathTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/S3PathTest.java @@ -1,22 +1,26 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; import java.io.IOException; -import java.nio.file.FileSystem; import java.nio.file.Path; import java.nio.file.WatchEvent; import java.util.HashMap; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_TEST; -import static org.junit.jupiter.api.Assertions.*; - -public class S3PathTest +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.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class S3PathTest extends S3UnitTestBase { @@ -34,7 +38,7 @@ private S3Path forPath(String path) } @Test - public void createNoPath() + void createNoPath() { S3Path path = forPath("/bucket"); @@ -43,7 +47,7 @@ public void createNoPath() } @Test - public void createWithTrailingSlash() + void createWithTrailingSlash() { S3Path path = forPath("/bucket/"); @@ -52,7 +56,7 @@ public void createWithTrailingSlash() } @Test - public void createWithPath() + void createWithPath() { S3Path path = forPath("/bucket/path/to/file"); @@ -61,7 +65,7 @@ public void createWithPath() } @Test - public void createWithPathAndTrailingSlash() + void createWithPathAndTrailingSlash() { S3Path path = forPath("/bucket/path/to/dir/"); @@ -70,7 +74,7 @@ public void createWithPathAndTrailingSlash() } @Test - public void createWithPathAndTrailingSlashDir() + void createWithPathAndTrailingSlashDir() { S3Path path = forPath("/bucket/path/to/dir/"); @@ -79,7 +83,7 @@ public void createWithPathAndTrailingSlashDir() } @Test - public void createRelative() + void createRelative() { S3Path path = forPath("path/to/file"); @@ -89,7 +93,7 @@ public void createRelative() } @Test - public void getParent() + void getParent() { assertEquals(forPath("/bucket/path/to/"), forPath("/bucket/path/to/file").getParent()); assertEquals(forPath("/bucket/path/to/"), forPath("/bucket/path/to/file/").getParent()); @@ -98,14 +102,14 @@ public void getParent() } @Test - public void nameCount() + void nameCount() { assertEquals(forPath("/bucket/path/to/file").getNameCount(), 3); assertEquals(forPath("/bucket/").getNameCount(), 0); } @Test - public void relativize() + void relativize() { Path path = forPath("/bucket/path/to/file"); Path other = forPath("/bucket/path/to/file/hello"); @@ -122,7 +126,7 @@ public void relativize() // register @Test - public void registerWithEventsThrowException() + void registerWithEventsThrowException() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { @@ -133,7 +137,7 @@ public void registerWithEventsThrowException() } @Test - public void registerThrowException() + void registerThrowException() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { @@ -144,7 +148,7 @@ public void registerThrowException() } @Test - public void registerWithEventsAndModifierThrowException() + void registerWithEventsAndModifierThrowException() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { @@ -156,7 +160,7 @@ public void registerWithEventsAndModifierThrowException() // to file @Test - public void toFile() + void toFile() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { @@ -169,7 +173,7 @@ public void toFile() // compares to @Test - public void compare() + void compare() { assertEquals(0, forPath("file1").compareTo(forPath("file1"))); assertEquals(0, forPath("/path/file1").compareTo(forPath("/path/file1"))); @@ -183,7 +187,7 @@ public void compare() // toRealPath @Test - public void toRealPathThrowException() + void toRealPathThrowException() throws IOException { Path path = forPath("/file1"); @@ -196,7 +200,7 @@ public void toRealPathThrowException() @SuppressWarnings("unused") @Test - public void toAbsolutePathRelativePathThrowException() + void toAbsolutePathRelativePathThrowException() { // We're expecting an exception here to be thrown Exception exception = assertThrows(IllegalStateException.class, () -> { @@ -207,7 +211,7 @@ public void toAbsolutePathRelativePathThrowException() } @Test - public void toAbsolutePath() + void toAbsolutePath() { Path path = forPath("/file1"); Path other = path.toAbsolutePath(); @@ -216,7 +220,7 @@ public void toAbsolutePath() } @Test - public void hashCodeHashMap() + void hashCodeHashMap() { HashMap hashMap = new HashMap<>(); hashMap.put(forPath("/bucket/a"), "a"); @@ -227,7 +231,7 @@ public void hashCodeHashMap() } @Test - public void preconditions() + void preconditions() { // We're expecting an exception here to be thrown Exception exception = assertThrows(IllegalArgumentException.class, () -> { @@ -240,7 +244,7 @@ public void preconditions() } @Test - public void constructors() + void constructors() { S3FileSystem fileSystem = s3fsProvider.getFileSystem(S3EndpointConstant.S3_GLOBAL_URI_TEST); S3Path path = new S3Path(fileSystem, "/buckname"); @@ -285,7 +289,7 @@ public void constructors() } @Test - public void register() + void register() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { @@ -297,7 +301,7 @@ public void register() } @Test - public void registerWatchService() + void registerWatchService() { // We're expecting an exception here to be thrown Exception exception = assertThrows(UnsupportedOperationException.class, () -> { diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/StartsWithTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/StartsWithTest.java similarity index 77% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/StartsWithTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/StartsWithTest.java index 6e80c969..35ad9165 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/StartsWithTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/StartsWithTest.java @@ -1,13 +1,11 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; import java.io.IOException; -import java.nio.file.FileSystem; import java.nio.file.Paths; import org.junit.jupiter.api.AfterEach; @@ -17,7 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -public class StartsWithTest +class StartsWithTest extends S3UnitTestBase { @@ -44,119 +42,119 @@ private S3Path getPath(String path) } @Test - public void startsWithBucket() + void startsWithBucket() { assertTrue(getPath("/bucket/file1").startsWith(getPath("/bucket/"))); assertFalse(getPath("/bucket/file1").startsWith(getPath("/bucket"))); } @Test - public void startsWithBlank() + void startsWithBlank() { assertFalse(getPath("/bucket/file1").startsWith(getPath(""))); } @Test - public void startsWithBlankRelative() + void startsWithBlankRelative() { assertFalse(getPath("file1").startsWith(getPath(""))); } @Test - public void startsWithSlash() + void startsWithSlash() { assertTrue(getPath("/bucket/file").startsWith(getPath("/bucket/"))); } @Test - public void startsWithBlankBlank() + void startsWithBlankBlank() { assertTrue(getPath("").startsWith(getPath(""))); } @Test - public void startsWithOnlyBuckets() + void startsWithOnlyBuckets() { assertTrue(getPath("/bucket").startsWith(getPath("/bucket"))); } @Test - public void startsWithRelativeVsAbsolute() + void startsWithRelativeVsAbsolute() { assertFalse(getPath("/bucket/file1").startsWith(getPath("file1"))); } @Test - public void startsWithRelativeVsAbsoluteInBucket() + void startsWithRelativeVsAbsoluteInBucket() { assertFalse(getPath("/bucket/file1").startsWith(getPath("bucket"))); } @Test - public void startsWithFalse() + void startsWithFalse() { assertFalse(getPath("/bucket/file1").startsWith(getPath("/bucket/file1/file2"))); assertTrue(getPath("/bucket/file1/file2").startsWith(getPath("/bucket/file1"))); } @Test - public void startsWithNotNormalize() + void startsWithNotNormalize() { assertFalse(getPath("/bucket/file1/file2").startsWith(getPath("/bucket/file1/../"))); } @Test - public void startsWithNormalize() + void startsWithNormalize() { // in this implementation not exists .. or . special paths assertFalse(getPath("/bucket/file1/file2").startsWith(getPath("/bucket/file1/../").normalize())); } @Test - public void startsWithRelative() + void startsWithRelative() { assertTrue(getPath("file/file1").startsWith(getPath("file"))); } @Test - public void startsWithDifferentProvider() + void startsWithDifferentProvider() { assertFalse(getPath("/bucket/hello").startsWith(Paths.get("/bucket"))); } @Test - public void startsWithString() + void startsWithString() { assertTrue(getPath("/bucket/hello").startsWith("/bucket/hello")); } @Test - public void startsWithStringRelative() + void startsWithStringRelative() { assertTrue(getPath("subkey1/hello").startsWith("subkey1/hello")); } @Test - public void startsWithStringOnlyBuckets() + void startsWithStringOnlyBuckets() { assertTrue(getPath("/bucket").startsWith("/bucket")); } @Test - public void startsWithStringRelativeVsAbsolute() + void startsWithStringRelativeVsAbsolute() { assertFalse(getPath("/bucket/file1").startsWith("file1")); } @Test - public void startsWithStringFalse() + void startsWithStringFalse() { assertFalse(getPath("/bucket/file1").startsWith("/bucket/file1/file2")); assertTrue(getPath("/bucket/file1/file2").startsWith("/bucket/file1")); } @Test - public void startsWithStringRelativeVsAbsoluteInBucket() + void startsWithStringRelativeVsAbsoluteInBucket() { assertFalse(getPath("/bucket/file1").startsWith("bucket")); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/SubpathTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/SubpathTest.java similarity index 79% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/SubpathTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/SubpathTest.java index 514cd519..3f171eb3 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/SubpathTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/SubpathTest.java @@ -1,21 +1,21 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; -import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; import org.carlspring.cloud.storage.s3fs.S3Path; import org.carlspring.cloud.storage.s3fs.S3UnitTestBase; import org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant; import java.io.IOException; -import java.nio.file.FileSystem; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_TEST; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; -public class SubpathTest +class SubpathTest extends S3UnitTestBase { @@ -42,13 +42,13 @@ private S3Path getPath(String path) } @Test - public void subPath0() + void subPath0() { assertEquals(getPath("/bucket/path/"), getPath("/bucket/path/to/file").subpath(0, 1)); } @Test - public void subPath() + void subPath() { assertEquals(getPath("/bucket/path/to/"), getPath("/bucket/path/to/file").subpath(0, 2)); assertEquals(getPath("/bucket/path/to/file"), getPath("/bucket/path/to/file").subpath(0, 3)); @@ -58,12 +58,13 @@ public void subPath() } @Test - public void subPathOutOfRange() + void subPathOutOfRange() { + S3Path path = getPath("/bucket/path/to/file"); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - getPath("/bucket/path/to/file").subpath(0, 4); - }); + Exception exception = assertThrows(IllegalArgumentException.class, + () -> path.subpath(0, 4)); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/path/ToURLIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ToURLIT.java new file mode 100644 index 00000000..2855edba --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ToURLIT.java @@ -0,0 +1,151 @@ +package org.carlspring.cloud.storage.s3fs.path; + +import org.carlspring.cloud.storage.s3fs.S3FileSystemProvider; +import org.carlspring.cloud.storage.s3fs.S3Path; +import org.carlspring.cloud.storage.s3fs.util.EnvironmentBuilder; + +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemAlreadyExistsException; +import java.nio.file.FileSystems; +import java.util.HashMap; +import java.util.Map; + +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; +import static org.carlspring.cloud.storage.s3fs.S3Factory.REGION; +import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_IT; +import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_REGION_URI_IT; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ToURLIT +{ + + private static final URI uriGlobal = EnvironmentBuilder.getS3URI(S3_GLOBAL_URI_IT); + + private static final Map realEnv = EnvironmentBuilder.getRealEnv(); + + public FileSystem getS3FileSystem(Entry... props) + throws IOException + { + System.clearProperty(S3FileSystemProvider.S3_FACTORY_CLASS); + + Map env = new HashMap<>(realEnv); + if (props != null) + { + for (Entry entry : props) + { + env.put(entry.getKey(), entry.getValue()); + } + } + + try + { + return FileSystems.newFileSystem(uriGlobal, env); + } + catch (FileSystemAlreadyExistsException e) + { + FileSystems.getFileSystem(uriGlobal).close(); + + return FileSystems.newFileSystem(uriGlobal, env); + } + } + + @Test + void toURLDefault() + throws IOException + { + final FileSystem fs = getS3FileSystem(new Entry(PROTOCOL, "https")); + + final String bucketName = "bucket-with-hyphens"; + final S3Path s3Path = (S3Path) fs.getPath("/" + bucketName).resolve("index.html"); + + /* + * According to software.amazon.awssdk.services.s3.internal.BucketUtils.isVirtualAddressingCompatibleBucketName, + * if bucket name contain dots, it can't be prefixed to the host URL. If this method returns true, + * then the method software.amazon.awssdk.services.s3.internal.S3EndpointUTILS.changeToDnsEndpoint allows + * to change this host URL. + */ + final String host = getHost(bucketName); + final URL expected = new URL("https", host, "/index.html"); + final URL actual = s3Path.toURL(); + assertEquals(expected, actual); + } + + @Test + void toURLWithPathStyle() + throws IOException + { + final FileSystem fs = getS3FileSystem(new Entry(PATH_STYLE_ACCESS, "true")); + + final String bucketName = "bucket-with-hyphens"; + final S3Path s3Path = (S3Path) fs.getPath("/" + bucketName).resolve("index.html"); + + final String host = getHost(null); + final URL expected = new URL("https", host, "/bucket-with-hyphens/index.html"); + final URL actual = s3Path.toURL(); + assertEquals(expected, actual); + } + + @Test + void toURLNull() + throws IOException + { + FileSystem fs = getS3FileSystem(new Entry(PATH_STYLE_ACCESS, "true")); + + S3Path s3Path = (S3Path) fs.getPath("directory").resolve("index.html"); + + assertNull(s3Path.toURL()); + } + + private String getHost(final String bucketName) + { + final String region = (String) realEnv.get(REGION); + final URI uriWithRegion = URI.create(String.format(S3_REGION_URI_IT, region)); + if(bucketName != null){ + return String.format("%s.%s", bucketName, uriWithRegion.getHost()); + } + + return uriWithRegion.getHost(); + } + + public static class Entry + { + + private String key; + + private String value; + + + public Entry(String key, String value) + { + this.key = key; + this.value = value; + } + + public String getKey() + { + return key; + } + + public void setKey(String key) + { + this.key = key; + } + + public String getValue() + { + return value; + } + + public void setValue(String value) + { + this.value = value; + } + } + +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/ToUriTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ToUriTest.java similarity index 87% rename from src/test/java/org/carlspring/cloud/storage/s3fs/Path/ToUriTest.java rename to src/test/java/org/carlspring/cloud/storage/s3fs/path/ToUriTest.java index dd3fb89e..713b624d 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/Path/ToUriTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/path/ToUriTest.java @@ -1,4 +1,4 @@ -package org.carlspring.cloud.storage.s3fs.Path; +package org.carlspring.cloud.storage.s3fs.path; import org.carlspring.cloud.storage.s3fs.S3FileSystem; import org.carlspring.cloud.storage.s3fs.S3Path; @@ -14,12 +14,12 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_TEST; import static org.junit.jupiter.api.Assertions.assertEquals; -public class ToUriTest +class ToUriTest extends S3UnitTestBase { @@ -38,7 +38,7 @@ public void tearDown() } @Test - public void toUri() + void toUri() { Path path = getPath("/bucket/path/to/file"); URI uri = path.toUri(); @@ -59,7 +59,7 @@ public void toUri() } @Test - public void toUriWithEndSlash() + void toUriWithEndSlash() { S3Path s3Path = getPath("/bucket/folder/"); @@ -67,7 +67,7 @@ public void toUriWithEndSlash() } @Test - public void toUriWithSpaces() + void toUriWithSpaces() { S3Path s3Path = getPath("/bucket/with spaces"); @@ -75,7 +75,7 @@ public void toUriWithSpaces() } @Test - public void toUriWithNotEndSlash() + void toUriWithNotEndSlash() { S3Path s3Path = getPath("/bucket/file"); @@ -83,7 +83,7 @@ public void toUriWithNotEndSlash() } @Test - public void toUriRelative() + void toUriRelative() { S3FileSystem fileSystem = s3fsProvider.getFileSystem(S3_GLOBAL_URI_TEST); @@ -93,7 +93,7 @@ public void toUriRelative() } @Test - public void toUriRelativeWithSpaces() + void toUriRelativeWithSpaces() { S3FileSystem fileSystem = s3fsProvider.getFileSystem(S3_GLOBAL_URI_TEST); @@ -103,7 +103,7 @@ public void toUriRelativeWithSpaces() } @Test - public void toUriBucketWithoutEndSlash() + void toUriBucketWithoutEndSlash() { S3Path s3Path = getPath("/bucket"); @@ -111,7 +111,7 @@ public void toUriBucketWithoutEndSlash() } @Test - public void toUriWithCredentials() + void toUriWithCredentials() { Map envs = ImmutableMap.builder().put(ACCESS_KEY, "access") .put(SECRET_KEY, "secret") @@ -125,7 +125,7 @@ public void toUriWithCredentials() } @Test - public void toUriWithCredentialBySystemProperty() + void toUriWithCredentialBySystemProperty() { System.setProperty(ACCESS_KEY, "accessKeywii"); System.setProperty(SECRET_KEY, "secretKey"); @@ -141,7 +141,7 @@ public void toUriWithCredentialBySystemProperty() } @Test - public void toUriWithEndpoint() + void toUriWithEndpoint() throws IOException { try (FileSystem fs = s3fsProvider.newFileSystem(URI.create("s3://endpoint/"), null)) diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentIT.java b/src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentIT.java index 7c8a690b..1f1a276d 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentIT.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/spike/EnvironmentIT.java @@ -5,16 +5,14 @@ import java.util.Map; import org.junit.jupiter.api.Test; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.ACCESS_KEY; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.SECRET_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.ACCESS_KEY; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; import static org.junit.jupiter.api.Assertions.assertNotNull; -public class EnvironmentIT +class EnvironmentIT { - - @Test - public void couldCreateFileSystem() + void couldCreateFileSystem() { Map res = EnvironmentBuilder.getRealEnv(); diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/spike/InstallProviderTest.java b/src/test/java/org/carlspring/cloud/storage/s3fs/spike/InstallProviderTest.java index 0b6300a2..14f9e3e8 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/spike/InstallProviderTest.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/spike/InstallProviderTest.java @@ -6,22 +6,33 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; -import java.nio.file.*; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashMap; +import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import static org.carlspring.cloud.storage.s3fs.S3Factory.REGION; import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_GLOBAL_URI_TEST; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * A test to search using ServiceLoader for available FileSystemsProvider-s and call them with newFileSystem. * * @author jarnaiz */ -public class InstallProviderTest +class InstallProviderTest { @@ -40,14 +51,14 @@ public void cleanup() } @Test - public void useZipProvider() + void useZipProvider() throws IOException { Path path = createZipTempFile(); String pathFinal = pathToString(path); FileSystem fs = FileSystems.newFileSystem(URI.create("jar:file:" + pathFinal), - new HashMap(), + new HashMap<>(), this.getClass().getClassLoader()); Path zipPath = fs.getPath("test.zip"); @@ -55,31 +66,31 @@ public void useZipProvider() assertNotNull(zipPath); assertNotNull(zipPath.getFileSystem()); assertNotNull(zipPath.getFileSystem().provider()); - //assertTrue(zipPath.getFileSystem().provider() instanceof com.sun.nio.zipfs.ZipFileSystemProvider); } @Test - public void useZipProviderPathNotExists() + void useZipProviderPathNotExists() { + final URI uri = URI.create("jar:file:/not/exists/zip.zip"); + final HashMap envMap = new HashMap<>(); + final ClassLoader classLoader = this.getClass().getClassLoader(); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(FileSystemNotFoundException.class, () -> { - FileSystems.newFileSystem(URI.create("jar:file:/not/exists/zip.zip"), - new HashMap(), - this.getClass().getClassLoader()); - }); + Exception exception = assertThrows(FileSystemNotFoundException.class, + () -> FileSystems.newFileSystem(uri, envMap, classLoader)); assertNotNull(exception); } @Test - public void useAlternativeZipProvider() + void useAlternativeZipProvider() throws IOException { Path path = createZipTempFile(); String pathFinal = pathToString(path); FileSystem fs = FileSystems.newFileSystem(URI.create("zipfs:file:" + pathFinal), - new HashMap(), + new HashMap<>(), this.getClass().getClassLoader()); Path zipPath = fs.getPath("test.zip"); @@ -92,15 +103,19 @@ public void useAlternativeZipProvider() } @Test - public void newS3Provider() + void newS3Provider() throws IOException { - URI uri = URI.create("s3:///hello/there/"); + final URI uri = URI.create("s3:///hello/there/"); + + // Region property is needed to create S3 client. + final Map envMap = ImmutableMap.builder().put(REGION, Region.US_EAST_1.id()) + .build(); - // if meta-inf/services/java.ni.spi.FileSystemProvider is not present with + // if META-INF/services/java.nio.file.spi.FileSystemProvider is not present with // the content: org.carlspring.cloud.storage.s3fs.S3FileSystemProvider // this method return ProviderNotFoundException - FileSystem fs = FileSystems.newFileSystem(uri, new HashMap(), this.getClass().getClassLoader()); + FileSystem fs = FileSystems.newFileSystem(uri, envMap, this.getClass().getClassLoader()); Path path = fs.getPath("test.zip"); @@ -114,37 +129,36 @@ public void newS3Provider() } @Test - public void getZipProvider() + void getZipProvider() { + final URI uri = URI.create("jar:file:/file.zip"); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(FileSystemNotFoundException.class, () -> { - URI uri = URI.create("jar:file:/file.zip"); - FileSystems.getFileSystem(uri); - }); + Exception exception = assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(uri)); assertNotNull(exception); } // deviation from spec @Test - public void getZipPath() + void getZipPath() { + final URI uri = URI.create("jar:file:/file.zip!/BAR"); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(FileSystemNotFoundException.class, () -> { - Paths.get(URI.create("jar:file:/file.zip!/BAR")); - }); + Exception exception = assertThrows(FileSystemNotFoundException.class, () -> Paths.get(uri)); assertNotNull(exception); } // deviation from spec @Test - public void getMemoryPath() + void getMemoryPath() { + final URI uri = URI.create("memory:hellou:/file.zip"); + // We're expecting an exception here to be thrown - Exception exception = assertThrows(FileSystemNotFoundException.class, () -> { - Paths.get(URI.create("memory:hellou:/file.zip")); - }); + Exception exception = assertThrows(FileSystemNotFoundException.class, () -> Paths.get(uri)); assertNotNull(exception); } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/AmazonS3ClientMock.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/AmazonS3ClientMock.java deleted file mode 100644 index 0840e4df..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/AmazonS3ClientMock.java +++ /dev/null @@ -1,1844 +0,0 @@ -package org.carlspring.cloud.storage.s3fs.util; - -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -import java.io.*; -import java.net.URL; -import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileAttribute; -import java.nio.file.attribute.PosixFileAttributes; -import java.nio.file.attribute.PosixFilePermission; -import java.util.*; - -import com.amazonaws.AmazonClientException; -import com.amazonaws.AmazonServiceException; -import com.amazonaws.AmazonWebServiceRequest; -import com.amazonaws.HttpMethod; -import com.amazonaws.regions.Region; -import com.amazonaws.services.s3.AbstractAmazonS3; -import com.amazonaws.services.s3.S3ClientOptions; -import com.amazonaws.services.s3.S3ResponseMetadata; -import com.amazonaws.services.s3.model.*; -import com.amazonaws.services.s3.waiters.AmazonS3Waiters; -import com.amazonaws.util.StringUtils; - -public class AmazonS3ClientMock - extends AbstractAmazonS3 -{ - - /** - * max elements amazon aws - */ - private static final int LIMIT_AWS_MAX_ELEMENTS = 1000; - - - // default owner - private Owner defaultOwner = new Owner() - { - private static final long serialVersionUID = 5510838843790352879L; - - { - setDisplayName("Mock"); - setId("1"); - } - }; - - private Path base; - - private Map bucketOwners = new HashMap<>(); - - - public AmazonS3ClientMock(Path base) - { - this.base = base; - } - - /** - * list all objects without and return ObjectListing with all elements - * and with truncated to false - */ - @Override - public ObjectListing listObjects(ListObjectsRequest listObjectsRequest) - throws AmazonClientException - { - String bucketName = listObjectsRequest.getBucketName(); - String prefix = listObjectsRequest.getPrefix(); - String marker = listObjectsRequest.getMarker(); - String delimiter = listObjectsRequest.getDelimiter(); - - ObjectListing objectListing = new ObjectListing(); - objectListing.setBucketName(bucketName); - objectListing.setPrefix(prefix); - objectListing.setMarker(marker); - objectListing.setDelimiter(delimiter); - - final Path bucket = find(bucketName); - final TreeMap elems = new TreeMap<>(); - - try - { - for (Path elem : Files.newDirectoryStream(bucket)) - { - S3Element element = parse(elem, bucket); - - if (!elems.containsKey(element.getS3Object().getKey())) - { - elems.put(element.getS3Object().getKey(), element); - } - } - } - catch (IOException e) - { - throw new AmazonClientException(e); - } - - Iterator iterator = elems.values().iterator(); - - int i = 0; - boolean waitForMarker = !StringUtils.isNullOrEmpty(marker); - - while (iterator.hasNext()) - { - S3Element elem = iterator.next(); - if (elem.getS3Object().getKey().equals("/")) - { - continue; - } - - String key = elem.getS3Object().getKey(); - if (waitForMarker) - { - waitForMarker = !key.startsWith(marker); - if (waitForMarker) - { - continue; - } - } - - if (prefix != null && key.startsWith(prefix)) - { - int beginIndex = key.indexOf(prefix) + prefix.length(); - String rest = key.substring(beginIndex); - - if (delimiter != null && delimiter.length() > 0 && rest.contains(delimiter)) - { - String substring = key.substring(0, beginIndex + rest.indexOf(delimiter)); - - if (!objectListing.getCommonPrefixes().contains(substring)) - { - objectListing.getCommonPrefixes().add(substring); - } - - continue; - } - - S3ObjectSummary s3ObjectSummary = parseToS3ObjectSummary(elem); - objectListing.getObjectSummaries().add(s3ObjectSummary); - - if (i + 1 == LIMIT_AWS_MAX_ELEMENTS && iterator.hasNext()) - { - objectListing.setTruncated(true); - objectListing.setNextMarker(iterator.next().getS3Object().getKey()); - - return objectListing; - } - - objectListing.setTruncated(false); - - i++; - } - } - - objectListing.getObjectSummaries().sort(Comparator.comparing(S3ObjectSummary::getKey)); - - return objectListing; - } - - @Override - public ListObjectsV2Result listObjectsV2(String bucketName) - throws AmazonClientException - { - return null; - } - - @Override - public ListObjectsV2Result listObjectsV2(String bucketName, String prefix) - throws AmazonClientException - { - return null; - } - - @Override - public ListObjectsV2Result listObjectsV2(ListObjectsV2Request listObjectsV2Request) - throws AmazonClientException - { - return null; - } - - @Override - public ObjectListing listNextBatchOfObjects(ObjectListing previousObjectListing) - { - ObjectListing objectListing = new ObjectListing(); - objectListing.setBucketName(previousObjectListing.getBucketName()); - objectListing.setPrefix(previousObjectListing.getPrefix()); - objectListing.setMarker(previousObjectListing.getMarker()); - objectListing.setDelimiter(previousObjectListing.getDelimiter()); - - if (!previousObjectListing.isTruncated() || previousObjectListing.getNextMarker() == null) - { - return objectListing; - } - - Path bucket = find(previousObjectListing.getBucketName()); - List elems = new ArrayList<>(); - - try - { - for (Path elem : Files.newDirectoryStream(bucket)) - { - elems.add(parse(elem, bucket)); - } - } - catch (IOException e) - { - throw new AmazonClientException(e); - } - - elems.sort(Comparator.comparing(o -> o.getS3Object().getKey())); - - Iterator iterator = elems.iterator(); - - int i = 0; - boolean continueElement = false; - - while (iterator.hasNext()) - { - - S3Element elem = iterator.next(); - - if (!continueElement && elem.getS3Object().getKey().equals(previousObjectListing.getNextMarker())) - { - continueElement = true; - } - - if (continueElement) - { - // TODO. add delimiter and marker support - if (previousObjectListing.getPrefix() != null && elem.getS3Object().getKey().startsWith( - previousObjectListing.getPrefix())) - { - S3ObjectSummary s3ObjectSummary = parseToS3ObjectSummary(elem); - objectListing.getObjectSummaries().add(s3ObjectSummary); - - // max 1000 elements at same time. - if (i + 1 == LIMIT_AWS_MAX_ELEMENTS && iterator.hasNext()) - { - objectListing.setTruncated(true); - objectListing.setNextMarker(iterator.next().getS3Object().getKey()); - - return objectListing; - } - - objectListing.setTruncated(false); - - i++; - } - } - } - - return objectListing; - } - - @Override - public ObjectListing listNextBatchOfObjects(ListNextBatchOfObjectsRequest listNextBatchOfObjectsRequest) - throws AmazonClientException - { - return null; - } - - /** - * create a new S3ObjectSummary using the S3Element - * - * @param elem S3Element to parse - * @return S3ObjectSummary - */ - private S3ObjectSummary parseToS3ObjectSummary(S3Element elem) - { - S3Object s3Object = elem.getS3Object(); - - ObjectMetadata objectMetadata = s3Object.getObjectMetadata(); - - S3ObjectSummary s3ObjectSummary = new S3ObjectSummary(); - s3ObjectSummary.setBucketName(s3Object.getBucketName()); - s3ObjectSummary.setKey(s3Object.getKey()); - s3ObjectSummary.setLastModified(objectMetadata.getLastModified()); - s3ObjectSummary.setOwner(getOwner(s3Object.getBucketName())); - s3ObjectSummary.setETag(objectMetadata.getETag()); - s3ObjectSummary.setSize(objectMetadata.getContentLength()); - - return s3ObjectSummary; - } - - private Owner getOwner(String bucketName) - { - if (!bucketOwners.containsKey(bucketName)) - { - return defaultOwner; - } - - return bucketOwners.get(bucketName); - } - - @Override - public Owner getS3AccountOwner() - throws AmazonClientException - { - return defaultOwner; - } - - @Override - public Owner getS3AccountOwner(GetS3AccountOwnerRequest getS3AccountOwnerRequest) - throws AmazonClientException - { - return null; - } - - public void setS3AccountOwner(Owner owner) - { - this.defaultOwner = owner; - } - - @Override - public List listBuckets() - throws AmazonClientException - { - List result = new ArrayList<>(); - try - { - for (Path path : Files.newDirectoryStream(base)) - { - String bucketName = path.getFileName().toString(); - - Bucket bucket = new Bucket(bucketName); - bucket.setOwner(getOwner(bucketName)); - bucket.setCreationDate(new Date(Files.readAttributes(path, BasicFileAttributes.class) - .creationTime() - .toMillis())); - - result.add(bucket); - } - } - catch (IOException e) - { - throw new AmazonClientException(e); - } - - return result; - } - - @Override - public Bucket createBucket(CreateBucketRequest createBucketRequest) - throws AmazonClientException - { - return createBucket(createBucketRequest.getBucketName()); - } - - @Override - public Bucket createBucket(String bucketName) - throws AmazonClientException - { - try - { - String name = bucketName.replaceAll("//", ""); - - Path path = Files.createDirectories(base.resolve(name)); - - Bucket bucket = new Bucket(name); - bucket.setOwner(getOwner(name)); - bucket.setCreationDate(new Date(Files.readAttributes(path, BasicFileAttributes.class) - .creationTime() - .toMillis())); - - return bucket; - } - catch (IOException e) - { - throw new AmazonClientException(e); - } - } - - @Override - public AccessControlList getObjectAcl(String bucketName, String key) - throws AmazonClientException - { - Path elem = find(bucketName, key); - if (elem != null) - { - try - { - return parse(elem, find(bucketName)).getPermission(); - } - catch (IOException e) - { - throw new AmazonServiceException("Problem getting mock ACL: ", e); - } - } - - throw new AmazonServiceException("key not found, " + key); - } - - @Override - public AccessControlList getBucketAcl(String bucketName) - throws AmazonClientException - { - Path bucket = find(bucketName); - if (bucket == null) - { - throw new AmazonServiceException("bucket not found, " + bucketName); - } - - return createAclPermission(bucket, bucketName); - } - - @Override - public S3Object getObject(String bucketName, String key) - throws AmazonClientException - { - Path result = find(bucketName, key); - if (result == null || !Files.exists(result)) - { - result = find(bucketName, key + "/"); - } - - if (result == null || !Files.exists(result)) - { - AmazonS3Exception amazonS3Exception = new AmazonS3Exception("not found with key: " + key); - amazonS3Exception.setStatusCode(404); - - throw amazonS3Exception; - } - - try - { - return parse(result, find(bucketName)).getS3Object(); - } - catch (IOException e) - { - throw new AmazonServiceException("Problem getting Mock Object: ", e); - } - } - - @Override - public PutObjectResult putObject(String bucketName, String key, File file) - throws AmazonClientException - { - try - { - ByteArrayInputStream stream = new ByteArrayInputStream(Files.readAllBytes(file.toPath())); - S3Element elem = parse(stream, bucketName, key); - - persist(bucketName, elem); - - PutObjectResult putObjectResult = new PutObjectResult(); - putObjectResult.setETag("3a5c8b1ad448bca04584ecb55b836264"); - - return putObjectResult; - } - catch (IOException e) - { - throw new AmazonServiceException("", e); - } - } - - @Override - public PutObjectResult putObject(String bucket, String keyName, InputStream inputStream, ObjectMetadata metadata) - { - S3Element elem = parse(inputStream, bucket, keyName); - - persist(bucket, elem); - - PutObjectResult putObjectResult = new PutObjectResult(); - putObjectResult.setETag("3a5c8b1ad448bca04584ecb55b836264"); - - return putObjectResult; - } - - @Override - public PutObjectResult putObject(String bucketName, String key, String content) - throws AmazonClientException - { - return null; - } - - /** - * store in the memory map - * - * @param bucketName bucket where persist - * @param elem - */ - private void persist(String bucketName, S3Element elem) - { - Path bucket = find(bucketName); - - String key = elem.getS3Object().getKey().replaceAll("/", "%2F"); - - Path resolve = bucket.resolve(key); - - if (Files.exists(resolve)) - { - try - { - Files.delete(resolve); - } - catch (IOException e1) - { - // ignore - } - } - - try - { - Files.createFile(resolve); - - S3ObjectInputStream objectContent = elem.getS3Object().getObjectContent(); - if (objectContent != null) - { - byte[] byteArray = IOUtils.toByteArray(objectContent); - - Files.write(resolve, byteArray); - } - } - catch (IOException e) - { - throw new AmazonServiceException("Problem creating mock element: ", e); - } - } - - @Override - public CopyObjectResult copyObject(String sourceBucketName, - String sourceKey, - String destinationBucketName, - String destinationKey) - throws AmazonClientException - { - Path src = find(sourceBucketName, sourceKey); - if (src != null && Files.exists(src)) - { - Path bucket = find(destinationBucketName); - Path dest = bucket.resolve(destinationKey.replaceAll("/", "%2F")); - - try - { - Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING); - } - catch (IOException e) - { - throw new AmazonServiceException("Problem copying mock objects: ", e); - } - - return new CopyObjectResult(); - } - - throw new AmazonServiceException("object source not found"); - } - - @Override - public void deleteObject(String bucketName, String key) - throws AmazonClientException - { - Path bucket = find(bucketName); - Path resolve = bucket.resolve(key); - - if (Files.exists(resolve)) - { - try - { - Files.delete(resolve); - } - catch (IOException e) - { - throw new AmazonServiceException("Problem deleting mock object: ", e); - } - } - else - { - resolve = bucket.resolve(key.replaceAll("/", "%2F")); - if (Files.exists(resolve)) - { - try - { - Files.delete(resolve); - } - catch (IOException e) - { - throw new AmazonServiceException("Problem deleting mock object: ", e); - } - } - } - } - - private S3Element parse(InputStream stream, String bucketName, String key) - { - try (S3Object object = new S3Object()) - { - object.setBucketName(bucketName); - object.setKey(key); - - byte[] content = IOUtils.toByteArray(stream); - - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setLastModified(new Date()); - metadata.setContentLength(content.length); - - object.setObjectContent(new ByteArrayInputStream(content)); - object.setObjectMetadata(metadata); - - // TODO: create converter between path permission and s3 permission - AccessControlList permission = createAllPermission(bucketName); - - return new S3Element(object, permission, false); - } - catch (IOException e) - { - throw new IllegalStateException("the stream is closed", e); - } - } - - private S3Element parse(Path elem, Path bucket) - throws IOException - { - S3Object object = new S3Object(); - - String bucketName = bucket.getFileName().toString(); - object.setBucketName(bucketName); - - String key = bucket.relativize(elem).toString().replaceAll("%2F", "/"); - boolean dir = key.endsWith("/") || key.isEmpty(); - object.setKey(key); - - ObjectMetadata metadata = new ObjectMetadata(); - BasicFileAttributes attr = Files.readAttributes(elem, BasicFileAttributes.class); - metadata.setLastModified(new Date(attr.lastAccessTime().toMillis())); - - if (dir) - { - metadata.setContentLength(0); - object.setObjectContent(null); - } - else - { - metadata.setContentLength(attr.size()); - object.setObjectContent(new ByteArrayInputStream(Files.readAllBytes(elem))); - } - - object.setObjectMetadata(metadata); - AccessControlList permission = createAclPermission(elem, bucketName); - - return new S3Element(object, permission, dir); - } - - /** - * create the com.amazonaws.services.s3.model.AccessControlList from a Path - * - * @param elem Path - * @param bucketName String - * @return AccessControlList never null - */ - private AccessControlList createAclPermission(Path elem, String bucketName) - { - AccessControlList res = new AccessControlList(); - final Owner owner = getOwner(bucketName); - res.setOwner(owner); - - Grantee grant = new Grantee() - { - @Override - public void setIdentifier(String id) - { - // - } - - @Override - public String getTypeIdentifier() - { - return owner.getId(); - } - - @Override - public String getIdentifier() - { - return owner.getId(); - } - }; - - try - { - Set permission = Files.readAttributes(elem, PosixFileAttributes.class).permissions(); - for (PosixFilePermission posixFilePermission : permission) - { - switch (posixFilePermission) - { - case GROUP_READ: - case OTHERS_READ: - case OWNER_READ: - res.grantPermission(grant, Permission.Read); - break; - case OWNER_WRITE: - case GROUP_WRITE: - case OTHERS_WRITE: - res.grantPermission(grant, Permission.Write); - break; - case OWNER_EXECUTE: - case GROUP_EXECUTE: - case OTHERS_EXECUTE: - res.grantPermission(grant, Permission.WriteAcp); - res.grantPermission(grant, Permission.ReadAcp); - break; - - } - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } - - return res; - } - - private AccessControlList createAllPermission(String bucketName) - { - AccessControlList res = new AccessControlList(); - final Owner owner = getOwner(bucketName); - res.setOwner(owner); - - Grantee grant = new Grantee() - { - @Override - public void setIdentifier(String id) - { - // - } - - @Override - public String getTypeIdentifier() - { - return owner.getId(); - } - - @Override - public String getIdentifier() - { - return owner.getId(); - } - }; - - res.grantPermission(grant, Permission.FullControl); - res.grantPermission(grant, Permission.Read); - res.grantPermission(grant, Permission.Write); - - return res; - } - - public AccessControlList createReadOnly(String bucketName) - { - return createReadOnly(getOwner(bucketName)); - } - - public AccessControlList createReadOnly(final Owner owner) - { - AccessControlList res = new AccessControlList(); - res.setOwner(owner); - - Grantee grant = new Grantee() - { - @Override - public void setIdentifier(String id) - { - // - } - - @Override - public String getTypeIdentifier() - { - return owner.getId(); - } - - @Override - public String getIdentifier() - { - return owner.getId(); - } - }; - - res.grantPermission(grant, Permission.Read); - - return res; - } - - private Path find(String bucketName, final String key) - { - final Path bucket = find(bucketName); - - if (bucket == null || !Files.exists(bucket)) - { - return null; - } - - try - { - final String fileKey = key.replaceAll("/", "%2F"); - final List matches = new ArrayList(); - - Files.walkFileTree(bucket, new SimpleFileVisitor() - { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) - { - String relativize = bucket.relativize(dir).toString(); - - if (relativize.equals(fileKey)) - { - matches.add(dir); - } - - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - { - String relativize = bucket.relativize(file).toString(); - if (relativize.equals(fileKey)) - { - matches.add(file); - } - - return FileVisitResult.CONTINUE; - } - }); - - if (!matches.isEmpty()) - { - return matches.iterator().next(); - } - } - catch (IOException e) - { - throw new AmazonServiceException("Problem getting mock S3Element: ", e); - } - - return null; - } - - private Path find(String bucketName) - { - return base.resolve(bucketName); - } - - public static class S3Element - { - - private S3Object s3Object; - - private boolean directory; - - private AccessControlList permission; - - - public S3Element(S3Object s3Object, AccessControlList permission, boolean directory) - { - this.s3Object = s3Object; - this.directory = directory; - this.permission = permission; - } - - public S3Object getS3Object() - { - return s3Object; - } - - public void setS3Object(S3Object s3Object) - { - this.s3Object = s3Object; - } - - public AccessControlList getPermission() - { - return permission; - } - - public boolean isDirectory() - { - return directory; - } - - public void setDirectory(boolean directory) - { - this.directory = directory; - } - - public void setPermission(AccessControlList permission) - { - this.permission = permission; - } - - @Override - public boolean equals(Object object) - { - if (object == null) - { - return false; - } - - if (object instanceof S3Element) - { - S3Element elem = (S3Element) object; - // only is the same if bucketname and key are not null and are the same - if (elem.getS3Object() != null && this.getS3Object() != null && - elem.getS3Object().getBucketName() != null && - elem.getS3Object().getBucketName().equals(this.getS3Object().getBucketName()) && - elem.getS3Object().getKey() != null && - elem.getS3Object().getKey().equals(this.getS3Object().getKey())) - { - return true; - } - - return false; - } - - return false; - } - - @Override - public int hashCode() - { - int result = s3Object != null && s3Object.getBucketName() != null ? s3Object.getBucketName().hashCode() : 0; - result = 31 * result + (s3Object != null && s3Object.getKey() != null ? s3Object.getKey().hashCode() : 0); - return result; - } - } - - @Override - public ObjectMetadata getObjectMetadata(String bucketName, String key) - { - S3Object object = getObject(bucketName, key); - if (object.getKey().equals(key)) - { - return object.getObjectMetadata(); - } - - AmazonS3Exception exception = new AmazonS3Exception("Resource not available: " + bucketName + "/" + key); - exception.setStatusCode(404); - - throw exception; - } - - @Override - public boolean doesBucketExist(String bucketName) - throws AmazonClientException - { - return Files.exists(base.resolve(bucketName)); - } - - @Override - public HeadBucketResult headBucket(HeadBucketRequest headBucketRequest) - throws AmazonClientException - { - return null; - } - - public MockBucket bucket(String bucketName) - throws IOException - { - return new MockBucket(this, Files.createDirectories(base.resolve(bucketName))); - } - - public Path bucket(String bucketName, Owner owner) - throws IOException - { - bucketOwners.put(bucketName, owner); - - return Files.createDirectories(base.resolve(bucketName)); - } - - @Override - public void deleteBucket(String bucketName) - throws AmazonClientException - { - try - { - Path bucket = base.resolve(bucketName); - - Files.walkFileTree(bucket, new SimpleFileVisitor() - { - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) - throws IOException - { - Files.delete(dir); - - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException - { - Files.delete(file); - - return FileVisitResult.CONTINUE; - } - }); - } - catch (IOException e) - { - throw new AmazonClientException(e); - } - } - - public void addFile(Path bucket, String fileName) - throws IOException - { - if (fileName.endsWith("/")) - { - fileName.substring(0, fileName.length() - 1); - } - - Files.createFile(bucket.resolve(fileName.replaceAll("/", "%2F"))); - } - - public void addFile(Path bucket, String fileName, byte[] content) - throws IOException - { - addFile(bucket, fileName, content, new FileAttribute[0]); - } - - public void addFile(Path bucket, String fileName, byte[] content, FileAttribute... attrs) - throws IOException - { - if (fileName.endsWith("/")) - { - fileName.substring(0, fileName.length() - 1); - } - - Path file = Files.createFile(bucket.resolve(fileName.replaceAll("/", "%2F")), attrs); - - try (OutputStream outputStream = Files.newOutputStream(file)) - { - outputStream.write(content); - } - } - - public void addDirectory(Path bucket, String directoryName) - throws IOException - { - if (!directoryName.endsWith("/")) - { - directoryName += "/"; - } - - Files.createFile(bucket.resolve(directoryName.replaceAll("/", "%2F"))); - } - - public void clear() - { - try - { - Files.walkFileTree(base, new SimpleFileVisitor() - { - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) - throws IOException - { - if (dir != base) - { - Files.delete(dir); - } - - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException - { - Files.delete(file); - - return FileVisitResult.CONTINUE; - } - }); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - @Override - public void setEndpoint(String endpoint) - { - throw new UnsupportedOperationException(); - } - - @Override - public void setRegion(Region region) - throws IllegalArgumentException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setS3ClientOptions(S3ClientOptions clientOptions) - { - throw new UnsupportedOperationException(); - } - - @Override - public void changeObjectStorageClass(String bucketName, String key, StorageClass newStorageClass) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setObjectRedirectLocation(String bucketName, String key, String newRedirectLocation) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public ObjectListing listObjects(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public ObjectListing listObjects(String bucketName, String prefix) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public VersionListing listVersions(String bucketName, String prefix) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public VersionListing listNextBatchOfVersions(VersionListing previousVersionListing) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public VersionListing listNextBatchOfVersions(ListNextBatchOfVersionsRequest listNextBatchOfVersionsRequest) - throws AmazonClientException - { - return null; - } - - @Override - public VersionListing listVersions(String bucketName, - String prefix, - String keyMarker, - String versionIdMarker, - String delimiter, - Integer maxResults) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public VersionListing listVersions(ListVersionsRequest listVersionsRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public List listBuckets(ListBucketsRequest listBucketsRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public String getBucketLocation(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public String getBucketLocation(GetBucketLocationRequest getBucketLocationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public Bucket createBucket(String bucketName, com.amazonaws.services.s3.model.Region region) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public Bucket createBucket(String bucketName, String region) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public AccessControlList getObjectAcl(String bucketName, String key, String versionId) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public AccessControlList getObjectAcl(GetObjectAclRequest getObjectAclRequest) - throws AmazonClientException - { - return null; - } - - @Override - public void setObjectAcl(String bucketName, String key, AccessControlList acl) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setObjectAcl(String bucketName, String key, CannedAccessControlList acl) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setObjectAcl(String bucketName, String key, String versionId, AccessControlList acl) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setObjectAcl(String bucketName, String key, String versionId, CannedAccessControlList acl) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setObjectAcl(SetObjectAclRequest setObjectAclRequest) - throws AmazonClientException - { - - } - - @Override - public void setBucketAcl(SetBucketAclRequest setBucketAclRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public AccessControlList getBucketAcl(GetBucketAclRequest getBucketAclRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketAcl(String bucketName, AccessControlList acl) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketAcl(String bucketName, CannedAccessControlList acl) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public ObjectMetadata getObjectMetadata(GetObjectMetadataRequest getObjectMetadataRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public S3Object getObject(GetObjectRequest getObjectRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public ObjectMetadata getObject(GetObjectRequest getObjectRequest, File destinationFile) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public String getObjectAsString(String bucketName, String key) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucket(DeleteBucketRequest deleteBucketRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public PutObjectResult putObject(PutObjectRequest putObjectRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public CopyObjectResult copyObject(CopyObjectRequest copyObjectRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public CopyPartResult copyPart(CopyPartRequest copyPartRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteObject(DeleteObjectRequest deleteObjectRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public DeleteObjectsResult deleteObjects(DeleteObjectsRequest deleteObjectsRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteVersion(String bucketName, String key, String versionId) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteVersion(DeleteVersionRequest deleteVersionRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketLoggingConfiguration getBucketLoggingConfiguration(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketLoggingConfiguration getBucketLoggingConfiguration(GetBucketLoggingConfigurationRequest getBucketLoggingConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketLoggingConfiguration(SetBucketLoggingConfigurationRequest setBucketLoggingConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketVersioningConfiguration getBucketVersioningConfiguration(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketVersioningConfiguration getBucketVersioningConfiguration(GetBucketVersioningConfigurationRequest getBucketVersioningConfigurationRequest) - throws AmazonClientException - { - return null; - } - - @Override - public void setBucketVersioningConfiguration(SetBucketVersioningConfigurationRequest setBucketVersioningConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketLifecycleConfiguration getBucketLifecycleConfiguration(String bucketName) - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketLifecycleConfiguration getBucketLifecycleConfiguration(GetBucketLifecycleConfigurationRequest getBucketLifecycleConfigurationRequest) - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketLifecycleConfiguration(String bucketName, - BucketLifecycleConfiguration bucketLifecycleConfiguration) - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketLifecycleConfiguration(SetBucketLifecycleConfigurationRequest setBucketLifecycleConfigurationRequest) - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketLifecycleConfiguration(String bucketName) - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketLifecycleConfiguration(DeleteBucketLifecycleConfigurationRequest deleteBucketLifecycleConfigurationRequest) - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketCrossOriginConfiguration getBucketCrossOriginConfiguration(String bucketName) - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketCrossOriginConfiguration getBucketCrossOriginConfiguration(GetBucketCrossOriginConfigurationRequest getBucketCrossOriginConfigurationRequest) - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketCrossOriginConfiguration(String bucketName, - BucketCrossOriginConfiguration bucketCrossOriginConfiguration) - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketCrossOriginConfiguration(SetBucketCrossOriginConfigurationRequest setBucketCrossOriginConfigurationRequest) - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketCrossOriginConfiguration(String bucketName) - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketCrossOriginConfiguration(DeleteBucketCrossOriginConfigurationRequest deleteBucketCrossOriginConfigurationRequest) - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketTaggingConfiguration getBucketTaggingConfiguration(String bucketName) - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketTaggingConfiguration getBucketTaggingConfiguration(GetBucketTaggingConfigurationRequest getBucketTaggingConfigurationRequest) - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketTaggingConfiguration(String bucketName, BucketTaggingConfiguration bucketTaggingConfiguration) - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketTaggingConfiguration(SetBucketTaggingConfigurationRequest setBucketTaggingConfigurationRequest) - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketTaggingConfiguration(String bucketName) - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketTaggingConfiguration(DeleteBucketTaggingConfigurationRequest deleteBucketTaggingConfigurationRequest) - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketNotificationConfiguration getBucketNotificationConfiguration(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketNotificationConfiguration getBucketNotificationConfiguration(GetBucketNotificationConfigurationRequest getBucketNotificationConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketNotificationConfiguration(SetBucketNotificationConfigurationRequest setBucketNotificationConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketNotificationConfiguration(String bucketName, - BucketNotificationConfiguration bucketNotificationConfiguration) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketWebsiteConfiguration getBucketWebsiteConfiguration(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketWebsiteConfiguration getBucketWebsiteConfiguration(GetBucketWebsiteConfigurationRequest getBucketWebsiteConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketWebsiteConfiguration(String bucketName, BucketWebsiteConfiguration configuration) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketWebsiteConfiguration(SetBucketWebsiteConfigurationRequest setBucketWebsiteConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketWebsiteConfiguration(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketWebsiteConfiguration(DeleteBucketWebsiteConfigurationRequest deleteBucketWebsiteConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketPolicy getBucketPolicy(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketPolicy getBucketPolicy(GetBucketPolicyRequest getBucketPolicyRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketPolicy(String bucketName, String policyText) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketPolicy(SetBucketPolicyRequest setBucketPolicyRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketPolicy(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketPolicy(DeleteBucketPolicyRequest deleteBucketPolicyRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public URL generatePresignedUrl(String bucketName, String key, Date expiration) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public URL generatePresignedUrl(String bucketName, String key, Date expiration, HttpMethod method) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public URL generatePresignedUrl(GeneratePresignedUrlRequest generatePresignedUrlRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public InitiateMultipartUploadResult initiateMultipartUpload(InitiateMultipartUploadRequest request) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public UploadPartResult uploadPart(UploadPartRequest request) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public PartListing listParts(ListPartsRequest request) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void abortMultipartUpload(AbortMultipartUploadRequest request) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public CompleteMultipartUploadResult completeMultipartUpload(CompleteMultipartUploadRequest request) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public MultipartUploadListing listMultipartUploads(ListMultipartUploadsRequest request) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public S3ResponseMetadata getCachedResponseMetadata(AmazonWebServiceRequest request) - { - throw new UnsupportedOperationException(); - } - - @Override - public void restoreObject(RestoreObjectRequest request) - throws AmazonServiceException - { - throw new UnsupportedOperationException(); - } - - @Override - public void restoreObject(String bucketName, String key, int expirationInDays) - throws AmazonServiceException - { - throw new UnsupportedOperationException(); - } - - @Override - public void enableRequesterPays(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void disableRequesterPays(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isRequesterPaysEnabled(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketReplicationConfiguration(String bucketName, BucketReplicationConfiguration configuration) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketReplicationConfiguration(SetBucketReplicationConfigurationRequest setBucketReplicationConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketReplicationConfiguration getBucketReplicationConfiguration(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketReplicationConfiguration getBucketReplicationConfiguration(GetBucketReplicationConfigurationRequest getBucketReplicationConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketReplicationConfiguration(String bucketName) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void deleteBucketReplicationConfiguration(DeleteBucketReplicationConfigurationRequest request) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean doesObjectExist(String bucketName, String objectName) - throws AmazonClientException - { - // TODO: review - throw new UnsupportedOperationException(); - } - - @Override - public BucketAccelerateConfiguration getBucketAccelerateConfiguration(String bucket) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public BucketAccelerateConfiguration getBucketAccelerateConfiguration(GetBucketAccelerateConfigurationRequest getBucketAccelerateConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketAccelerateConfiguration(String bucketName, - BucketAccelerateConfiguration accelerateConfiguration) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public void setBucketAccelerateConfiguration(SetBucketAccelerateConfigurationRequest setBucketAccelerateConfigurationRequest) - throws AmazonClientException - { - throw new UnsupportedOperationException(); - } - - @Override - public com.amazonaws.services.s3.model.Region getRegion() - { - throw new UnsupportedOperationException(); - } - - @Override - public URL getUrl(String bucketName, String key) - { - // TODO: review - throw new UnsupportedOperationException(); - } - - @Override - public AmazonS3Waiters waiters() - { - throw new UnsupportedOperationException(); - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/AmazonS3MockFactory.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/AmazonS3MockFactory.java deleted file mode 100644 index 97e17e9f..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/AmazonS3MockFactory.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.carlspring.cloud.storage.s3fs.util; - -import org.carlspring.cloud.storage.s3fs.AmazonS3Factory; - -import java.io.IOException; -import java.net.URI; -import java.nio.file.FileSystem; -import java.util.Properties; -import java.util.UUID; - -import com.amazonaws.ClientConfiguration; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.metrics.RequestMetricCollector; -import com.amazonaws.services.s3.AmazonS3; -import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder; -import static org.mockito.Mockito.spy; - -public class AmazonS3MockFactory - extends AmazonS3Factory -{ - - private static FileSystem fsMem; - - private static AmazonS3ClientMock amazonS3Client; - - - @Override - public AmazonS3 getAmazonS3(URI uri, Properties props) - { - return getAmazonClientMock(); - } - - @Override - protected AmazonS3 createAmazonS3(AWSCredentialsProvider credentialsProvider, - ClientConfiguration clientConfiguration, - RequestMetricCollector requestMetricsCollector) - { - return getAmazonClientMock(); - } - - public static AmazonS3ClientMock getAmazonClientMock() - { - if (amazonS3Client == null) - { - amazonS3Client = spy(new AmazonS3ClientMock(getFsMem().getPath("/"))); - } - - return amazonS3Client; - } - - private static FileSystem getFsMem() - { - if (fsMem == null) - { - try - { - fsMem = MemoryFileSystemBuilder.newLinux() - .setCurrentWorkingDirectory("/") - .build(UUID.randomUUID().toString()); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - return fsMem; - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/BrokenAmazonS3Factory.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/BrokenAmazonS3Factory.java deleted file mode 100644 index cc67de4a..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/BrokenAmazonS3Factory.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.carlspring.cloud.storage.s3fs.util; - -import org.carlspring.cloud.storage.s3fs.AmazonS3Factory; - -import com.amazonaws.ClientConfiguration; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.metrics.RequestMetricCollector; -import com.amazonaws.services.s3.AmazonS3; - -public class BrokenAmazonS3Factory - extends AmazonS3Factory -{ - - - /** - * @param name to make the constructor non default - */ - public BrokenAmazonS3Factory(String name) - { - // only non default constructor - } - - @Override - protected AmazonS3 createAmazonS3(AWSCredentialsProvider credentialsProvider, - ClientConfiguration clientConfiguration, - RequestMetricCollector requestMetricsCollector) - { - return null; - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/BrokenRequestMetricCollector.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/BrokenRequestMetricCollector.java deleted file mode 100644 index ca37f4a8..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/BrokenRequestMetricCollector.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.carlspring.cloud.storage.s3fs.util; - -public class BrokenRequestMetricCollector - extends NoOpRequestMetricCollector -{ - - - /** - * @param name to make the constructor non default - */ - public BrokenRequestMetricCollector(String name) - { - // only non-default constructor - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/BrokenS3Factory.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/BrokenS3Factory.java new file mode 100644 index 00000000..1544a37a --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/BrokenS3Factory.java @@ -0,0 +1,27 @@ +package org.carlspring.cloud.storage.s3fs.util; + +import org.carlspring.cloud.storage.s3fs.S3Factory; + +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3ClientBuilder; + +public class BrokenS3Factory + extends S3Factory +{ + + + /** + * @param name to make the constructor non default + */ + public BrokenS3Factory(final String name) + { + // only non default constructor + } + + @Override + protected S3Client createS3Client(final S3ClientBuilder builder) + { + return null; + } + +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/CopyDirVisitor.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/CopyDirVisitor.java index 3b960fa8..fe0e7afb 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/CopyDirVisitor.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/CopyDirVisitor.java @@ -1,40 +1,44 @@ package org.carlspring.cloud.storage.s3fs.util; import java.io.IOException; -import java.nio.file.*; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; public class CopyDirVisitor extends SimpleFileVisitor { - private Path fromPath; + private final Path fromPath; - private Path toPath; + private final Path toPath; - private StandardCopyOption copyOption; + private final StandardCopyOption copyOption; - public CopyDirVisitor(Path fromPath, Path toPath, StandardCopyOption copyOption) + public CopyDirVisitor(final Path fromPath, final Path toPath, final StandardCopyOption copyOption) { this.fromPath = fromPath; this.toPath = toPath; this.copyOption = copyOption; } - public CopyDirVisitor(Path fromPath, Path toPath) + public CopyDirVisitor(final Path fromPath, final Path toPath) { this(fromPath, toPath, StandardCopyOption.REPLACE_EXISTING); } @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) + public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { // we allow to work against different providers Path targetPath = appendPath(dir); - if (!Files.exists(targetPath)) + if (Files.notExists(targetPath)) { if (!targetPath.toString().endsWith("/")) { @@ -48,10 +52,10 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) } @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { - Path targetPath = appendPath(file); + final Path targetPath = appendPath(file); Files.copy(file, targetPath, copyOption); @@ -65,7 +69,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) * @param to Path * @return */ - private Path appendPath(Path to) + private Path appendPath(final Path to) { Path targetPath = toPath; 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 a4a7f4d3..e7f2d12a 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 @@ -8,7 +8,11 @@ import com.google.common.collect.ImmutableMap; import org.apache.http.client.utils.URIBuilder; -import static org.carlspring.cloud.storage.s3fs.AmazonS3Factory.*; +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; +import static org.carlspring.cloud.storage.s3fs.S3Factory.SECRET_KEY; +import static org.carlspring.cloud.storage.s3fs.util.S3EndpointConstant.S3_REGION_URI_IT; /** * Test Helper @@ -31,13 +35,15 @@ public static Map getRealEnv() String accessKey = System.getenv(ACCESS_KEY); String secretKey = System.getenv(SECRET_KEY); String region = System.getenv(REGION); + String protocol = System.getenv(PROTOCOL); - if (accessKey != null && secretKey != null && region != null) + if (accessKey != null && secretKey != null && region != null && protocol != null) { env = ImmutableMap.builder().put(ACCESS_KEY, accessKey) - .put(SECRET_KEY, secretKey) - .put(REGION, region) - .build(); + .put(SECRET_KEY, secretKey) + .put(REGION, region) + .put(PROTOCOL, protocol) + .build(); } else { @@ -55,6 +61,7 @@ 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(); } @@ -111,8 +118,12 @@ public static URI getS3URI(URI s3GlobalUri) try { - return new URIBuilder(s3GlobalUri).setUserInfo((String) env.get(ACCESS_KEY), (String) env.get(SECRET_KEY)) - .build(); + final String accessKey = (String) env.get(ACCESS_KEY); + final String secretKey = (String) env.get(SECRET_KEY); + final String region = (String) env.get(REGION); + final URI s3Uri = region != null ? URI.create(String.format(S3_REGION_URI_IT, region)) : s3GlobalUri; + return new URIBuilder(s3Uri).setUserInfo(accessKey, secretKey) + .build(); } catch (URISyntaxException e) { diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingAmazonS3Client.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingAmazonS3Client.java deleted file mode 100644 index 57cf1d91..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingAmazonS3Client.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.carlspring.cloud.storage.s3fs.util; - -import java.net.URI; - -import com.amazonaws.ClientConfiguration; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.metrics.RequestMetricCollector; -import com.amazonaws.services.s3.AmazonS3Client; -import com.amazonaws.services.s3.S3ClientOptions; - -public class ExposingAmazonS3Client - extends AmazonS3Client -{ - - private AWSCredentialsProvider awsCredentialsProvider; - - private S3ClientOptions s3ClientOptions = S3ClientOptions.builder().build(); - - - public ExposingAmazonS3Client(AWSCredentialsProvider credentialsProvider, - ClientConfiguration clientConfiguration, - RequestMetricCollector requestMetricsCollector) - { - super(credentialsProvider, clientConfiguration, requestMetricsCollector); - - this.awsCredentialsProvider = credentialsProvider; - } - - public AWSCredentialsProvider getAWSCredentialsProvider() - { - return awsCredentialsProvider; - } - - public ClientConfiguration getClientConfiguration() - { - return clientConfiguration; - } - - public synchronized void setS3ClientOptions(S3ClientOptions clientOptions) - { - super.setS3ClientOptions(clientOptions); - - this.s3ClientOptions = clientOptions; - } - - public S3ClientOptions getClientOptions() - { - return this.s3ClientOptions; - } - - public RequestMetricCollector getRequestMetricCollector() - { - return super.requestMetricCollector(); - } - - public URI getEndpoint() - { - return endpoint; - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingAmazonS3ClientFactory.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingAmazonS3ClientFactory.java deleted file mode 100644 index 8fca9308..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingAmazonS3ClientFactory.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.carlspring.cloud.storage.s3fs.util; - -import org.carlspring.cloud.storage.s3fs.AmazonS3ClientFactory; - -import com.amazonaws.ClientConfiguration; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.metrics.RequestMetricCollector; -import com.amazonaws.services.s3.AmazonS3Client; - -public class ExposingAmazonS3ClientFactory - extends AmazonS3ClientFactory -{ - - - @Override - protected AmazonS3Client createAmazonS3(AWSCredentialsProvider credentialsProvider, - ClientConfiguration clientConfiguration, - RequestMetricCollector requestMetricsCollector) - { - return new ExposingAmazonS3Client(credentialsProvider, clientConfiguration, requestMetricsCollector); - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3BaseClientBuilder.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3BaseClientBuilder.java new file mode 100644 index 00000000..cfe91f20 --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3BaseClientBuilder.java @@ -0,0 +1,78 @@ +package org.carlspring.cloud.storage.s3fs.util; + +import java.util.List; + +import software.amazon.awssdk.auth.signer.AwsS3V4Signer; +import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; +import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; +import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientOption; +import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; +import software.amazon.awssdk.core.signer.Signer; +import software.amazon.awssdk.services.s3.S3BaseClientBuilder; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.S3Configuration.Builder; +import software.amazon.awssdk.utils.CollectionUtils; + +abstract class ExposingS3BaseClientBuilder, C> + extends AwsDefaultClientBuilder +{ + + ExposingS3BaseClientBuilder() + { + } + + protected final String serviceEndpointPrefix() + { + return "s3"; + } + + protected final String serviceName() + { + return "S3"; + } + + protected final SdkClientConfiguration mergeServiceDefaults(SdkClientConfiguration config) + { + return config.merge((c) -> c.option(SdkAdvancedClientOption.SIGNER, this.defaultSigner()).option( + SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED, false).option( + SdkClientOption.SERVICE_CONFIGURATION, S3Configuration.builder().build())); + } + + protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientConfiguration config) + { + ClasspathInterceptorChainFactory interceptorFactory = new ClasspathInterceptorChainFactory(); + List interceptors = interceptorFactory.getInterceptors( + "software/amazon/awssdk/services/s3/execution.interceptors"); + interceptors = CollectionUtils.mergeLists(interceptors, + config.option(SdkClientOption.EXECUTION_INTERCEPTORS)); + Builder c = ((S3Configuration) config.option(SdkClientOption.SERVICE_CONFIGURATION)).toBuilder(); + c.profileFile(c.profileFile() != null ? c.profileFile() : + config.option(SdkClientOption.PROFILE_FILE)).profileName( + c.profileName() != null ? c.profileName() : config.option(SdkClientOption.PROFILE_NAME)); + return config.toBuilder().option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors).option( + SdkClientOption.SERVICE_CONFIGURATION, c.build()).build(); + } + + private Signer defaultSigner() + { + return AwsS3V4Signer.create(); + } + + protected final String signingName() + { + return "s3"; + } + + public B serviceConfiguration(S3Configuration serviceConfiguration) + { + this.clientConfiguration.option(SdkClientOption.SERVICE_CONFIGURATION, serviceConfiguration); + return this.thisBuilder(); + } + + public void setServiceConfiguration(S3Configuration serviceConfiguration) + { + this.serviceConfiguration(serviceConfiguration); + } +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3Client.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3Client.java new file mode 100644 index 00000000..3c25496d --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3Client.java @@ -0,0 +1,42 @@ +package org.carlspring.cloud.storage.s3fs.util; + +import software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler; +import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.handler.SyncClientHandler; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3ClientBuilder; + +public class ExposingS3Client + implements S3Client +{ + + private final SyncClientHandler clientHandler; + private final SdkClientConfiguration clientConfiguration; + + public ExposingS3Client(SdkClientConfiguration clientConfiguration) + { + this.clientHandler = new AwsSyncClientHandler(clientConfiguration); + this.clientConfiguration = clientConfiguration; + } + + public SdkClientConfiguration getClientConfiguration() + { + return clientConfiguration; + } + + static S3ClientBuilder builder() { + return new ExposingS3ClientBuilder(); + } + + @Override + public String serviceName() + { + return SERVICE_NAME; + } + + @Override + public void close() + { + this.clientHandler.close(); + } +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3ClientBuilder.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3ClientBuilder.java new file mode 100644 index 00000000..0cfe8d77 --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3ClientBuilder.java @@ -0,0 +1,19 @@ +package org.carlspring.cloud.storage.s3fs.util; + +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3ClientBuilder; + +public class ExposingS3ClientBuilder + extends ExposingS3BaseClientBuilder + implements S3ClientBuilder +{ + + ExposingS3ClientBuilder() + { + } + + protected final S3Client buildClient() + { + return new ExposingS3Client(super.syncClientConfiguration()); + } +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3ClientFactory.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3ClientFactory.java new file mode 100644 index 00000000..b0170066 --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/ExposingS3ClientFactory.java @@ -0,0 +1,24 @@ +package org.carlspring.cloud.storage.s3fs.util; + +import org.carlspring.cloud.storage.s3fs.S3ClientFactory; + +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3ClientBuilder; + +public class ExposingS3ClientFactory + extends S3ClientFactory +{ + + @Override + protected S3Client createS3Client(final S3ClientBuilder builder) + { + return builder.build(); + } + + @Override + protected S3ClientBuilder getS3ClientBuilder() + { + return ExposingS3Client.builder(); + } + +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/MockBucket.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/MockBucket.java index 6dc8952a..6a8114d6 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/MockBucket.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/MockBucket.java @@ -7,14 +7,14 @@ public class MockBucket { - private AmazonS3ClientMock amazonS3ClientMock; + private final S3ClientMock s3ClientMock; - private Path mockedPath; + private final Path mockedPath; - - public MockBucket(AmazonS3ClientMock amazonS3ClientMock, Path mockedPath) + public MockBucket(final S3ClientMock s3ClientMock, + final Path mockedPath) { - this.amazonS3ClientMock = amazonS3ClientMock; + this.s3ClientMock = s3ClientMock; this.mockedPath = mockedPath; } @@ -23,24 +23,27 @@ public MockBucket file(String... file) { for (String string : file) { - amazonS3ClientMock.addFile(mockedPath, string, "sample-content".getBytes()); + s3ClientMock.addFile(mockedPath, string, "sample-content".getBytes()); } return this; } - public MockBucket file(String file, byte[] content) + public MockBucket file(String file, + final byte[] content) throws IOException { - amazonS3ClientMock.addFile(mockedPath, file, content); + s3ClientMock.addFile(mockedPath, file, content); return this; } - public MockBucket file(String file, byte[] content, FileAttribute... attrs) + public MockBucket file(String file, + final byte[] content, + final FileAttribute... attrs) throws IOException { - amazonS3ClientMock.addFile(mockedPath, file, content, attrs); + s3ClientMock.addFile(mockedPath, file, content, attrs); return this; } @@ -50,15 +53,17 @@ public MockBucket dir(String... dir) { for (String string : dir) { - amazonS3ClientMock.addDirectory(mockedPath, string); + s3ClientMock.addDirectory(mockedPath, string); } return this; } - public Path resolve(String file) + public Path resolve(final String file) { - return mockedPath.resolve(file.replaceAll("/", "%2F")); + final String encodedFile = file.replaceAll("/", "%2F"); + return mockedPath.resolve(encodedFile); } + } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/NoOpRequestMetricCollector.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/NoOpRequestMetricCollector.java deleted file mode 100644 index e27019c6..00000000 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/NoOpRequestMetricCollector.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.carlspring.cloud.storage.s3fs.util; - -import com.amazonaws.Request; -import com.amazonaws.Response; -import com.amazonaws.metrics.RequestMetricCollector; - -public class NoOpRequestMetricCollector - extends RequestMetricCollector -{ - - - @Override - public void collectMetrics(Request request, Response response) - { - // - } - - @Override - public boolean isEnabled() - { - return false; - } - -} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3ClientMock.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3ClientMock.java new file mode 100644 index 00000000..13c1a20e --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3ClientMock.java @@ -0,0 +1,1024 @@ +package org.carlspring.cloud.storage.s3fs.util; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFileAttributes; +import java.nio.file.attribute.PosixFilePermission; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.core.exception.SdkException; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.core.sync.ResponseTransformer; +import software.amazon.awssdk.http.AbortableInputStream; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.Bucket; +import software.amazon.awssdk.services.s3.model.CommonPrefix; +import software.amazon.awssdk.services.s3.model.CopyObjectRequest; +import software.amazon.awssdk.services.s3.model.CopyObjectResponse; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; +import software.amazon.awssdk.services.s3.model.CreateBucketResponse; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.DeleteObjectResponse; +import software.amazon.awssdk.services.s3.model.GetBucketAclRequest; +import software.amazon.awssdk.services.s3.model.GetBucketAclResponse; +import software.amazon.awssdk.services.s3.model.GetBucketLocationRequest; +import software.amazon.awssdk.services.s3.model.GetBucketLocationResponse; +import software.amazon.awssdk.services.s3.model.GetObjectAclRequest; +import software.amazon.awssdk.services.s3.model.GetObjectAclResponse; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.Grant; +import software.amazon.awssdk.services.s3.model.Grantee; +import software.amazon.awssdk.services.s3.model.HeadBucketRequest; +import software.amazon.awssdk.services.s3.model.HeadBucketResponse; +import software.amazon.awssdk.services.s3.model.HeadObjectRequest; +import software.amazon.awssdk.services.s3.model.HeadObjectResponse; +import software.amazon.awssdk.services.s3.model.ListBucketsRequest; +import software.amazon.awssdk.services.s3.model.ListBucketsResponse; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; +import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; +import software.amazon.awssdk.services.s3.model.NoSuchBucketException; +import software.amazon.awssdk.services.s3.model.NoSuchKeyException; +import software.amazon.awssdk.services.s3.model.ObjectStorageClass; +import software.amazon.awssdk.services.s3.model.Owner; +import software.amazon.awssdk.services.s3.model.Permission; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectResponse; +import software.amazon.awssdk.services.s3.model.S3Exception; +import software.amazon.awssdk.services.s3.model.S3Object; +import software.amazon.awssdk.utils.StringUtils; +import static java.util.Arrays.asList; +import static software.amazon.awssdk.http.HttpStatusCode.NOT_FOUND; + +public class S3ClientMock + implements S3Client +{ + + private static final Logger LOGGER = LoggerFactory.getLogger(S3ClientMock.class); + + /** + * max elements amazon aws + */ + private static final int LIMIT_AWS_MAX_ELEMENTS = 1000; + + private final Path base; + + private final Owner defaultOwner; + + private final Map bucketOwners; + + public S3ClientMock(final Path base) + { + this.base = base; + this.defaultOwner = Owner.builder().id("1").displayName("Mock").build(); + this.bucketOwners = new HashMap<>(); + } + + public String serviceName() + { + return null; + } + + @Override + public void close() + { + try + { + Files.walkFileTree(base, new SimpleFileVisitor() + { + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException exc) + throws IOException + { + if (dir != base) + { + Files.delete(dir); + } + + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) + throws IOException + { + Files.delete(file); + + return FileVisitResult.CONTINUE; + } + }); + } + catch (final IOException e) + { + LOGGER.error("Exception while closing the client base path", e); + } + } + + void addFile(final Path bucket, + String fileName, + final byte[] content) + throws IOException + { + addFile(bucket, fileName, content, new FileAttribute[0]); + } + + void addFile(final Path bucket, + String fileName, + final byte[] content, + final FileAttribute... attrs) + throws IOException + { + if (fileName.endsWith("/")) + { + fileName = fileName.substring(0, fileName.length() - 1); + } + + Path file = Files.createFile(bucket.resolve(fileName.replaceAll("/", "%2F")), attrs); + + try (OutputStream outputStream = Files.newOutputStream(file)) + { + outputStream.write(content); + } + } + + void addDirectory(final Path bucket, + String directoryName) + throws IOException + { + if (!directoryName.endsWith("/")) + { + directoryName += "/"; + } + + final String encodedDirectory = directoryName.replaceAll("/", "%2F"); + Files.createFile(bucket.resolve(encodedDirectory)); + } + + public MockBucket bucket(final String bucketName) + throws IOException + { + final Path bucketPath = base.resolve(bucketName); + return new MockBucket(this, Files.createDirectories(bucketPath)); + } + + public Path bucket(final String bucketName, + final Owner owner) + throws IOException + { + bucketOwners.put(bucketName, owner); + + return Files.createDirectories(base.resolve(bucketName)); + } + + @Override + public CopyObjectResponse copyObject(final CopyObjectRequest copyObjectRequest) + throws AwsServiceException, SdkClientException + { + final String source = copyObjectRequest.copySource(); + final String[] sources = source.split("%2F", 2); + try + { + final String sourceBucketName = decode(sources[0]); + final String sourceKey = decode(sources[1]); + + final String destinationBucketName = copyObjectRequest.destinationBucket(); + final String destinationKey = copyObjectRequest.destinationKey(); + + final Path src = find(sourceBucketName, sourceKey); + if (src != null && Files.exists(src)) + { + final Path bucket = find(destinationBucketName); + final Path dest = bucket.resolve(destinationKey.replaceAll("/", "%2F")); + + try + { + Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING); + } + catch (IOException e) + { + throw AwsServiceException.create("Problem copying mock objects: ", e); + } + + return CopyObjectResponse.builder().build(); + } + + } + catch (final UnsupportedEncodingException e) + { + LOGGER.error(e.getMessage()); + } + + throw AwsServiceException.builder().message("object source not found").build(); + } + + @Override + public CreateBucketResponse createBucket(final CreateBucketRequest createBucketRequest) + throws AwsServiceException, SdkClientException + { + final String bucketName = createBucketRequest.bucket(); + Path element = null; + try + { + final String name = bucketName.replaceAll("//", ""); + + element = base.resolve(name); + Files.createDirectories(element); + + return CreateBucketResponse.builder().build(); + } + catch (final IOException e) + { + throw SdkException.create("Error while creating the directory: " + element, e); + } + } + + @Override + public DeleteObjectResponse deleteObject(final DeleteObjectRequest deleteObjectRequest) + throws AwsServiceException, SdkClientException + { + boolean deleteMarker; + final String bucketName = deleteObjectRequest.bucket(); + final String key = deleteObjectRequest.key(); + + final Path bucket = find(bucketName); + Path resolve = bucket.resolve(key); + + try + { + deleteMarker = Files.deleteIfExists(resolve); + } + catch (final IOException e) + { + throw AwsServiceException.create("Problem deleting mock object: ", e); + } + + if(!deleteMarker) + { + resolve = bucket.resolve(key.replaceAll("/", "%2F")); + try + { + deleteMarker = Files.deleteIfExists(resolve); + } + catch (final IOException e) + { + throw AwsServiceException.create("Problem deleting mock object: ", e); + } + } + + return DeleteObjectResponse.builder().deleteMarker(deleteMarker).build(); + } + + @Override + public GetBucketLocationResponse getBucketLocation(final GetBucketLocationRequest getBucketLocationRequest) throws AwsServiceException, SdkClientException, S3Exception { + throw new UnsupportedOperationException(); + } + + private String decode(final String value) + throws UnsupportedEncodingException + { + try + { + return URLDecoder.decode(value, StandardCharsets.UTF_8.toString()); + } + catch (final UnsupportedEncodingException e) + { + throw new UnsupportedEncodingException("URL could not be decoded: " + e.getMessage()); + } + } + + @Override + public GetBucketAclResponse getBucketAcl(final GetBucketAclRequest getBucketAclRequest) + throws AwsServiceException, SdkClientException + { + final String bucketName = getBucketAclRequest.bucket(); + final Path element = find(bucketName); + + return createGetBucketAclResponse(element, bucketName); + } + + private GetBucketAclResponse createGetBucketAclResponse(final Path element, + final String bucketName) + { + final Owner owner = getOwner(bucketName); + final Collection grants = getGrants(element, owner); + + return GetBucketAclResponse.builder().owner(owner).grants(grants).build(); + } + + + @Override + public HeadBucketResponse headBucket(final HeadBucketRequest headBucketRequest) + { + final String bucketName = headBucketRequest.bucket(); + final Path bucket = find(bucketName); + + if (Files.notExists(bucket)) + { + throw NoSuchBucketException.builder().message("Bucket not found: " + bucketName).build(); + } + else + { + return HeadBucketResponse.builder().build(); + } + } + + @Override + public HeadObjectResponse headObject(final HeadObjectRequest headObjectRequest) + throws AwsServiceException, SdkClientException + { + final String bucketName = headObjectRequest.bucket(); + final String key = headObjectRequest.key(); + final GetObjectRequest request = GetObjectRequest.builder().bucket(bucketName).key(key).build(); + + try + { + final GetObjectResponse response; + final boolean isDirectory = key.endsWith("/") || key.isEmpty(); + if(isDirectory){ + Path path = find(bucketName, key); + response = getObject(request, path); + }else{ + final ResponseInputStream object = getObject(request); + response = object.response(); + } + + return parse(response); + } + catch (final SdkException e) + { + throw S3Exception.builder() + .message("Resource not available: " + bucketName + "/" + key) + .statusCode(NOT_FOUND) + .build(); + } + + } + + private S3Object getObject(final String bucketName, + final String key) + throws AwsServiceException + { + Path element = find(bucketName, key); + + if (element == null || Files.notExists(element)) + { + element = find(bucketName, key + "/"); + } + + if (element == null || Files.notExists(element)) + { + throw S3Exception.builder() + .message("Not found with key: " + key) + .statusCode(NOT_FOUND) + .build(); + } + + try + { + return parse(element, find(bucketName)).getS3Object(); + } + catch (final IOException e) + { + throw AwsServiceException.create("Problem getting mock for object: ", e); + } + } + + @SuppressWarnings("unchecked") + @Override + public ReturnT getObject(final GetObjectRequest getObjectRequest, + final ResponseTransformer responseTransformer) + throws AwsServiceException, SdkClientException + { + final String bucketName = getObjectRequest.bucket(); + final String key = getObjectRequest.key(); + Path element = find(bucketName, key); + + if (element == null || Files.notExists(element)) + { + element = find(bucketName, key + "/"); + } + + S3Object object = null; + if (element != null && Files.exists(element)) + { + object = getObject(bucketName, key); + if (StringUtils.equals(object.key(), key)) + { + final GetObjectResponse response = buildGetObjectResponse(object); + + final boolean isDirectory = key.endsWith("/") || key.isEmpty(); + if(!isDirectory) + { + final InputStream inputStream = getInputStream(false, element); + final AbortableInputStream abortableInputStream = AbortableInputStream.create(inputStream); + try + { + return responseTransformer.transform(response, abortableInputStream); + } + catch (final Exception e) + { + throw SdkException.create("Error while transforming the response: " + response, e); + } + } + + return (ReturnT) response; + } + } + + throw NoSuchKeyException.builder() + .message("Key not found: " + (object != null ? object.key() : key)) + .statusCode(NOT_FOUND) + .build(); + } + + private GetObjectResponse buildGetObjectResponse(final S3Object object) + { + return GetObjectResponse.builder() + .lastModified(object.lastModified()) + .eTag(object.eTag()) + .contentLength(object.size()) + .storageClass(object.storageClassAsString()) + .build(); + } + + @Override + public GetObjectAclResponse getObjectAcl(final GetObjectAclRequest getObjectAclRequest) + throws AwsServiceException, SdkClientException + { + final String bucketName = getObjectAclRequest.bucket(); + final String key = getObjectAclRequest.key(); + Path element = find(bucketName, key); + + if (element == null || Files.notExists(element)) + { + element = find(bucketName, key + "/"); + } + + if (element == null || Files.notExists(element)) + { + throw NoSuchKeyException.builder() + .message("Key not found: " + key) + .statusCode(NOT_FOUND) + .build(); + } + + return createGetObjectAclResponse(element, bucketName); + } + + @Override + public ListBucketsResponse listBuckets(final ListBucketsRequest listBucketsRequest) + throws AwsServiceException, SdkClientException + { + + final List buckets = new ArrayList<>(); + Owner owner = null; + try + { + for (final Path path : Files.newDirectoryStream(base)) + { + final String bucketName = path.getFileName().toString(); + owner = getOwner(bucketName); + + final Instant creationTime = Files.readAttributes(path, + BasicFileAttributes.class).creationTime().toInstant(); + final Bucket bucket = Bucket.builder() + .name(bucketName) + .creationDate(creationTime) + .build(); + + buckets.add(bucket); + } + } + catch (final IOException e) + { + throw SdkException.create("Error while opening the directory: " + base, e); + } + + return ListBucketsResponse.builder().buckets(buckets).owner(owner).build(); + } + + @Override + public ListObjectsV2Response listObjectsV2(final ListObjectsV2Request request) + throws AwsServiceException, SdkClientException + { + final String bucketName = request.bucket(); + final String prefix = request.prefix(); + final String marker = request.continuationToken(); + final String delimiter = request.delimiter(); + + final Path bucket = find(bucketName); + final TreeMap elements = new TreeMap<>(); + + try + { + for (final Path path : Files.newDirectoryStream(bucket)) + { + final S3Element element = parse(path, bucket); + + if (!elements.containsKey(element.getS3Object().key())) + { + elements.put(element.getS3Object().key(), element); + } + } + } + catch (final IOException e) + { + throw SdkException.create("Error while opening the directory: " + bucket, e); + } + + final Iterator iterator = elements.values().iterator(); + + int i = 0; + final List objects = new ArrayList<>(); + final List commonPrefixes = new ArrayList<>(); + boolean waitForMarker = StringUtils.isNotBlank(marker); + + while (iterator.hasNext()) + { + final S3Element element = iterator.next(); + final String key = element.getS3Object().key(); + if (key.equals("/")) + { + continue; + } + + if (waitForMarker) + { + waitForMarker = !key.startsWith(marker); + if (waitForMarker) + { + continue; + } + } + + if (prefix != null && key.startsWith(prefix)) + { + final int beginIndex = key.indexOf(prefix) + prefix.length(); + final String rest = key.substring(beginIndex); + + if (StringUtils.isNotBlank(delimiter) && rest.contains(delimiter)) + { + final String substring = key.substring(0, beginIndex + rest.indexOf(delimiter)); + final CommonPrefix commonPrefix = CommonPrefix.builder().prefix(substring).build(); + + if (!commonPrefixes.contains(commonPrefix)) + { + commonPrefixes.add(commonPrefix); + } + + continue; + } + + final S3Object object = element.getS3Object(); + objects.add(object); + + if (i + 1 == LIMIT_AWS_MAX_ELEMENTS && iterator.hasNext()) + { + return ListObjectsV2Response.builder() + .isTruncated(true) + .contents(objects) + .name(bucketName) + .prefix(prefix) + .delimiter(delimiter) + .commonPrefixes(commonPrefixes) + .nextContinuationToken(iterator.next().getS3Object().key()) + .build(); + } + + i++; + } + } + + objects.sort(Comparator.comparing(S3Object::key)); + + return ListObjectsV2Response.builder() + .isTruncated(false) + .contents(objects) + .name(bucketName) + .prefix(prefix) + .delimiter(delimiter) + .commonPrefixes(commonPrefixes) + .build(); + } + + private GetObjectAclResponse createGetObjectAclResponse(final Path element, + final String bucketName) + { + final Owner owner = getOwner(bucketName); + final Collection grants = getGrants(element, owner); + + return GetObjectAclResponse.builder().owner(owner).grants(grants).build(); + } + + private Path find(final String bucketName, + final String key) + { + final Path bucket = find(bucketName); + + if (Files.notExists(bucket)) + { + return null; + } + + try + { + final String fileKey = key.replaceAll("/", "%2F"); + final List matches = new ArrayList<>(); + + Files.walkFileTree(bucket, new SimpleFileVisitor() + { + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attrs) + { + String relativize = bucket.relativize(dir).toString(); + + if (relativize.equals(fileKey)) + { + matches.add(dir); + } + + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) + { + String relativize = bucket.relativize(file).toString(); + + if (relativize.equals(fileKey)) + { + matches.add(file); + } + + return FileVisitResult.CONTINUE; + } + }); + + if (!matches.isEmpty()) + { + return matches.iterator().next(); + } + } + catch (final IOException e) + { + throw AwsServiceException.create("Problem getting mock S3Element: ", e); + } + + return null; + } + + private Path find(final String bucketName) + { + return base.resolve(bucketName); + } + + private S3Element parse(final Path element, + final Path bucket) + throws IOException + { + final String bucketName = bucket.getFileName().toString(); + final String key = bucket.relativize(element).toString().replaceAll("%2F", "/"); + boolean isDirectory = key.endsWith("/") || key.isEmpty(); + + final BasicFileAttributes attr = Files.readAttributes(element, BasicFileAttributes.class); + final Instant lastModified = attr.lastAccessTime().toInstant(); + final long size = isDirectory ? 0L : attr.size(); + final ObjectStorageClass storageClass = ObjectStorageClass.STANDARD; + final Owner owner = getOwner(bucketName); + + final S3Object object = S3Object.builder() + .key(key) + .lastModified(lastModified) + .size(size) + .storageClass(storageClass) + .owner(owner) + .build(); + + final InputStream inputStream = getInputStream(isDirectory, element); + + return new S3Element(object, isDirectory, inputStream); + } + + private InputStream getInputStream(final boolean isDirectory, + final Path element) + { + InputStream inputStream = null; + if (!isDirectory) + { + byte[] bytes; + try + { + bytes = Files.readAllBytes(element); + } + catch (final IOException e) + { + throw SdkException.create("Error while reading the element: " + element, e); + } + + inputStream = new ByteArrayInputStream(bytes); + } + return inputStream; + } + + /** + * create the org.carlspring.cloud.storage.s3fs.AccessControlList from a Path + * + * @param element Path + * @param owner Owner + * @return GetObjectAclResponse never null + */ + private GetObjectAclResponse createAclPermission(final Path element, + final Owner owner) + { + final Collection grants = getGrants(element, owner); + + return GetObjectAclResponse.builder().owner(owner).grants(grants).build(); + } + + private Collection getGrants(final Path element, + final Owner owner) + { + final Grantee grantee = Grantee.builder().type(owner.id()).id(owner.id()).build(); + + final Set permissions = new HashSet<>(); + + try + { + final Set posixFilePermissions = Files.readAttributes(element, + PosixFileAttributes.class).permissions(); + for (PosixFilePermission posixFilePermission : posixFilePermissions) + { + switch (posixFilePermission) + { + case GROUP_READ: + case OTHERS_READ: + case OWNER_READ: + permissions.add(Permission.READ); + break; + case OWNER_WRITE: + case GROUP_WRITE: + case OTHERS_WRITE: + permissions.add(Permission.WRITE); + break; + case OWNER_EXECUTE: + case GROUP_EXECUTE: + case OTHERS_EXECUTE: + permissions.add(Permission.WRITE_ACP); + permissions.add(Permission.READ_ACP); + break; + + } + } + } + catch (IOException e) + { + throw new RuntimeException(e); + } + + return permissions.stream() + .map(permission -> Grant.builder().grantee(grantee).permission(permission).build()) + .collect(Collectors.toList()); + } + + private GetObjectAclResponse createAllPermission(final String bucketName) + { + final Owner owner = getOwner(bucketName); + final Grantee grantee = Grantee.builder().type(owner.id()).id(owner.id()).build(); + final Grant grantFullControl = Grant.builder().grantee(grantee).permission( + Permission.FULL_CONTROL.name()).build(); + final Grant grantRead = Grant.builder().grantee(grantee).permission(Permission.READ).build(); + final Grant grantWrite = Grant.builder().grantee(grantee).permission(Permission.WRITE).build(); + final Collection grants = asList(grantFullControl, grantRead, grantWrite); + + return GetObjectAclResponse.builder().owner(owner).grants(grants).build(); + } + + private Owner getOwner(final String bucketName) + { + if (!bucketOwners.containsKey(bucketName)) + { + return defaultOwner; + } + + return bucketOwners.get(bucketName); + } + + private HeadObjectResponse parse(final GetObjectResponse object) + { + return HeadObjectResponse.builder() + .lastModified(object.lastModified()) + .eTag(object.eTag()) + .contentLength(object.contentLength()) + .storageClass(object.storageClassAsString()) + .build(); + } + + @Override + public PutObjectResponse putObject(final PutObjectRequest putObjectRequest, + final RequestBody requestBody) + throws AwsServiceException, SdkClientException + { + final String bucketName = putObjectRequest.bucket(); + final String key = putObjectRequest.key(); + final InputStream inputStream = requestBody.contentStreamProvider().newStream(); + + final S3Element element = parse(inputStream, bucketName, key); + + persist(bucketName, element); + + final String eTag = "3a5c8b1ad448bca04584ecb55b836264"; + return PutObjectResponse.builder().eTag(eTag).build(); + } + + private S3Element parse(final InputStream inputStream, + final String bucketName, + final String key) + { + final S3Object.Builder builder = S3Object.builder(); + builder.key(key); + + final Owner owner = getOwner(bucketName); + builder.owner(owner); + + try + { + builder.lastModified(Instant.now()); + builder.size((long) inputStream.available()); + + return new S3Element(builder.build(), false, inputStream); + } + catch (final IOException e) + { + throw new IllegalStateException("the inputStream is closed", e); + } + } + + /** + * store in the memory map + * + * @param bucketName bucket where persist + * @param element + */ + private void persist(final String bucketName, + final S3Element element) + { + final Path bucket = find(bucketName); + + final String key = element.getS3Object().key().replaceAll("/", "%2F"); + + final Path resolve = bucket.resolve(key); + + if (Files.exists(resolve)) + { + try + { + Files.delete(resolve); + } + catch (final IOException ignored) + { + // ignore + } + } + + try + { + Files.createFile(resolve); + + final InputStream inputStream = element.getInputStream(); + if (inputStream != null) + { + byte[] byteArray = IOUtils.toByteArray(inputStream); + + Files.write(resolve, byteArray); + } + } + catch (final IOException e) + { + throw AwsServiceException.create("Problem creating mock element: ", e); + } + } + + public static class S3Element + { + + private S3Object s3Object; + + private boolean directory; + + private InputStream inputStream; + + public S3Element(final S3Object s3Object, + final boolean directory, + final InputStream inputStream) + { + this.s3Object = s3Object; + this.directory = directory; + this.inputStream = inputStream; + } + + public S3Object getS3Object() + { + return s3Object; + } + + public void setS3Object(final S3Object s3Object) + { + this.s3Object = s3Object; + } + + public boolean isDirectory() + { + return directory; + } + + public void setDirectory(final boolean directory) + { + this.directory = directory; + } + + public InputStream getInputStream() + { + return inputStream; + } + + public void setInputStream(InputStream inputStream) + { + this.inputStream = inputStream; + } + + @Override + public boolean equals(final Object object) + { + if (object == null) + { + return false; + } + + if (object instanceof S3Element) + { + S3Element elem = (S3Element) object; + // only is the same if keys are not null and they are the same + return elem.getS3Object() != null && this.getS3Object() != null && + elem.getS3Object().key() != null && + elem.getS3Object().key().equals(this.getS3Object().key()); + } + + return false; + } + + @Override + public int hashCode() + { + return 31 * (s3Object != null && s3Object.key() != null ? s3Object.key().hashCode() : 0); + } + } +} diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3EndpointConstant.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3EndpointConstant.java index 4f77d722..307af444 100644 --- a/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3EndpointConstant.java +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3EndpointConstant.java @@ -7,6 +7,10 @@ public class S3EndpointConstant public static final URI S3_GLOBAL_URI_TEST = URI.create("s3://s3.test.amazonaws.com/"); + public static final String S3_REGION_URI_TEST = "s3://s3.test.%s.amazonaws.com/"; + public static final URI S3_GLOBAL_URI_IT = URI.create("s3://s3.amazonaws.com/"); + public static final String S3_REGION_URI_IT = "s3://s3.%s.amazonaws.com/"; + } diff --git a/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3MockFactory.java b/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3MockFactory.java new file mode 100644 index 00000000..5cfb0e3e --- /dev/null +++ b/src/test/java/org/carlspring/cloud/storage/s3fs/util/S3MockFactory.java @@ -0,0 +1,69 @@ +package org.carlspring.cloud.storage.s3fs.util; + +import org.carlspring.cloud.storage.s3fs.S3Factory; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.util.Properties; +import java.util.UUID; + +import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3ClientBuilder; +import static org.mockito.Mockito.spy; + +public class S3MockFactory + extends S3Factory +{ + + private static FileSystem fsMem; + + private static S3ClientMock s3Client; + + + @Override + public S3Client getS3Client(final URI uri, final Properties props) + { + return getS3ClientMock(); + } + + @Override + protected S3Client createS3Client(final S3ClientBuilder builder) + { + return getS3ClientMock(); + } + + public static S3ClientMock getS3ClientMock() + { + if (s3Client == null) + { + final Path path = getFsMem().getPath("/"); + final S3ClientMock s3ClientMock = new S3ClientMock(path); + s3Client = spy(s3ClientMock); + } + + return s3Client; + } + + private static FileSystem getFsMem() + { + if (fsMem == null) + { + try + { + fsMem = MemoryFileSystemBuilder.newLinux() + .setCurrentWorkingDirectory("/") + .build(UUID.randomUUID().toString()); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + return fsMem; + } + +} diff --git a/src/test/resources/amazon-test-sample.properties b/src/test/resources/amazon-test-sample.properties index 7bbcf2c5..0ac5aa8c 100644 --- a/src/test/resources/amazon-test-sample.properties +++ b/src/test/resources/amazon-test-sample.properties @@ -2,5 +2,6 @@ bucket_name=/your-bucket-name-for-test # http://docs.aws.amazon.com/general/latest/gr/rande.html s3fs_access_key=access-key-for-test s3fs_secret_key=secret-key-for-test -# check com.amazonaws.regions.Regions for quick list +# check software.amazon.awssdk.regions.Region for quick list s3fs_region=eu-central-1 +s3fs_protocol=https