package com.xiaomi.infra.galaxy.fds.android; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.junit.WireMockRule; import com.github.tomakehurst.wiremock.stubbing.Scenario; import com.google.gson.Gson; import org.apache.http.HttpHeaders; import org.apache.http.HttpStatus; import org.apache.http.entity.ContentType; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import com.xiaomi.infra.galaxy.fds.android.auth.OAuthCredential; import com.xiaomi.infra.galaxy.fds.android.auth.SSOCredential; import com.xiaomi.infra.galaxy.fds.android.exception.GalaxyFDSClientException; import com.xiaomi.infra.galaxy.fds.android.model.ExpiresParam; import com.xiaomi.infra.galaxy.fds.android.model.FDSObject; import com.xiaomi.infra.galaxy.fds.android.model.InitMultipartUploadResult; import com.xiaomi.infra.galaxy.fds.android.model.ObjectMetadata; import com.xiaomi.infra.galaxy.fds.android.model.ProgressListener; import com.xiaomi.infra.galaxy.fds.android.model.PutObjectResult; import com.xiaomi.infra.galaxy.fds.android.model.ResponseContentTypeParam; import com.xiaomi.infra.galaxy.fds.android.model.ResponseExpiresParam; import com.xiaomi.infra.galaxy.fds.android.model.StorageAccessToken; import com.xiaomi.infra.galaxy.fds.android.model.ThumbParam; import com.xiaomi.infra.galaxy.fds.android.model.UploadPartResult; import com.xiaomi.infra.galaxy.fds.android.model.UploadPartResultList; import com.xiaomi.infra.galaxy.fds.android.model.UserParam; import com.xiaomi.infra.galaxy.fds.android.util.Consts; import com.xiaomi.infra.galaxy.fds.android.util.Util; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.delete; import static com.github.tomakehurst.wiremock.client.WireMock.deleteRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.head; import static com.github.tomakehurst.wiremock.client.WireMock.headRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.put; import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.verify; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertFalse; public class TestGalaxyFDSClient { private static final int WIRE_MOCK_BASE_URI_PORT = 8964; private static final String SSO_SERVICE_TOKEN = "ossServiceToken"; private static final String STORAGE_ACCESS_TOKEN = "storageAccessToken"; private static final String APP_ID = "appId"; private static final String OAUTH_APPID = "oauthAppId"; private static final String OAUTH_ACCESS_TOKEN = "oauthAccessToken"; private static final String OAUTH_PROVIDER = "oauthProvider"; private static final String OAUTH_MAC_KEY = "oauthMacKey"; private static final String OAUTH_MAC_ALGORITHM = "oauthMacAlgorithm"; private final FDSClientConfiguration config; private final GalaxyFDSClient client; private final int partSize; @Rule public WireMockRule baseUriMockRule = new WireMockRule(WIRE_MOCK_BASE_URI_PORT); @Before public void setup() { WireMock.reset(); } public TestGalaxyFDSClient() { config = new FDSClientConfiguration() .withCredential(new SSOCredential(SSO_SERVICE_TOKEN)) .withUnitTestMode(true) .withBaseUriForUnitTest("http://localhost:" + WIRE_MOCK_BASE_URI_PORT + "/"); client = new GalaxyFDSClientImpl(config); partSize = config.DEFAULT_UPLOAD_PART_SIZE; } @Test(timeout = 120*1000) public void testInvalidConfig() { try { new FDSClientConfiguration().withCredential(new SSOCredential(null)); fail("null sso token. should fail"); } catch (IllegalArgumentException e) { System.out.print(Util.getStackTrace(e)); } try { new FDSClientConfiguration().withCredential(null); fail("null credential. should fail"); } catch (IllegalArgumentException e) { System.out.print(Util.getStackTrace(e)); } } @Test(timeout = 120*1000) public void testPutInvalidParam() { String bucketName = "testPutInvalidParam_bucket"; String objectName = "testPutInvalidParam_object"; try { client.putObject(bucketName, objectName, new File("/notexist/xxx")); fail("File not exist, should fail"); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); } ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentLength(-1); byte[] data = new byte[FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE]; InputStream in = new ByteArrayInputStream(data); try { client.putObject(bucketName, objectName, in, metadata); fail("Content length is negative, should fail"); } catch (GalaxyFDSClientException e) { fail("Should not raise this exception"); } catch (IllegalArgumentException e) { System.out.print(Util.getStackTrace(e)); } } @Test(timeout = 120*1000) public void testPutBadResponse() { String bucketName = "testPutBadResponse_bucket"; String objectName = "testPutBadResponse_object"; String uploadId = "8964"; int partNumber = 1; String initMultipartUrl = "/" + bucketName + "/" + objectName + "?uploads&serviceToken=" + SSO_SERVICE_TOKEN; String completeMultipartUrl = "/" + bucketName + "/" + objectName + "?uploadId=" + uploadId + "&serviceToken=" + SSO_SERVICE_TOKEN; String uploadPartUrl = getUploadPartUrl(bucketName, objectName, uploadId, partNumber); String abortMultipartUrl = "/" + bucketName + "/" + objectName + "?uploadId=" + uploadId + "&serviceToken=" + SSO_SERVICE_TOKEN; InitMultipartUploadResult initMultipartUploadResult = new InitMultipartUploadResult(); initMultipartUploadResult.setBucketName(bucketName); initMultipartUploadResult.setObjectName(objectName); initMultipartUploadResult.setUploadId(uploadId); UploadPartResult uploadPartResult = new UploadPartResult(partNumber, partSize, Integer.toString(partNumber)); baseUriMockRule.stubFor(put(urlEqualTo(initMultipartUrl)) .inScenario("BadInitMultipartUpload") .whenScenarioStateIs(Scenario.STARTED) .willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString())) .willSetStateTo("success")); baseUriMockRule.stubFor(put(urlEqualTo(initMultipartUrl)) .inScenario("BadInitMultipartUpload") .whenScenarioStateIs("success") .willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(initMultipartUploadResult)))); baseUriMockRule.stubFor(put(urlEqualTo(uploadPartUrl)) .inScenario("BadUploadPartResult") .whenScenarioStateIs(Scenario.STARTED) .willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString())) .willSetStateTo("second")); baseUriMockRule.stubFor(put(urlEqualTo(uploadPartUrl)) .inScenario("BadUploadPartResult") .whenScenarioStateIs("second") .willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString())) .willSetStateTo("third")); baseUriMockRule.stubFor(put(urlEqualTo(uploadPartUrl)) .inScenario("BadUploadPartResult") .whenScenarioStateIs("third") .willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString())) .willSetStateTo("success")); baseUriMockRule.stubFor(put(urlEqualTo(uploadPartUrl)) .inScenario("BadUploadPartResult") .whenScenarioStateIs("success") .willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(uploadPartResult)))); baseUriMockRule.stubFor(put(urlEqualTo(completeMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()))); baseUriMockRule.stubFor(delete(urlEqualTo(abortMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK))); byte[] data = new byte[FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE]; Arrays.fill(data, (byte) 5); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentLength(data.length); InputStream in = null; try { in = new ByteArrayInputStream(data); client.putObject(bucketName, objectName, in, metadata); fail("Should fail. Bad response of initMultipartUpload"); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } try { in = new ByteArrayInputStream(data); client.putObject(bucketName, objectName, in, metadata); fail("Should fail. Bad response of uploadPart"); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } try { in = new ByteArrayInputStream(data); client.putObject(bucketName, objectName, in, metadata); fail("Should fail. Bad response of completeMultipartUpload"); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } } @Test(timeout = 120*1000) public void testPutBadRequest() { String bucketName = "testPutBadRequest_bucket"; String objectName = "testPutBadRequest_object"; String url = "/" + bucketName + "/" + objectName + "?uploads&serviceToken=" + SSO_SERVICE_TOKEN; baseUriMockRule.stubFor(put(urlEqualTo(url)).willReturn(aResponse() .withStatus(HttpStatus.SC_FORBIDDEN))); byte[] data = new byte[FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE]; Arrays.fill(data, (byte) 5); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentLength(data.length); InputStream in = new ByteArrayInputStream(data); try { client.putObject(bucketName, objectName, in, metadata); fail("bucket not accessible, should fail"); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); } baseUriMockRule.verify(putRequestedFor(urlEqualTo(url)) .withHeader(Consts.ESTIMATED_OBJECT_SIZE, equalTo(Long.toString(metadata .getContentLength()))) .withHeader(HttpHeaders.AUTHORIZATION, equalTo("SSO"))); } @Test(timeout = 120*1000) public void testPutNormal() { int numParts = 3; String bucketName = "testPutNormal_bucket"; String objectName = "testPutNormal_object"; String uploadId = "8964"; String signature = "abcdefg"; String initMultipartUrl = "/" + bucketName + "/" + objectName + "?uploads&serviceToken=" + SSO_SERVICE_TOKEN; String completeMultipartUrl = "/" + bucketName + "/" + objectName + "?uploadId=" + uploadId + "&serviceToken=" + SSO_SERVICE_TOKEN; String checkObjectUrl = "/" + bucketName + "/" + objectName + "?serviceToken=" + SSO_SERVICE_TOKEN; InitMultipartUploadResult initMultipartUploadResult = new InitMultipartUploadResult(); initMultipartUploadResult.setBucketName(bucketName); initMultipartUploadResult.setObjectName(objectName); initMultipartUploadResult.setUploadId(uploadId); baseUriMockRule.stubFor(put(urlEqualTo(initMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(initMultipartUploadResult)))); List<UploadPartResult> uploadPartResults = new ArrayList<UploadPartResult>(numParts); for (int partNumber = 1; partNumber <= numParts; partNumber++) { UploadPartResult uploadPartResult = new UploadPartResult(partNumber, partSize, Integer.toString(partNumber)); baseUriMockRule.stubFor(put(urlEqualTo( getUploadPartUrl(bucketName, objectName, uploadId, partNumber))).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(uploadPartResult)))); uploadPartResults.add(uploadPartResult); } UploadPartResultList uploadPartResultList = new UploadPartResultList(); uploadPartResultList.setUploadPartResultList(uploadPartResults); PutObjectResult putObjectResult = new PutObjectResult(); putObjectResult.setBucketName(bucketName); putObjectResult.setObjectName(objectName); putObjectResult.setAccessKeyId(SSO_SERVICE_TOKEN); putObjectResult.setExpires(Long.MAX_VALUE); putObjectResult.setSignature(signature); baseUriMockRule.stubFor(put(urlEqualTo(completeMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(putObjectResult)))); baseUriMockRule.stubFor(head(urlEqualTo(checkObjectUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK))); byte[] data = new byte[(int) (partSize * 2.5)]; for (int partNumber = 1; partNumber <= numParts; partNumber++) { if (partNumber == numParts) { Arrays.fill(data, (partNumber - 1) * partSize, (int) ( (partNumber - 1 + 0.5) * partSize), (byte) partNumber); } else { Arrays.fill(data, (partNumber - 1) * partSize, partNumber * partSize, (byte) partNumber); } } ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentLength(data.length); InputStream in = new ByteArrayInputStream(data); try { PutObjectResult result = client.putObject(bucketName, objectName, in, metadata); assertNotNull(result); assertEquals(SSO_SERVICE_TOKEN, result.getAccessKeyId()); assertEquals(bucketName, result.getBucketName()); assertEquals(objectName, result.getObjectName()); assertEquals(Long.MAX_VALUE, result.getExpires()); assertEquals(signature, result.getSignature()); assertTrue(client.doesObjectExist(bucketName, objectName)); } catch (GalaxyFDSClientException e) { fail("Should not raise exception"); } baseUriMockRule.verify(putRequestedFor(urlEqualTo(initMultipartUrl)) .withHeader(Consts.ESTIMATED_OBJECT_SIZE, equalTo(Long.toString(metadata.getContentLength()))) .withHeader(HttpHeaders.AUTHORIZATION, equalTo("SSO"))); String dataString = new String(data); for (int partNumber = 1; partNumber <= numParts; partNumber++) { String subString; if (partNumber != numParts) { subString = dataString.substring((partNumber - 1) * partSize, partNumber * partSize); } else { subString = dataString.substring((partNumber - 1) * partSize, (int) ((partNumber - 1 + 0.5) * partSize)); } baseUriMockRule.verify(putRequestedFor( urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber))) .withHeader(HttpHeaders.CONTENT_LENGTH, equalTo(Long.toString(partNumber == numParts ? (int) (0.5 * partSize) : partSize))) .withHeader(HttpHeaders.AUTHORIZATION, equalTo("SSO")) .withRequestBody(equalTo(subString))); } baseUriMockRule.verify(putRequestedFor(urlEqualTo(completeMultipartUrl)) .withHeader(HttpHeaders.AUTHORIZATION, equalTo("SSO")) .withRequestBody(equalToJson(new Gson().toJson(uploadPartResultList)))); baseUriMockRule.verify(headRequestedFor(urlEqualTo(checkObjectUrl))); } @Test(timeout = 120*1000) public void testPutRetryFail() { int numParts = 3; String bucketName = "testPutRetryFail_bucket"; String objectName = "testPutRetryFail_object"; String uploadId = "8964"; String initMultipartUrl = "/" + bucketName + "/" + objectName + "?uploads&serviceToken=" + SSO_SERVICE_TOKEN; String abortMultipartUrl = "/" + bucketName + "/" + objectName + "?uploadId=" + uploadId + "&serviceToken=" + SSO_SERVICE_TOKEN; String checkObjectUrl = "/" + bucketName + "/" + objectName + "?serviceToken=" + SSO_SERVICE_TOKEN;; InitMultipartUploadResult initMultipartUploadResult = new InitMultipartUploadResult(); initMultipartUploadResult.setBucketName(bucketName); initMultipartUploadResult.setObjectName(objectName); initMultipartUploadResult.setUploadId(uploadId); baseUriMockRule.stubFor(put(urlEqualTo(initMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(initMultipartUploadResult)))); for (int partNumber = 1; partNumber <= numParts; partNumber++) { if (partNumber != numParts) { UploadPartResult uploadPartResult = new UploadPartResult(partNumber, partSize, Integer.toString(partNumber)); baseUriMockRule.stubFor(put(urlEqualTo( getUploadPartUrl(bucketName, objectName, uploadId, partNumber))).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(uploadPartResult)))); } else { baseUriMockRule.stubFor(put(urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber))) .willReturn(aResponse().withStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR))); } } baseUriMockRule.stubFor(delete(urlEqualTo(abortMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK))); baseUriMockRule.stubFor(head(urlEqualTo(checkObjectUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_NOT_FOUND))); byte[] data = new byte[(int) (FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE * 2.5)]; Arrays.fill(data, (byte) 1); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentLength(data.length); InputStream in = new ByteArrayInputStream(data); try { client.putObject(bucketName, objectName, in, metadata); fail("should fail in uploading the third part"); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } try { assertFalse(client.doesObjectExist(bucketName, objectName)); } catch (GalaxyFDSClientException e) { fail("should not throw exception"); } baseUriMockRule.verify(putRequestedFor(urlEqualTo(initMultipartUrl))); for (int partNumber = 1; partNumber <= numParts; partNumber++) { if (partNumber != numParts) { baseUriMockRule.verify(putRequestedFor( urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber)))); } else { baseUriMockRule.verify(3, putRequestedFor( urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber)))); } baseUriMockRule.verify(deleteRequestedFor(urlEqualTo(abortMultipartUrl))); } baseUriMockRule.verify(headRequestedFor(urlEqualTo(checkObjectUrl))); } @Test(timeout = 120*1000) public void testPutRetrySuccess() { int numParts = 3; String bucketName = "testPutRetrySuccess_bucket"; String objectName = "testPutRetrySuccess_object"; String uploadId = "8964"; String signature = "abcdefg"; long expire = 123456; String initMultipartUrl = "/" + bucketName + "/" + objectName + "?uploads&serviceToken=" + SSO_SERVICE_TOKEN; String completeMultipartUrl = "/" + bucketName + "/" + objectName + "?uploadId=" + uploadId + "&expires=" + expire + "&serviceToken=" + SSO_SERVICE_TOKEN; InitMultipartUploadResult initMultipartUploadResult = new InitMultipartUploadResult(); initMultipartUploadResult.setBucketName(bucketName); initMultipartUploadResult.setObjectName(objectName); initMultipartUploadResult.setUploadId(uploadId); baseUriMockRule.stubFor(put(urlEqualTo(initMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(initMultipartUploadResult)))); List<UploadPartResult> uploadPartResults = new ArrayList<UploadPartResult>(numParts); for (int partNumber = 1; partNumber <= numParts; partNumber++) { UploadPartResult uploadPartResult = new UploadPartResult(partNumber, partSize, Integer.toString(partNumber)); if (partNumber != 2) { baseUriMockRule.stubFor(put(urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber))).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(uploadPartResult)))); } else { baseUriMockRule.stubFor(put(urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber))) .inScenario("Retry") .whenScenarioStateIs(Scenario.STARTED) .willReturn(aResponse().withStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR)) .willSetStateTo("second")); baseUriMockRule.stubFor(put(urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber))) .inScenario("Retry") .whenScenarioStateIs("second") .willReturn(aResponse().withStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR)) .willSetStateTo("last")); baseUriMockRule.stubFor(put(urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber))) .inScenario("Retry") .whenScenarioStateIs("last") .willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(uploadPartResult)))); } uploadPartResults.add(uploadPartResult); } UploadPartResultList uploadPartResultList = new UploadPartResultList(); uploadPartResultList.setUploadPartResultList(uploadPartResults); PutObjectResult putObjectResult = new PutObjectResult(); putObjectResult.setBucketName(bucketName); putObjectResult.setObjectName(objectName); putObjectResult.setAccessKeyId(SSO_SERVICE_TOKEN); putObjectResult.setExpires(Long.MAX_VALUE); putObjectResult.setSignature(signature); baseUriMockRule.stubFor(put(urlEqualTo(completeMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(putObjectResult)))); byte[] data = new byte[(int) (FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE * 2.5)]; Arrays.fill(data, (byte) 1); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentLength(data.length); InputStream in = new ByteArrayInputStream(data); try { List<UserParam> params = new ArrayList<UserParam>(1); params.add(new ExpiresParam(expire)); MyProgressListener listener = new MyProgressListener(); PutObjectResult result = client.putObject(bucketName, objectName, in, metadata, params, listener); assertNotNull(result); assertEquals(SSO_SERVICE_TOKEN, result.getAccessKeyId()); assertEquals(bucketName, result.getBucketName()); assertEquals(objectName, result.getObjectName()); assertEquals(Long.MAX_VALUE, result.getExpires()); assertEquals(signature, result.getSignature()); assertEquals(1.0, listener.getTransferredPercentage()); } catch (GalaxyFDSClientException e) { System.out.println(Util.getStackTrace(e)); fail("should not throw any exceptions"); } baseUriMockRule.verify(putRequestedFor(urlEqualTo(initMultipartUrl))); for (int partNumber = 1; partNumber <= numParts; partNumber++) { if (partNumber != 2) { baseUriMockRule.verify(putRequestedFor( urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber)))); } else { baseUriMockRule.verify(3, putRequestedFor( urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber)))); } } baseUriMockRule.verify(putRequestedFor(urlEqualTo(completeMultipartUrl)) .withHeader(HttpHeaders.AUTHORIZATION, equalTo("SSO")) .withRequestBody(equalToJson(new Gson().toJson(uploadPartResultList)))); } @Test(timeout = 120*1000) public void testPost() { int numParts = 3; String bucketName = "testPost_bucket"; String objectName = "testPost_object"; String uploadId = "8964"; String signature = "signature"; String initMultipartUrl = "/" + bucketName + "/" + "?uploads&serviceToken=" + SSO_SERVICE_TOKEN; String completeMultipartUrl = "/" + bucketName + "/" + objectName + "?uploadId=" + uploadId + "&serviceToken=" + SSO_SERVICE_TOKEN; InitMultipartUploadResult initMultipartUploadResult = new InitMultipartUploadResult(); initMultipartUploadResult.setBucketName(bucketName); initMultipartUploadResult.setObjectName(objectName); initMultipartUploadResult.setUploadId(uploadId); baseUriMockRule.stubFor(post(urlEqualTo(initMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(initMultipartUploadResult)))); List<UploadPartResult> uploadPartResults = new ArrayList<UploadPartResult>(numParts); for (int partNumber = 1; partNumber <= numParts; partNumber++) { UploadPartResult uploadPartResult = new UploadPartResult(partNumber, partSize, Integer.toString(partNumber)); baseUriMockRule.stubFor(put(urlEqualTo( getUploadPartUrl(bucketName, objectName, uploadId, partNumber))).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(uploadPartResult)))); uploadPartResults.add(uploadPartResult); } UploadPartResultList uploadPartResultList = new UploadPartResultList(); uploadPartResultList.setUploadPartResultList(uploadPartResults); PutObjectResult putObjectResult = new PutObjectResult(); putObjectResult.setBucketName(bucketName); putObjectResult.setObjectName(objectName); putObjectResult.setAccessKeyId(SSO_SERVICE_TOKEN); putObjectResult.setExpires(Long.MAX_VALUE); putObjectResult.setSignature(signature); baseUriMockRule.stubFor(put(urlEqualTo(completeMultipartUrl)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) .withBody(new Gson().toJson(putObjectResult)))); byte[] data = new byte[(int) (FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE * 2.5)]; Arrays.fill(data, (byte) 1); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentLength(data.length); InputStream in = new ByteArrayInputStream(data); try { PutObjectResult result = client.putObject(bucketName, in, metadata); assertNotNull(result); assertEquals(SSO_SERVICE_TOKEN, result.getAccessKeyId()); assertEquals(bucketName, result.getBucketName()); assertEquals(objectName, result.getObjectName()); assertEquals(Long.MAX_VALUE, result.getExpires()); assertEquals(signature, result.getSignature()); assertEquals(config.getBaseUriForUnitTest() + "/" + bucketName + "/" + objectName + "?" + Consts.GALAXY_ACCESS_KEY_ID + "=" + SSO_SERVICE_TOKEN + "&" + Consts.EXPIRES + "=" + Long.MAX_VALUE + "&" + Consts.SIGNATURE + "=" + signature, result.getAbsolutePresignedUri()); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); fail("should not throw any exceptions"); } baseUriMockRule.verify(postRequestedFor(urlEqualTo(initMultipartUrl))); for (int partNumber = 1; partNumber <= numParts; partNumber++) { baseUriMockRule.verify(putRequestedFor( urlEqualTo(getUploadPartUrl(bucketName, objectName, uploadId, partNumber)))); } baseUriMockRule.verify(putRequestedFor(urlEqualTo(completeMultipartUrl)) .withHeader(HttpHeaders.AUTHORIZATION, equalTo("SSO")) .withRequestBody(equalToJson(new Gson().toJson(uploadPartResultList)))); } @Test(timeout = 120*1000) public void testGetInvalidParam() { String bucketName = "testGetInvalidParam_bucket"; String objectName = "testGetInvalidParam_object"; String url = "/" + bucketName + "/" + objectName + "?serviceToken=" + SSO_SERVICE_TOKEN; byte[] data = new byte[FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE]; baseUriMockRule.stubFor(get(urlEqualTo(url)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_OCTET_STREAM.toString()) .withBody(data))); try { client.getObject(bucketName, objectName, new File("/root/no_permission")); fail("Have no rights to access file, should fail"); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); } baseUriMockRule.stubFor(get(urlEqualTo(url)).willReturn(aResponse().withStatus(HttpStatus.SC_FORBIDDEN))); try { client.getObject(bucketName, objectName); fail("Have no rights to access file, should fail"); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); } try { client.getObject(bucketName, objectName); fail("Have no rights to access file, should fail"); } catch (GalaxyFDSClientException e) { System.out.print(Util.getStackTrace(e)); } } @Test(timeout = 120*1000) public void testGetNormal() { String bucketName = "testGetNormal_bucket"; String objectName = "testGetNormal_object"; String url = "/" + bucketName + "/" + objectName + "?serviceToken=" + SSO_SERVICE_TOKEN; int size = FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE * 10; byte[] data = new byte[size]; Arrays.fill(data, (byte) 2); baseUriMockRule.stubFor(get(urlEqualTo(url)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_OCTET_STREAM.toString()) .withHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(size)) .withBody(data))); try { FDSObject object = client.getObject(bucketName, objectName); assertNotNull(object); assertEquals(data.length, object.getObjectMetadata().getContentLength()); assertEquals(ContentType.APPLICATION_OCTET_STREAM.toString(), object.getObjectMetadata().getContentType()); InputStream in = object.getObjectContent(); ByteArrayOutputStream out = new ByteArrayOutputStream(size); byte[] buffer = new byte[partSize]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } assertArrayEquals(data, out.toByteArray()); } catch (Exception e) { fail("Should not throw any exception here"); } baseUriMockRule.verify(getRequestedFor(urlEqualTo(url))); } @Test(timeout = 120*1000) public void testGetRange() { String bucketName = "testGetRange_bucket"; String objectName = "testGetRange_object"; long expire = 123456; String url = "/" + bucketName + "/" + objectName + "?expires=" + expire + "&serviceToken=" + SSO_SERVICE_TOKEN; int numParts = 10; int size = partSize * numParts; int off = (int) (2.5 * partSize); byte[] data = new byte[size]; for (int partNumber = 1; partNumber <= numParts; partNumber++) { Arrays.fill(data, (partNumber - 1) * partSize, partNumber * partSize, (byte) partNumber); } byte[] rangeData = Arrays.copyOfRange(data, off, size); baseUriMockRule.stubFor(get(urlEqualTo(url)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_OCTET_STREAM.toString()) .withHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(size - off)) .withHeader(HttpHeaders.CONTENT_RANGE, "bytes=" + Integer.toString(off) + "-") .withBody(rangeData))); try { List<UserParam> params = new ArrayList<UserParam>(1); params.add(new ExpiresParam(expire)); FDSObject object = client.getObject(bucketName, objectName, off, params, null); assertNotNull(object); assertEquals(rangeData.length, object.getObjectMetadata().getContentLength()); assertEquals(ContentType.APPLICATION_OCTET_STREAM.toString(), object.getObjectMetadata().getContentType()); InputStream in = object.getObjectContent(); ByteArrayOutputStream out = new ByteArrayOutputStream(size); byte[] buffer = new byte[FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } assertArrayEquals(rangeData, out.toByteArray()); } catch (Exception e) { System.out.print(Util.getStackTrace(e)); fail("Should not throw any exception here"); } } @Test(timeout = 120*1000) public void testGetWithUserParams() { String bucketName = "testGetWithUserParams_bucket"; String objectName = "testGetWithUserParams_object"; ResponseContentTypeParam contentTypeParam = new ResponseContentTypeParam(); ResponseExpiresParam responseExpiresParam = new ResponseExpiresParam(); ExpiresParam expiresParam = new ExpiresParam(1000); String url = "/" + bucketName + "/" + objectName + "?response-content-type" + "&response-expires&expires=1000&serviceToken=" + SSO_SERVICE_TOKEN; try { List<UserParam> params = new ArrayList<UserParam>(3); params.add(contentTypeParam); params.add(responseExpiresParam); params.add(expiresParam); client.getObject(bucketName, objectName, 0, params, null); } catch (Exception e) { } verify(getRequestedFor(urlEqualTo(url))); } @Test(timeout = 120*1000) public void testGetFromCdn() { String bucketName = "testGetCdn_bucket"; String objectName = "testGetCdn_object"; String url = "/" + bucketName + "/" + objectName + "?serviceToken=" + SSO_SERVICE_TOKEN; int size = FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE * 10; byte[] data = new byte[size]; Arrays.fill(data, (byte) 2); baseUriMockRule.stubFor(get(urlEqualTo(url)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_OCTET_STREAM.toString()) .withHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(size)) .withBody(data))); try { FDSObject object = client.getObject(bucketName, objectName, 0, null, null, true); assertNotNull(object); assertEquals(data.length, object.getObjectMetadata().getContentLength()); assertEquals(ContentType.APPLICATION_OCTET_STREAM.toString(), object.getObjectMetadata().getContentType()); InputStream in = object.getObjectContent(); ByteArrayOutputStream out = new ByteArrayOutputStream(size); byte[] buffer = new byte[partSize]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } assertArrayEquals(data, out.toByteArray()); } catch (Exception e) { System.out.print(Util.getStackTrace(e)); fail("Should not throw any exception here"); } baseUriMockRule.verify(getRequestedFor(urlEqualTo(url))); } @Test(timeout = 120*1000) public void testGetFromPreSignedUrl() { String bucketName = "testGetFromPreSignedUrl_bucket"; String objectName = "testGetFromPreSignedUrl_object"; int width = 100; int height = 200; ThumbParam thumbParam = new ThumbParam(width, height); String preSignedUrlParams = "?GalaxyAccessKeyId=5211722473393" + "&Expires=1409385418532&Signature=3E6lB8NdY/1+KYxVaLLAXlLfLCM="; String preSignedUrl = config.getBaseUriForUnitTest() + "/" + bucketName + "/" + objectName + preSignedUrlParams; String url = "/" + bucketName + "/" + objectName + preSignedUrlParams + "&" + thumbParam.toString() + "&serviceToken=" + SSO_SERVICE_TOKEN; try { List<UserParam> params = new ArrayList<UserParam>(1); params.add(thumbParam); client.getObject(preSignedUrl, 0, params, null); } catch (Exception e) { } baseUriMockRule.verify(getRequestedFor(urlEqualTo(url))); } @Test(timeout = 120*1000) public void testOauthAuthentication() throws Exception { String bucketName = "testOAuth_bucket"; String objectName = "testOAuth_object"; long expireTime = 3000; StorageAccessToken accessToken = new StorageAccessToken(); accessToken.setExpireTime(expireTime); accessToken.setToken(STORAGE_ACCESS_TOKEN); String getStorageAccessTokenUri = "/?storageAccessToken&appId=" + APP_ID + "&oauthAppId=" + OAUTH_APPID + "&oauthAccessToken=" + OAUTH_ACCESS_TOKEN + "&oauthProvider=" + OAUTH_PROVIDER + "&oauthMacAlgorithm=" + OAUTH_MAC_ALGORITHM + "&oauthMacKey=" + OAUTH_MAC_KEY; baseUriMockRule.stubFor(get(urlEqualTo(getStorageAccessTokenUri)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withBody(new Gson().toJson(accessToken)))); int size = FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE * 10; byte[] data = new byte[size]; Arrays.fill(data, (byte) 2); String getObjectUri = "/" + bucketName + "/" + objectName + "?appId=" + APP_ID + "&storageAccessToken=" + STORAGE_ACCESS_TOKEN; baseUriMockRule.stubFor(get(urlEqualTo(getObjectUri)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_OCTET_STREAM.toString()) .withHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(size)) .withBody(data))); FDSClientConfiguration newConfig = new FDSClientConfiguration() .withUnitTestMode(true) .withBaseUriForUnitTest(config.getBaseUriForUnitTest()); newConfig.setCredential(new OAuthCredential( newConfig.getBaseUri(), APP_ID, OAUTH_APPID, OAUTH_ACCESS_TOKEN, OAUTH_PROVIDER, OAUTH_MAC_KEY, OAUTH_MAC_ALGORITHM)); GalaxyFDSClient newClient = new GalaxyFDSClientImpl(newConfig); FDSObject object = newClient.getObject(bucketName, objectName); assertNotNull(object); assertEquals(data.length, object.getObjectMetadata().getContentLength()); assertEquals(ContentType.APPLICATION_OCTET_STREAM.toString(), object.getObjectMetadata().getContentType()); InputStream in = object.getObjectContent(); ByteArrayOutputStream out = new ByteArrayOutputStream(size); byte[] buffer = new byte[partSize]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } assertArrayEquals(data, out.toByteArray()); baseUriMockRule.verify(getRequestedFor(urlEqualTo(getStorageAccessTokenUri)) .withHeader(HttpHeaders.AUTHORIZATION, equalTo("OAuth"))); baseUriMockRule.verify(getRequestedFor(urlEqualTo(getObjectUri))); } @Test(timeout = 120*1000) public void testGetObjectWithSlashInName() { String bucketName = "testGetObjectWithSlashInName_bucket"; String objectName = "test/get/object"; String url = "/" + bucketName + "/" + objectName + "?serviceToken=" + SSO_SERVICE_TOKEN; int size = FDSClientConfiguration.DEFAULT_UPLOAD_PART_SIZE * 10; byte[] data = new byte[size]; Arrays.fill(data, (byte) 2); baseUriMockRule.stubFor(get(urlEqualTo(url)).willReturn(aResponse() .withStatus(HttpStatus.SC_OK) .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_OCTET_STREAM.toString()) .withHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(size)) .withBody(data))); try { FDSObject object = client.getObject(bucketName, objectName); assertNotNull(object); assertEquals(data.length, object.getObjectMetadata().getContentLength()); assertEquals(ContentType.APPLICATION_OCTET_STREAM.toString(), object.getObjectMetadata().getContentType()); InputStream in = object.getObjectContent(); ByteArrayOutputStream out = new ByteArrayOutputStream(size); byte[] buffer = new byte[partSize]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } assertArrayEquals(data, out.toByteArray()); } catch (Exception e) { fail("Should not throw any exception here"); } baseUriMockRule.verify(getRequestedFor(urlEqualTo(url))); } @Test(timeout = 120 * 1000) public void testInvalidObjectMetadata() { ObjectMetadata metadata = new ObjectMetadata(); metadata.addUserMetadata(Consts.XIAOMI_META_HEADER_PREFIX + "test", "test-value"); metadata.addPredefinedMetadata(HttpHeaders.CACHE_CONTROL, "no-cache"); try { metadata.addUserMetadata("test-key", "test-value"); fail("Should not arrive here"); } catch (Exception e) { } } private static class MyProgressListener extends ProgressListener { private double transferredPercentage; @Override public void onProgress(long transferred, long total) { transferredPercentage = (double) transferred / total; } public double getTransferredPercentage() { return transferredPercentage; } } private String getUploadPartUrl(String bucketName, String objectName, String uploadId, int partNumber) { return "/" + bucketName + "/" + objectName + "?uploadId=" + uploadId + "&partNumber=" + partNumber + "&serviceToken=" + SSO_SERVICE_TOKEN; } }