diff --git a/aws-modules/aws-s3/pom.xml b/aws-modules/aws-s3/pom.xml
index 9ba436b43f..b7bc34f863 100644
--- a/aws-modules/aws-s3/pom.xml
+++ b/aws-modules/aws-s3/pom.xml
@@ -20,6 +20,12 @@
s3
${aws.java.sdk.version}
+
+ software.amazon.awssdk
+ url-connection-client
+ ${aws.java.sdk.version}
+ test
+
commons-io
@@ -37,12 +43,34 @@
commons-codec
${commons-codec-version}
+
+
+ com.adobe.testing
+ s3mock
+ ${com.adobe.testing.version}
+ test
+
+
+ com.adobe.testing
+ s3mock-testcontainers
+ ${com.adobe.testing.version}
+ test
+
+
+
+ org.testcontainers
+ junit-jupiter
+ ${org.testcontainers.version}
+ test
+
2.20.52
1.10.L001
0.9.4.0006L
+ 3.3.0
+ 1.19.4
\ No newline at end of file
diff --git a/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3CrudService.java b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3CrudService.java
new file mode 100644
index 0000000000..75990516b2
--- /dev/null
+++ b/aws-modules/aws-s3/src/main/java/com/baeldung/s3/S3CrudService.java
@@ -0,0 +1,65 @@
+package com.baeldung.s3;
+
+import java.util.Optional;
+
+import software.amazon.awssdk.core.ResponseBytes;
+import software.amazon.awssdk.core.sync.RequestBody;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
+import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
+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 software.amazon.awssdk.services.s3.model.S3Exception;
+
+public class S3CrudService {
+
+ private final S3Client s3Client;
+
+ public S3CrudService(S3Client s3Client) {
+ this.s3Client = s3Client;
+ }
+
+ public void createBucket(String bucketName) {
+ CreateBucketRequest bucketRequest = CreateBucketRequest.builder()
+ .bucket(bucketName)
+ .build();
+
+ s3Client.createBucket(bucketRequest);
+ }
+
+ public void createObject(String bucketName, File inMemoryObject) {
+ PutObjectRequest request = PutObjectRequest.builder()
+ .bucket(bucketName)
+ .key(inMemoryObject.getName())
+ .build();
+ s3Client.putObject(request, RequestBody.fromByteBuffer(inMemoryObject.getContent()));
+ }
+
+ public Optional getObject(String bucketName, String objectKey) {
+ try {
+ GetObjectRequest getObjectRequest = GetObjectRequest.builder()
+ .bucket(bucketName)
+ .key(objectKey)
+ .build();
+ ResponseBytes responseResponseBytes = s3Client.getObjectAsBytes(getObjectRequest);
+ return Optional.of(responseResponseBytes.asByteArray());
+ } catch (S3Exception e) {
+ return Optional.empty();
+ }
+ }
+
+ public boolean deleteObject(String bucketName, String objectKey) {
+ try {
+ DeleteObjectRequest deleteObjectRequest = DeleteObjectRequest.builder()
+ .bucket(bucketName)
+ .key(objectKey)
+ .build();
+
+ s3Client.deleteObject(deleteObjectRequest);
+ return true;
+ } catch (S3Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/aws-modules/aws-s3/src/test/java/com/baeldung/s3/S3CrudServiceIntegrationTest.java b/aws-modules/aws-s3/src/test/java/com/baeldung/s3/S3CrudServiceIntegrationTest.java
new file mode 100644
index 0000000000..19a5f713d2
--- /dev/null
+++ b/aws-modules/aws-s3/src/test/java/com/baeldung/s3/S3CrudServiceIntegrationTest.java
@@ -0,0 +1,82 @@
+package com.baeldung.s3;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static software.amazon.awssdk.http.SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES;
+
+import java.net.URI;
+import java.util.Arrays;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import com.adobe.testing.s3mock.testcontainers.S3MockContainer;
+
+import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
+import software.amazon.awssdk.services.s3.S3Client;
+import software.amazon.awssdk.services.s3.S3Configuration;
+import software.amazon.awssdk.utils.AttributeMap;
+
+// This live test needs a running Docker instance so that a S3Mock Container can be started
+
+@Testcontainers
+public class S3CrudServiceIntegrationTest {
+
+ private static final String TEST_BUCKET_NAME = "test-bucket";
+
+ @Container
+ private final S3MockContainer s3Mock = new S3MockContainer("latest");
+ private S3Client s3Client;
+
+ @BeforeEach
+ void setUp() {
+ var endpoint = s3Mock.getHttpsEndpoint();
+ var serviceConfig = S3Configuration.builder()
+ .pathStyleAccessEnabled(true)
+ .build();
+ var httpClient = UrlConnectionHttpClient.builder()
+ .buildWithDefaults(AttributeMap.builder()
+ .put(TRUST_ALL_CERTIFICATES, Boolean.TRUE)
+ .build());
+ s3Client = S3Client.builder()
+ .endpointOverride(URI.create(endpoint))
+ .serviceConfiguration(serviceConfig)
+ .httpClient(httpClient)
+ .build();
+ }
+
+ @Test
+ void whenVerifyingCreationOfS3Bucket_thenCorrect() {
+ var s3CrudService = new S3CrudService(s3Client);
+ s3CrudService.createBucket(TEST_BUCKET_NAME);
+
+ var createdBucketName = s3Client.listBuckets()
+ .buckets()
+ .get(0)
+ .name();
+ assertThat(TEST_BUCKET_NAME).isEqualTo(createdBucketName);
+ }
+
+ @Test
+ void whenCreatingAnObjectOnS3Bucket_thenSameObjectIsRetrived() {
+ var s3CrudService = new S3CrudService(s3Client);
+ s3CrudService.createBucket(TEST_BUCKET_NAME);
+
+ var fileToSave = FileGenerator.generateFiles(1, 100)
+ .get(0);
+ s3CrudService.createObject(TEST_BUCKET_NAME, fileToSave);
+
+ var savedFileContent = s3CrudService.getObject(TEST_BUCKET_NAME, fileToSave.getName());
+
+ assertThat(Arrays.equals(fileToSave.getContent()
+ .array(), savedFileContent.orElse(new byte[]{}))).isTrue();
+
+ s3CrudService.deleteObject(TEST_BUCKET_NAME,fileToSave.getName());
+
+ var deletedFileContent = s3CrudService.getObject(TEST_BUCKET_NAME, fileToSave.getName());
+ assertThat(deletedFileContent).isEmpty();
+ }
+}
+
+