/**
* Copyright Microsoft Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.microsoft.azure.storage;
import com.microsoft.azure.storage.TestRunners.CloudTests;
import com.microsoft.azure.storage.TestRunners.DevFabricTests;
import com.microsoft.azure.storage.TestRunners.DevStoreTests;
import com.microsoft.azure.storage.TestRunners.SlowTests;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.core.SR;
import com.microsoft.azure.storage.file.CloudFileClient;
import com.microsoft.azure.storage.file.FileServiceProperties;
import com.microsoft.azure.storage.queue.CloudQueueClient;
import com.microsoft.azure.storage.table.CloudTableClient;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import static org.junit.Assert.*;
@Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class, CloudTests.class })
public class ServicePropertiesTests {
/**
* Test Analytics Disable Service Properties
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testAnalyticsDisable() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testAnalyticsDisable(client, props);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testAnalyticsDisable(client, props);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testAnalyticsDisable(client, props);
}
private void testAnalyticsDisable(ServiceClient client, ServiceProperties props) throws StorageException,
InterruptedException {
props.getLogging().setLogOperationTypes(EnumSet.noneOf(LoggingOperations.class));
props.getLogging().setRetentionIntervalInDays(null);
props.getLogging().setVersion("1.0");
props.getHourMetrics().setMetricsLevel(MetricsLevel.DISABLED);
props.getHourMetrics().setRetentionIntervalInDays(null);
props.getHourMetrics().setVersion("1.0");
props.getMinuteMetrics().setMetricsLevel(MetricsLevel.DISABLED);
props.getMinuteMetrics().setRetentionIntervalInDays(null);
props.getMinuteMetrics().setVersion("1.0");
props.getCors().getCorsRules().clear();
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
/**
* Test Analytics Default Service Version
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testAnalyticsDefaultServiceVersion() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testAnalyticsDefaultServiceVersion(client, props);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testAnalyticsDefaultServiceVersion(client, props);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testAnalyticsDefaultServiceVersion(client, props);
}
private void testAnalyticsDefaultServiceVersion(ServiceClient client, ServiceProperties props)
throws StorageException, InterruptedException {
if (client.getClass().equals(CloudBlobClient.class)) {
props.setDefaultServiceVersion("2009-09-19");
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
props.setDefaultServiceVersion("2011-08-18");
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
props.setDefaultServiceVersion("2012-02-12");
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
else {
try {
props.setDefaultServiceVersion("2009-09-19");
callUploadServiceProps(client, props, null);
fail("Should not be able to set default Service Version for non Blob Client");
}
catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), SR.DEFAULT_SERVICE_VERSION_ONLY_SET_FOR_BLOB_SERVICE);
}
catch (Exception e) {
fail();
}
}
}
/**
* Test Analytics Logging Operations
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testAnalyticsLoggingOperations() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testAnalyticsLoggingOperations(client, props);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testAnalyticsLoggingOperations(client, props);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testAnalyticsLoggingOperations(client, props);
}
private void testAnalyticsLoggingOperations(ServiceClient client, ServiceProperties props) throws StorageException,
InterruptedException {
// None
props.getLogging().setLogOperationTypes(EnumSet.noneOf(LoggingOperations.class));
props.getLogging().setRetentionIntervalInDays(null);
props.getLogging().setVersion("1.0");
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
// None
props.getLogging().setLogOperationTypes(EnumSet.allOf(LoggingOperations.class));
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
/**
* Test Analytics Hour Metrics Level
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testAnalyticsHourMetricsLevel() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testAnalyticsHourMetricsLevel(client, props, null);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testAnalyticsHourMetricsLevel(client, props, null);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testAnalyticsHourMetricsLevel(client, props, null);
client = TestHelper.createCloudFileClient();
FileServiceProperties fileProps = new FileServiceProperties();
testAnalyticsHourMetricsLevel(client, null, fileProps);
}
private void testAnalyticsHourMetricsLevel(
ServiceClient client, ServiceProperties props, FileServiceProperties fileProps)
throws StorageException, InterruptedException {
final MetricsProperties hours = (props == null) ? fileProps.getHourMetrics() : props.getHourMetrics();
// None
hours.setMetricsLevel(MetricsLevel.DISABLED);
hours.setRetentionIntervalInDays(null);
hours.setVersion("1.0");
callUploadServiceProps(client, props, fileProps);
if (props == null) {
assertFileServicePropertiesAreEqual(fileProps, ((CloudFileClient) client).downloadServiceProperties());
}
else {
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
// Service
hours.setMetricsLevel(MetricsLevel.SERVICE);
callUploadServiceProps(client, props, fileProps);
if (props == null) {
assertFileServicePropertiesAreEqual(fileProps, ((CloudFileClient) client).downloadServiceProperties());
}
else {
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
// ServiceAndAPI
hours.setMetricsLevel(MetricsLevel.SERVICE_AND_API);
callUploadServiceProps(client, props, fileProps);
if (props == null) {
assertFileServicePropertiesAreEqual(fileProps, ((CloudFileClient) client).downloadServiceProperties());
}
else {
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
}
/**
* Test Analytics Minute Metrics Level
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testAnalyticsMinuteMetricsLevel() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testAnalyticsMinuteMetricsLevel(client, props, null);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testAnalyticsMinuteMetricsLevel(client, props, null);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testAnalyticsMinuteMetricsLevel(client, props, null);
client = TestHelper.createCloudFileClient();
FileServiceProperties fileProps = new FileServiceProperties();
testAnalyticsMinuteMetricsLevel(client, null, fileProps);
}
private void testAnalyticsMinuteMetricsLevel(
final ServiceClient client, final ServiceProperties props, final FileServiceProperties fileProps)
throws StorageException, InterruptedException {
final MetricsProperties minutes = (props == null) ? fileProps.getMinuteMetrics() : props.getMinuteMetrics();
// None
minutes.setMetricsLevel(MetricsLevel.DISABLED);
minutes.setRetentionIntervalInDays(null);
minutes.setVersion("1.0");
callUploadServiceProps(client, props, fileProps);
if (props == null) {
assertFileServicePropertiesAreEqual(fileProps, ((CloudFileClient) client).downloadServiceProperties());
}
else {
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
// Service
minutes.setMetricsLevel(MetricsLevel.SERVICE);
callUploadServiceProps(client, props, fileProps);
if (props == null) {
assertFileServicePropertiesAreEqual(fileProps, ((CloudFileClient) client).downloadServiceProperties());
}
else {
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
// ServiceAndAPI
minutes.setMetricsLevel(MetricsLevel.SERVICE_AND_API);
callUploadServiceProps(client, props, fileProps);
if (props == null) {
assertFileServicePropertiesAreEqual(fileProps, ((CloudFileClient) client).downloadServiceProperties());
}
else {
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
}
/**
* Test Analytics Retention Policies
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testAnalyticsRetentionPolicies() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testAnalyticsRetentionPolicies(client, props);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testAnalyticsRetentionPolicies(client, props);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testAnalyticsRetentionPolicies(client, props);
}
private void testAnalyticsRetentionPolicies(ServiceClient client, ServiceProperties props) throws StorageException,
InterruptedException {
// Set retention policy null with metrics disabled.
props.getHourMetrics().setMetricsLevel(MetricsLevel.DISABLED);
props.getHourMetrics().setRetentionIntervalInDays(null);
props.getMinuteMetrics().setMetricsLevel(MetricsLevel.DISABLED);
props.getMinuteMetrics().setRetentionIntervalInDays(null);
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
// Set retention policy not null with metrics enabled.
props.getHourMetrics().setRetentionIntervalInDays(1);
props.getHourMetrics().setMetricsLevel(MetricsLevel.SERVICE);
props.getMinuteMetrics().setRetentionIntervalInDays(1);
props.getMinuteMetrics().setMetricsLevel(MetricsLevel.SERVICE);
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
// Set retention policy not null with metrics enabled.
props.getHourMetrics().setRetentionIntervalInDays(2);
props.getHourMetrics().setMetricsLevel(MetricsLevel.SERVICE_AND_API);
props.getMinuteMetrics().setRetentionIntervalInDays(2);
props.getMinuteMetrics().setMetricsLevel(MetricsLevel.SERVICE_AND_API);
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
// Set retention policy null with logging disabled.
props.getLogging().setRetentionIntervalInDays(null);
props.getLogging().setLogOperationTypes(EnumSet.noneOf(LoggingOperations.class));
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
// Set retention policy not null with logging disabled.
props.getLogging().setRetentionIntervalInDays(3);
props.getLogging().setLogOperationTypes(EnumSet.noneOf(LoggingOperations.class));
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
// Set retention policy null with logging enabled.
props.getLogging().setRetentionIntervalInDays(null);
props.getLogging().setLogOperationTypes(EnumSet.allOf(LoggingOperations.class));
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
// Set retention policy not null with logging enabled.
props.getLogging().setRetentionIntervalInDays(4);
props.getLogging().setLogOperationTypes(EnumSet.allOf(LoggingOperations.class));
callUploadServiceProps(client, props, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
/**
* Test CORS with different rules.
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testCloudValidCorsRules() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testCloudValidCorsRules(client, props, null);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testCloudValidCorsRules(client, props, null);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testCloudValidCorsRules(client, props, null);
client = TestHelper.createCloudFileClient();
testCloudValidCorsRules(client, null, new FileServiceProperties());
}
private void testCloudValidCorsRules(
ServiceClient client, ServiceProperties props, FileServiceProperties fileServiceProperties)
throws StorageException, InterruptedException {
CorsRule ruleMinRequired = new CorsRule();
ruleMinRequired.getAllowedOrigins().add("www.xyz.com");
ruleMinRequired.getAllowedMethods().add(CorsHttpMethods.GET);
final CorsRule ruleBasic = new CorsRule();
ruleBasic.getAllowedOrigins().addAll(Arrays.asList("www.ab.com", "www.bc.com"));
ruleBasic.getAllowedMethods().addAll(EnumSet.of(CorsHttpMethods.GET, CorsHttpMethods.PUT));
ruleBasic.getAllowedHeaders().addAll(
Arrays.asList("x-ms-meta-data*", "x-ms-meta-target*", "x-ms-meta-xyz", "x-ms-meta-foo"));
ruleBasic.getExposedHeaders().addAll(
Arrays.asList("x-ms-meta-data*", "x-ms-meta-source*", "x-ms-meta-abc", "x-ms-meta-bcd"));
ruleBasic.setMaxAgeInSeconds(500);
CorsRule ruleAllMethods = new CorsRule();
ruleAllMethods.getAllowedOrigins().addAll(Arrays.asList("www.ab.com", "www.bc.com"));
ruleAllMethods.getAllowedMethods().addAll(EnumSet.allOf(CorsHttpMethods.class));
CorsRule ruleSingleExposedHeader = new CorsRule();
ruleSingleExposedHeader.getAllowedOrigins().add("www.ab.com");
ruleSingleExposedHeader.getAllowedMethods().add(CorsHttpMethods.GET);
ruleSingleExposedHeader.getExposedHeaders().add("x-ms-meta-bcd");
CorsRule ruleSingleExposedPrefixHeader = new CorsRule();
ruleSingleExposedPrefixHeader.getAllowedOrigins().add("www.ab.com");
ruleSingleExposedPrefixHeader.getAllowedMethods().add(CorsHttpMethods.GET);
ruleSingleExposedPrefixHeader.getExposedHeaders().add("x-ms-meta-data*");
CorsRule ruleSingleAllowedHeader = new CorsRule();
ruleSingleAllowedHeader.getAllowedOrigins().add("www.ab.com");
ruleSingleAllowedHeader.getAllowedMethods().add(CorsHttpMethods.GET);
ruleSingleAllowedHeader.getAllowedHeaders().add("x-ms-meta-xyz");
CorsRule ruleSingleAllowedPrefixHeader = new CorsRule();
ruleSingleAllowedPrefixHeader.getAllowedOrigins().add("www.ab.com");
ruleSingleAllowedPrefixHeader.getAllowedMethods().add(CorsHttpMethods.GET);
ruleSingleAllowedPrefixHeader.getAllowedHeaders().add("x-ms-meta-target*");
CorsRule ruleAllowAll = new CorsRule();
ruleAllowAll.getAllowedOrigins().add("*");
ruleAllowAll.getAllowedMethods().add(CorsHttpMethods.GET);
ruleAllowAll.getAllowedHeaders().add("*");
ruleAllowAll.getExposedHeaders().add("*");
this.testCorsRules(ruleBasic, client, props, fileServiceProperties);
this.testCorsRules(ruleMinRequired, client, props, fileServiceProperties);
this.testCorsRules(ruleAllMethods, client, props, fileServiceProperties);
this.testCorsRules(ruleSingleExposedHeader, client, props, fileServiceProperties);
this.testCorsRules(ruleSingleExposedPrefixHeader, client, props, fileServiceProperties);
this.testCorsRules(ruleSingleAllowedHeader, client, props, fileServiceProperties);
this.testCorsRules(ruleSingleAllowedPrefixHeader, client, props, fileServiceProperties);
this.testCorsRules(ruleAllowAll, client, props, fileServiceProperties);
List<CorsRule> testList = new ArrayList<CorsRule>();
// Empty rule set should delete all rules
this.testCorsRules(testList, client, props, fileServiceProperties);
// Test duplicate rules
testList.add(ruleBasic);
testList.add(ruleBasic);
this.testCorsRules(testList, client, props, fileServiceProperties);
// Test max number of rules (five)
testList.clear();
testList.add(ruleBasic);
testList.add(ruleMinRequired);
testList.add(ruleAllMethods);
testList.add(ruleSingleExposedHeader);
testList.add(ruleSingleExposedPrefixHeader);
this.testCorsRules(testList, client, props, fileServiceProperties);
// Test over max number of rules (six)
testList.clear();
testList.add(ruleBasic);
testList.add(ruleMinRequired);
testList.add(ruleAllMethods);
testList.add(ruleSingleExposedHeader);
testList.add(ruleSingleExposedPrefixHeader);
testList.add(ruleSingleAllowedHeader);
try {
this.testCorsRules(testList, client, props, fileServiceProperties);
fail("Expecting exception but no exception received. Services are limited to a maximum of five CORS rules.");
}
catch (StorageException e) {
}
catch (Exception e) {
fail("Invalid exception " + e + " received when expecting StorageException");
}
}
/**
* Test CORS with invalid values.
*/
@Test
public void testCorsExpectedExceptions() throws StorageException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testCorsExpectedExceptions(client, props, null);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testCorsExpectedExceptions(client, props, null);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testCorsExpectedExceptions(client, props, null);
client = TestHelper.createCloudFileClient();
testCorsExpectedExceptions(client, null, new FileServiceProperties());
}
private void testCorsExpectedExceptions(
ServiceClient client, ServiceProperties props, FileServiceProperties fileServiceProperties) {
CorsRule ruleEmpty = new CorsRule();
CorsRule ruleInvalidMaxAge = new CorsRule();
ruleInvalidMaxAge.getAllowedOrigins().add("www.xyz.com");
ruleInvalidMaxAge.getAllowedMethods().add(CorsHttpMethods.GET);
ruleInvalidMaxAge.setMaxAgeInSeconds(-1);
try {
this.testCorsRules(ruleEmpty, client, props, fileServiceProperties);
fail("No exception received. A CORS rule must contain at least one allowed origin and allowed method.");
}
catch (StorageException e) {
assertEquals(e.getCause().getClass(), IllegalArgumentException.class);
assertEquals(e.getCause().getMessage(),
"A CORS rule must contain at least one allowed origin and allowed method, and "
+ "MaxAgeInSeconds cannot have a value less than zero.");
}
catch (Exception e) {
fail("Invalid exception " + e.getClass() + " received when expecting StorageException");
}
try {
this.testCorsRules(ruleInvalidMaxAge, client, props, fileServiceProperties);
fail("No exception received. MaxAgeInSeconds cannot have a value less than 0.");
}
catch (StorageException e) {
assertEquals(e.getCause().getClass(), IllegalArgumentException.class);
assertEquals(e.getCause().getMessage(),
"A CORS rule must contain at least one allowed origin and allowed method, and "
+ "MaxAgeInSeconds cannot have a value less than zero.");
}
catch (Exception e) {
fail("Invalid exception " + e + " received when expecting StorageException");
}
}
/**
* Test CORS with a valid and invalid number of origin values sent to server.
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testCorsMaxOrigins() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testCorsMaxOrigins(client, props, null);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testCorsMaxOrigins(client, props, null);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testCorsMaxOrigins(client, props, null);
client = TestHelper.createCloudFileClient();
testCorsMaxOrigins(client, null, new FileServiceProperties());
}
private void testCorsMaxOrigins(
ServiceClient client, ServiceProperties props, FileServiceProperties fileServiceProperties)
throws StorageException, InterruptedException {
CorsRule ruleManyOrigins = new CorsRule();
ruleManyOrigins.getAllowedMethods().add(CorsHttpMethods.GET);
// Add maximum number of allowed origins
for (int i = 0; i < 64; i++) {
ruleManyOrigins.getAllowedOrigins().add("www.xyz" + i + ".com");
}
this.testCorsRules(ruleManyOrigins, client, props, fileServiceProperties);
ruleManyOrigins.getAllowedOrigins().add("www.xyz64.com");
try {
this.testCorsRules(ruleManyOrigins, client, props, fileServiceProperties);
fail("No exception received. A maximum of 64 origins are allowed.");
}
catch (StorageException e) {
}
catch (Exception e) {
fail("Invalid exception " + e + " received when expecting StorageException");
}
}
/**
* Test CORS with a valid and invalid number of header values sent to server.
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testCorsMaxHeaders() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testCorsMaxHeaders(client, props, null);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testCorsMaxHeaders(client, props, null);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testCorsMaxHeaders(client, props, null);
client = TestHelper.createCloudFileClient();
testCorsMaxHeaders(client, null, new FileServiceProperties());
}
private void testCorsMaxHeaders(
ServiceClient client, ServiceProperties props, FileServiceProperties fileServiceProperties)
throws StorageException, InterruptedException {
CorsRule ruleManyHeaders = new CorsRule();
ruleManyHeaders.getAllowedOrigins().add("www.xyz.com");
ruleManyHeaders.getAllowedMethods().add(CorsHttpMethods.GET);
ruleManyHeaders.getAllowedHeaders().addAll(Arrays.asList("x-ms-meta-target*", "x-ms-meta-other*"));
ruleManyHeaders.getExposedHeaders().addAll(Arrays.asList("x-ms-meta-data*", "x-ms-meta-source*"));
// Add maximum number of non-prefixed headers
for (int i = 0; i < 64; i++) {
ruleManyHeaders.getAllowedHeaders().add("x-ms-meta-" + i);
ruleManyHeaders.getExposedHeaders().add("x-ms-meta-" + i);
}
this.testCorsRules(ruleManyHeaders, client, props, fileServiceProperties);
// Test with too many Exposed Headers (65)
ruleManyHeaders.getExposedHeaders().add("x-ms-meta-toomany");
try {
this.testCorsRules(ruleManyHeaders, client, props, fileServiceProperties);
fail("No exception received. A maximum of 64 exposed headers are allowed.");
}
catch (StorageException e) {
}
catch (Exception e) {
fail("Invalid exception " + e + " received when expecting StorageException");
}
ruleManyHeaders.getExposedHeaders().remove("x-ms-meta-toomany");
// Test with too many Allowed Headers (65)
ruleManyHeaders.getAllowedHeaders().add("x-ms-meta-toomany");
try {
this.testCorsRules(ruleManyHeaders, client, props, fileServiceProperties);
fail("No exception received. A maximum of 64 allowed headers are allowed.");
}
catch (StorageException e) {
}
catch (Exception e) {
fail("Invalid exception " + e + " received when expecting StorageException");
}
ruleManyHeaders.getExposedHeaders().remove("x-ms-meta-toomany");
// Test with too many Exposed Prefixed Headers (three)
ruleManyHeaders.getExposedHeaders().add("x-ms-meta-toomany*");
try {
this.testCorsRules(ruleManyHeaders, client, props, fileServiceProperties);
fail("No exception received. A maximum of 2 exposed headers are allowed.");
}
catch (StorageException e) {
}
catch (Exception e) {
fail("Invalid exception " + e + " received when expecting StorageException");
}
ruleManyHeaders.getExposedHeaders().remove("x-ms-meta-toomany*");
// Test with too many Allowed Prefixed Headers (three)
ruleManyHeaders.getAllowedHeaders().add("x-ms-meta-toomany*");
try {
this.testCorsRules(ruleManyHeaders, client, props, fileServiceProperties);
fail("No exception received. A maximum of 64 allowed headers are allowed.");
}
catch (StorageException e) {
}
catch (Exception e) {
fail("Invalid exception " + e + " received when expecting StorageException");
}
ruleManyHeaders.getExposedHeaders().remove("x-ms-meta-toomany*");
}
/**
* Test Optional Service Properties
*
* @throws StorageException
* @throws InterruptedException
*/
@Test
public void testOptionalServiceProperties() throws StorageException, InterruptedException {
ServiceClient client = TestHelper.createCloudBlobClient();
ServiceProperties props = new ServiceProperties();
props.setDefaultServiceVersion(Constants.HeaderConstants.TARGET_STORAGE_VERSION);
testOptionalServiceProperties(client, props);
client = TestHelper.createCloudQueueClient();
props = new ServiceProperties();
testOptionalServiceProperties(client, props);
client = TestHelper.createCloudTableClient();
props = new ServiceProperties();
testOptionalServiceProperties(client, props);
}
private void testOptionalServiceProperties(ServiceClient client, ServiceProperties props) throws StorageException,
InterruptedException {
// None
props.getLogging().setLogOperationTypes(EnumSet.of(LoggingOperations.READ, LoggingOperations.WRITE));
props.getLogging().setRetentionIntervalInDays(5);
props.getLogging().setVersion("1.0");
// None
props.getHourMetrics().setMetricsLevel(MetricsLevel.SERVICE);
props.getHourMetrics().setRetentionIntervalInDays(6);
props.getHourMetrics().setVersion("1.0");
// None
props.getMinuteMetrics().setMetricsLevel(MetricsLevel.SERVICE);
props.getMinuteMetrics().setRetentionIntervalInDays(6);
props.getMinuteMetrics().setVersion("1.0");
props.getCors().getCorsRules().clear();
callUploadServiceProps(client, props, null);
ServiceProperties newProps = new ServiceProperties();
newProps.setLogging(null);
newProps.setHourMetrics(null);
newProps.setMinuteMetrics(null);
final CorsRule ruleBasic = new CorsRule();
ruleBasic.getAllowedOrigins().addAll(Arrays.asList("www.ab.com", "www.bc.com"));
ruleBasic.getAllowedMethods().addAll(EnumSet.of(CorsHttpMethods.GET, CorsHttpMethods.PUT));
ruleBasic.getAllowedHeaders().addAll(
Arrays.asList("x-ms-meta-data*", "x-ms-meta-target*", "x-ms-meta-xyz", "x-ms-meta-foo"));
ruleBasic.getExposedHeaders().addAll(
Arrays.asList("x-ms-meta-data*", "x-ms-meta-source*", "x-ms-meta-abc", "x-ms-meta-bcd"));
ruleBasic.setMaxAgeInSeconds(500);
newProps.getCors().getCorsRules().add(ruleBasic);
callUploadServiceProps(client, newProps, null);
props.setCors(newProps.getCors());
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
newProps.setLogging(props.getLogging());
newProps.setHourMetrics(props.getHourMetrics());
newProps.setMinuteMetrics(props.getMinuteMetrics());
newProps.setCors(null);
callUploadServiceProps(client, newProps, null);
assertServicePropertiesAreEqual(props, callDownloadServiceProperties(client));
}
private void callUploadServiceProps(
ServiceClient client, ServiceProperties props, FileServiceProperties fileProps)
throws StorageException, InterruptedException {
if (client.getClass().equals(CloudBlobClient.class)) {
((CloudBlobClient) client).uploadServiceProperties(props);
}
else if (client.getClass().equals(CloudTableClient.class)) {
((CloudTableClient) client).uploadServiceProperties(props);
}
else if (client.getClass().equals(CloudQueueClient.class)) {
((CloudQueueClient) client).uploadServiceProperties(props);
}
else if (client.getClass().equals(CloudFileClient.class)) {
((CloudFileClient) client).uploadServiceProperties(fileProps);
}
else {
fail();
}
Thread.sleep(30000);
}
private ServiceProperties callDownloadServiceProperties(ServiceClient client) throws StorageException {
if (client.getClass().equals(CloudBlobClient.class)) {
CloudBlobClient blobClient = (CloudBlobClient) client;
return blobClient.downloadServiceProperties();
}
else if (client.getClass().equals(CloudTableClient.class)) {
CloudTableClient tableClient = (CloudTableClient) client;
return tableClient.downloadServiceProperties();
}
else if (client.getClass().equals(CloudQueueClient.class)) {
CloudQueueClient queueClient = (CloudQueueClient) client;
return queueClient.downloadServiceProperties();
}
else {
fail();
}
return null;
}
/**
* Takes a CorsRule and tries to upload it. Then tries to download it and compares it to the initial CorsRule.
*/
private void testCorsRules(CorsRule rule, ServiceClient client, ServiceProperties properties,
FileServiceProperties fileServiceProperties) throws StorageException, InterruptedException {
CorsProperties cors = (fileServiceProperties == null) ? properties.getCors() : fileServiceProperties.getCors();
cors.getCorsRules().clear();
cors.getCorsRules().add(rule);
if (fileServiceProperties == null) {
callUploadServiceProps(client, properties, null);
assertServicePropertiesAreEqual(properties, callDownloadServiceProperties(client));
} else {
CloudFileClient fileClient = ((CloudFileClient) client);
fileClient.uploadServiceProperties(fileServiceProperties);
Thread.sleep(30000);
assertFileServicePropertiesAreEqual(fileServiceProperties, fileClient.downloadServiceProperties());
}
}
/**
* Takes a List of CorsRules and tries to upload them. Then tries to download them and compares the list to the
* initial CorsRule List.
*/
private void testCorsRules(List<CorsRule> corsRules, ServiceClient client, ServiceProperties properties,
FileServiceProperties fileServiceProperties) throws StorageException, InterruptedException {
CorsProperties cors = (fileServiceProperties == null) ? properties.getCors() : fileServiceProperties.getCors();
cors.getCorsRules().clear();
for (CorsRule rule : corsRules) {
cors.getCorsRules().add(rule);
}
if (fileServiceProperties == null) {
callUploadServiceProps(client, properties, null);
assertServicePropertiesAreEqual(properties, callDownloadServiceProperties(client));
} else {
CloudFileClient fileClient = ((CloudFileClient) client);
fileClient.uploadServiceProperties(fileServiceProperties);
Thread.sleep(30000);
assertFileServicePropertiesAreEqual(fileServiceProperties, fileClient.downloadServiceProperties());
}
}
/**
* Checks two ServiceProperties for equality
*/
private static void assertServicePropertiesAreEqual(ServiceProperties propsA, ServiceProperties propsB) {
if (propsA == null && propsB == null) {
return;
} else {
assertNotNull(propsA);
assertNotNull(propsB);
}
if (propsA.getLogging() != null && propsB.getLogging() != null) {
assertTrue(propsA.getLogging().getLogOperationTypes().equals(propsB.getLogging().getLogOperationTypes()));
assertEquals(propsA.getLogging().getRetentionIntervalInDays(), propsB.getLogging()
.getRetentionIntervalInDays());
assertEquals(propsA.getLogging().getVersion(), propsB.getLogging().getVersion());
}
else {
assertNull(propsA.getLogging());
assertNull(propsB.getLogging());
}
if (propsA.getHourMetrics() != null && propsB.getHourMetrics() != null) {
assertTrue(propsA.getHourMetrics().getMetricsLevel().equals(propsB.getHourMetrics().getMetricsLevel()));
assertEquals(propsA.getHourMetrics().getRetentionIntervalInDays(), propsB.getHourMetrics()
.getRetentionIntervalInDays());
assertEquals(propsA.getHourMetrics().getVersion(), propsB.getHourMetrics().getVersion());
}
else {
assertNull(propsA.getHourMetrics());
assertNull(propsB.getHourMetrics());
}
if (propsA.getMinuteMetrics() != null && propsB.getMinuteMetrics() != null) {
assertTrue(propsA.getMinuteMetrics().getMetricsLevel().equals(propsB.getMinuteMetrics().getMetricsLevel()));
assertEquals(propsA.getMinuteMetrics().getRetentionIntervalInDays(), propsB.getMinuteMetrics()
.getRetentionIntervalInDays());
assertEquals(propsA.getMinuteMetrics().getVersion(), propsB.getMinuteMetrics().getVersion());
}
else {
assertNull(propsA.getMinuteMetrics());
assertNull(propsB.getMinuteMetrics());
}
if (propsA.getDefaultServiceVersion() != null && propsB.getDefaultServiceVersion() != null) {
assertEquals(propsA.getDefaultServiceVersion(), propsB.getDefaultServiceVersion());
}
else {
assertNull(propsA.getDefaultServiceVersion());
assertNull(propsB.getDefaultServiceVersion());
}
if (propsA.getCors() != null && propsB.getCors() != null) {
assertEquals(propsA.getCors().getCorsRules().size(), propsB.getCors().getCorsRules().size());
// Check that rules are equal and in the same order.
for (int i = 0; i < propsA.getCors().getCorsRules().size(); i++) {
CorsRule ruleA = propsA.getCors().getCorsRules().get(i);
CorsRule ruleB = propsB.getCors().getCorsRules().get(i);
assertTrue(ruleA.getAllowedOrigins().size() == ruleB.getAllowedOrigins().size()
&& ruleA.getAllowedOrigins().containsAll(ruleB.getAllowedOrigins()));
assertTrue(ruleA.getExposedHeaders().size() == ruleB.getExposedHeaders().size()
&& ruleA.getExposedHeaders().containsAll(ruleB.getExposedHeaders()));
assertTrue(ruleA.getAllowedHeaders().size() == ruleB.getAllowedHeaders().size()
&& ruleA.getAllowedHeaders().containsAll(ruleB.getAllowedHeaders()));
assertTrue(ruleA.getAllowedMethods().equals(ruleB.getAllowedMethods()));
assertTrue(ruleA.getMaxAgeInSeconds() == ruleB.getMaxAgeInSeconds());
}
}
else {
assertNull(propsA.getCors());
assertNull(propsB.getCors());
}
}
/**
* Checks the CORS rules of two <code>FileServiceProperties</code> objects to ensure they match.
*
* @param original
* The <code>FileServiceProperties</code> used as a point of comparison
* @param target
* The generated <code>FileServiceProperties</code>, which should match the original
*/
private static void assertFileServicePropertiesAreEqual(FileServiceProperties original, FileServiceProperties target) {
if (original == null && target == null) {
return;
} else {
assertNotNull(original);
assertNotNull(target);
}
if (original.getCors() != null && target.getCors() != null) {
assertEquals(original.getCors().getCorsRules().size(), target.getCors().getCorsRules().size());
// Check that rules are equal and in the same order.
for (int i = 0; i < original.getCors().getCorsRules().size(); i++) {
CorsRule ruleOriginal = original.getCors().getCorsRules().get(i);
CorsRule ruleTarget = target.getCors().getCorsRules().get(i);
assertTrue(ruleOriginal.getAllowedOrigins().size() == ruleTarget.getAllowedOrigins().size());
assertTrue(ruleOriginal.getAllowedOrigins().containsAll(ruleTarget.getAllowedOrigins()));
assertTrue(ruleOriginal.getExposedHeaders().size() == ruleTarget.getExposedHeaders().size());
assertTrue(ruleOriginal.getExposedHeaders().containsAll(ruleTarget.getExposedHeaders()));
assertTrue(ruleOriginal.getAllowedHeaders().size() == ruleTarget.getAllowedHeaders().size());
assertTrue(ruleOriginal.getAllowedHeaders().containsAll(ruleTarget.getAllowedHeaders()));
assertTrue(ruleOriginal.getAllowedMethods().equals(ruleTarget.getAllowedMethods()));
assertTrue(ruleOriginal.getMaxAgeInSeconds() == ruleTarget.getMaxAgeInSeconds());
}
}
else {
assertNull(original.getCors());
assertNull(target.getCors());
}
}
}