Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support versioning #1895

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Of these [operations of the Amazon S3 API](https://docs.aws.amazon.com/AmazonS3/
| [GetBucketReplication](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketReplication.html) | :x: | |
| [GetBucketRequestPayment](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketRequestPayment.html) | :x: | |
| [GetBucketTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html) | :x: | |
| [GetBucketVersioning](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html) | :x: | |
| [GetBucketVersioning](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html) | :white_check_mark: | |
| [GetBucketWebsite](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketWebsite.html) | :x: | |
| [GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) | :white_check_mark: | |
| [GetObjectAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html) | :white_check_mark: | |
Expand Down Expand Up @@ -143,7 +143,7 @@ Of these [operations of the Amazon S3 API](https://docs.aws.amazon.com/AmazonS3/
| [PutBucketReplication](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketReplication.html) | :x: | |
| [PutBucketRequestPayment](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketRequestPayment.html) | :x: | |
| [PutBucketTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html) | :x: | |
| [PutBucketVersioning](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketVersioning.html) | :x: | |
| [PutBucketVersioning](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketVersioning.html) | :white_check_mark: | |
| [PutBucketWebsite](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketWebsite.html) | :x: | |
| [PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) | :white_check_mark: | |
| [PutObjectAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html) | :white_check_mark: | |
Expand Down
2 changes: 2 additions & 0 deletions integration-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<groupId>com.adobe.testing</groupId>
<artifactId>s3mock-docker</artifactId>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
Expand Down Expand Up @@ -70,6 +71,7 @@
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,24 @@ import software.amazon.awssdk.awscore.exception.AwsServiceException
import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.AbortIncompleteMultipartUpload
import software.amazon.awssdk.services.s3.model.BucketLifecycleConfiguration
import software.amazon.awssdk.services.s3.model.BucketVersioningStatus
import software.amazon.awssdk.services.s3.model.CreateBucketRequest
import software.amazon.awssdk.services.s3.model.DeleteBucketLifecycleRequest
import software.amazon.awssdk.services.s3.model.DeleteBucketRequest
import software.amazon.awssdk.services.s3.model.ExpirationStatus
import software.amazon.awssdk.services.s3.model.GetBucketLifecycleConfigurationRequest
import software.amazon.awssdk.services.s3.model.GetBucketLocationRequest
import software.amazon.awssdk.services.s3.model.GetBucketVersioningRequest
import software.amazon.awssdk.services.s3.model.HeadBucketRequest
import software.amazon.awssdk.services.s3.model.LifecycleExpiration
import software.amazon.awssdk.services.s3.model.LifecycleRule
import software.amazon.awssdk.services.s3.model.LifecycleRuleFilter
import software.amazon.awssdk.services.s3.model.MFADelete
import software.amazon.awssdk.services.s3.model.MFADeleteStatus
import software.amazon.awssdk.services.s3.model.NoSuchBucketException
import software.amazon.awssdk.services.s3.model.PutBucketLifecycleConfigurationRequest
import software.amazon.awssdk.services.s3.model.PutBucketVersioningRequest
import software.amazon.awssdk.services.s3.model.VersioningConfiguration
import java.util.concurrent.TimeUnit

/**
Expand Down Expand Up @@ -79,6 +85,52 @@ internal class BucketV2IT : S3TestBase() {
assertThat(bucketLocation.locationConstraint().toString()).isEqualTo("eu-west-1")
}

@Test
@S3VerifiedSuccess(year = 2024)
fun getDefaultBucketVersioning(testInfo: TestInfo) {
val bucketName = givenBucketV2(testInfo)

s3ClientV2.getBucketVersioning(
GetBucketVersioningRequest
.builder()
.bucket(bucketName)
.build()
).also {
assertThat(it.status()).isNull()
assertThat(it.mfaDelete()).isNull()
}
}

@Test
@S3VerifiedFailure(year = 2024, reason = "No real Mfa value")
fun putAndGetBucketVersioning(testInfo: TestInfo) {
val bucketName = givenBucketV2(testInfo)
s3ClientV2.putBucketVersioning(
PutBucketVersioningRequest
.builder()
.bucket(bucketName)
.mfa("fakeMfaValue")
.versioningConfiguration(
VersioningConfiguration
.builder()
.status(BucketVersioningStatus.ENABLED)
.mfaDelete(MFADelete.ENABLED)
.build()
)
.build()
)

s3ClientV2.getBucketVersioning(
GetBucketVersioningRequest
.builder()
.bucket(bucketName)
.build()
).also {
assertThat(it.status()).isEqualTo(BucketVersioningStatus.ENABLED)
assertThat(it.mfaDelete()).isEqualTo(MFADeleteStatus.ENABLED)
}
}

@Test
@S3VerifiedSuccess(year = 2024)
fun duplicateBucketCreation(testInfo: TestInfo) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2017-2024 Adobe.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.adobe.testing.s3mock.its

import software.amazon.awssdk.services.s3.S3Client

internal class VersionsV2IT : S3TestBase() {
private val s3ClientV2: S3Client = createS3ClientV2()


}
24 changes: 13 additions & 11 deletions server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
Expand All @@ -59,11 +63,6 @@
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>auth</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
Expand All @@ -82,9 +81,15 @@
<artifactId>httpcore</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>auth</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand All @@ -101,23 +106,20 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<artifactId>spring-boot-starter-actuator</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_LOCATION;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_OBJECT_LOCK;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_UPLOADS;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_VERSIONING;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.NOT_VERSIONS;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.OBJECT_LOCK;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.START_AFTER;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.VERSIONING;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.VERSIONS;
import static com.adobe.testing.s3mock.util.AwsHttpParameters.VERSION_ID_MARKER;
import static org.springframework.http.MediaType.APPLICATION_XML_VALUE;
Expand All @@ -44,6 +46,7 @@
import com.adobe.testing.s3mock.dto.ListVersionsResult;
import com.adobe.testing.s3mock.dto.LocationConstraint;
import com.adobe.testing.s3mock.dto.ObjectLockConfiguration;
import com.adobe.testing.s3mock.dto.VersioningConfiguration;
import com.adobe.testing.s3mock.service.BucketService;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
Expand Down Expand Up @@ -116,7 +119,8 @@ public ResponseEntity<ListAllMyBucketsResult> listBuckets() {
},
params = {
NOT_OBJECT_LOCK,
NOT_LIFECYCLE
NOT_LIFECYCLE,
NOT_VERSIONING
}
)
public ResponseEntity<Void> createBucket(@PathVariable final String bucketName,
Expand Down Expand Up @@ -180,6 +184,62 @@ public ResponseEntity<Void> deleteBucket(@PathVariable String bucketName) {
return ResponseEntity.noContent().build();
}

/**
* Get VersioningConfiguration of a bucket.
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html">API Reference</a>
*
* @param bucketName name of the Bucket.
*
* @return 200, VersioningConfiguration
*/
@GetMapping(
value = {
//AWS SDK V2 pattern
"/{bucketName:.+}",
//AWS SDK V1 pattern
"/{bucketName:.+}/"
},
params = {
VERSIONING,
NOT_LIST_TYPE
},
produces = APPLICATION_XML_VALUE
)
public ResponseEntity<VersioningConfiguration> getVersioningConfiguration(
@PathVariable String bucketName) {
bucketService.verifyBucketExists(bucketName);
var configuration = bucketService.getVersioningConfiguration(bucketName);
return ResponseEntity.ok(configuration);
}

/**
* Put VersioningConfiguration of a bucket.
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketVersioning.html">API Reference</a>
*
* @param bucketName name of the Bucket.
*
* @return 200
*/
@PutMapping(
value = {
//AWS SDK V2 pattern
"/{bucketName:.+}",
//AWS SDK V1 pattern
"/{bucketName:.+}/"
},
params = {
VERSIONING
},
consumes = APPLICATION_XML_VALUE
)
public ResponseEntity<Void> putVersioningConfiguration(
@PathVariable String bucketName,
@RequestBody VersioningConfiguration configuration) {
bucketService.verifyBucketExists(bucketName);
bucketService.setVersioningConfiguration(bucketName, configuration);
return ResponseEntity.ok().build();
}

/**
* Get ObjectLockConfiguration of a bucket.
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectLockConfiguration.html">API Reference</a>
Expand Down Expand Up @@ -360,7 +420,8 @@ public ResponseEntity<LocationConstraint> getBucketLocation(
NOT_LIST_TYPE,
NOT_LIFECYCLE,
NOT_LOCATION,
NOT_VERSIONS
NOT_VERSIONS,
NOT_VERSIONING
},
produces = APPLICATION_XML_VALUE
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2023 Adobe.
* Copyright 2017-2024 Adobe.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,20 +16,18 @@

package com.adobe.testing.s3mock;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
* Spring Boot 2.2+ does not include the default favicon.ico anymore.
* This is needed to check if the S3 Mock is up (at least in our examples and some use-cases)
*/
@Controller
@RestController
@RequestMapping
class FaviconController {
@GetMapping("favicon.ico")
@ResponseBody
void favicon() {
// Method is intentionally empty.
}
Expand Down
Loading
Loading