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

myniva/gradle-s3-build-cache#5: Adds option to use reduced redundancy… #6

Merged
merged 3 commits into from
Sep 26, 2017
Merged
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
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ buildscript {

### Configuration

The AWS S3 build cache implementation requires two configuration options:
The AWS S3 build cache implementation has a few configuration options:

| Configuration Key | Description |
| ----------------- | ----------- |
| region | The AWS region the S3 bucket is located in. |
| bucket | The name of the AWS S3 bucket where cache objects should be stored. |
| Configuration Key | Description | Default Value |
| ----------------- | ----------- | ----------- |
| region | The AWS region the S3 bucket is located in. | |
| bucket | The name of the AWS S3 bucket where cache objects should be stored. | |
| reducedRedundancy | Whether or not to use [reduced redundancy](https://aws.amazon.com/s3/reduced-redundancy/). | true |

(Options without a default value are mandatory.)


The `buildCache` configuration block might look like this:
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/ch/myniva/gradle/caching/s3/AwsS3BuildCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
import org.gradle.caching.configuration.AbstractBuildCache;

public class AwsS3BuildCache extends AbstractBuildCache {

private String region;
private String bucket;
private boolean reducedRedundancy = true;

public String getRegion() {
return region;
Expand All @@ -38,4 +38,12 @@ public String getBucket() {
public void setBucket(String bucket) {
this.bucket = bucket;
}

public boolean isReducedRedundancy() {
return reducedRedundancy;
}

public void setReducedRedundancy(boolean reducedRedundancy) {
this.reducedRedundancy = reducedRedundancy;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import com.amazonaws.services.s3.model.StorageClass;
import org.gradle.caching.BuildCacheEntryReader;
import org.gradle.caching.BuildCacheEntryWriter;
import org.gradle.caching.BuildCacheException;
Expand All @@ -38,10 +41,12 @@ public class AwsS3BuildCacheService implements BuildCacheService {

private final AmazonS3 s3;
private final String bucketName;
private final boolean reducedRedundancy;

AwsS3BuildCacheService(AmazonS3 s3, String bucketName) {
AwsS3BuildCacheService(AmazonS3 s3, String bucketName, boolean reducedRedundancy) {
this.s3 = s3;
this.bucketName = bucketName;
this.reducedRedundancy = reducedRedundancy;
}

@Override
Expand Down Expand Up @@ -71,13 +76,21 @@ public void store(BuildCacheKey key, BuildCacheEntryWriter writer) {
writer.writeTo(os);
meta.setContentLength(os.size());
try (InputStream is = new ByteArrayInputStream(os.toByteArray())) {
s3.putObject(bucketName, key.getHashCode(), is, meta);
PutObjectRequest request = getPutObjectRequest(key, meta, is);
if(this.reducedRedundancy) {
request.withStorageClass(StorageClass.ReducedRedundancy);
}
s3.putObject(request);
}
} catch (IOException e) {
throw new BuildCacheException("Error while storing cache object in S3 bucket", e);
}
}

protected PutObjectRequest getPutObjectRequest(BuildCacheKey key, ObjectMetadata meta, InputStream is) {
return new PutObjectRequest(bucketName, key.getHashCode(), is, meta);
}

@Override
public void close() throws IOException {
// The AWS S3 client does not need to be closed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public BuildCacheService createBuildCacheService(AwsS3BuildCache config, Describ
verifyConfig(config);
AmazonS3 s3 = createS3Client(config);

return new AwsS3BuildCacheService(s3, config.getBucket());
return new AwsS3BuildCacheService(s3, config.getBucket(), config.isReducedRedundancy());
}

private void verifyConfig(AwsS3BuildCache config) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright 2017 the original author or authors.
*
* 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 ch.myniva.gradle.caching.s3.internal;

import static org.junit.Assert.assertNotNull;
Expand Down Expand Up @@ -47,15 +63,6 @@ public void testIllegalConfigWithoutBucket() throws Exception {
subject.createBuildCacheService(conf, buildCacheDescriber);
}

@Test(expected = GradleException.class)
public void testIllegalConfigWithInvalidRegion() throws Exception {
AwsS3BuildCache conf = new AwsS3BuildCache();
conf.setRegion("not-a-valid-aws-region");
conf.setBucket("my-bucket");

subject.createBuildCacheService(conf, buildCacheDescriber);
}

private class NoopBuildCacheDescriber implements Describer {

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2017 the original author or authors.
*
* 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 ch.myniva.gradle.caching.s3.internal;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add missing license header:

/*
 * Copyright 2017 the original author or authors.
 *
 * 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.
 */


import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.StorageClass;
import org.gradle.caching.BuildCacheEntryWriter;
import org.gradle.caching.BuildCacheKey;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class AwsS3BuildCacheServiceTest {
@Mock
AmazonS3 s3;
@Mock
BuildCacheKey key;
@Mock
BuildCacheEntryWriter writer;
@Mock
PutObjectRequest putObjectRequest = mock(PutObjectRequest.class);

AwsS3BuildCacheService buildCacheService;

@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}

@Test
public void storePutsObjectAndUsesReducedRedundancyWhenConfigured() throws IOException {
/** Setup **/
buildCacheService = spy(new AwsS3BuildCacheService(s3, "bucketName", true));
doReturn(putObjectRequest).when(buildCacheService).getPutObjectRequest(any(BuildCacheKey.class),
any(ObjectMetadata.class), any(InputStream.class));

/** Run **/
buildCacheService.store(key, writer);

/** Check **/
verifyThatStoreStores();
verify(putObjectRequest).withStorageClass(eq(StorageClass.ReducedRedundancy));
}

@Test
public void storePutsObjectAndDoesNotUseReducedRedundancyWhenConfigured() throws IOException {
/** Setup **/
buildCacheService = spy(new AwsS3BuildCacheService(s3, "bucketName", false));
doReturn(putObjectRequest).when(buildCacheService).getPutObjectRequest(any(BuildCacheKey.class),
any(ObjectMetadata.class), any(InputStream.class));

/** Run **/
buildCacheService.store(key, writer);

/** Check **/
verifyThatStoreStores();
verify(putObjectRequest, never()).withStorageClass(eq(StorageClass.ReducedRedundancy));
}

private void verifyThatStoreStores() throws IOException {
verify(writer).writeTo(any(ByteArrayOutputStream.class));
verify(buildCacheService).getPutObjectRequest(eq(key), any(ObjectMetadata.class), any(InputStream.class));
verify(s3).putObject(eq(putObjectRequest));
}
}