http://git-wip-us.apache.org/repos/asf/jclouds/blob/34663f3c/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java new file mode 100644 index 0000000..84d08fe --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiMockTest.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.features; + +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_BYTES_USED; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_CONTAINER_COUNT; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_METADATA_PREFIX; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_OBJECT_COUNT; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_REMOVE_METADATA_PREFIX; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Map; +import java.util.Map.Entry; + +import org.jclouds.openstack.swift.v1.SwiftApi; +import org.jclouds.openstack.swift.v1.domain.Account; +import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; + +@Test(groups = "unit", testName = "AccountApiMockTest") +public class AccountApiMockTest extends BaseOpenStackMockTest<SwiftApi> { + + /** upper-cases first char, and lower-cases rest!! **/ + public void getKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(accountResponse() + // note silly casing + .addHeader(ACCOUNT_METADATA_PREFIX + "Apiname", "swift") + .addHeader(ACCOUNT_METADATA_PREFIX + "Apiversion", "v1.1"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + Account account = api.getAccountApi("DFW").get(); + assertEquals(account.getContainerCount(), 3l); + assertEquals(account.getObjectCount(), 42l); + assertEquals(account.getBytesUsed(), 323479l); + for (Entry<String, String> entry : metadata.entrySet()) { + assertEquals(account.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue()); + } + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"); + } finally { + server.shutdown(); + } + } + + public void updateMetadata() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(accountResponse() + .addHeader(ACCOUNT_METADATA_PREFIX + "ApiName", "swift") + .addHeader(ACCOUNT_METADATA_PREFIX + "ApiVersion", "v1.1"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getAccountApi("DFW").updateMetadata(metadata)); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + + RecordedRequest replaceRequest = server.takeRequest(); + assertRequest(replaceRequest, "POST", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"); + for (Entry<String, String> entry : metadata.entrySet()) { + assertEquals(replaceRequest.getHeader(ACCOUNT_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue()); + } + } finally { + server.shutdown(); + } + } + + public void updateTemporaryUrlKey() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(accountResponse())); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getAccountApi("DFW").updateTemporaryUrlKey("foobar")); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + + RecordedRequest replaceRequest = server.takeRequest(); + assertRequest(replaceRequest, "POST", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"); + assertEquals(replaceRequest.getHeader(ACCOUNT_TEMPORARY_URL_KEY), "foobar"); + } finally { + server.shutdown(); + } + } + + public void deleteMetadata() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(accountResponse())); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getAccountApi("DFW").deleteMetadata(metadata)); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest deleteRequest = server.takeRequest(); + assertEquals(deleteRequest.getRequestLine(), + "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9 HTTP/1.1"); + for (String key : metadata.keySet()) { + assertEquals(deleteRequest.getHeader(ACCOUNT_REMOVE_METADATA_PREFIX + key.toLowerCase()), "ignored"); + } + } finally { + server.shutdown(); + } + } + + private static final Map<String, String> metadata = ImmutableMap.of("ApiName", "swift", "ApiVersion", "v1.1"); + + public static MockResponse accountResponse() { + return new MockResponse() + .addHeader(ACCOUNT_CONTAINER_COUNT, "3") + .addHeader(ACCOUNT_OBJECT_COUNT, "42") + .addHeader(ACCOUNT_BYTES_USED, "323479"); + } +}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/34663f3c/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiLiveTest.java new file mode 100644 index 0000000..6901ac9 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiLiveTest.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +import org.jboss.shrinkwrap.api.GenericArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.exporter.TarGzExporter; +import org.jclouds.io.ByteStreams2; +import org.jclouds.io.Payload; +import org.jclouds.io.payloads.ByteSourcePayload; +import org.jclouds.openstack.swift.v1.SwiftApi; +import org.jclouds.openstack.swift.v1.domain.BulkDeleteResponse; +import org.jclouds.openstack.swift.v1.domain.ExtractArchiveResponse; +import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.io.ByteSource; + +@Test(groups = "live", testName = "BulkApiLiveTest") +public class BulkApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> { + + private static final int OBJECT_COUNT = 10; + private String containerName = getClass().getSimpleName(); + List<String> paths = Lists.newArrayList(); + byte[] tarGz; + + public void testNotPresentWhenDeleting() throws Exception { + for (String regionId : regions) { + BulkDeleteResponse deleteResponse = api.getBulkApi(regionId).bulkDelete( + ImmutableList.of(UUID.randomUUID().toString())); + assertEquals(deleteResponse.getDeleted(), 0); + assertEquals(deleteResponse.getNotFound(), 1); + assertTrue(deleteResponse.getErrors().isEmpty()); + } + } + + public void testExtractArchive() throws Exception { + for (String regionId : regions) { + Payload payload = new ByteSourcePayload(ByteSource.wrap(tarGz)); + + ExtractArchiveResponse extractResponse = api.getBulkApi(regionId) + .extractArchive(containerName, payload, "tar.gz"); + assertEquals(extractResponse.getCreated(), OBJECT_COUNT); + assertTrue(extractResponse.getErrors().isEmpty()); + assertEquals(api.getContainerApi(regionId).get(containerName).getObjectCount(), OBJECT_COUNT); + + // repeat the command + extractResponse = api.getBulkApi(regionId).extractArchive(containerName, payload, "tar.gz"); + assertEquals(extractResponse.getCreated(), OBJECT_COUNT); + assertTrue(extractResponse.getErrors().isEmpty()); + } + } + + @Test(dependsOnMethods = "testExtractArchive") + public void testBulkDelete() throws Exception { + for (String regionId : regions) { + BulkDeleteResponse deleteResponse = api.getBulkApi(regionId).bulkDelete(paths); + assertEquals(deleteResponse.getDeleted(), OBJECT_COUNT); + assertEquals(deleteResponse.getNotFound(), 0); + assertTrue(deleteResponse.getErrors().isEmpty()); + assertEquals(api.getContainerApi(regionId).get(containerName).getObjectCount(), 0); + } + } + + @Override + @BeforeClass(groups = "live") + public void setup() { + super.setup(); + for (String regionId : regions) { + boolean created = api.getContainerApi(regionId).create(containerName); + if (!created) { + deleteAllObjectsInContainer(regionId, containerName); + } + } + GenericArchive files = ShrinkWrap.create(GenericArchive.class, "files.tar.gz"); + StringAsset content = new StringAsset("foo"); + for (int i = 0; i < OBJECT_COUNT; i++) { + paths.add(containerName + "/file" + i); + files.add(content, "/file" + i); + } + + try { + tarGz = ByteStreams2.toByteArrayAndClose(files.as(TarGzExporter.class).exportAsInputStream()); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + @Override + @AfterClass(groups = "live") + public void tearDown() { + for (String regionId : regions) { + deleteAllObjectsInContainer(regionId, containerName); + api.getContainerApi(regionId).deleteIfEmpty(containerName); + } + super.tearDown(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/34663f3c/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiMockTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiMockTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiMockTest.java new file mode 100644 index 0000000..3136b52 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/BulkApiMockTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import org.jboss.shrinkwrap.api.GenericArchive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.exporter.TarGzExporter; +import org.jclouds.io.ByteStreams2; +import org.jclouds.io.Payload; +import org.jclouds.io.Payloads; +import org.jclouds.openstack.swift.v1.SwiftApi; +import org.jclouds.openstack.swift.v1.domain.ExtractArchiveResponse; +import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest; +import org.testng.annotations.Test; + +import com.google.common.io.ByteSource; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; + +@Test(groups = "unit", testName = "BulkApiMockTest") +public class BulkApiMockTest extends BaseOpenStackMockTest<SwiftApi> { + + public void testExtractArchive() throws Exception { + GenericArchive files = ShrinkWrap.create(GenericArchive.class, "files.tar.gz"); + StringAsset content = new StringAsset("foo"); + for (int i = 0; i < 10; i++) { + files.add(content, "/file" + i); + } + + byte[] tarGz = ByteStreams2.toByteArrayAndClose(files.as(TarGzExporter.class).exportAsInputStream()); + + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201).setBody("{\"Number Files Created\": 10, \"Errors\": []}"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + Payload payload = Payloads.newByteSourcePayload(ByteSource.wrap(tarGz)); + ExtractArchiveResponse response = api.getBulkApi("DFW").extractArchive("myContainer", payload, "tar.gz"); + + assertEquals(response.getCreated(), 10); + assertTrue(response.getErrors().isEmpty()); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + RecordedRequest extractRequest = server.takeRequest(); + assertRequest(extractRequest, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer?extract-archive=tar.gz"); + assertEquals(extractRequest.getBody(), tarGz); + } finally { + server.shutdown(); + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/34663f3c/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java new file mode 100644 index 0000000..bf2ba98 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.Map; +import java.util.Map.Entry; + +import org.jclouds.openstack.swift.v1.SwiftApi; +import org.jclouds.openstack.swift.v1.domain.Container; +import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest; +import org.jclouds.openstack.swift.v1.options.CreateContainerOptions; +import org.jclouds.openstack.swift.v1.options.ListContainerOptions; +import org.jclouds.openstack.swift.v1.options.UpdateContainerOptions; +import org.jclouds.openstack.swift.v1.reference.SwiftHeaders; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; + +/** + * Provides live tests for the {@link ContainerApi}. + */ +@Test(groups = "live", testName = "ContainerApiLiveTest") +public class ContainerApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> { + + private String name = getClass().getSimpleName(); + + public void testCreateWithOptions() throws Exception { + for (String regionId : regions) { + ImmutableMultimap<String, String> headers = + ImmutableMultimap.of(SwiftHeaders.STATIC_WEB_INDEX, "__index.html", + SwiftHeaders.STATIC_WEB_ERROR, "__error.html"); + CreateContainerOptions opts = new CreateContainerOptions().headers(headers); + + assertNotNull(api.getContainerApi(regionId).create(name, opts)); + + Container container = api.getContainerApi(regionId).get(name); + assertNotNull(container); + assertEquals(container.getName(), name); + assertEquals(container.getMetadata().size(), 2); + assertEquals(container.getMetadata().get("web-index"), "__index.html"); + assertEquals(container.getMetadata().get("web-error"), "__error.html"); + + assertTrue(api.getContainerApi(regionId).deleteIfEmpty(name)); + } + } + + public void testCreateWithSpacesAndSpecialCharacters() throws Exception { + final String nameWithSpaces = "container # ! special"; + + for (String regionId : regions) { + assertTrue(api.getContainerApi(regionId).create(nameWithSpaces)); + Container container = api.getContainerApi(regionId).get(nameWithSpaces); + assertNotNull(container); + assertEquals(container.getName(), nameWithSpaces); + + assertTrue(api.getContainerApi(regionId).deleteIfEmpty(nameWithSpaces)); + } + } + + public void testList() throws Exception { + for (String regionId : regions) { + ContainerApi containerApi = api.getContainerApi(regionId); + FluentIterable<Container> response = containerApi.list(); + assertNotNull(response); + for (Container container : response) { + assertNotNull(container.getName()); + assertTrue(container.getObjectCount() >= 0); + assertTrue(container.getBytesUsed() >= 0); + } + } + } + + public void testListWithOptions() throws Exception { + String lexicographicallyBeforeName = name.substring(0, name.length() - 1); + for (String regionId : regions) { + ListContainerOptions options = ListContainerOptions.Builder.marker(lexicographicallyBeforeName); + Container container = api.getContainerApi(regionId).list(options).get(0); + assertEquals(container.getName(), name); + assertTrue(container.getObjectCount() == 0); + assertTrue(container.getBytesUsed() == 0); + } + } + + public void testUpdate() throws Exception { + for (String regionId : regions) { + ImmutableMultimap<String, String> headers = + ImmutableMultimap.of(SwiftHeaders.STATIC_WEB_INDEX, "__index.html", + SwiftHeaders.STATIC_WEB_ERROR, "__error.html"); + UpdateContainerOptions opts = new UpdateContainerOptions().headers(headers); + + assertNotNull(api.getContainerApi(regionId).create(name)); + + Container container = api.getContainerApi(regionId).get(name); + assertNotNull(container); + assertEquals(container.getName(), name); + assertTrue(container.getMetadata().isEmpty()); + + assertNotNull(api.getContainerApi(regionId).update(name, opts)); + + Container updatedContainer = api.getContainerApi(regionId).get(name); + assertNotNull(updatedContainer); + assertEquals(updatedContainer.getName(), name); + assertEquals(updatedContainer.getMetadata().size(), 2); + assertEquals(updatedContainer.getMetadata().get("web-index"), "__index.html"); + assertEquals(updatedContainer.getMetadata().get("web-error"), "__error.html"); + + assertTrue(api.getContainerApi(regionId).deleteIfEmpty(name)); + } + } + + public void testGet() throws Exception { + for (String regionId : regions) { + Container container = api.getContainerApi(regionId).get(name); + assertEquals(container.getName(), name); + assertTrue(container.getObjectCount() == 0); + assertTrue(container.getBytesUsed() == 0); + } + } + + public void testUpdateMetadata() throws Exception { + Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar"); + + for (String regionId : regions) { + ContainerApi containerApi = api.getContainerApi(regionId); + assertTrue(containerApi.updateMetadata(name, meta)); + containerHasMetadata(containerApi, name, meta); + } + } + + public void testDeleteMetadata() throws Exception { + Map<String, String> meta = ImmutableMap.of("MyDelete1", "foo", "MyDelete2", "bar"); + + for (String regionId : regions) { + ContainerApi containerApi = api.getContainerApi(regionId); + // update + assertTrue(containerApi.updateMetadata(name, meta)); + containerHasMetadata(containerApi, name, meta); + // delete + assertTrue(containerApi.deleteMetadata(name, meta)); + Container container = containerApi.get(name); + for (Entry<String, String> entry : meta.entrySet()) { + // note keys are returned in lower-case! + assertFalse(container.getMetadata().containsKey(entry.getKey().toLowerCase())); + } + } + } + + static void containerHasMetadata(ContainerApi containerApi, String name, Map<String, String> meta) { + Container container = containerApi.get(name); + for (Entry<String, String> entry : meta.entrySet()) { + // note keys are returned in lower-case! + assertEquals(container.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue(), + container + " didn't have metadata: " + entry); + } + } + + @Override + @BeforeClass(groups = "live") + public void setup() { + super.setup(); + for (String regionId : regions) { + api.getContainerApi(regionId).create(name); + } + } + + @Override + @AfterClass(groups = "live") + public void tearDown() { + for (String regionId : regions) { + api.getContainerApi(regionId).deleteIfEmpty(name); + } + super.tearDown(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/34663f3c/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java new file mode 100644 index 0000000..6b3ef66 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java @@ -0,0 +1,363 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.features; + +import static org.jclouds.openstack.swift.v1.options.CreateContainerOptions.Builder.anybodyRead; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_ACL_ANYBODY_READ; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_BYTES_USED; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_METADATA_PREFIX; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_OBJECT_COUNT; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_READ; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_REMOVE_METADATA_PREFIX; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.Map; +import java.util.Map.Entry; + +import org.jclouds.blobstore.ContainerNotFoundException; +import org.jclouds.openstack.swift.v1.SwiftApi; +import org.jclouds.openstack.swift.v1.domain.Container; +import org.jclouds.openstack.swift.v1.options.ListContainerOptions; +import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; + +@Test(groups = "unit", testName = "ContainerApiMockTest") +public class ContainerApiMockTest extends BaseOpenStackMockTest<SwiftApi> { + + public void testList() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/container_list.json")))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + ImmutableList<Container> containers = api.getContainerApi("DFW").list().toList(); + assertEquals(containers, ImmutableList.of( + Container.builder() + .name("test_container_1") + .objectCount(2) + .bytesUsed(78).build(), + Container.builder() + .name("test_container_2") + .objectCount(1) + .bytesUsed(17).build())); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"); + } finally { + server.shutdown(); + } + } + + public void testListWithOptions() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/container_list.json")))); + + ListContainerOptions options = ListContainerOptions.Builder.marker("test"); + assertNotNull(options); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + ImmutableList<Container> containers = api.getContainerApi("DFW").list(options).toList(); + assertEquals(containers, ImmutableList.of( + Container.builder() + .name("test_container_1") + .objectCount(2) + .bytesUsed(78).build(), + Container.builder() + .name("test_container_2") + .objectCount(1) + .bytesUsed(17).build())); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9?marker=test"); + } finally { + server.shutdown(); + } + } + + public void testContainerExists() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201))); + server.enqueue(addCommonHeaders(containerResponse() + .addHeader(CONTAINER_METADATA_PREFIX + "ApiName", "swift") + .addHeader(CONTAINER_METADATA_PREFIX + "ApiVersion", "v1.1"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getContainerApi("DFW").create("myContainer", anybodyRead().metadata(metadata))); + + Container container = api.getContainerApi("DFW").get("myContainer"); + assertEquals(container.getName(), "myContainer"); + assertEquals(container.getObjectCount(), 42l); + assertEquals(container.getBytesUsed(), 323479l); + for (Entry<String, String> entry : container.getMetadata().entrySet()) { + assertEquals(container.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue()); + } + assertEquals(server.getRequestCount(), 3); + assertAuthentication(server); + assertRequest(server.takeRequest(), "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer"); + assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer"); + } finally { + server.shutdown(); + } + } + + @Test(expectedExceptions = ContainerNotFoundException.class) + public void testContainerDoesNotExist() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getContainerApi("DFW").create("myContainer", anybodyRead().metadata(metadata))); + + // the head call will throw the ContainerNotFoundException + api.getContainerApi("DFW").get("myContainer"); + } finally { + server.shutdown(); + } + } + + public void testCreate() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getContainerApi("DFW").create("myContainer")); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer"); + } finally { + server.shutdown(); + } + } + + public void testCreateWithOptions() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getContainerApi("DFW").create("myContainer", anybodyRead().metadata(metadata))); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + + RecordedRequest createRequest = server.takeRequest(); + assertRequest(createRequest, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer"); + + assertEquals(createRequest.getHeader(CONTAINER_READ), CONTAINER_ACL_ANYBODY_READ); + + for (Entry<String, String> entry : metadata.entrySet()) { + assertEquals(createRequest.getHeader(CONTAINER_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue()); + } + } finally { + server.shutdown(); + } + } + + public void testCreateWithSpacesAndSpecialCharacters() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getContainerApi("DFW").create("container # ! special")); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container%20%23%20%21%20special"); + } finally { + server.shutdown(); + } + } + + public void testAlreadyCreated() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(202))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertFalse(api.getContainerApi("DFW").create("myContainer")); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer"); + } finally { + server.shutdown(); + } + } + + /** upper-cases first char, and lower-cases rest!! **/ + public void testGetKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(containerResponse() + // note silly casing + .addHeader(CONTAINER_METADATA_PREFIX + "Apiname", "swift") + .addHeader(CONTAINER_METADATA_PREFIX + "Apiversion", "v1.1"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + Container container = api.getContainerApi("DFW").get("myContainer"); + assertEquals(container.getName(), "myContainer"); + assertEquals(container.getObjectCount(), 42l); + assertEquals(container.getBytesUsed(), 323479l); + for (Entry<String, String> entry : container.getMetadata().entrySet()) { + assertEquals(container.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue()); + } + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer"); + } finally { + server.shutdown(); + } + } + + public void testUpdateMetadata() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(containerResponse() + .addHeader(CONTAINER_METADATA_PREFIX + "ApiName", "swift") + .addHeader(CONTAINER_METADATA_PREFIX + "ApiVersion", "v1.1"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getContainerApi("DFW").updateMetadata("myContainer", metadata)); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest replaceRequest = server.takeRequest(); + assertEquals(replaceRequest.getRequestLine(), + "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1"); + for (Entry<String, String> entry : metadata.entrySet()) { + assertEquals(replaceRequest.getHeader(CONTAINER_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue()); + } + } finally { + server.shutdown(); + } + } + + public void testDeleteMetadata() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(containerResponse())); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getContainerApi("DFW").deleteMetadata("myContainer", metadata)); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest deleteRequest = server.takeRequest(); + assertEquals(deleteRequest.getRequestLine(), + "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1"); + for (String key : metadata.keySet()) { + assertEquals(deleteRequest.getHeader(CONTAINER_REMOVE_METADATA_PREFIX + key.toLowerCase()), "ignored"); + } + } finally { + server.shutdown(); + } + } + + public void testDeleteIfEmpty() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(204))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getContainerApi("DFW").deleteIfEmpty("myContainer")); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest deleteRequest = server.takeRequest(); + assertEquals(deleteRequest.getRequestLine(), + "DELETE /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1"); + } finally { + server.shutdown(); + } + } + + public void testAlreadyDeleted() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getContainerApi("DFW").deleteIfEmpty("myContainer")); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest deleteRequest = server.takeRequest(); + assertEquals(deleteRequest.getRequestLine(), + "DELETE /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1"); + } finally { + server.shutdown(); + } + } + + public void testDeleteWhenNotEmpty() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(409))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertFalse(api.getContainerApi("DFW").deleteIfEmpty("myContainer")); + + } finally { + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest deleteRequest = server.takeRequest(); + assertEquals(deleteRequest.getRequestLine(), + "DELETE /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1"); + server.shutdown(); + } + } + + private static final Map<String, String> metadata = ImmutableMap.of("ApiName", "swift", "ApiVersion", "v1.1"); + + static MockResponse containerResponse() { + return new MockResponse() + .addHeader(CONTAINER_OBJECT_COUNT, "42") + .addHeader(CONTAINER_BYTES_USED, "323479"); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/34663f3c/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java new file mode 100644 index 0000000..09e34b5 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.features; + +import static org.jclouds.openstack.swift.v1.options.CreateContainerOptions.Builder.anybodyRead; +import static org.testng.Assert.assertTrue; + +import org.jclouds.openstack.swift.v1.SwiftApi; +import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "CreatePublicContainerLiveTest") +public class CreatePublicContainerLiveTest extends BaseSwiftApiLiveTest<SwiftApi> { + + private String name = getClass().getSimpleName(); + + public void testAnybodyReadUpdatesMetadata() throws Exception { + for (String regionId : api.getConfiguredRegions()) { + api.getContainerApi(regionId).create(name, anybodyRead()); + assertTrue(api.getContainerApi(regionId).get(name).getAnybodyRead().get()); + } + } + + @Override + @AfterClass(groups = "live") + public void tearDown() { + for (String regionId : api.getConfiguredRegions()) { + api.getContainerApi(regionId).deleteIfEmpty(name); + } + super.tearDown(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/34663f3c/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java new file mode 100644 index 0000000..5a472ff --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java @@ -0,0 +1,286 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.features; + +import static org.jclouds.http.options.GetOptions.Builder.tail; +import static org.jclouds.io.Payloads.newByteSourcePayload; +import static org.jclouds.openstack.swift.v1.options.ListContainerOptions.Builder.marker; +import static org.jclouds.util.Strings2.toStringAndClose; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.io.IOException; +import java.util.Date; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +import org.jclouds.http.options.GetOptions; +import org.jclouds.io.Payload; +import org.jclouds.openstack.swift.v1.CopyObjectException; +import org.jclouds.openstack.swift.v1.SwiftApi; +import org.jclouds.openstack.swift.v1.domain.ObjectList; +import org.jclouds.openstack.swift.v1.domain.SwiftObject; +import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest; +import org.jclouds.openstack.swift.v1.options.ListContainerOptions; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.io.ByteSource; + +/** + * Provides live tests for the {@link ObjectApi}. + */ +@Test(groups = "live", testName = "ObjectApiLiveTest", singleThreaded = true) +public class ObjectApiLiveTest extends BaseSwiftApiLiveTest<SwiftApi> { + + private String name = getClass().getSimpleName(); + private String containerName = getClass().getSimpleName() + "Container"; + static final Payload PAYLOAD = newByteSourcePayload(ByteSource.wrap("swifty".getBytes())); + + public void testCreateWithSpacesAndSpecialCharacters() throws Exception { + final String containerName = "container # ! special"; + final String objectName = "object # ! special"; + + for (String regionId : regions) { + assertNotNull(api.getContainerApi(regionId).create(containerName)); + assertNotNull(api.getObjectApi(regionId, containerName).put(objectName, PAYLOAD)); + + SwiftObject object = api.getObjectApi(regionId, containerName).get(objectName); + assertEquals(object.getName(), objectName); + checkObject(object); + assertEquals(toStringAndClose(object.getPayload().openStream()), "swifty"); + + api.getObjectApi(regionId, containerName).delete(objectName); + api.getContainerApi(regionId).deleteIfEmpty(containerName); + } + } + + public void testPutWithExpiration() throws Exception { + String objectName = "test-expiration"; + + long expireMillis = new Date().getTime() + 1000 * 60 * 60 * 24; + Date expireAt = new Date(expireMillis); + + Payload payload = newByteSourcePayload(ByteSource.wrap("swifty".getBytes())); + payload.getContentMetadata().setExpires(expireAt); + + for (String regionId : regions) { + String etag = api.getObjectApi(regionId, containerName).put(objectName, payload); + assertNotNull(etag); + + SwiftObject object = api.getObjectApi(regionId, containerName).get(objectName); + assertEquals(object.getName(), objectName); + checkObject(object); + assertEquals(toStringAndClose(object.getPayload().openStream()), "swifty"); + + api.getObjectApi(regionId, containerName).delete(objectName); + } + } + public void testCopyObject() throws Exception { + for (String regionId : regions) { + // source + String sourceContainer = "src" + containerName; + String sourceObjectName = "original.txt"; + String badSource = "badSource"; + + // destination + String destinationContainer = "dest" + containerName; + String destinationObject = "copy.txt"; + String destinationPath = "/" + destinationContainer + "/" + destinationObject; + + ContainerApi containerApi = api.getContainerApi(regionId); + + // create source and destination dirs + containerApi.create(sourceContainer); + containerApi.create(destinationContainer); + + // get the api for this region and container + ObjectApi srcApi = api.getObjectApi(regionId, sourceContainer); + ObjectApi destApi = api.getObjectApi(regionId, destinationContainer); + + // Create source object + assertNotNull(srcApi.put(sourceObjectName, PAYLOAD)); + SwiftObject sourceObject = srcApi.get(sourceObjectName); + checkObject(sourceObject); + + // Create the destination object + assertNotNull(destApi.put(destinationObject, PAYLOAD)); + SwiftObject object = destApi.get(destinationObject); + checkObject(object); + + // check the copy operation + assertTrue(destApi.copy(destinationObject, sourceContainer, sourceObjectName)); + assertNotNull(destApi.get(destinationObject)); + + // now get a real SwiftObject + SwiftObject destSwiftObject = destApi.get(destinationObject); + assertEquals(toStringAndClose(destSwiftObject.getPayload().openStream()), "swifty"); + + // test exception thrown on bad source name + try { + destApi.copy(destinationObject, badSource, sourceObjectName); + fail("Expected CopyObjectException"); + } catch (CopyObjectException e) { + assertEquals(e.getSourcePath(), "/" + badSource + "/" + sourceObjectName); + assertEquals(e.getDestinationPath(), destinationPath); + } + + deleteAllObjectsInContainer(regionId, sourceContainer); + containerApi.deleteIfEmpty(sourceContainer); + + deleteAllObjectsInContainer(regionId, destinationContainer); + containerApi.deleteIfEmpty(destinationContainer); + } + } + + public void testList() throws Exception { + for (String regionId : regions) { + ObjectApi objectApi = api.getObjectApi(regionId, containerName); + ObjectList response = objectApi.list(); + assertEquals(response.getContainer(), api.getContainerApi(regionId).get(containerName)); + for (SwiftObject object : response) { + checkObject(object); + } + } + } + + public void testListWithOptions() throws Exception { + for (String regionId : regions) { + ObjectApi objectApi = api.getObjectApi(regionId, containerName); + ObjectList response = objectApi.list(ListContainerOptions.NONE); + assertEquals(response.getContainer(), api.getContainerApi(regionId).get(containerName)); + for (SwiftObject object : response) { + checkObject(object); + } + } + } + + public void testMetadata() throws Exception { + for (String regionId : regions) { + SwiftObject object = api.getObjectApi(regionId, containerName).get(name); + assertEquals(object.getName(), name); + checkObject(object); + assertEquals(toStringAndClose(object.getPayload().openStream()), "swifty"); + } + } + + public void testUpdateMetadata() throws Exception { + for (String regionId : regions) { + ObjectApi objectApi = api.getObjectApi(regionId, containerName); + + Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar"); + assertTrue(objectApi.updateMetadata(name, meta)); + + SwiftObject object = objectApi.get(name); + for (Entry<String, String> entry : meta.entrySet()) { + // note keys are returned in lower-case! + assertEquals(object.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue(), + object + " didn't have metadata: " + entry); + } + } + } + + public void testGet() throws Exception { + for (String regionId : regions) { + SwiftObject object = api.getObjectApi(regionId, containerName).get(name, GetOptions.NONE); + assertEquals(object.getName(), name); + checkObject(object); + assertEquals(toStringAndClose(object.getPayload().openStream()), "swifty"); + } + } + + public void testPrivateByDefault() throws Exception { + for (String regionId : regions) { + SwiftObject object = api.getObjectApi(regionId, containerName).get(name); + try { + object.getUri().toURL().openStream(); + fail("shouldn't be able to access " + object); + } catch (IOException expected) { + } + } + } + + public void testGetOptions() throws Exception { + for (String regionId : regions) { + SwiftObject object = api.getObjectApi(regionId, containerName).get(name, tail(1)); + assertEquals(object.getName(), name); + checkObject(object); + assertEquals(toStringAndClose(object.getPayload().openStream()), "y"); + } + } + + public void testListOptions() throws Exception { + String lexicographicallyBeforeName = name.substring(0, name.length() - 1); + for (String regionId : regions) { + SwiftObject object = api.getObjectApi(regionId, containerName) + .list(marker(lexicographicallyBeforeName)).get(0); + assertEquals(object.getName(), name); + checkObject(object); + } + } + + public void testDeleteMetadata() throws Exception { + for (String regionId : regions) { + ObjectApi objectApi = api.getObjectApi(regionId, containerName); + + Map<String, String> meta = ImmutableMap.of("MyDelete1", "foo", "MyDelete2", "bar"); + + assertTrue(objectApi.updateMetadata(name, meta)); + assertFalse(objectApi.get(name).getMetadata().isEmpty()); + + assertTrue(objectApi.deleteMetadata(name, meta)); + assertTrue(objectApi.get(name).getMetadata().isEmpty()); + } + } + + @Override + @BeforeClass(groups = "live") + public void setup() { + super.setup(); + for (String regionId : regions) { + api.getContainerApi(regionId).create(containerName); + api.getObjectApi(regionId, containerName).put(name, PAYLOAD); + } + } + + @Override + @AfterClass(groups = "live") + public void tearDown() { + for (String regionId : regions) { + deleteAllObjectsInContainer(regionId, containerName); + api.getObjectApi(regionId, containerName).delete(name); + api.getContainerApi(regionId).deleteIfEmpty(containerName); + } + + super.tearDown(); + } + + static void checkObject(SwiftObject object) { + assertNotNull(object.getName()); + assertNotNull(object.getUri()); + assertNotNull(object.getETag()); + assertTrue(object.getLastModified().getTime() <= System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5)); + assertNotNull(object.getPayload().getContentMetadata().getContentLength()); + assertNotNull(object.getPayload().getContentMetadata().getContentType()); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/34663f3c/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java new file mode 100644 index 0000000..8c0e4d1 --- /dev/null +++ b/apis/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java @@ -0,0 +1,515 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.v1.features; + +import static com.google.common.base.Charsets.US_ASCII; +import static com.google.common.io.BaseEncoding.base16; +import static com.google.common.net.HttpHeaders.EXPIRES; +import static org.jclouds.Constants.PROPERTY_MAX_RETRIES; +import static org.jclouds.Constants.PROPERTY_RETRY_DELAY_START; +import static org.jclouds.Constants.PROPERTY_SO_TIMEOUT; +import static org.jclouds.http.options.GetOptions.Builder.tail; +import static org.jclouds.io.Payloads.newByteSourcePayload; +import static org.jclouds.openstack.swift.v1.features.ContainerApiMockTest.containerResponse; +import static org.jclouds.openstack.swift.v1.options.ListContainerOptions.Builder.marker; +import static org.jclouds.openstack.swift.v1.options.PutOptions.Builder.metadata; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_ACL_ANYBODY_READ; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.CONTAINER_READ; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_METADATA_PREFIX; +import static org.jclouds.openstack.swift.v1.reference.SwiftHeaders.OBJECT_REMOVE_METADATA_PREFIX; +import static org.jclouds.util.Strings2.toStringAndClose; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.io.IOException; +import java.net.URI; +import java.util.Date; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.http.HttpResponseException; +import org.jclouds.io.Payload; +import org.jclouds.io.payloads.ByteSourcePayload; +import org.jclouds.openstack.swift.v1.CopyObjectException; +import org.jclouds.openstack.swift.v1.SwiftApi; +import org.jclouds.openstack.swift.v1.domain.ObjectList; +import org.jclouds.openstack.swift.v1.domain.SwiftObject; +import org.jclouds.openstack.swift.v1.options.ListContainerOptions; +import org.jclouds.openstack.swift.v1.reference.SwiftHeaders; +import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.io.ByteSource; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; + +/** + * Provides mock tests for the {@link ObjectApi}. + */ +@Test(groups = "unit", testName = "ObjectApiMockTest") +public class ObjectApiMockTest extends BaseOpenStackMockTest<SwiftApi> { + SimpleDateFormatDateService dates = new SimpleDateFormatDateService(); + + static final Payload PAYLOAD = newByteSourcePayload(ByteSource.wrap("swifty".getBytes())); + + protected ImmutableList<SwiftObject> parsedObjectsForUrl(String baseUri) { + baseUri += "v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer"; + return ImmutableList.of( + SwiftObject.builder() + .name("test_obj_1") + .uri(URI.create(baseUri + "/test_obj_1")) + .etag("4281c348eaf83e70ddce0e07221c3d28") + .payload(payload(14, "application/octet-stream", new Date(1406243553))) + .lastModified(dates.iso8601DateParse("2009-02-03T05:26:32.612278")).build(), + SwiftObject.builder() + .name("test_obj_2") + .uri(URI.create(baseUri + "/test_obj_2")) + .etag("b039efe731ad111bc1b0ef221c3849d0") + .payload(payload(64l, "application/octet-stream", null)) + .lastModified(dates.iso8601DateParse("2009-02-03T05:26:32.612278")).build(), + SwiftObject.builder() + .name("test obj 3") + .uri(URI.create(baseUri + "/test%20obj%203")) + .etag("0b2e80bd0744d9ebb20484149a57c82e") + .payload(payload(14, "application/octet-stream", new Date())) + .lastModified(dates.iso8601DateParse("2014-05-20T05:26:32.612278")).build()); + } + + public void testList() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(containerResponse() + .addHeader(CONTAINER_READ, CONTAINER_ACL_ANYBODY_READ) + .setBody(stringFromResource("/object_list.json")))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + ObjectList objects = api.getObjectApi("DFW", "myContainer").list(); + assertEquals(objects, parsedObjectsForUrl(server.getUrl("/").toString())); + assertEquals(objects.getContainer().getName(), "myContainer"); + assertTrue(objects.getContainer().getAnybodyRead().get()); + + // Check MD5 is parsed from the ETag header. + SwiftObject object1 = objects.get(1); + assertEquals(base16().lowerCase().decode(object1.getETag()), + object1.getPayload().getContentMetadata().getContentMD5AsHashCode().asBytes()); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer"); + } finally { + server.shutdown(); + } + } + + public void testListWithOptions() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(containerResponse() + .addHeader(CONTAINER_READ, CONTAINER_ACL_ANYBODY_READ) + .setBody(stringFromResource("/object_list.json")))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + ObjectList objects = api.getObjectApi("DFW", "myContainer").list(new ListContainerOptions()); + assertEquals(objects, parsedObjectsForUrl(server.getUrl("/").toString())); + assertEquals(objects.getContainer().getName(), "myContainer"); + assertTrue(objects.getContainer().getAnybodyRead().get()); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer"); + } finally { + server.shutdown(); + } + } + + public void testListOptions() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(containerResponse().setBody(stringFromResource("/object_list.json")))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + ObjectList objects = api.getObjectApi("DFW", "myContainer").list(marker("test")); + assertEquals(objects, parsedObjectsForUrl(server.getUrl("/").toString())); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer?marker=test"); + } finally { + server.shutdown(); + } + } + + public void testCreate() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse() + .setResponseCode(201) + .addHeader("ETag", "d9f5eb4bba4e2f2f046e54611bc8196b")) + .addHeader("Expires", "1406243553")); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertEquals( + api.getObjectApi("DFW", "myContainer").put("myObject", PAYLOAD, + metadata(metadata)), "d9f5eb4bba4e2f2f046e54611bc8196b"); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + RecordedRequest replace = server.takeRequest(); + assertRequest(replace, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject"); + + assertEquals(new String(replace.getBody()), "swifty"); + for (Entry<String, String> entry : metadata.entrySet()) { + assertEquals(replace.getHeader(OBJECT_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue()); + } + } finally { + server.shutdown(); + } + } + + public void testCreateWithSpacesAndSpecialCharacters() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201).addHeader("ETag", "d9f5eb4bba4e2f2f046e54611bc8196b"))); + + final String containerName = "container # ! special"; + final String objectName = "object # ! special"; + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertEquals( + api.getObjectApi("DFW", containerName).put(objectName, PAYLOAD, + metadata(metadata)), "d9f5eb4bba4e2f2f046e54611bc8196b"); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + RecordedRequest replace = server.takeRequest(); + assertRequest(replace, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/container%20%23%20%21%20special/object%20%23%20%21%20special"); + + assertEquals(new String(replace.getBody()), "swifty"); + } finally { + server.shutdown(); + } + } + + public void testCreateWith408Retry() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(408))); // 1 + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(408))); // 2 + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(408))); // 3 + + // Finally success + server.enqueue(addCommonHeaders(new MockResponse() + .setResponseCode(201) + .addHeader("ETag", "d9f5eb4bba4e2f2f046e54611bc8196b"))); + + try { + Properties overrides = new Properties(); + overrides.setProperty(PROPERTY_MAX_RETRIES, 5 + ""); + + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift", overrides); + assertEquals( + api.getObjectApi("DFW", "myContainer").put("myObject", PAYLOAD, + metadata(metadata)), "d9f5eb4bba4e2f2f046e54611bc8196b"); + + assertEquals(server.getRequestCount(), 5); + assertAuthentication(server); + RecordedRequest replace = server.takeRequest(); + // This should take a while. + assertRequest(replace, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject"); + + assertEquals(new String(replace.getBody()), "swifty"); + for (Entry<String, String> entry : metadata.entrySet()) { + assertEquals(replace.getHeader(OBJECT_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue()); + } + } finally { + server.shutdown(); + } + } + + /** upper-cases first char, and lower-cases rest!! **/ + public void testGetWithoutKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(objectResponse() + // note silly casing + .addHeader(OBJECT_METADATA_PREFIX + "Apiname", "swift") + .addHeader(OBJECT_METADATA_PREFIX + "Apiversion", "v1.1"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + SwiftObject object = api.getObjectApi("DFW", "myContainer").getWithoutBody("myObject"); + assertEquals(object.getName(), "myObject"); + assertEquals(object.getETag(), "8a964ee2a5e88be344f36c22562a6486"); + + // Check MD5 is parsed from the ETag header. + assertEquals(base16().lowerCase().decode(object.getETag()), + object.getPayload().getContentMetadata().getContentMD5AsHashCode().asBytes()); + + assertEquals(object.getLastModified(), dates.rfc822DateParse("Fri, 12 Jun 2010 13:40:18 GMT")); + for (Entry<String, String> entry : object.getMetadata().entrySet()) { + assertEquals(object.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue()); + } + assertEquals(object.getPayload().getContentMetadata().getContentType(), "text/plain; charset=UTF-8"); + assertEquals(toStringAndClose(object.getPayload().openStream()), ""); + + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "HEAD", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject"); + } finally { + server.shutdown(); + } + } + + public void testGet() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(objectResponse() + // note silly casing + .addHeader(OBJECT_METADATA_PREFIX + "Apiname", "swift") + .addHeader(OBJECT_METADATA_PREFIX + "Apiversion", "v1.1"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + SwiftObject object = api.getObjectApi("DFW", "myContainer").get("myObject", tail(1)); + assertEquals(object.getName(), "myObject"); + assertEquals(object.getETag(), "8a964ee2a5e88be344f36c22562a6486"); + assertEquals(object.getLastModified(), dates.rfc822DateParse("Fri, 12 Jun 2010 13:40:18 GMT")); + for (Entry<String, String> entry : object.getMetadata().entrySet()) { + assertEquals(object.getMetadata().get(entry.getKey().toLowerCase()), entry.getValue()); + } + + Payload payload = object.getPayload(); + assertEquals(payload.getContentMetadata().getContentLength(), Long.valueOf(4)); + assertEquals(payload.getContentMetadata().getContentType(), "text/plain; charset=UTF-8"); + assertEquals(payload.getContentMetadata().getExpires(), dates.rfc822DateParse("Wed, 23 Jul 2014 14:00:00 GMT")); + + assertEquals(toStringAndClose(payload.openStream()), "ABCD"); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest get = server.takeRequest(); + assertEquals(get.getRequestLine(), + "GET /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1"); + } finally { + server.shutdown(); + } + } + + @Test(expectedExceptions = HttpResponseException.class, timeOut = 20000) + public void testCreateWithTimeout() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + // Typically we would enqueue a response for the put. However, in this case, test the timeout by not providing one. + + try { + Properties overrides = new Properties(); + + overrides.setProperty(PROPERTY_SO_TIMEOUT, 5000 + ""); // This time-outs the connection + overrides.setProperty(PROPERTY_MAX_RETRIES, 0 + ""); // 0 retries == 1 try. Semantics. + overrides.setProperty(PROPERTY_RETRY_DELAY_START, 0 + ""); // exponential backoff already working for this call. This is the delay BETWEEN attempts. + + final SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift", overrides); + + api.getObjectApi("DFW", "myContainer").put("myObject", new ByteSourcePayload(ByteSource.wrap("swifty".getBytes())), metadata(metadata)); + + fail("testReplaceTimeout test should have failed with an HttpResponseException."); + } finally { + server.shutdown(); + } + } + + public void testUpdateMetadata() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(objectResponse() + .addHeader(OBJECT_METADATA_PREFIX + "ApiName", "swift") + .addHeader(OBJECT_METADATA_PREFIX + "ApiVersion", "v1.1"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getObjectApi("DFW", "myContainer").updateMetadata("myObject", metadata)); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest replaceRequest = server.takeRequest(); + assertEquals(replaceRequest.getRequestLine(), + "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1"); + for (Entry<String, String> entry : metadata.entrySet()) { + assertEquals(replaceRequest.getHeader(OBJECT_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue()); + } + } finally { + server.shutdown(); + } + } + + public void testUpdateMetadataContentType() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(objectResponse() + .addHeader(OBJECT_METADATA_PREFIX + "ApiName", "swift") + .addHeader(OBJECT_METADATA_PREFIX + "ApiVersion", "v1.1"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getObjectApi("DFW", "myContainer").updateMetadata("myObject", metadata)); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest replaceRequest = server.takeRequest(); + assertEquals(replaceRequest.getHeaders("Content-Type").get(0), "", "updateMetadata should send an empty content-type header, but sent " + + replaceRequest.getHeaders("Content-Type").get(0).toString()); + + assertEquals(replaceRequest.getRequestLine(), + "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1"); + for (Entry<String, String> entry : metadata.entrySet()) { + assertEquals(replaceRequest.getHeader(OBJECT_METADATA_PREFIX + entry.getKey().toLowerCase()), entry.getValue()); + } + } finally { + server.shutdown(); + } + } + + public void testDeleteMetadata() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(objectResponse())); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getObjectApi("DFW", "myContainer").deleteMetadata("myObject", metadata)); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest deleteRequest = server.takeRequest(); + assertEquals(deleteRequest.getRequestLine(), + "POST /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1"); + for (String key : metadata.keySet()) { + assertEquals(deleteRequest.getHeader(OBJECT_REMOVE_METADATA_PREFIX + key.toLowerCase()), "ignored"); + } + } finally { + server.shutdown(); + } + } + + public void testDelete() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(204))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + api.getObjectApi("DFW", "myContainer").delete("myObject"); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest deleteRequest = server.takeRequest(); + assertEquals(deleteRequest.getRequestLine(), + "DELETE /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1"); + } finally { + server.shutdown(); + } + } + + public void testAlreadyDeleted() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + api.getObjectApi("DFW", "myContainer").delete("myObject"); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + RecordedRequest deleteRequest = server.takeRequest(); + assertEquals(deleteRequest.getRequestLine(), + "DELETE /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject HTTP/1.1"); + } finally { + server.shutdown(); + } + } + + public void testCopyObject() throws Exception { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(201) + .addHeader(SwiftHeaders.OBJECT_COPY_FROM, "/bar/foo.txt"))); + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + assertTrue(api.getObjectApi("DFW", "foo") + .copy("bar.txt", "bar", "foo.txt")); + + assertEquals(server.getRequestCount(), 2); + assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1"); + + RecordedRequest copyRequest = server.takeRequest(); + assertEquals(copyRequest.getRequestLine(), + "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/foo/bar.txt HTTP/1.1"); + } finally { + server.shutdown(); + } + } + + @Test(expectedExceptions = CopyObjectException.class) + public void testCopyObjectFail() throws InterruptedException, IOException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404) + .addHeader(SwiftHeaders.OBJECT_COPY_FROM, "/bogus/foo.txt"))); + + try { + SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift"); + // the following line will throw the CopyObjectException + api.getObjectApi("DFW", "foo").copy("bar.txt", "bogus", "foo.txt"); + } finally { + server.shutdown(); + } + } + + private static final Map<String, String> metadata = ImmutableMap.of("ApiName", "swift", "ApiVersion", "v1.1"); + + static MockResponse objectResponse() { + return new MockResponse() + .addHeader("Last-Modified", "Fri, 12 Jun 2010 13:40:18 GMT") + .addHeader("ETag", "8a964ee2a5e88be344f36c22562a6486") + // TODO: MWS doesn't allow you to return content length w/o content + // on HEAD! + .setBody("ABCD".getBytes(US_ASCII)) + .addHeader("Content-Length", "4") + .addHeader("Content-Type", "text/plain; charset=UTF-8") + .addHeader(EXPIRES, "Wed, 23 Jul 2014 14:00:00 GMT"); + } + + static Payload payload(long bytes, String contentType, Date expires) { + Payload payload = newByteSourcePayload(ByteSource.empty()); + payload.getContentMetadata().setContentLength(bytes); + payload.getContentMetadata().setContentType(contentType); + payload.getContentMetadata().setExpires(expires); + return payload; + } +}
