Issue 191: changed encryption service so that it can decode a PEM key. updated chef to work in google appengine

This commit is contained in:
Adrian Cole 2010-07-22 15:35:03 -07:00
parent 126460fd1d
commit 7c3518f7ff
24 changed files with 718 additions and 448 deletions

View File

@ -34,7 +34,7 @@ import org.jclouds.logging.Logger;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
* Handles Retryable responses with error codes in the 3xx range * Handles Retryable responses with error codes in the 4xx range
* *
* @author Adrian Cole * @author Adrian Cole
*/ */

View File

@ -23,6 +23,7 @@ import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay; import static org.easymock.classextension.EasyMock.replay;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.security.NoSuchAlgorithmException;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
@ -42,6 +43,7 @@ import org.jclouds.io.Payloads;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
/** /**
@ -49,7 +51,15 @@ import com.google.common.collect.ImmutableMap;
*/ */
@Test(testName = "s3.ParseObjectMetadataFromHeadersTest") @Test(testName = "s3.ParseObjectMetadataFromHeadersTest")
public class ParseObjectMetadataFromHeadersTest { public class ParseObjectMetadataFromHeadersTest {
private static final EncryptionService encryptionService = new JCEEncryptionService();
protected volatile static EncryptionService encryptionService;
static {
try {
encryptionService = new JCEEncryptionService();
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
}
}
@Test @Test
void testNormal() throws Exception { void testNormal() throws Exception {
@ -59,8 +69,8 @@ public class ParseObjectMetadataFromHeadersTest {
http.getHeaders().put(HttpHeaders.CACHE_CONTROL, "cacheControl"); http.getHeaders().put(HttpHeaders.CACHE_CONTROL, "cacheControl");
http.getHeaders().put("Content-Disposition", "contentDisposition"); http.getHeaders().put("Content-Disposition", "contentDisposition");
http.getHeaders().put(HttpHeaders.CONTENT_ENCODING, "encoding"); http.getHeaders().put(HttpHeaders.CONTENT_ENCODING, "encoding");
ParseObjectMetadataFromHeaders parser = new ParseObjectMetadataFromHeaders(blobParser(http, ParseObjectMetadataFromHeaders parser = new ParseObjectMetadataFromHeaders(blobParser(http, "\"abc\""),
"\"abc\""), blobToObjectMetadata, encryptionService, "x-amz-meta-"); blobToObjectMetadata, encryptionService, "x-amz-meta-");
MutableObjectMetadata response = parser.apply(http); MutableObjectMetadata response = parser.apply(http);
assertEquals(response, expects); assertEquals(response, expects);
} }
@ -75,8 +85,8 @@ public class ParseObjectMetadataFromHeadersTest {
http.getHeaders().put("Content-Disposition", "contentDisposition"); http.getHeaders().put("Content-Disposition", "contentDisposition");
http.getHeaders().put(HttpHeaders.CONTENT_ENCODING, "encoding"); http.getHeaders().put(HttpHeaders.CONTENT_ENCODING, "encoding");
http.getHeaders().put("x-amz-meta-object-eTag", "\"abc\""); http.getHeaders().put("x-amz-meta-object-eTag", "\"abc\"");
ParseObjectMetadataFromHeaders parser = new ParseObjectMetadataFromHeaders(blobParser(http, ParseObjectMetadataFromHeaders parser = new ParseObjectMetadataFromHeaders(blobParser(http, null),
null), blobToObjectMetadata, encryptionService, "x-amz-meta-"); blobToObjectMetadata, encryptionService, "x-amz-meta-");
MutableObjectMetadata response = parser.apply(http); MutableObjectMetadata response = parser.apply(http);
assertEquals(response, expects); assertEquals(response, expects);
} }

View File

@ -21,6 +21,7 @@ package org.jclouds.aws.s3.xml;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.util.TreeSet; import java.util.TreeSet;
import org.jclouds.aws.s3.domain.CanonicalUser; import org.jclouds.aws.s3.domain.CanonicalUser;
@ -39,6 +40,7 @@ import org.jclouds.util.Utils;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@Test(groups = "unit", testName = "s3.ListBucketHandlerTest") @Test(groups = "unit", testName = "s3.ListBucketHandlerTest")
@ -46,7 +48,15 @@ public class ListBucketHandlerTest extends BaseHandlerTest {
public static final String listBucketWithPrefixAppsSlash = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>adriancole.org.jclouds.aws.s3.amazons3testdelimiter</Name><Prefix>apps/</Prefix><Marker></Marker><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><Key>apps/0</Key><LastModified>2009-05-07T18:27:08.000Z</LastModified><ETag>&quot;c82e6a0025c31c5de5947fda62ac51ab&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/1</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;944fab2c5a9a6bacf07db5e688310d7a&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/2</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;a227b8888045c8fd159fb495214000f0&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/3</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;c9caa76c3dec53e2a192608ce73eef03&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/4</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;1ce5d0dcc6154a647ea90c7bdf82a224&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/5</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;79433524d87462ee05708a8ef894ed55&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/6</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;dd00a060b28ddca8bc5a21a49e306f67&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/7</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;8cd06eca6e819a927b07a285d750b100&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/8</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;174495094d0633b92cbe46603eee6bad&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/9</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;cd8a19b26fea8a827276df0ad11c580d&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents></ListBucketResult>"; public static final String listBucketWithPrefixAppsSlash = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>adriancole.org.jclouds.aws.s3.amazons3testdelimiter</Name><Prefix>apps/</Prefix><Marker></Marker><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><Key>apps/0</Key><LastModified>2009-05-07T18:27:08.000Z</LastModified><ETag>&quot;c82e6a0025c31c5de5947fda62ac51ab&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/1</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;944fab2c5a9a6bacf07db5e688310d7a&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/2</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;a227b8888045c8fd159fb495214000f0&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/3</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;c9caa76c3dec53e2a192608ce73eef03&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/4</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;1ce5d0dcc6154a647ea90c7bdf82a224&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/5</Key><LastModified>2009-05-07T18:27:09.000Z</LastModified><ETag>&quot;79433524d87462ee05708a8ef894ed55&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/6</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;dd00a060b28ddca8bc5a21a49e306f67&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/7</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;8cd06eca6e819a927b07a285d750b100&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/8</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;174495094d0633b92cbe46603eee6bad&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents><Contents><Key>apps/9</Key><LastModified>2009-05-07T18:27:10.000Z</LastModified><ETag>&quot;cd8a19b26fea8a827276df0ad11c580d&quot;</ETag><Size>8</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents></ListBucketResult>";
public static final String listBucketWithSlashDelimiterAndCommonPrefixApps = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Delimiter>/</Delimiter> <CommonPrefixes><Prefix>apps/</Prefix></CommonPrefixes></ListBucketResult>"; public static final String listBucketWithSlashDelimiterAndCommonPrefixApps = "<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"> <Delimiter>/</Delimiter> <CommonPrefixes><Prefix>apps/</Prefix></CommonPrefixes></ListBucketResult>";
private DateService dateService; private DateService dateService;
private static final EncryptionService encryptionService = new JCEEncryptionService();
protected volatile static EncryptionService encryptionService;
static {
try {
encryptionService = new JCEEncryptionService();
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
}
}
@BeforeTest @BeforeTest
@Override @Override
@ -58,71 +68,57 @@ public class ListBucketHandlerTest extends BaseHandlerTest {
public void testApplyInputStream() { public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/s3/list_bucket.xml"); InputStream is = getClass().getResourceAsStream("/s3/list_bucket.xml");
CanonicalUser owner = new CanonicalUser( CanonicalUser owner = new CanonicalUser("e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0",
"e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0", "ferncam"); "ferncam");
ListBucketResponse expected = new ListBucketResponseImpl( ListBucketResponse expected = new ListBucketResponseImpl("adriancole.org.jclouds.aws.s3.amazons3testdelimiter",
"adriancole.org.jclouds.aws.s3.amazons3testdelimiter", ImmutableList.of( ImmutableList
.of(
(ObjectMetadata) new BucketListObjectMetadata("apps/0", dateService (ObjectMetadata) new BucketListObjectMetadata("apps/0", dateService
.iso8601DateParse("2009-05-07T18:27:08.000Z"), .iso8601DateParse("2009-05-07T18:27:08.000Z"), "\"c82e6a0025c31c5de5947fda62ac51ab\"",
"\"c82e6a0025c31c5de5947fda62ac51ab\"", encryptionService encryptionService.fromHex("c82e6a0025c31c5de5947fda62ac51ab"), 8, owner,
.fromHex("c82e6a0025c31c5de5947fda62ac51ab"), 8, owner, StorageClass.STANDARD), (ObjectMetadata) new BucketListObjectMetadata("apps/1",
StorageClass.STANDARD), dateService.iso8601DateParse("2009-05-07T18:27:09.000Z"),
(ObjectMetadata) new BucketListObjectMetadata("apps/1", dateService "\"944fab2c5a9a6bacf07db5e688310d7a\"", encryptionService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), .fromHex("944fab2c5a9a6bacf07db5e688310d7a"), 8, owner, StorageClass.STANDARD),
"\"944fab2c5a9a6bacf07db5e688310d7a\"", encryptionService
.fromHex("944fab2c5a9a6bacf07db5e688310d7a"), 8, owner,
StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/2", dateService (ObjectMetadata) new BucketListObjectMetadata("apps/2", dateService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), .iso8601DateParse("2009-05-07T18:27:09.000Z"), "\"a227b8888045c8fd159fb495214000f0\"",
"\"a227b8888045c8fd159fb495214000f0\"", encryptionService encryptionService.fromHex("a227b8888045c8fd159fb495214000f0"), 8, owner,
.fromHex("a227b8888045c8fd159fb495214000f0"), 8, owner, StorageClass.STANDARD), (ObjectMetadata) new BucketListObjectMetadata("apps/3",
StorageClass.STANDARD), dateService.iso8601DateParse("2009-05-07T18:27:09.000Z"),
(ObjectMetadata) new BucketListObjectMetadata("apps/3", dateService "\"c9caa76c3dec53e2a192608ce73eef03\"", encryptionService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), .fromHex("c9caa76c3dec53e2a192608ce73eef03"), 8, owner, StorageClass.STANDARD),
"\"c9caa76c3dec53e2a192608ce73eef03\"", encryptionService
.fromHex("c9caa76c3dec53e2a192608ce73eef03"), 8, owner,
StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/4", dateService (ObjectMetadata) new BucketListObjectMetadata("apps/4", dateService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), .iso8601DateParse("2009-05-07T18:27:09.000Z"), "\"1ce5d0dcc6154a647ea90c7bdf82a224\"",
"\"1ce5d0dcc6154a647ea90c7bdf82a224\"", encryptionService encryptionService.fromHex("1ce5d0dcc6154a647ea90c7bdf82a224"), 8, owner,
.fromHex("1ce5d0dcc6154a647ea90c7bdf82a224"), 8, owner, StorageClass.STANDARD), (ObjectMetadata) new BucketListObjectMetadata("apps/5",
StorageClass.STANDARD), dateService.iso8601DateParse("2009-05-07T18:27:09.000Z"),
(ObjectMetadata) new BucketListObjectMetadata("apps/5", dateService "\"79433524d87462ee05708a8ef894ed55\"", encryptionService
.iso8601DateParse("2009-05-07T18:27:09.000Z"), .fromHex("79433524d87462ee05708a8ef894ed55"), 8, owner, StorageClass.STANDARD),
"\"79433524d87462ee05708a8ef894ed55\"", encryptionService
.fromHex("79433524d87462ee05708a8ef894ed55"), 8, owner,
StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/6", dateService (ObjectMetadata) new BucketListObjectMetadata("apps/6", dateService
.iso8601DateParse("2009-05-07T18:27:10.000Z"), .iso8601DateParse("2009-05-07T18:27:10.000Z"), "\"dd00a060b28ddca8bc5a21a49e306f67\"",
"\"dd00a060b28ddca8bc5a21a49e306f67\"", encryptionService encryptionService.fromHex("dd00a060b28ddca8bc5a21a49e306f67"), 8, owner,
.fromHex("dd00a060b28ddca8bc5a21a49e306f67"), 8, owner, StorageClass.STANDARD), (ObjectMetadata) new BucketListObjectMetadata("apps/7",
StorageClass.STANDARD), dateService.iso8601DateParse("2009-05-07T18:27:10.000Z"),
(ObjectMetadata) new BucketListObjectMetadata("apps/7", dateService "\"8cd06eca6e819a927b07a285d750b100\"", encryptionService
.iso8601DateParse("2009-05-07T18:27:10.000Z"), .fromHex("8cd06eca6e819a927b07a285d750b100"), 8, owner, StorageClass.STANDARD),
"\"8cd06eca6e819a927b07a285d750b100\"", encryptionService
.fromHex("8cd06eca6e819a927b07a285d750b100"), 8, owner,
StorageClass.STANDARD),
(ObjectMetadata) new BucketListObjectMetadata("apps/8", dateService (ObjectMetadata) new BucketListObjectMetadata("apps/8", dateService
.iso8601DateParse("2009-05-07T18:27:10.000Z"), .iso8601DateParse("2009-05-07T18:27:10.000Z"), "\"174495094d0633b92cbe46603eee6bad\"",
"\"174495094d0633b92cbe46603eee6bad\"", encryptionService encryptionService.fromHex("174495094d0633b92cbe46603eee6bad"), 8, owner,
.fromHex("174495094d0633b92cbe46603eee6bad"), 8, owner, StorageClass.STANDARD), (ObjectMetadata) new BucketListObjectMetadata("apps/9",
StorageClass.STANDARD), dateService.iso8601DateParse("2009-05-07T18:27:10.000Z"),
(ObjectMetadata) new BucketListObjectMetadata("apps/9", dateService "\"cd8a19b26fea8a827276df0ad11c580d\"", encryptionService
.iso8601DateParse("2009-05-07T18:27:10.000Z"), .fromHex("cd8a19b26fea8a827276df0ad11c580d"), 8, owner, StorageClass.STANDARD)),
"\"cd8a19b26fea8a827276df0ad11c580d\"", encryptionService "apps/", null, null, 1000, null, false, new TreeSet<String>());
.fromHex("cd8a19b26fea8a827276df0ad11c580d"), 8, owner,
StorageClass.STANDARD)), "apps/", null, null, 1000, null, false,
new TreeSet<String>());
ListBucketResponse result = (ListBucketResponse) factory.create( ListBucketResponse result = (ListBucketResponse) factory.create(injector.getInstance(ListBucketHandler.class))
injector.getInstance(ListBucketHandler.class)).parse(is); .parse(is);
assertEquals(result, expected); assertEquals(result, expected);
} }
ParseSax<ListBucketResponse> createParser() { ParseSax<ListBucketResponse> createParser() {
ParseSax<ListBucketResponse> parser = (ParseSax<ListBucketResponse>) factory.create(injector ParseSax<ListBucketResponse> parser = (ParseSax<ListBucketResponse>) factory.create(injector
.getInstance(ListBucketHandler.class)); .getInstance(ListBucketHandler.class));
return parser; return parser;
} }
@ -130,7 +126,7 @@ public class ListBucketHandlerTest extends BaseHandlerTest {
public void testListMyBucketsWithDelimiterSlashAndCommonPrefixesAppsSlash() throws HttpException { public void testListMyBucketsWithDelimiterSlashAndCommonPrefixesAppsSlash() throws HttpException {
ListBucketResponse bucket = createParser().parse( ListBucketResponse bucket = createParser().parse(
Utils.toInputStream(listBucketWithSlashDelimiterAndCommonPrefixApps)); Utils.toInputStream(listBucketWithSlashDelimiterAndCommonPrefixApps));
assertEquals(bucket.getCommonPrefixes().iterator().next(), "apps/"); assertEquals(bucket.getCommonPrefixes().iterator().next(), "apps/");
assertEquals(bucket.getDelimiter(), "/"); assertEquals(bucket.getDelimiter(), "/");
assert bucket.getMarker() == null; assert bucket.getMarker() == null;
@ -139,8 +135,7 @@ public class ListBucketHandlerTest extends BaseHandlerTest {
@Test @Test
public void testListMyBucketsWithPrefixAppsSlash() throws HttpException { public void testListMyBucketsWithPrefixAppsSlash() throws HttpException {
ListBucketResponse bucket = createParser().parse( ListBucketResponse bucket = createParser().parse(Utils.toInputStream(listBucketWithPrefixAppsSlash));
Utils.toInputStream(listBucketWithPrefixAppsSlash));
assertEquals(bucket.getPrefix(), "apps/"); assertEquals(bucket.getPrefix(), "apps/");
assertEquals(bucket.getMaxKeys(), 1000); assertEquals(bucket.getMaxKeys(), 1000);
assert bucket.getMarker() == null; assert bucket.getMarker() == null;

View File

@ -24,6 +24,7 @@ import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import java.io.IOException; import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
@ -40,6 +41,7 @@ import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.inject.Module; import com.google.inject.Module;
@ -57,7 +59,15 @@ public class SQSClientLiveTest {
private RestContext<SQSClient, SQSAsyncClient> context; private RestContext<SQSClient, SQSAsyncClient> context;
private EncryptionService encryptionService = new JCEEncryptionService(); protected volatile static EncryptionService encryptionService;
static {
try {
encryptionService = new JCEEncryptionService();
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
}
}
private Set<Queue> queues = Sets.newHashSet(); private Set<Queue> queues = Sets.newHashSet();
@BeforeGroups(groups = { "live" }) @BeforeGroups(groups = { "live" })
@ -66,14 +76,14 @@ public class SQSClientLiveTest {
String credential = checkNotNull(System.getProperty("jclouds.test.credential"), "jclouds.test.credential"); String credential = checkNotNull(System.getProperty("jclouds.test.credential"), "jclouds.test.credential");
context = new RestContextFactory().createContext("sqs", identity, credential, ImmutableSet context = new RestContextFactory().createContext("sqs", identity, credential, ImmutableSet
.<Module> of(new Log4JLoggingModule())); .<Module> of(new Log4JLoggingModule()));
this.client = context.getApi(); this.client = context.getApi();
} }
@Test @Test
void testListQueuesInRegion() throws InterruptedException { void testListQueuesInRegion() throws InterruptedException {
for (String region : Lists.newArrayList(null, Region.EU_WEST_1, Region.US_EAST_1, Region.US_WEST_1, for (String region : Lists.newArrayList(null, Region.EU_WEST_1, Region.US_EAST_1, Region.US_WEST_1,
Region.AP_SOUTHEAST_1)) { Region.AP_SOUTHEAST_1)) {
SortedSet<Queue> allResults = Sets.newTreeSet(client.listQueuesInRegion(region)); SortedSet<Queue> allResults = Sets.newTreeSet(client.listQueuesInRegion(region));
assertNotNull(allResults); assertNotNull(allResults);
if (allResults.size() >= 1) { if (allResults.size() >= 1) {
@ -90,7 +100,7 @@ public class SQSClientLiveTest {
String queueName = PREFIX + "1"; String queueName = PREFIX + "1";
for (final String region : Lists.newArrayList(null, Region.EU_WEST_1, Region.US_EAST_1, Region.US_WEST_1, for (final String region : Lists.newArrayList(null, Region.EU_WEST_1, Region.US_EAST_1, Region.US_WEST_1,
Region.AP_SOUTHEAST_1)) { Region.AP_SOUTHEAST_1)) {
try { try {
SortedSet<Queue> result = Sets.newTreeSet(client.listQueuesInRegion(region, queuePrefix(queueName))); SortedSet<Queue> result = Sets.newTreeSet(client.listQueuesInRegion(region, queuePrefix(queueName)));
if (result.size() >= 1) { if (result.size() >= 1) {
@ -147,8 +157,9 @@ public class SQSClientLiveTest {
private static final int INCONSISTENCY_WINDOW = 10000; private static final int INCONSISTENCY_WINDOW = 10000;
/** /**
* Due to eventual consistency, container commands may not return correctly immediately. Hence, * Due to eventual consistency, container commands may not return correctly
* we will try up to the inconsistency window to see if the assertion completes. * immediately. Hence, we will try up to the inconsistency window to see if
* the assertion completes.
*/ */
protected static void assertEventually(Runnable assertion) throws InterruptedException { protected static void assertEventually(Runnable assertion) throws InterruptedException {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
@ -158,7 +169,7 @@ public class SQSClientLiveTest {
assertion.run(); assertion.run();
if (i > 0) if (i > 0)
System.err.printf("%d attempts and %dms asserting %s%n", i + 1, System.currentTimeMillis() - start, System.err.printf("%d attempts and %dms asserting %s%n", i + 1, System.currentTimeMillis() - start,
assertion.getClass().getSimpleName()); assertion.getClass().getSimpleName());
return; return;
} catch (AssertionError e) { } catch (AssertionError e) {
error = e; error = e;

View File

@ -35,6 +35,7 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@ -47,6 +48,7 @@ import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType; import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.encryption.internal.JCEEncryptionService; import org.jclouds.encryption.internal.JCEEncryptionService;
import org.jclouds.http.BaseJettyTest; import org.jclouds.http.BaseJettyTest;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
@ -61,6 +63,7 @@ import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
@ -79,8 +82,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@Override @Override
public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception { public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception {
super.setUpResourcesOnThisThread(testContext); super.setUpResourcesOnThisThread(testContext);
Payload result = context.utils().encryption().generatePayloadWithMD5For( Payload result = context.utils().encryption().generatePayloadWithMD5For(getTestDataSupplier().getInput());
getTestDataSupplier().getInput());
oneHundredOneConstitutions = (byte[]) result.getRawContent(); oneHundredOneConstitutions = (byte[]) result.getRawContent();
oneHundredOneConstitutionsMD5 = result.getContentMD5(); oneHundredOneConstitutionsMD5 = result.getContentMD5();
} }
@ -88,9 +90,8 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static InputSupplier<InputStream> getTestDataSupplier() throws IOException { public static InputSupplier<InputStream> getTestDataSupplier() throws IOException {
byte[] oneConstitution = ByteStreams.toByteArray(new GZIPInputStream(BaseJettyTest.class byte[] oneConstitution = ByteStreams.toByteArray(new GZIPInputStream(BaseJettyTest.class
.getResourceAsStream("/const.txt.gz"))); .getResourceAsStream("/const.txt.gz")));
InputSupplier<ByteArrayInputStream> constitutionSupplier = ByteStreams InputSupplier<ByteArrayInputStream> constitutionSupplier = ByteStreams.newInputStreamSupplier(oneConstitution);
.newInputStreamSupplier(oneConstitution);
InputSupplier<InputStream> temp = ByteStreams.join(constitutionSupplier); InputSupplier<InputStream> temp = ByteStreams.join(constitutionSupplier);
@ -110,20 +111,20 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
Map<Integer, ListenableFuture<?>> responses = Maps.newHashMap(); Map<Integer, ListenableFuture<?>> responses = Maps.newHashMap();
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
responses.put(i, Futures.compose(context.getAsyncBlobStore() responses.put(i, Futures.compose(context.getAsyncBlobStore().getBlob(containerName, key),
.getBlob(containerName, key), new Function<Blob, Void>() { new Function<Blob, Void>() {
@Override @Override
public Void apply(Blob from) { public Void apply(Blob from) {
assertEquals(context.utils().encryption().md5(from.getPayload().getInput()), assertEquals(context.utils().encryption().md5(from.getPayload().getInput()),
oneHundredOneConstitutionsMD5); oneHundredOneConstitutionsMD5);
return null; return null;
} }
})); }));
} }
Map<Integer, Exception> exceptions = awaitCompletion(responses, exec, 30000l, Map<Integer, Exception> exceptions = awaitCompletion(responses, exec, 30000l, Logger.CONSOLE,
Logger.CONSOLE, "get constitution"); "get constitution");
assert exceptions.size() == 0 : exceptions; assert exceptions.size() == 0 : exceptions;
} finally { } finally {
@ -250,10 +251,8 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
Blob blob1 = context.getBlobStore().getBlob(containerName, key, range(0, 5)); Blob blob1 = context.getBlobStore().getBlob(containerName, key, range(0, 5));
assertEquals(getContentAsStringOrNullAndClose(blob1), TEST_STRING.substring(0, 6)); assertEquals(getContentAsStringOrNullAndClose(blob1), TEST_STRING.substring(0, 6));
Blob blob2 = context.getBlobStore().getBlob(containerName, key, Blob blob2 = context.getBlobStore().getBlob(containerName, key, range(6, TEST_STRING.length()));
range(6, TEST_STRING.length())); assertEquals(getContentAsStringOrNullAndClose(blob2), TEST_STRING.substring(6, TEST_STRING.length()));
assertEquals(getContentAsStringOrNullAndClose(blob2), TEST_STRING.substring(6, TEST_STRING
.length()));
} finally { } finally {
returnContainer(containerName); returnContainer(containerName);
} }
@ -267,8 +266,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
String key = "apples"; String key = "apples";
addObjectAndValidateContent(containerName, key); addObjectAndValidateContent(containerName, key);
Blob blob = context.getBlobStore().getBlob(containerName, key, Blob blob = context.getBlobStore().getBlob(containerName, key, range(0, 5).range(6, TEST_STRING.length()));
range(0, 5).range(6, TEST_STRING.length()));
assertEquals(getContentAsStringOrNullAndClose(blob), TEST_STRING); assertEquals(getContentAsStringOrNullAndClose(blob), TEST_STRING);
} finally { } finally {
@ -277,7 +275,8 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
} }
// @Test(groups = { "integration", "live" }) // @Test(groups = { "integration", "live" })
// public void testGetTail() throws InterruptedException, ExecutionException, TimeoutException, // public void testGetTail() throws InterruptedException, ExecutionException,
// TimeoutException,
// IOException { // IOException {
// String containerName = getContainerName(); // String containerName = getContainerName();
// try { // try {
@ -285,7 +284,8 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// String key = "apples"; // String key = "apples";
// //
// addObjectAndValidateContent(containerName, key); // addObjectAndValidateContent(containerName, key);
// Blob blob = context.getBlobStore().getBlob(containerName, key, tail(5)).get(30, // Blob blob = context.getBlobStore().getBlob(containerName, key,
// tail(5)).get(30,
// TimeUnit.SECONDS); // TimeUnit.SECONDS);
// assertEquals(BlobStoreUtils.getContentAsStringAndClose(blob), TEST_STRING // assertEquals(BlobStoreUtils.getContentAsStringAndClose(blob), TEST_STRING
// .substring(TEST_STRING.length() - 5)); // .substring(TEST_STRING.length() - 5));
@ -297,7 +297,8 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// } // }
// @Test(groups = { "integration", "live" }) // @Test(groups = { "integration", "live" })
// public void testGetStartAt() throws InterruptedException, ExecutionException, // public void testGetStartAt() throws InterruptedException,
// ExecutionException,
// TimeoutException, // TimeoutException,
// IOException { // IOException {
// String containerName = getContainerName(); // String containerName = getContainerName();
@ -305,9 +306,11 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// String key = "apples"; // String key = "apples";
// //
// addObjectAndValidateContent(containerName, key); // addObjectAndValidateContent(containerName, key);
// Blob blob = context.getBlobStore().getBlob(containerName, key, startAt(5)).get(30, // Blob blob = context.getBlobStore().getBlob(containerName, key,
// startAt(5)).get(30,
// TimeUnit.SECONDS); // TimeUnit.SECONDS);
// assertEquals(BlobStoreUtils.getContentAsStringAndClose(blob), TEST_STRING.substring(5, // assertEquals(BlobStoreUtils.getContentAsStringAndClose(blob),
// TEST_STRING.substring(5,
// TEST_STRING.length())); // TEST_STRING.length()));
// assertEquals(blob.getContentLength(), TEST_STRING.length() - 5); // assertEquals(blob.getContentLength(), TEST_STRING.length() - 5);
// assertEquals(blob.getMetadata().getSize(), TEST_STRING.length()); // assertEquals(blob.getMetadata().getSize(), TEST_STRING.length());
@ -316,8 +319,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
// } // }
// } // }
private String addObjectAndValidateContent(String sourcecontainerName, String sourceKey) private String addObjectAndValidateContent(String sourcecontainerName, String sourceKey) throws InterruptedException {
throws InterruptedException {
String eTag = addBlobToContainer(sourcecontainerName, sourceKey); String eTag = addBlobToContainer(sourcecontainerName, sourceKey);
validateContent(sourcecontainerName, sourceKey); validateContent(sourcecontainerName, sourceKey);
return eTag; return eTag;
@ -347,9 +349,8 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@DataProvider(name = "delete") @DataProvider(name = "delete")
public Object[][] createData() { public Object[][] createData() {
return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unic₪de" }, return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unic₪de" }, { "path/foo" },
{ "path/foo" }, { "colon:" }, { "asteri*k" }, { "quote\"" }, { "{great<r}" }, { "colon:" }, { "asteri*k" }, { "quote\"" }, { "{great<r}" }, { "lesst>en" }, { "p|pe" } };
{ "lesst>en" }, { "p|pe" } };
} }
@Test(groups = { "integration", "live" }, dataProvider = "delete") @Test(groups = { "integration", "live" }, dataProvider = "delete")
@ -365,18 +366,18 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
} }
private void assertContainerEmptyDeleting(String containerName, String key) { private void assertContainerEmptyDeleting(String containerName, String key) {
Iterable<? extends StorageMetadata> listing = Iterables.filter(context.getBlobStore().list( Iterable<? extends StorageMetadata> listing = Iterables.filter(context.getBlobStore().list(containerName),
containerName), new Predicate<StorageMetadata>() { new Predicate<StorageMetadata>() {
@Override @Override
public boolean apply(StorageMetadata input) { public boolean apply(StorageMetadata input) {
return input.getType() == StorageType.BLOB; return input.getType() == StorageType.BLOB;
} }
}); });
assertEquals(Iterables.size(listing), 0, String.format( assertEquals(Iterables.size(listing), 0, String.format(
"deleting %s, we still have %s blobs left in container %s, using encoding %s", key, "deleting %s, we still have %s blobs left in container %s, using encoding %s", key,
Iterables.size(listing), containerName, LOCAL_ENCODING)); Iterables.size(listing), containerName, LOCAL_ENCODING));
} }
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
@ -396,13 +397,13 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
String realObject = Utils.toStringAndClose(new FileInputStream("pom.xml")); String realObject = Utils.toStringAndClose(new FileInputStream("pom.xml"));
return new Object[][] { { "file", "text/xml", new File("pom.xml"), realObject }, return new Object[][] { { "file", "text/xml", new File("pom.xml"), realObject },
{ "string", "text/xml", realObject, realObject }, { "string", "text/xml", realObject, realObject },
{ "bytes", "application/octet-stream", realObject.getBytes(), realObject } }; { "bytes", "application/octet-stream", realObject.getBytes(), realObject } };
} }
@Test(groups = { "integration", "live" }, dataProvider = "putTests") @Test(groups = { "integration", "live" }, dataProvider = "putTests")
public void testPutObject(String key, String type, Object content, Object realObject) public void testPutObject(String key, String type, Object content, Object realObject) throws InterruptedException,
throws InterruptedException, IOException { IOException {
Blob blob = context.getBlobStore().newBlob(key); Blob blob = context.getBlobStore().newBlob(key);
blob.getMetadata().setContentType(type); blob.getMetadata().setContentType(type);
blob.setPayload(Payloads.newPayload(content)); blob.setPayload(Payloads.newPayload(content));
@ -422,6 +423,15 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
} }
} }
protected volatile static EncryptionService encryptionService;
static {
try {
encryptionService = new JCEEncryptionService();
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
}
}
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testMetadata() throws InterruptedException { public void testMetadata() throws InterruptedException {
String key = "hello"; String key = "hello";
@ -430,11 +440,11 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
blob.setPayload(TEST_STRING); blob.setPayload(TEST_STRING);
blob.getMetadata().setContentType(MediaType.TEXT_PLAIN); blob.getMetadata().setContentType(MediaType.TEXT_PLAIN);
blob.getMetadata().setSize(new Long(TEST_STRING.length())); blob.getMetadata().setSize(new Long(TEST_STRING.length()));
// NOTE all metadata in jclouds comes out as lowercase, in an effort to normalize the // NOTE all metadata in jclouds comes out as lowercase, in an effort to
// normalize the
// providers. // providers.
blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff"); blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff");
blob.getMetadata().setContentMD5( blob.getMetadata().setContentMD5(encryptionService.md5(Utils.toInputStream(TEST_STRING)));
new JCEEncryptionService().md5(Utils.toInputStream(TEST_STRING)));
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
assertNull(context.getBlobStore().blobMetadata(containerName, "powderpuff")); assertNull(context.getBlobStore().blobMetadata(containerName, "powderpuff"));
@ -447,7 +457,8 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
validateMetadata(metadata); validateMetadata(metadata);
validateMetadata(context.getBlobStore().blobMetadata(containerName, key)); validateMetadata(context.getBlobStore().blobMetadata(containerName, key));
// write 2 items with the same key to ensure that provider doesn't accept dupes // write 2 items with the same key to ensure that provider doesn't
// accept dupes
blob.getMetadata().getUserMetadata().put("Adrian", "wonderpuff"); blob.getMetadata().getUserMetadata().put("Adrian", "wonderpuff");
blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff"); blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff");
@ -463,8 +474,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
assert metadata.getContentType().startsWith("text/plain") : metadata.getContentType(); assert metadata.getContentType().startsWith("text/plain") : metadata.getContentType();
assertEquals(metadata.getSize(), new Long(TEST_STRING.length())); assertEquals(metadata.getSize(), new Long(TEST_STRING.length()));
assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff"); assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff");
assertEquals(metadata.getContentMD5(), new JCEEncryptionService().md5(Utils assertEquals(metadata.getContentMD5(), encryptionService.md5(Utils.toInputStream(TEST_STRING)));
.toInputStream(TEST_STRING)));
} }
} }

View File

@ -23,6 +23,7 @@ import static org.jclouds.blobstore.util.BlobStoreUtils.getContentAsStringOrNull
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -39,6 +40,8 @@ import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType; import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.encryption.internal.JCEEncryptionService;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.testng.ITestContext; import org.testng.ITestContext;
import org.testng.annotations.AfterClass; import org.testng.annotations.AfterClass;
@ -58,16 +61,14 @@ public class BaseBlobStoreIntegrationTest {
protected static final String XML_STRING_FORMAT = "<apples><apple name=\"%s\"></apple> </apples>"; protected static final String XML_STRING_FORMAT = "<apples><apple name=\"%s\"></apple> </apples>";
protected static final String TEST_STRING = String.format(XML_STRING_FORMAT, "apple"); protected static final String TEST_STRING = String.format(XML_STRING_FORMAT, "apple");
protected Map<String, String> fiveStrings = ImmutableMap.of("one", String.format( protected Map<String, String> fiveStrings = ImmutableMap.of("one", String.format(XML_STRING_FORMAT, "apple"), "two",
XML_STRING_FORMAT, "apple"), "two", String.format(XML_STRING_FORMAT, "bear"), "three", String.format(XML_STRING_FORMAT, "bear"), "three", String.format(XML_STRING_FORMAT, "candy"), "four", String
String.format(XML_STRING_FORMAT, "candy"), "four", String.format(XML_STRING_FORMAT, .format(XML_STRING_FORMAT, "dogma"), "five", String.format(XML_STRING_FORMAT, "emma"));
"dogma"), "five", String.format(XML_STRING_FORMAT, "emma"));
protected Map<String, String> fiveStringsUnderPath = ImmutableMap.of("path/1", String.format( protected Map<String, String> fiveStringsUnderPath = ImmutableMap.of("path/1", String.format(XML_STRING_FORMAT,
XML_STRING_FORMAT, "apple"), "path/2", String.format(XML_STRING_FORMAT, "bear"), "apple"), "path/2", String.format(XML_STRING_FORMAT, "bear"), "path/3", String.format(XML_STRING_FORMAT,
"path/3", String.format(XML_STRING_FORMAT, "candy"), "path/4", String.format( "candy"), "path/4", String.format(XML_STRING_FORMAT, "dogma"), "path/5", String.format(XML_STRING_FORMAT,
XML_STRING_FORMAT, "dogma"), "path/5", String "emma"));
.format(XML_STRING_FORMAT, "emma"));
public static long INCONSISTENCY_WINDOW = 10000; public static long INCONSISTENCY_WINDOW = 10000;
protected static volatile AtomicInteger containerIndex = new AtomicInteger(0); protected static volatile AtomicInteger containerIndex = new AtomicInteger(0);
@ -78,11 +79,20 @@ public class BaseBlobStoreIntegrationTest {
/** /**
* two test groups integration and live. * two test groups integration and live.
*/ */
private volatile static BlockingQueue<String> containerNames = new ArrayBlockingQueue<String>( private volatile static BlockingQueue<String> containerNames = new ArrayBlockingQueue<String>(containerCount);
containerCount);
protected volatile static EncryptionService encryptionService;
static {
try {
encryptionService = new JCEEncryptionService();
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
}
}
/** /**
* There are a lot of retries here mainly from experience running inside amazon EC2. * There are a lot of retries here mainly from experience running inside
* amazon EC2.
*/ */
@BeforeSuite @BeforeSuite
public void setUpResourcesForAllThreads(ITestContext testContext) throws Exception { public void setUpResourcesForAllThreads(ITestContext testContext) throws Exception {
@ -91,13 +101,10 @@ public class BaseBlobStoreIntegrationTest {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private BlobStoreContext getCloudResources(ITestContext testContext) private BlobStoreContext getCloudResources(ITestContext testContext) throws ClassNotFoundException,
throws ClassNotFoundException, InstantiationException, IllegalAccessException, InstantiationException, IllegalAccessException, Exception {
Exception { String initializerClass = checkNotNull(System.getProperty("jclouds.test.initializer"), "jclouds.test.initializer");
String initializerClass = checkNotNull(System.getProperty("jclouds.test.initializer"), Class<BaseTestInitializer> clazz = (Class<BaseTestInitializer>) Class.forName(initializerClass);
"jclouds.test.initializer");
Class<BaseTestInitializer> clazz = (Class<BaseTestInitializer>) Class
.forName(initializerClass);
BaseTestInitializer initializer = clazz.newInstance(); BaseTestInitializer initializer = clazz.newInstance();
return initializer.init(createHttpModule(), testContext); return initializer.init(createHttpModule(), testContext);
} }
@ -105,10 +112,11 @@ public class BaseBlobStoreIntegrationTest {
protected ExecutorService exec; protected ExecutorService exec;
/** /**
* we are doing this at a class level, as the context.getBlobStore() object is going to be shared * we are doing this at a class level, as the context.getBlobStore() object
* for all methods in the class. We don't want to do this for group, as some test classes may * is going to be shared for all methods in the class. We don't want to do
* want to have a different implementation of context.getBlobStore(). For example, one class may * this for group, as some test classes may want to have a different
* want non-blocking i/o and another class google appengine. * implementation of context.getBlobStore(). For example, one class may want
* non-blocking i/o and another class google appengine.
*/ */
@BeforeClass(groups = { "integration", "live" }) @BeforeClass(groups = { "integration", "live" })
public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception { public void setUpResourcesOnThisThread(ITestContext testContext) throws Exception {
@ -127,8 +135,8 @@ public class BaseBlobStoreIntegrationTest {
private static volatile boolean initialized = false; private static volatile boolean initialized = false;
protected void createContainersSharedByAllThreads(BlobStoreContext context, protected void createContainersSharedByAllThreads(BlobStoreContext context, ITestContext testContext)
ITestContext testContext) throws Exception { throws Exception {
while (!initialized) { while (!initialized) {
synchronized (BaseBlobStoreIntegrationTest.class) { synchronized (BaseBlobStoreIntegrationTest.class) {
if (!initialized) { if (!initialized) {
@ -143,7 +151,8 @@ public class BaseBlobStoreIntegrationTest {
containerNames.put(containerName); containerNames.put(containerName);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
// throw away the container and try again with the next index // throw away the container and try again with the next
// index
deleteContainerOrWarnIfUnable(context, containerName); deleteContainerOrWarnIfUnable(context, containerName);
containerCount++; containerCount++;
} }
@ -177,13 +186,13 @@ public class BaseBlobStoreIntegrationTest {
protected static void deleteEverything(final BlobStoreContext context) throws Exception { protected static void deleteEverything(final BlobStoreContext context) throws Exception {
try { try {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
Iterable<? extends StorageMetadata> testContainers = Iterables.filter(context Iterable<? extends StorageMetadata> testContainers = Iterables.filter(context.getBlobStore().list(),
.getBlobStore().list(), new Predicate<StorageMetadata>() { new Predicate<StorageMetadata>() {
public boolean apply(StorageMetadata input) { public boolean apply(StorageMetadata input) {
return (input.getType() == StorageType.CONTAINER || input.getType() == StorageType.FOLDER) return (input.getType() == StorageType.CONTAINER || input.getType() == StorageType.FOLDER)
&& input.getName().startsWith(CONTAINER_PREFIX.toLowerCase()); && input.getName().startsWith(CONTAINER_PREFIX.toLowerCase());
} }
}); });
for (StorageMetadata container : testContainers) { for (StorageMetadata container : testContainers) {
deleteContainerOrWarnIfUnable(context, container.getName()); deleteContainerOrWarnIfUnable(context, container.getName());
} }
@ -200,11 +209,12 @@ public class BaseBlobStoreIntegrationTest {
public static boolean SANITY_CHECK_RETURNED_BUCKET_NAME = false; public static boolean SANITY_CHECK_RETURNED_BUCKET_NAME = false;
/** /**
* Due to eventual consistency, container commands may not return correctly immediately. Hence, * Due to eventual consistency, container commands may not return correctly
* we will try up to the inconsistency window to see if the assertion completes. * immediately. Hence, we will try up to the inconsistency window to see if
* the assertion completes.
*/ */
protected static void assertConsistencyAware(BlobStoreContext context, Runnable assertion) protected static void assertConsistencyAware(BlobStoreContext context, Runnable assertion)
throws InterruptedException { throws InterruptedException {
if (context.getConsistencyModel() == ConsistencyModel.STRICT) { if (context.getConsistencyModel() == ConsistencyModel.STRICT) {
assertion.run(); assertion.run();
return; return;
@ -229,8 +239,8 @@ public class BaseBlobStoreIntegrationTest {
assertConsistencyAware(context, assertion); assertConsistencyAware(context, assertion);
} }
protected static void createContainerAndEnsureEmpty(BlobStoreContext context, protected static void createContainerAndEnsureEmpty(BlobStoreContext context, final String containerName)
final String containerName) throws InterruptedException { throws InterruptedException {
context.getBlobStore().createContainerInLocation(null, containerName); context.getBlobStore().createContainerInLocation(null, containerName);
if (context.getConsistencyModel() == ConsistencyModel.EVENTUAL) if (context.getConsistencyModel() == ConsistencyModel.EVENTUAL)
Thread.sleep(1000); Thread.sleep(1000);
@ -249,8 +259,7 @@ public class BaseBlobStoreIntegrationTest {
} }
protected void add5BlobsUnderPathAnd5UnderRootToContainer(String sourceContainer) { protected void add5BlobsUnderPathAnd5UnderRootToContainer(String sourceContainer) {
for (Entry<String, String> entry : Iterables.concat(fiveStrings.entrySet(), for (Entry<String, String> entry : Iterables.concat(fiveStrings.entrySet(), fiveStringsUnderPath.entrySet())) {
fiveStringsUnderPath.entrySet())) {
Blob sourceObject = context.getBlobStore().newBlob(entry.getKey()); Blob sourceObject = context.getBlobStore().newBlob(entry.getKey());
sourceObject.getMetadata().setContentType("text/xml"); sourceObject.getMetadata().setContentType("text/xml");
sourceObject.setPayload(entry.getValue()); sourceObject.setPayload(entry.getValue());
@ -275,20 +284,19 @@ public class BaseBlobStoreIntegrationTest {
} }
protected void assertConsistencyAwareContainerSize(final String containerName, final int count) protected void assertConsistencyAwareContainerSize(final String containerName, final int count)
throws InterruptedException { throws InterruptedException {
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
try { try {
assert context.getBlobStore().countBlobs(containerName) == count : String.format( assert context.getBlobStore().countBlobs(containerName) == count : String.format(
"expected only %d values in %s: %s", count, containerName, Sets "expected only %d values in %s: %s", count, containerName, Sets.newHashSet(Iterables.transform(
.newHashSet(Iterables.transform(context.getBlobStore().list( context.getBlobStore().list(containerName), new Function<StorageMetadata, String>() {
containerName), new Function<StorageMetadata, String>() {
public String apply(StorageMetadata from) { public String apply(StorageMetadata from) {
return from.getName(); return from.getName();
} }
}))); })));
} catch (Exception e) { } catch (Exception e) {
Throwables.propagateIfPossible(e); Throwables.propagateIfPossible(e);
} }
@ -304,9 +312,9 @@ public class BaseBlobStoreIntegrationTest {
} }
/** /**
* requestor will create a container using the name returned from this. This method will take * requestor will create a container using the name returned from this. This
* care not to exceed the maximum containers permitted by a provider by deleting an existing * method will take care not to exceed the maximum containers permitted by a
* container first. * provider by deleting an existing container first.
* *
* @throws InterruptedException * @throws InterruptedException
*/ */
@ -318,12 +326,13 @@ public class BaseBlobStoreIntegrationTest {
if (containerName != null) { if (containerName != null) {
containerNames.add(containerName); containerNames.add(containerName);
/* /*
* Ensure that any returned container name actually exists on the server. Return of a * Ensure that any returned container name actually exists on the
* non-existent container introduces subtle testing bugs, where later unrelated tests will * server. Return of a non-existent container introduces subtle testing
* fail. * bugs, where later unrelated tests will fail.
* *
* NOTE: This sanity check should only be run for Stub-based Integration testing -- it will * NOTE: This sanity check should only be run for Stub-based
* *substantially* slow down tests on a real server over a network. * Integration testing -- it will *substantially* slow down tests on a
* real server over a network.
*/ */
if (SANITY_CHECK_RETURNED_BUCKET_NAME) { if (SANITY_CHECK_RETURNED_BUCKET_NAME) {
if (!Iterables.any(context.getBlobStore().list(), new Predicate<StorageMetadata>() { if (!Iterables.any(context.getBlobStore().list(), new Predicate<StorageMetadata>() {
@ -331,15 +340,15 @@ public class BaseBlobStoreIntegrationTest {
return containerName.equals(md.getName()); return containerName.equals(md.getName());
} }
})) { })) {
throw new IllegalStateException( throw new IllegalStateException("Test returned the name of a non-existent container: " + containerName);
"Test returned the name of a non-existent container: " + containerName);
} }
} }
} }
} }
/** /**
* abandon old container name instead of waiting for the container to be created. * abandon old container name instead of waiting for the container to be
* created.
* *
* @throws InterruptedException * @throws InterruptedException
*/ */

View File

@ -37,7 +37,6 @@ import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.encryption.internal.JCEEncryptionService;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -48,8 +47,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void containerDoesntExist() { public void containerDoesntExist() {
assert !context.getBlobStore().containerExists("forgetaboutit"); assert !context.getBlobStore().containerExists("forgetaboutit");
assert !context.getBlobStore().containerExists( assert !context.getBlobStore().containerExists("cloudcachestorefunctionalintegrationtest-first");
"cloudcachestorefunctionalintegrationtest-first");
} }
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
@ -77,26 +75,25 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
object.setPayload(TEST_STRING); object.setPayload(TEST_STRING);
object.getMetadata().setContentType(MediaType.TEXT_PLAIN); object.getMetadata().setContentType(MediaType.TEXT_PLAIN);
object.getMetadata().setSize(new Long(TEST_STRING.length())); object.getMetadata().setSize(new Long(TEST_STRING.length()));
// NOTE all metadata in jclouds comes out as lowercase, in an effort to normalize the // NOTE all metadata in jclouds comes out as lowercase, in an effort to
// normalize the
// providers. // providers.
object.getMetadata().getUserMetadata().put("Adrian", "powderpuff"); object.getMetadata().getUserMetadata().put("Adrian", "powderpuff");
object.getMetadata() object.getMetadata().setContentMD5(encryptionService.md5(toInputStream(TEST_STRING)));
.setContentMD5(new JCEEncryptionService().md5(toInputStream(TEST_STRING)));
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
addBlobToContainer(containerName, object); addBlobToContainer(containerName, object);
validateContent(containerName, key); validateContent(containerName, key);
PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName,
maxResults(1).withDetails()); maxResults(1).withDetails());
BlobMetadata metadata = BlobMetadata.class.cast(get(container, 0)); BlobMetadata metadata = BlobMetadata.class.cast(get(container, 0));
assert metadata.getContentType().startsWith("text/plain") : metadata.getContentType(); assert metadata.getContentType().startsWith("text/plain") : metadata.getContentType();
assertEquals(metadata.getSize(), new Long(TEST_STRING.length())); assertEquals(metadata.getSize(), new Long(TEST_STRING.length()));
assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff"); assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff");
assertEquals(metadata.getContentMD5(), new JCEEncryptionService() assertEquals(metadata.getContentMD5(), encryptionService.md5(toInputStream(TEST_STRING)));
.md5(toInputStream(TEST_STRING)));
} finally { } finally {
returnContainer(containerName); returnContainer(containerName);
} }
@ -119,8 +116,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
addAlphabetUnderRoot(containerName); addAlphabetUnderRoot(containerName);
PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, maxResults(1));
maxResults(1));
assert container.getNextMarker() != null; assert container.getNextMarker() != null;
assertEquals(container.size(), 1); assertEquals(container.size(), 1);
@ -128,8 +124,8 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
container = context.getBlobStore().list(containerName, afterMarker(marker)); container = context.getBlobStore().list(containerName, afterMarker(marker));
assertEquals(container.getNextMarker(), null); assertEquals(container.getNextMarker(), null);
assert container.size() == 25 : String.format("size should have been 25, but was %d: %s", assert container.size() == 25 : String.format("size should have been 25, but was %d: %s", container.size(),
container.size(), container); container);
assert container.getNextMarker() == null; assert container.getNextMarker() == null;
} finally { } finally {
@ -138,8 +134,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
} }
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testListRootUsesDelimiter() throws InterruptedException, public void testListRootUsesDelimiter() throws InterruptedException, UnsupportedEncodingException {
UnsupportedEncodingException {
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
String prefix = "rootdelimeter"; String prefix = "rootdelimeter";
@ -239,8 +234,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
addTenObjectsUnderPrefix(containerName, prefix); addTenObjectsUnderPrefix(containerName, prefix);
add15UnderRoot(containerName); add15UnderRoot(containerName);
PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, inDirectory(prefix));
inDirectory(prefix));
assert container.getNextMarker() == null; assert container.getNextMarker() == null;
assertEquals(container.size(), 10); assertEquals(container.size(), 10);
} finally { } finally {
@ -250,13 +244,11 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
} }
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testListContainerMaxResults() throws InterruptedException, public void testListContainerMaxResults() throws InterruptedException, UnsupportedEncodingException {
UnsupportedEncodingException {
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
addAlphabetUnderRoot(containerName); addAlphabetUnderRoot(containerName);
PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, PageSet<? extends StorageMetadata> container = context.getBlobStore().list(containerName, maxResults(5));
maxResults(5));
assertEquals(container.size(), 5); assertEquals(container.size(), 5);
assert container.getNextMarker() != null; assert container.getNextMarker() != null;
} finally { } finally {
@ -302,8 +294,8 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
assertConsistencyAware(new Runnable() { assertConsistencyAware(new Runnable() {
public void run() { public void run() {
try { try {
assert !context.getBlobStore().containerExists(containerName) : "container " assert !context.getBlobStore().containerExists(containerName) : "container " + containerName
+ containerName + " still exists"; + " still exists";
} catch (Exception e) { } catch (Exception e) {
propagateIfPossible(e); propagateIfPossible(e);
} }
@ -312,8 +304,8 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
} }
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void testListContainer() throws InterruptedException, ExecutionException, public void testListContainer() throws InterruptedException, ExecutionException, TimeoutException,
TimeoutException, UnsupportedEncodingException { UnsupportedEncodingException {
String containerName = getContainerName(); String containerName = getContainerName();
try { try {
add15UnderRoot(containerName); add15UnderRoot(containerName);
@ -341,8 +333,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest {
} }
} }
protected void addTenObjectsUnderPrefix(String containerName, String prefix) protected void addTenObjectsUnderPrefix(String containerName, String prefix) throws InterruptedException {
throws InterruptedException {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
Blob blob = context.getBlobStore().newBlob(prefix + "/" + i); Blob blob = context.getBlobStore().newBlob(prefix + "/" + i);
blob.setPayload(i + "content"); blob.setPayload(i + "content");

View File

@ -1,102 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
$HeadURL$ $HeadURL$ $Revision$ $Date$ Copyright (C) 2009 Cloud Conscious, LLC
$Revision$ <info@cloudconscious.com>
$Date$
Copyright (C) 2009 Cloud Conscious, LLC <info@cloudconscious.com> ====================================================================
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.html Unless required by
Licensed to the Apache Software Foundation (ASF) under one applicable law or agreed to in writing, software distributed under the
or more contributor license agreements. See the NOTICE file License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
distributed with this work for additional information CONDITIONS OF ANY KIND, either express or implied. See the License for
regarding copyright ownership. The ASF licenses this file the specific language governing permissions and limitations under the
to you under the Apache License, Version 2.0 (the License.
"License"); you may not use this file except in compliance ====================================================================
with the License. You may obtain a copy of the License at -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../project/pom.xml</relativePath>
</parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-chef</artifactId>
<name>jclouds Chef core</name>
<description>jclouds components to access Chef</description>
http://www.apache.org/licenses/LICENSE-2.0.html <scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/chef</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/chef</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk/chef</url>
</scm>
Unless required by applicable law or agreed to in writing, <!-- bootstrapping: need to fetch the project POM -->
software distributed under the License is distributed on an <repositories>
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY <repository>
KIND, either express or implied. See the License for the <id>jclouds-googlecode-deploy</id>
specific language governing permissions and limitations <url>http://jclouds.googlecode.com/svn/repo</url>
under the License. </repository>
==================================================================== <repository>
--> <id>jclouds-rimu-snapshots-nexus</id>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <url>http://jclouds.rimuhosting.com:8081/nexus/content/repositories/snapshots</url>
<modelVersion>4.0.0</modelVersion> <snapshots>
<parent> <enabled>true</enabled>
<groupId>org.jclouds</groupId> </snapshots>
<artifactId>jclouds-project</artifactId> </repository>
<version>1.0-SNAPSHOT</version> </repositories>
<relativePath>../project/pom.xml</relativePath>
</parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-chef</artifactId>
<name>jclouds Chef core</name>
<description>jclouds components to access Chef</description>
<scm> <properties>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/chef</connection> <jclouds.chef.identity>chef-validator</jclouds.chef.identity>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/chef</developerConnection> <jclouds.chef.rsa-key>/etc/chef/validation.pem</jclouds.chef.rsa-key>
<url>http://jclouds.googlecode.com/svn/trunk/chef</url> <jclouds.chef.endpoint>http://localhost:4000</jclouds.chef.endpoint>
</scm> <jclouds.test.identity>${jclouds.chef.identity}</jclouds.test.identity>
<jclouds.test.credential>${jclouds.chef.rsa-key}</jclouds.test.credential>
<jclouds.test.endpoint>${jclouds.chef.endpoint}</jclouds.test.endpoint>
</properties>
<!-- bootstrapping: need to fetch the project POM --> <dependencies>
<repositories> <dependency>
<repository> <groupId>${project.groupId}</groupId>
<id>jclouds-googlecode-deploy</id> <artifactId>jclouds-core</artifactId>
<url>http://jclouds.googlecode.com/svn/repo</url> <version>${project.version}</version>
</repository> </dependency>
<repository> <dependency>
<id>jclouds-rimu-snapshots-nexus</id> <groupId>${project.groupId}</groupId>
<url>http://jclouds.rimuhosting.com:8081/nexus/content/repositories/snapshots</url> <artifactId>jclouds-core</artifactId>
<snapshots> <version>${project.version}</version>
<enabled>true</enabled> <type>test-jar</type>
</snapshots> <scope>test</scope>
</repository> </dependency>
</repositories> <dependency>
<groupId>log4j</groupId>
<properties> <artifactId>log4j</artifactId>
<jclouds.chef.identity>chef-validator</jclouds.chef.identity> <version>1.2.14</version>
<jclouds.chef.rsa-key>/etc/chef/validation.pem</jclouds.chef.rsa-key> <scope>test</scope>
<jclouds.chef.endpoint>http://localhost:4000</jclouds.chef.endpoint> </dependency>
<jclouds.test.identity>${jclouds.chef.identity}</jclouds.test.identity> <dependency>
<jclouds.test.credential>${jclouds.chef.rsa-key}</jclouds.test.credential> <groupId>${project.groupId}</groupId>
<jclouds.test.endpoint>${jclouds.chef.endpoint}</jclouds.test.endpoint> <artifactId>jclouds-log4j</artifactId>
</properties> <version>${project.version}</version>
<scope>test</scope>
<dependencies> </dependency>
<dependency> </dependencies>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<version>1.44</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-log4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project> </project>

View File

@ -44,24 +44,22 @@ package org.jclouds.chef.config;
import static org.jclouds.Constants.PROPERTY_CREDENTIAL; import static org.jclouds.Constants.PROPERTY_CREDENTIAL;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import java.io.IOException; import java.io.UnsupportedEncodingException;
import java.io.StringReader;
import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.Security;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.jclouds.chef.handlers.ChefClientErrorRetryHandler;
import org.bouncycastle.openssl.PEMReader;
import org.jclouds.chef.handlers.ChefErrorHandler; import org.jclouds.chef.handlers.ChefErrorHandler;
import org.jclouds.concurrent.ExpirableSupplier; import org.jclouds.concurrent.ExpirableSupplier;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.Redirection;
@ -88,7 +86,7 @@ public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
} }
protected BaseChefRestClientModule(Class<S> syncClientType, Class<A> asyncClientType, protected BaseChefRestClientModule(Class<S> syncClientType, Class<A> asyncClientType,
Map<Class<?>, Class<?>> delegates) { Map<Class<?>, Class<?>> delegates) {
super(syncClientType, asyncClientType, delegates); super(syncClientType, asyncClientType, delegates);
} }
@ -103,8 +101,7 @@ public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
*/ */
@Provides @Provides
@TimeStamp @TimeStamp
Supplier<String> provideTimeStampCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, Supplier<String> provideTimeStampCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, final DateService dateService) {
final DateService dateService) {
return new ExpirableSupplier<String>(new Supplier<String>() { return new ExpirableSupplier<String>(new Supplier<String>() {
public String get() { public String get() {
return dateService.iso8601SecondsDateFormat(); return dateService.iso8601SecondsDateFormat();
@ -114,11 +111,9 @@ public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
@Provides @Provides
@Singleton @Singleton
public PrivateKey provideKey(@Named(PROPERTY_CREDENTIAL) String key) throws IOException { public PrivateKey provideKey(EncryptionService encryptionService, @Named(PROPERTY_CREDENTIAL) String pem)
// TODO do this without adding a provider throws UnsupportedEncodingException {
Security.addProvider(new BouncyCastleProvider()); return encryptionService.readPrivateKeyFromPEM(pem.getBytes("UTF-8"));
KeyPair pair = KeyPair.class.cast(new PEMReader(new StringReader(key)).readObject());
return pair.getPrivate();
} }
@Override @Override
@ -128,6 +123,11 @@ public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ChefErrorHandler.class); bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ChefErrorHandler.class);
} }
@Override
protected void bindRetryHandlers() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(ChefClientErrorRetryHandler.class);
}
@Override @Override
protected void configure() { protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class); bind(DateAdapter.class).to(Iso8601DateAdapter.class);

View File

@ -0,0 +1,72 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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 org.jclouds.chef.handlers;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.Constants;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
/**
* Allow for eventual consistency on sandbox requests.
*
* @author Adrian Cole
*/
public class ChefClientErrorRetryHandler implements HttpRetryHandler {
@Inject(optional = true)
@Named(Constants.PROPERTY_MAX_RETRIES)
private int retryCountLimit = 5;
@Resource
protected Logger logger = Logger.NULL;
private final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
@Inject
ChefClientErrorRetryHandler(BackoffLimitedRetryHandler backoffLimitedRetryHandler) {
this.backoffLimitedRetryHandler = backoffLimitedRetryHandler;
}
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (command.getFailureCount() > retryCountLimit)
return false;
if (response.getStatusCode() == 400 && command.getRequest().getMethod().equals("PUT")
&& command.getRequest().getEndpoint().getPath().indexOf("sandboxes") != -1) {
if (response.getPayload() != null) {
String error = new String(closeClientButKeepContentStream(response));
if (error != null && error.indexOf("was not uploaded") != -1) {
return backoffLimitedRetryHandler.shouldRetryRequest(command, response);
}
}
}
return false;
}
}

View File

@ -106,6 +106,7 @@ public class ChefClientLiveTest {
// define the file you want in the cookbook // define the file you want in the cookbook
FilePayload content = Payloads.newFilePayload(new File(System.getProperty("user.dir"), "pom.xml")); FilePayload content = Payloads.newFilePayload(new File(System.getProperty("user.dir"), "pom.xml"));
content.setContentType("application/x-binary");
// get an md5 so that you can see if the server already has it or not // get an md5 so that you can see if the server already has it or not
adminConnection.utils().encryption().generateMD5BufferingIfNotRepeatable(content); adminConnection.utils().encryption().generateMD5BufferingIfNotRepeatable(content);
@ -126,7 +127,6 @@ public class ChefClientLiveTest {
adminConnection.utils().http().put(status.getUrl(), content); adminConnection.utils().http().put(status.getUrl(), content);
} }
// if we were able to get here, close the sandbox
adminConnection.getApi().commitSandbox(site.getSandboxId(), true); adminConnection.getApi().commitSandbox(site.getSandboxId(), true);
} catch (RuntimeException e) { } catch (RuntimeException e) {

View File

@ -26,19 +26,14 @@ package org.jclouds.chef.filters;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader;
import java.net.URI; import java.net.URI;
import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.Security;
import java.util.Properties; import java.util.Properties;
import javax.inject.Provider; import javax.inject.Provider;
import javax.ws.rs.HttpMethod; import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
@ -82,54 +77,42 @@ public class SignedHeaderAuthTest {
public static final String X_OPS_CONTENT_HASH = "DFteJZPVv6WKdQmMqZUQUumUyRs="; public static final String X_OPS_CONTENT_HASH = "DFteJZPVv6WKdQmMqZUQUumUyRs=";
public static final String[] X_OPS_AUTHORIZATION_LINES = new String[] { public static final String[] X_OPS_AUTHORIZATION_LINES = new String[] {
"jVHrNniWzpbez/eGWjFnO6lINRIuKOg40ZTIQudcFe47Z9e/HvrszfVXlKG4", "jVHrNniWzpbez/eGWjFnO6lINRIuKOg40ZTIQudcFe47Z9e/HvrszfVXlKG4",
"NMzYZgyooSvU85qkIUmKuCqgG2AIlvYa2Q/2ctrMhoaHhLOCWWoqYNMaEqPc", "NMzYZgyooSvU85qkIUmKuCqgG2AIlvYa2Q/2ctrMhoaHhLOCWWoqYNMaEqPc",
"3tKHE+CfvP+WuPdWk4jv4wpIkAz6ZLxToxcGhXmZbXpk56YTmqgBW2cbbw4O", "3tKHE+CfvP+WuPdWk4jv4wpIkAz6ZLxToxcGhXmZbXpk56YTmqgBW2cbbw4O",
"IWPZDHSiPcw//AYNgW1CCDptt+UFuaFYbtqZegcBd2n/jzcWODA7zL4KWEUy", "IWPZDHSiPcw//AYNgW1CCDptt+UFuaFYbtqZegcBd2n/jzcWODA7zL4KWEUy",
"9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0", "9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0", "utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w==" };
"utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w==" };
// We expect Mixlib::Authentication::SignedHeaderAuth//sign to return this // We expect Mixlib::Authentication::SignedHeaderAuth//sign to return this
// if passed the BODY above. // if passed the BODY above.
public static final Multimap<String, String> EXPECTED_SIGN_RESULT = ImmutableMultimap public static final Multimap<String, String> EXPECTED_SIGN_RESULT = ImmutableMultimap.<String, String> builder()
.<String, String> builder().put("X-Ops-Content-Hash", X_OPS_CONTENT_HASH).put( .put("X-Ops-Content-Hash", X_OPS_CONTENT_HASH).put("X-Ops-Userid", USER_ID).put("X-Ops-Sign", "version=1.0")
"X-Ops-Userid", USER_ID).put("X-Ops-Sign", "version=1.0").put( .put("X-Ops-Authorization-1", X_OPS_AUTHORIZATION_LINES[0]).put("X-Ops-Authorization-2",
"X-Ops-Authorization-1", X_OPS_AUTHORIZATION_LINES[0]).put( X_OPS_AUTHORIZATION_LINES[1]).put("X-Ops-Authorization-3", X_OPS_AUTHORIZATION_LINES[2]).put(
"X-Ops-Authorization-2", X_OPS_AUTHORIZATION_LINES[1]).put( "X-Ops-Authorization-4", X_OPS_AUTHORIZATION_LINES[3]).put("X-Ops-Authorization-5",
"X-Ops-Authorization-3", X_OPS_AUTHORIZATION_LINES[2]).put( X_OPS_AUTHORIZATION_LINES[4]).put("X-Ops-Authorization-6", X_OPS_AUTHORIZATION_LINES[5]).put(
"X-Ops-Authorization-4", X_OPS_AUTHORIZATION_LINES[3]).put( "X-Ops-Timestamp", TIMESTAMP_ISO8601).build();
"X-Ops-Authorization-5", X_OPS_AUTHORIZATION_LINES[4]).put(
"X-Ops-Authorization-6", X_OPS_AUTHORIZATION_LINES[5]).put("X-Ops-Timestamp",
TIMESTAMP_ISO8601).build();
// Content hash for empty string // Content hash for empty string
public static final String X_OPS_CONTENT_HASH_EMPTY = "2jmj7l5rSw0yVb/vlWAYkK/YBwk="; public static final String X_OPS_CONTENT_HASH_EMPTY = "2jmj7l5rSw0yVb/vlWAYkK/YBwk=";
public static final Multimap<String, String> EXPECTED_SIGN_RESULT_EMPTY = ImmutableMultimap public static final Multimap<String, String> EXPECTED_SIGN_RESULT_EMPTY = ImmutableMultimap
.<String, String> builder().put("X-Ops-Content-Hash", X_OPS_CONTENT_HASH_EMPTY).put( .<String, String> builder().put("X-Ops-Content-Hash", X_OPS_CONTENT_HASH_EMPTY).put("X-Ops-Userid", USER_ID)
"X-Ops-Userid", USER_ID).put("X-Ops-Sign", "version=1.0").put( .put("X-Ops-Sign", "version=1.0").put("X-Ops-Authorization-1",
"X-Ops-Authorization-1", "N6U75kopDK64cEFqrB6vw+PnubnXr0w5LQeXnIGNGLRP2LvifwIeisk7QxEx").put("X-Ops-Authorization-2",
"N6U75kopDK64cEFqrB6vw+PnubnXr0w5LQeXnIGNGLRP2LvifwIeisk7QxEx").put( "mtpQOWAw8HvnWErjzuk9AvUsqVmWpv14ficvkaD79qsPMvbje+aLcIrCGT1P").put("X-Ops-Authorization-3",
"X-Ops-Authorization-2", "3d2uvf4w7iqwzrIscPnkxLR6o6pymR90gvJXDPzV7Le0jbfD8kmZ8AAK0sGG").put("X-Ops-Authorization-4",
"mtpQOWAw8HvnWErjzuk9AvUsqVmWpv14ficvkaD79qsPMvbje+aLcIrCGT1P").put( "09F1ftW80bLatJTA66Cw2wBz261r6x/abZhIKFJFDWLzyQGJ8ZNOkUrDDtgI").put("X-Ops-Authorization-5",
"X-Ops-Authorization-3", "svLVXpOJKZZfKunsElpWjjsyNt3k8vpI1Y4ANO8Eg2bmeCPeEK+YriGm5fbC").put("X-Ops-Authorization-6",
"3d2uvf4w7iqwzrIscPnkxLR6o6pymR90gvJXDPzV7Le0jbfD8kmZ8AAK0sGG").put( "DzWNPylHJqMeGKVYwGQKpg62QDfe5yXh3wZLiQcXow==").put("X-Ops-Timestamp", TIMESTAMP_ISO8601).build();
"X-Ops-Authorization-4",
"09F1ftW80bLatJTA66Cw2wBz261r6x/abZhIKFJFDWLzyQGJ8ZNOkUrDDtgI").put(
"X-Ops-Authorization-5",
"svLVXpOJKZZfKunsElpWjjsyNt3k8vpI1Y4ANO8Eg2bmeCPeEK+YriGm5fbC").put(
"X-Ops-Authorization-6", "DzWNPylHJqMeGKVYwGQKpg62QDfe5yXh3wZLiQcXow==").put(
"X-Ops-Timestamp", TIMESTAMP_ISO8601).build();
public static String PUBLIC_KEY; public static String PUBLIC_KEY;
public static String PRIVATE_KEY; public static String PRIVATE_KEY;
static { static {
try { try {
PUBLIC_KEY = Utils.toStringAndClose(SignedHeaderAuthTest.class PUBLIC_KEY = Utils.toStringAndClose(SignedHeaderAuthTest.class.getResourceAsStream("/pubkey.txt"));
.getResourceAsStream("/pubkey.txt"));
PRIVATE_KEY = Utils.toStringAndClose(SignedHeaderAuthTest.class PRIVATE_KEY = Utils.toStringAndClose(SignedHeaderAuthTest.class.getResourceAsStream("/privkey.txt"));
.getResourceAsStream("/privkey.txt"));
} catch (IOException e) { } catch (IOException e) {
Throwables.propagate(e); Throwables.propagate(e);
} }
@ -152,20 +135,17 @@ public class SignedHeaderAuthTest {
HttpRequest request = new HttpRequest(HttpMethod.POST, host); HttpRequest request = new HttpRequest(HttpMethod.POST, host);
request.setPayload(BODY); request.setPayload(BODY);
String expected_string_to_sign = new StringBuilder().append("Method:POST").append("\n") String expected_string_to_sign = new StringBuilder().append("Method:POST").append("\n").append("Hashed Path:")
.append("Hashed Path:").append(HASHED_CANONICAL_PATH).append("\n").append( .append(HASHED_CANONICAL_PATH).append("\n").append("X-Ops-Content-Hash:").append(HASHED_BODY).append("\n")
"X-Ops-Content-Hash:").append(HASHED_BODY).append("\n").append( .append("X-Ops-Timestamp:").append(TIMESTAMP_ISO8601).append("\n").append("X-Ops-UserId:").append(USER_ID)
"X-Ops-Timestamp:").append(TIMESTAMP_ISO8601).append("\n").append( .toString();
"X-Ops-UserId:").append(USER_ID).toString();
assertEquals(signing_obj.createStringToSign("POST", HASHED_CANONICAL_PATH, HASHED_BODY, assertEquals(signing_obj.createStringToSign("POST", HASHED_CANONICAL_PATH, HASHED_BODY, TIMESTAMP_ISO8601),
TIMESTAMP_ISO8601), expected_string_to_sign); expected_string_to_sign);
assertEquals(signing_obj.sign(expected_string_to_sign), Joiner.on("").join( assertEquals(signing_obj.sign(expected_string_to_sign), Joiner.on("").join(X_OPS_AUTHORIZATION_LINES));
X_OPS_AUTHORIZATION_LINES));
signing_obj.filter(request); signing_obj.filter(request);
Multimap<String, String> headersWithoutContentLength = LinkedHashMultimap.create(request Multimap<String, String> headersWithoutContentLength = LinkedHashMultimap.create(request.getHeaders());
.getHeaders());
headersWithoutContentLength.removeAll(HttpHeaders.CONTENT_LENGTH); headersWithoutContentLength.removeAll(HttpHeaders.CONTENT_LENGTH);
assertEquals(headersWithoutContentLength.values(), EXPECTED_SIGN_RESULT.values()); assertEquals(headersWithoutContentLength.values(), EXPECTED_SIGN_RESULT.values());
} }
@ -177,8 +157,7 @@ public class SignedHeaderAuthTest {
HttpRequest request = new HttpRequest(HttpMethod.DELETE, host); HttpRequest request = new HttpRequest(HttpMethod.DELETE, host);
signing_obj.filter(request); signing_obj.filter(request);
Multimap<String, String> headersWithoutContentLength = LinkedHashMultimap.create(request Multimap<String, String> headersWithoutContentLength = LinkedHashMultimap.create(request.getHeaders());
.getHeaders());
assertEquals(headersWithoutContentLength.entries(), EXPECTED_SIGN_RESULT_EMPTY.entries()); assertEquals(headersWithoutContentLength.entries(), EXPECTED_SIGN_RESULT_EMPTY.entries());
} }
@ -196,12 +175,6 @@ public class SignedHeaderAuthTest {
private SignedHeaderAuth signing_obj; private SignedHeaderAuth signing_obj;
private EncryptionService encryptionService; private EncryptionService encryptionService;
@Test(enabled = false)
void canParseKeyFromCreateClient() throws IOException {
String key = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA50Iwgq8OIfm5vY9Gwfb6UBt17D7V4djyFSLJ1AbCU/o8Zlrr\nW73JqaK5dC3IO6Dcu+/qPYGtBUWvhFAXrsFOooz0mTod/LtBN1YVurJ60goJrR6w\nKhUYC9H45OW/qcdIM7kdDwiyMZfbHqW6fo0xPqjvgxtZoI+v7pgThacOG6pw7PO6\nGgnJa3MGK3xEbzlI6+EBJWG3EiwexguwOpTD4a4TDIAqKrlVDPeUpU7rFbsBPRS8\nkypR3lU58+WRz/zi9fiH/Sy2X+ChefyZg14HiutJjxc8zJsazF3eDxyLGPQmhv3Mso\nA0wbjGusbe6hPdDkzh/B2KO9u96QCdlGu/rc6QIDAQABAoIBAA/7OgD9+fsNF/Hq\nodgrqja4/xg5a2x1Ip2lTs9RPEKza1Mje1pWrkYD0c8ejtTYFAkE1mozuPJBU5TQ\nOCLChx2iohCovIPHqQUa9Nt3FBfJy8tj8Ian+IZwl0OyQOGJvQqeA00Tq8TTmrfu\negne1gVfhVXJIROAeocBiW/WEJqGti0OE5zQQMld3cJ5viTdEsaWYCu2HaEoblKB\nH6KfRGM2N3L3KjKFGtEg+cX1UdaMlzmp+O5/yvjBykZy6cuUOIsgz2e5nQV4hYEq\ntJ/+6E0QVTXfnVZi4IxKlkVMhyonqOxAOKGG+dWeWh3DqPJFzjmp3kcbRN9E3u+2\nqKU5gpECgYEA+a/i5z2jFCJ8rMpoCPPxm2eiIYZVs3LE33WU5FNNieBRC+KqO06h\nMB3rQ3k8KJDNJYWD5UwIrgjCD5mgkmcSDI6SbOn6PA1Mtw6qZlbeg17V9L9ryXxt\nSfC5AC+qVWd6unrLh0LgkvLS8rgG4GjLZY0HDDMrJWodcc+uWVk3Mo0CgYEA7RsG\nC9gOcHWi6WJ2uEDvLj4IkSkB4IFipEVcKl7VVDSnUgxaBZm3o0DLYDYhIOw7XcQL\n6vpxbRZdlApGyu1ahfMbk3+quFNMQuGxZcv9EhHz7ASnXK6mlrWkJzCGjLz6/MdI\nU0VGbtkBtOY/GaLXdTkQksWowVNoedISfQV9as0CgYEA0Tj1JVecw05yskeZDYd8\nOQCJ9xWd0pSlK6pXbUvweUwiHZd9ldy5bJxle1CnfEZ54KsUbptb2pk0I+ZTitob\nYbJGOEWHjbKHSg1b9A1uvx5EoqWUKG2/FmpEW0eVr6LaUFB9I4aCsCARa5mRCZJG\nfX3DHhHyYZOdwLSKIAyGGDECgYALEwkMQpIiFIyAZBXxcy74tPMHfKfWyZRG4ep1\nHCrQnQj3nxYRTuWx3VPicYTImeAH+CEqX3ouwy2pvXUjA0UIHpu6HutlYpacRRhZ\nDdcLIgWHj4wVmx6yyVcacXzHVAhRCCnLod+xS7d1sI9f7igsFHc+s7a3GOM3VWWB\nq2D5PQKBgQDY9eSb5pc5EYbPy0a/wKFLMNCVLXlDT8jRSC2UnhmcHbhi1IdUbn1j\nR+SuUgrAVNAKzJRY9wmF6Zt0pJ2YLFX7L8HaGyfzkib8kli2sXFonlQ4d0dTdcJo\nVGR1jTxfZQicdPcDPOLPpQz/rP31ZqdHtfaegTOxHebX7W2E5QvPZg==\n-----END RSA PRIVATE KEY-----\n";
KeyPair.class.cast(new PEMReader(new StringReader(key)).readObject());
}
/** /**
* before class, as we need to ensure that the filter is threadsafe. * before class, as we need to ensure that the filter is threadsafe.
* *
@ -211,28 +184,22 @@ public class SignedHeaderAuthTest {
@BeforeClass @BeforeClass
protected void createFilter() throws IOException { protected void createFilter() throws IOException {
Injector injector = new RestContextFactory().createContextBuilder("chef", USER_ID, Injector injector = new RestContextFactory().createContextBuilder("chef", USER_ID, PRIVATE_KEY,
PRIVATE_KEY, ImmutableSet.<Module> of(new MockModule(), new NullLoggingModule()), ImmutableSet.<Module> of(new MockModule(), new NullLoggingModule()), new Properties()).buildInjector();
new Properties()).buildInjector();
encryptionService = injector.getInstance(EncryptionService.class); encryptionService = injector.getInstance(EncryptionService.class);
HttpUtils utils = injector.getInstance(HttpUtils.class); HttpUtils utils = injector.getInstance(HttpUtils.class);
Security.addProvider(new BouncyCastleProvider()); PrivateKey privateKey = injector.getInstance(PrivateKey.class);
KeyPair pair = KeyPair.class.cast(new PEMReader(new StringReader(PRIVATE_KEY)).readObject()); signing_obj = new SignedHeaderAuth(new SignatureWire(), USER_ID, privateKey, new Provider<String>() {
PrivateKey privateKey = pair.getPrivate(); @Override
public String get() {
return TIMESTAMP_ISO8601;
}
signing_obj = new SignedHeaderAuth(new SignatureWire(), USER_ID, privateKey, }, encryptionService, utils);
new Provider<String>() {
@Override
public String get() {
return TIMESTAMP_ISO8601;
}
}, encryptionService, utils);
} }
} }

View File

@ -0,0 +1,101 @@
package org.jclouds.chef.handlers;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import java.net.URI;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.io.Payloads;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code ChefClientErrorRetryHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "chef.ChefClientErrorRetryHandlerTest")
public class ChefClientErrorRetryHandlerTest {
@Test
public void test401DoesNotRetry() {
HttpCommand command = createMock(HttpCommand.class);
HttpResponse response = createMock(HttpResponse.class);
BackoffLimitedRetryHandler retry = createMock(BackoffLimitedRetryHandler.class);
expect(command.getFailureCount()).andReturn(0);
expect(response.getStatusCode()).andReturn(401).atLeastOnce();
replay(response);
replay(retry);
replay(command);
ChefClientErrorRetryHandler handler = new ChefClientErrorRetryHandler(retry);
assert !handler.shouldRetryRequest(command, response);
verify(retry);
verify(command);
verify(response);
}
@Test
public void test400DoesNotRetry() {
HttpCommand command = createMock(HttpCommand.class);
HttpResponse response = createMock(HttpResponse.class);
BackoffLimitedRetryHandler retry = createMock(BackoffLimitedRetryHandler.class);
expect(command.getFailureCount()).andReturn(0);
expect(response.getStatusCode()).andReturn(401).atLeastOnce();
replay(response);
replay(retry);
replay(command);
ChefClientErrorRetryHandler handler = new ChefClientErrorRetryHandler(retry);
assert !handler.shouldRetryRequest(command, response);
verify(retry);
verify(command);
verify(response);
}
@Test
public void testRetryOn400PutSandbox() {
HttpCommand command = createMock(HttpCommand.class);
BackoffLimitedRetryHandler retry = createMock(BackoffLimitedRetryHandler.class);
HttpRequest request = new HttpRequest("PUT", URI
.create("https://api.opscode.com/organizations/jclouds/sandboxes/bfd68d4052f44053b2e593a33b5e1cd5"));
HttpResponse response = new HttpResponse(
400,
"400 Bad Request",
Payloads
.newStringPayload("{\"error\":[\"Cannot update sandbox bfd68d4052f44053b2e593a33b5e1cd5: checksum 9b7c23369f4b576451216c39f214af6c was not uploaded\"]}"));
expect(command.getFailureCount()).andReturn(0);
expect(command.getRequest()).andReturn(request).atLeastOnce();
expect(retry.shouldRetryRequest(command, response)).andReturn(true);
replay(retry);
replay(command);
ChefClientErrorRetryHandler handler = new ChefClientErrorRetryHandler(retry);
assert handler.shouldRetryRequest(command, response);
verify(retry);
verify(command);
}
}

View File

@ -45,9 +45,20 @@
<id>gson</id> <id>gson</id>
<url>http://google-gson.googlecode.com/svn/mavenrepo</url> <url>http://google-gson.googlecode.com/svn/mavenrepo</url>
</repository> </repository>
<repository>
<id>oauth</id>
<name>OAuth Repository</name>
<url>http://oauth.googlecode.com/svn/code/maven</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency>
<groupId>net.oauth.core</groupId>
<artifactId>oauth</artifactId>
<version>20100527</version>
</dependency>
<dependency> <dependency>
<groupId>aopalliance</groupId> <groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId> <artifactId>aopalliance</artifactId>

View File

@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.security.Key; import java.security.Key;
import java.security.PrivateKey;
import org.jclouds.encryption.internal.JCEEncryptionService; import org.jclouds.encryption.internal.JCEEncryptionService;
import org.jclouds.http.PayloadEnclosing; import org.jclouds.http.PayloadEnclosing;
@ -73,6 +74,8 @@ public interface EncryptionService {
MD5OutputStream md5OutputStream(OutputStream out); MD5OutputStream md5OutputStream(OutputStream out);
PrivateKey readPrivateKeyFromPEM(byte [] pem);
public static abstract class MD5OutputStream extends FilterOutputStream { public static abstract class MD5OutputStream extends FilterOutputStream {
public MD5OutputStream(OutputStream out) { public MD5OutputStream(OutputStream out) {
super(out); super(out);

View File

@ -21,15 +21,25 @@ package org.jclouds.encryption.internal;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.annotation.Resource; import javax.annotation.Resource;
import net.oauth.signature.pem.PEMReader;
import net.oauth.signature.pem.PKCS1EncodedKeySpec;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.PayloadEnclosing; import org.jclouds.http.PayloadEnclosing;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import com.google.common.base.Throwables;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
@ -41,10 +51,14 @@ public abstract class BaseEncryptionService implements EncryptionService {
protected static final int BUF_SIZE = 0x2000; // 8 protected static final int BUF_SIZE = 0x2000; // 8
final byte[] HEX_CHAR_TABLE = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
(byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f' };
final byte[] HEX_CHAR_TABLE = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', private final KeyFactory rsaKeyFactory;
(byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b',
(byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f' }; public BaseEncryptionService(KeyFactory rsaKeyFactory) {
this.rsaKeyFactory = rsaKeyFactory;
}
@Override @Override
public String hex(byte[] raw) { public String hex(byte[] raw) {
@ -90,7 +104,6 @@ public abstract class BaseEncryptionService implements EncryptionService {
/** /**
* {@inheritDoc} * {@inheritDoc}
* @
*/ */
@Override @Override
public <T extends PayloadEnclosing> T generateMD5BufferingIfNotRepeatable(T payloadEnclosing) { public <T extends PayloadEnclosing> T generateMD5BufferingIfNotRepeatable(T payloadEnclosing) {
@ -100,4 +113,30 @@ public abstract class BaseEncryptionService implements EncryptionService {
payloadEnclosing.setPayload(newPayload); payloadEnclosing.setPayload(newPayload);
return payloadEnclosing; return payloadEnclosing;
} }
/**
* {@inheritDoc}
*/
@Override
public PrivateKey readPrivateKeyFromPEM(byte[] pem) {
PEMReader reader;
try {
reader = new PEMReader(pem);
byte[] bytes = reader.getDerBytes();
KeySpec keySpec;
if (PEMReader.PRIVATE_PKCS1_MARKER.equals(reader.getBeginMarker())) {
keySpec = (new PKCS1EncodedKeySpec(bytes)).getKeySpec();
} else if (PEMReader.PRIVATE_PKCS8_MARKER.equals(reader.getBeginMarker())) {
keySpec = new PKCS8EncodedKeySpec(bytes);
} else {
throw new IOException("Invalid PEM file: Unknown marker " + "for private key " + reader.getBeginMarker());
}
return rsaKeyFactory.generatePrivate(keySpec);
} catch (Exception e) {
Throwables.propagate(e);
return null;
}
}
} }

View File

@ -28,6 +28,7 @@ import java.io.OutputStream;
import java.security.DigestOutputStream; import java.security.DigestOutputStream;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.Key; import java.security.Key;
import java.security.KeyFactory;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -43,6 +44,14 @@ import org.jclouds.io.payloads.ByteArrayPayload;
*/ */
public class JCEEncryptionService extends BaseEncryptionService { public class JCEEncryptionService extends BaseEncryptionService {
public JCEEncryptionService(KeyFactory rsaKeyFactory) {
super(rsaKeyFactory);
}
public JCEEncryptionService() throws NoSuchAlgorithmException {
super(KeyFactory.getInstance("RSA"));
}
@Override @Override
public byte[] hmacSha256(String toEncode, byte[] key) { public byte[] hmacSha256(String toEncode, byte[] key) {
return hmac(toEncode, key, "HmacSHA256"); return hmac(toEncode, key, "HmacSHA256");

View File

@ -24,6 +24,7 @@ import static org.jclouds.rest.RestContextFactory.createContextBuilder;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -85,12 +86,11 @@ public abstract class BaseJettyTest {
encryptionService = Guice.createInjector().getInstance(EncryptionService.class); encryptionService = Guice.createInjector().getInstance(EncryptionService.class);
md5 = encryptionService md5 = encryptionService.base64(encryptionService.md5(oneHundredOneConstitutions.getInput()));
.base64(encryptionService.md5(oneHundredOneConstitutions.getInput()));
Handler server1Handler = new AbstractHandler() { Handler server1Handler = new AbstractHandler() {
public void handle(String target, HttpServletRequest request, public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)
HttpServletResponse response, int dispatch) throws IOException, ServletException { throws IOException, ServletException {
if (failIfNoContentLength(request, response)) { if (failIfNoContentLength(request, response)) {
return; return;
} else if (target.indexOf("redirect") > 0) { } else if (target.indexOf("redirect") > 0) {
@ -103,8 +103,7 @@ public abstract class BaseJettyTest {
} else if (request.getMethod().equals("PUT")) { } else if (request.getMethod().equals("PUT")) {
if (request.getContentLength() > 0) { if (request.getContentLength() > 0) {
response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println( response.getWriter().println(Utils.toStringAndClose(request.getInputStream()) + "PUT");
Utils.toStringAndClose(request.getInputStream()) + "PUT");
} else { } else {
response.sendError(500, "no content"); response.sendError(500, "no content");
} }
@ -116,8 +115,13 @@ public abstract class BaseJettyTest {
if (request.getContentLength() > 0) { if (request.getContentLength() > 0) {
if (request.getHeader("Content-MD5") != null) { if (request.getHeader("Content-MD5") != null) {
String expectedMd5 = request.getHeader("Content-MD5"); String expectedMd5 = request.getHeader("Content-MD5");
String realMd5FromRequest = Base64.encodeBytes(new JCEEncryptionService() String realMd5FromRequest;
try {
realMd5FromRequest = Base64.encodeBytes(new JCEEncryptionService()
.md5(request.getInputStream())); .md5(request.getInputStream()));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
boolean matched = expectedMd5.equals(realMd5FromRequest); boolean matched = expectedMd5.equals(realMd5FromRequest);
if (matched) { if (matched) {
response.setContentType("text/xml"); response.setContentType("text/xml");
@ -126,8 +130,7 @@ public abstract class BaseJettyTest {
} }
} else { } else {
response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println( response.getWriter().println(Utils.toStringAndClose(request.getInputStream()) + "POST");
Utils.toStringAndClose(request.getInputStream()) + "POST");
} }
} else { } else {
handleAction(request, response); handleAction(request, response);
@ -140,7 +143,8 @@ public abstract class BaseJettyTest {
response.getWriter().println("test"); response.getWriter().println("test");
} else if (request.getMethod().equals("HEAD")) { } else if (request.getMethod().equals("HEAD")) {
/* /*
* NOTE: by HTML specification, HEAD response MUST NOT include a body * NOTE: by HTML specification, HEAD response MUST NOT include a
* body
*/ */
response.setContentType("text/xml"); response.setContentType("text/xml");
response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_OK);
@ -161,20 +165,24 @@ public abstract class BaseJettyTest {
server.start(); server.start();
Handler server2Handler = new AbstractHandler() { Handler server2Handler = new AbstractHandler() {
public void handle(String target, HttpServletRequest request, public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)
HttpServletResponse response, int dispatch) throws IOException, ServletException { throws IOException, ServletException {
if (request.getMethod().equals("PUT")) { if (request.getMethod().equals("PUT")) {
if (request.getContentLength() > 0) { if (request.getContentLength() > 0) {
response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println( response.getWriter().println(Utils.toStringAndClose(request.getInputStream()) + "PUTREDIRECT");
Utils.toStringAndClose(request.getInputStream()) + "PUTREDIRECT");
} }
} else if (request.getMethod().equals("POST")) { } else if (request.getMethod().equals("POST")) {
if (request.getContentLength() > 0) { if (request.getContentLength() > 0) {
if (request.getHeader("Content-MD5") != null) { if (request.getHeader("Content-MD5") != null) {
String expectedMd5 = request.getHeader("Content-MD5"); String expectedMd5 = request.getHeader("Content-MD5");
String realMd5FromRequest = Base64.encodeBytes(new JCEEncryptionService() String realMd5FromRequest;
try {
realMd5FromRequest = Base64.encodeBytes(new JCEEncryptionService()
.md5(request.getInputStream())); .md5(request.getInputStream()));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
boolean matched = expectedMd5.equals(realMd5FromRequest); boolean matched = expectedMd5.equals(realMd5FromRequest);
if (matched) { if (matched) {
response.setContentType("text/xml"); response.setContentType("text/xml");
@ -183,15 +191,15 @@ public abstract class BaseJettyTest {
} }
} else { } else {
response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println( response.getWriter().println(Utils.toStringAndClose(request.getInputStream()) + "POST");
Utils.toStringAndClose(request.getInputStream()) + "POST");
} }
} else { } else {
handleAction(request, response); handleAction(request, response);
} }
} else if (request.getMethod().equals("HEAD")) { } else if (request.getMethod().equals("HEAD")) {
/* /*
* NOTE: by HTML specification, HEAD response MUST NOT include a body * NOTE: by HTML specification, HEAD response MUST NOT include a
* body
*/ */
response.setContentType("text/xml"); response.setContentType("text/xml");
response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_OK);
@ -220,9 +228,8 @@ public abstract class BaseJettyTest {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static InputSupplier<InputStream> getTestDataSupplier() throws IOException { public static InputSupplier<InputStream> getTestDataSupplier() throws IOException {
byte[] oneConstitution = ByteStreams.toByteArray(new GZIPInputStream(BaseJettyTest.class byte[] oneConstitution = ByteStreams.toByteArray(new GZIPInputStream(BaseJettyTest.class
.getResourceAsStream("/const.txt.gz"))); .getResourceAsStream("/const.txt.gz")));
InputSupplier<ByteArrayInputStream> constitutionSupplier = ByteStreams InputSupplier<ByteArrayInputStream> constitutionSupplier = ByteStreams.newInputStreamSupplier(oneConstitution);
.newInputStreamSupplier(oneConstitution);
InputSupplier<InputStream> temp = ByteStreams.join(constitutionSupplier); InputSupplier<InputStream> temp = ByteStreams.join(constitutionSupplier);
@ -232,15 +239,14 @@ public abstract class BaseJettyTest {
return temp; return temp;
} }
public static RestContextBuilder<IntegrationTestClient, IntegrationTestAsyncClient> newBuilder( public static RestContextBuilder<IntegrationTestClient, IntegrationTestAsyncClient> newBuilder(int testPort,
int testPort, Properties properties, Module... connectionModules) { Properties properties, Module... connectionModules) {
ContextSpec<IntegrationTestClient, IntegrationTestAsyncClient> contextSpec = contextSpec( ContextSpec<IntegrationTestClient, IntegrationTestAsyncClient> contextSpec = contextSpec("test",
"test", "http://localhost:" + testPort, "1", "identity", null, "http://localhost:" + testPort, "1", "identity", null, IntegrationTestClient.class,
IntegrationTestClient.class, IntegrationTestAsyncClient.class); IntegrationTestAsyncClient.class);
return createContextBuilder(contextSpec, ImmutableSet.<Module> copyOf(connectionModules), return createContextBuilder(contextSpec, ImmutableSet.<Module> copyOf(connectionModules), properties);
properties);
} }
@AfterTest @AfterTest
@ -262,8 +268,7 @@ public abstract class BaseJettyTest {
* @return * @return
* @throws IOException * @throws IOException
*/ */
protected boolean failEveryTenRequests(HttpServletRequest request, HttpServletResponse response) protected boolean failEveryTenRequests(HttpServletRequest request, HttpServletResponse response) throws IOException {
throws IOException {
if (cycle.incrementAndGet() % 10 == 0) { if (cycle.incrementAndGet() % 10 == 0) {
response.sendError(500); response.sendError(500);
((Request) request).setHandled(true); ((Request) request).setHandled(true);
@ -272,8 +277,8 @@ public abstract class BaseJettyTest {
return false; return false;
} }
protected boolean redirectEveryTwentyRequests(HttpServletRequest request, protected boolean redirectEveryTwentyRequests(HttpServletRequest request, HttpServletResponse response)
HttpServletResponse response) throws IOException { throws IOException {
if (cycle.incrementAndGet() % 20 == 0) { if (cycle.incrementAndGet() % 20 == 0) {
response.sendRedirect("http://localhost:" + (testPort + 1) + "/"); response.sendRedirect("http://localhost:" + (testPort + 1) + "/");
((Request) request).setHandled(true); ((Request) request).setHandled(true);
@ -282,8 +287,7 @@ public abstract class BaseJettyTest {
return false; return false;
} }
protected boolean failIfNoContentLength(HttpServletRequest request, HttpServletResponse response) protected boolean failIfNoContentLength(HttpServletRequest request, HttpServletResponse response) throws IOException {
throws IOException {
if (request.getHeader(HttpHeaders.CONTENT_LENGTH) == null) { if (request.getHeader(HttpHeaders.CONTENT_LENGTH) == null) {
response.sendError(500); response.sendError(500);
((Request) request).setHandled(true); ((Request) request).setHandled(true);
@ -292,8 +296,7 @@ public abstract class BaseJettyTest {
return false; return false;
} }
private void handleAction(HttpServletRequest request, HttpServletResponse response) private void handleAction(HttpServletRequest request, HttpServletResponse response) throws IOException {
throws IOException {
final Matcher matcher = actionPattern.matcher(request.getRequestURI()); final Matcher matcher = actionPattern.matcher(request.getRequestURI());
boolean matchFound = matcher.find(); boolean matchFound = matcher.find();
if (matchFound) { if (matchFound) {

View File

@ -22,6 +22,7 @@ import static org.testng.Assert.assertEquals;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URI; import java.net.URI;
import java.security.NoSuchAlgorithmException;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
@ -39,13 +40,11 @@ public class BasicAuthenticationTest {
private static final String USER = "Aladdin"; private static final String USER = "Aladdin";
private static final String PASSWORD = "open sesame"; private static final String PASSWORD = "open sesame";
public void testAuth() throws UnsupportedEncodingException, NoSuchAlgorithmException {
public void testAuth() throws UnsupportedEncodingException {
BasicAuthentication filter = new BasicAuthentication(USER, PASSWORD, new JCEEncryptionService()); BasicAuthentication filter = new BasicAuthentication(USER, PASSWORD, new JCEEncryptionService());
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost")); HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
filter.filter(request); filter.filter(request);
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.AUTHORIZATION), assertEquals(request.getFirstHeaderOrNull(HttpHeaders.AUTHORIZATION), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
} }
} }

View File

@ -27,6 +27,7 @@ import java.io.ByteArrayOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -35,6 +36,7 @@ import org.jclouds.encryption.internal.JCEEncryptionService;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -49,7 +51,16 @@ public class WireLiveTest {
private static final String sysHttpStreamUrl = System.getProperty("jclouds.wire.httpstream.url"); private static final String sysHttpStreamUrl = System.getProperty("jclouds.wire.httpstream.url");
private static final String sysHttpStreamMd5 = System.getProperty("jclouds.wire.httpstream.md5"); private static final String sysHttpStreamMd5 = System.getProperty("jclouds.wire.httpstream.md5");
private static final EncryptionService encryptionService = new JCEEncryptionService(); private static EncryptionService encryptionService;
static {
try {
encryptionService = new JCEEncryptionService();
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
encryptionService = null;
}
}
private static class ConnectionTester implements Callable<Void> { private static class ConnectionTester implements Callable<Void> {
private final InputStream fromServer; private final InputStream fromServer;
@ -65,8 +76,7 @@ public class WireLiveTest {
ByteStreams.copy(in, out); ByteStreams.copy(in, out);
byte[] compare = encryptionService.md5(new ByteArrayInputStream(out.toByteArray())); byte[] compare = encryptionService.md5(new ByteArrayInputStream(out.toByteArray()));
Thread.sleep(100); Thread.sleep(100);
assertEquals(encryptionService.hex(compare), checkNotNull(sysHttpStreamMd5, assertEquals(encryptionService.hex(compare), checkNotNull(sysHttpStreamMd5, sysHttpStreamMd5));
sysHttpStreamMd5));
assertEquals(((BufferLogger) wire.getWireLog()).buff.toString().getBytes().length, 3331484); assertEquals(((BufferLogger) wire.getWireLog()).buff.toString().getBytes().length, 3331484);
return null; return null;
} }
@ -145,8 +155,7 @@ public class WireLiveTest {
InputStream in = wire.input(connection.getInputStream()); InputStream in = wire.input(connection.getInputStream());
byte[] compare = encryptionService.md5(in); byte[] compare = encryptionService.md5(in);
Thread.sleep(100); Thread.sleep(100);
assertEquals(encryptionService.hex(compare), checkNotNull(sysHttpStreamMd5, assertEquals(encryptionService.hex(compare), checkNotNull(sysHttpStreamMd5, sysHttpStreamMd5));
sysHttpStreamMd5));
assertEquals(((BufferLogger) wire.getWireLog()).buff.toString().getBytes().length, 3331484); assertEquals(((BufferLogger) wire.getWireLog()).buff.toString().getBytes().length, 3331484);
} }
@ -155,8 +164,7 @@ public class WireLiveTest {
URL url = new URL(checkNotNull(sysHttpStreamUrl, "sysHttpStreamUrl")); URL url = new URL(checkNotNull(sysHttpStreamUrl, "sysHttpStreamUrl"));
URLConnection connection = url.openConnection(); URLConnection connection = url.openConnection();
Callable<Void> callable = new ConnectionTester(connection.getInputStream()); Callable<Void> callable = new ConnectionTester(connection.getInputStream());
ListenableFuture<Void> result = Futures ListenableFuture<Void> result = Futures.makeListenable(newCachedThreadPool().submit(callable));
.makeListenable(newCachedThreadPool().submit(callable));
result.get(30, TimeUnit.SECONDS); result.get(30, TimeUnit.SECONDS);
} }
@ -168,8 +176,7 @@ public class WireLiveTest {
InputStream in = wire.input(connection.getInputStream()); InputStream in = wire.input(connection.getInputStream());
byte[] compare = encryptionService.md5(in); byte[] compare = encryptionService.md5(in);
Thread.sleep(100); Thread.sleep(100);
assertEquals(encryptionService.hex(compare), checkNotNull(sysHttpStreamMd5, assertEquals(encryptionService.hex(compare), checkNotNull(sysHttpStreamMd5, sysHttpStreamMd5));
sysHttpStreamMd5));
assertEquals(((BufferLogger) wire.getWireLog()).buff.toString().getBytes().length, 3331484); assertEquals(((BufferLogger) wire.getWireLog()).buff.toString().getBytes().length, 3331484);
} }

View File

@ -27,6 +27,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.security.Key; import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -48,6 +50,13 @@ import org.jclouds.io.payloads.ByteArrayPayload;
*/ */
@Singleton @Singleton
public class BouncyCastleEncryptionService extends BaseEncryptionService { public class BouncyCastleEncryptionService extends BaseEncryptionService {
public BouncyCastleEncryptionService(KeyFactory rsaKeyFactory) {
super(rsaKeyFactory);
}
public BouncyCastleEncryptionService() throws NoSuchAlgorithmException {
super(KeyFactory.getInstance("RSA"));
}
@Override @Override
public byte[] hmacSha256(String toEncode, byte[] key) { public byte[] hmacSha256(String toEncode, byte[] key) {

View File

@ -24,11 +24,13 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.util.Date; import java.util.Date;
import javax.ws.rs.HttpMethod; import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.encryption.internal.JCEEncryptionService; import org.jclouds.encryption.internal.JCEEncryptionService;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.io.Payloads; import org.jclouds.io.Payloads;
@ -40,6 +42,7 @@ import org.testng.annotations.Test;
import com.google.appengine.api.urlfetch.HTTPHeader; import com.google.appengine.api.urlfetch.HTTPHeader;
import com.google.appengine.api.urlfetch.HTTPRequest; import com.google.appengine.api.urlfetch.HTTPRequest;
import com.google.appengine.repackaged.com.google.common.base.Charsets; import com.google.appengine.repackaged.com.google.common.base.Charsets;
import com.google.common.base.Throwables;
import com.google.common.io.Files; import com.google.common.io.Files;
/** /**
@ -51,10 +54,19 @@ public class ConvertToGaeRequestTest {
ConvertToGaeRequest req; ConvertToGaeRequest req;
URI endPoint; URI endPoint;
protected volatile static EncryptionService encryptionService;
static {
try {
encryptionService = new JCEEncryptionService();
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
}
}
@BeforeTest @BeforeTest
void setupClient() throws MalformedURLException { void setupClient() throws MalformedURLException {
endPoint = URI.create("http://localhost:80/foo"); endPoint = URI.create("http://localhost:80/foo");
req = new ConvertToGaeRequest(new JCEEncryptionService()); req = new ConvertToGaeRequest(encryptionService);
} }
@Test @Test

View File

@ -26,11 +26,13 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import org.jclouds.encryption.EncryptionService;
import org.jclouds.encryption.internal.JCEEncryptionService; import org.jclouds.encryption.internal.JCEEncryptionService;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
@ -40,6 +42,7 @@ import org.testng.annotations.Test;
import com.google.appengine.api.urlfetch.HTTPHeader; import com.google.appengine.api.urlfetch.HTTPHeader;
import com.google.appengine.api.urlfetch.HTTPResponse; import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.common.base.Throwables;
/** /**
* *
@ -50,10 +53,19 @@ public class ConvertToJcloudsResponseTest {
ConvertToJcloudsResponse req; ConvertToJcloudsResponse req;
URI endPoint; URI endPoint;
protected volatile static EncryptionService encryptionService;
static {
try {
encryptionService = new JCEEncryptionService();
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
}
}
@BeforeTest @BeforeTest
void setupClient() throws MalformedURLException { void setupClient() throws MalformedURLException {
endPoint = URI.create("http://localhost:80/foo"); endPoint = URI.create("http://localhost:80/foo");
req = new ConvertToJcloudsResponse(new HttpUtils(new JCEEncryptionService(), 0, 0, 0, 0)); req = new ConvertToJcloudsResponse(new HttpUtils(encryptionService, 0, 0, 0, 0));
} }
@Test @Test

View File

@ -27,6 +27,7 @@ import static org.testng.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -51,6 +52,7 @@ import org.jclouds.util.Utils;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -61,7 +63,15 @@ import com.google.common.collect.Maps;
*/ */
@Test(groups = "live", testName = "cloudfiles.CloudFilesClientLiveTest") @Test(groups = "live", testName = "cloudfiles.CloudFilesClientLiveTest")
public class CloudFilesClientLiveTest extends BaseBlobStoreIntegrationTest { public class CloudFilesClientLiveTest extends BaseBlobStoreIntegrationTest {
private static final EncryptionService encryptionService = new JCEEncryptionService();
protected volatile static EncryptionService encryptionService;
static {
try {
encryptionService = new JCEEncryptionService();
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
}
}
public CloudFilesClient getApi() { public CloudFilesClient getApi() {
return (CloudFilesClient) context.getProviderSpecificContext().getApi(); return (CloudFilesClient) context.getProviderSpecificContext().getApi();