/** * 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 static org.junit.Assert.*; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.microsoft.azure.keyvault.extensions.RsaKey; import com.microsoft.azure.keyvault.extensions.SymmetricKey; import com.microsoft.azure.storage.analytics.CloudAnalyticsClient; import com.microsoft.azure.storage.blob.CloudBlobClient; import com.microsoft.azure.storage.file.CloudFileClient; import com.microsoft.azure.storage.queue.CloudQueueClient; import com.microsoft.azure.storage.table.CloudTableClient; public class TestHelper { private static Tenant tenant; private static StorageCredentialsAccountAndKey credentials; private static CloudStorageAccount account; private final static boolean enableFiddler = true; private final static boolean requireSecondaryEndpoint = false; public static CloudBlobClient createCloudBlobClient() throws StorageException { CloudBlobClient client = getAccount().createCloudBlobClient(); return client; } public static CloudBlobClient createCloudBlobClient(SharedAccessAccountPolicy policy, boolean useHttps) throws StorageException, InvalidKeyException, URISyntaxException { CloudStorageAccount sasAccount = getAccount(); final String token = sasAccount.generateSharedAccessSignature(policy); final StorageCredentials creds = new StorageCredentialsSharedAccessSignature(token); sasAccount = new CloudStorageAccount( creds, TestHelper.securePortUri(sasAccount.getBlobEndpoint(), useHttps, 'b'), sasAccount.getQueueEndpoint(), sasAccount.getTableEndpoint(), sasAccount.getFileEndpoint()); return sasAccount.createCloudBlobClient(); } public static CloudFileClient createCloudFileClient() throws StorageException { CloudFileClient client = getAccount().createCloudFileClient(); return client; } public static CloudFileClient createCloudFileClient(SharedAccessAccountPolicy policy, boolean useHttps) throws StorageException, InvalidKeyException, URISyntaxException { CloudStorageAccount sasAccount = getAccount(); final String token = sasAccount.generateSharedAccessSignature(policy); final StorageCredentials creds = new StorageCredentialsSharedAccessSignature(token); sasAccount = new CloudStorageAccount( creds, sasAccount.getBlobEndpoint(), sasAccount.getQueueEndpoint(), sasAccount.getTableEndpoint(), TestHelper.securePortUri(sasAccount.getFileEndpoint(), useHttps, 'f')); return sasAccount.createCloudFileClient(); } public static CloudQueueClient createCloudQueueClient() throws StorageException { CloudQueueClient client = getAccount().createCloudQueueClient(); return client; } public static CloudQueueClient createCloudQueueClient(SharedAccessAccountPolicy policy, boolean useHttps) throws StorageException, InvalidKeyException, URISyntaxException { CloudStorageAccount sasAccount = getAccount(); final String token = sasAccount.generateSharedAccessSignature(policy); final StorageCredentials creds = new StorageCredentialsSharedAccessSignature(token); sasAccount = new CloudStorageAccount( creds, sasAccount.getBlobEndpoint(), TestHelper.securePortUri(sasAccount.getQueueEndpoint(), useHttps, 'q'), sasAccount.getTableEndpoint(), sasAccount.getFileEndpoint()); return sasAccount.createCloudQueueClient(); } public static CloudTableClient createCloudTableClient() throws StorageException { CloudTableClient client = getAccount().createCloudTableClient(); return client; } public static CloudTableClient createCloudTableClient(SharedAccessAccountPolicy policy, boolean useHttps) throws StorageException, InvalidKeyException, URISyntaxException { CloudStorageAccount sasAccount = getAccount(); final String token = sasAccount.generateSharedAccessSignature(policy); final StorageCredentials creds = new StorageCredentialsSharedAccessSignature(token); sasAccount = new CloudStorageAccount( creds, sasAccount.getBlobEndpoint(), sasAccount.getQueueEndpoint(), TestHelper.securePortUri(sasAccount.getTableEndpoint(), useHttps, 't'), sasAccount.getFileEndpoint()); return sasAccount.createCloudTableClient(); } public static CloudAnalyticsClient createCloudAnalyticsClient() throws StorageException { CloudAnalyticsClient client = getAccount().createCloudAnalyticsClient(); return client; } protected static void enableFiddler() { System.setProperty("http.proxyHost", "localhost"); System.setProperty("http.proxyPort", "8888"); } public static byte[] getRandomBuffer(int length) { final Random randGenerator = new Random(); final byte[] buff = new byte[length]; randGenerator.nextBytes(buff); return buff; } public static ByteArrayInputStream getRandomDataStream(int length) { return new ByteArrayInputStream(getRandomBuffer(length)); } public static URI securePortUri(URI uri, boolean useHttps, char service) throws URISyntaxException { Integer port = null; String scheme; if (useHttps) { if (TestHelper.tenant != null) { switch(service) { case 'b' : port = TestHelper.tenant.getBlobHttpsPortOverride(); break; case 'f' : port = TestHelper.tenant.getFileHttpsPortOverride(); break; case 't' : port = TestHelper.tenant.getTableHttpsPortOverride(); break; case 'q' : port = TestHelper.tenant.getQueueHttpsPortOverride(); break; default : fail(); } } scheme = Constants.HTTPS; if (port == null) { port = 443; } } else { scheme = Constants.HTTP; port = uri.getPort(); } return new URI(scheme, uri.getUserInfo(), uri.getHost(), port, uri.getPath(), uri.getQuery(), uri.getFragment()); } public static void assertStreamsAreEqual(InputStream src, InputStream dst) throws IOException { dst.reset(); src.reset(); int next = src.read(); while (next != -1) { assertEquals(next, dst.read()); next = src.read(); } next = dst.read(); while (next != -1) { assertEquals(0, next); next = dst.read(); } } public static void assertStreamsAreEqualAtIndex(ByteArrayInputStream src, ByteArrayInputStream dst, int srcIndex, int dstIndex, int length, int bufferSize) throws IOException { dst.reset(); src.reset(); dst.skip(dstIndex); src.skip(srcIndex); for (int i = 0; i < length; i++) { assertEquals(src.read(), dst.read()); } } public static void assertURIsEqual(URI expected, URI actual, boolean ignoreQueryOrder) { if (expected == null) { assertEquals(null, actual); } assertEquals(expected.getScheme(), actual.getScheme()); assertEquals(expected.getAuthority(), actual.getAuthority()); assertEquals(expected.getPath(), actual.getPath()); assertEquals(expected.getFragment(), actual.getFragment()); ArrayList<String> expectedQueries = new ArrayList<String>(Arrays.asList(expected.getQuery().split("&"))); ArrayList<String> actualQueries = new ArrayList<String>(Arrays.asList(actual.getQuery().split("&"))); assertEquals(expectedQueries.size(), actualQueries.size()); for (String expectedQuery : expectedQueries) { assertTrue(expectedQuery, actualQueries.remove(expectedQuery)); } assertTrue(actualQueries.isEmpty()); } public static URI defiddler(URI uri) throws URISyntaxException { String fiddlerString = "ipv4.fiddler"; String replacementString = "127.0.0.1"; String uriString = uri.toString(); if (uriString.contains(fiddlerString)) { return new URI(uriString.replace(fiddlerString, replacementString)); } else { return uri; } } public static SymmetricKey getSymmetricKey() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(128); SecretKey wrapKey = keyGen.generateKey(); return new SymmetricKey("symmKey1", wrapKey.getEncoded()); } public static RsaKey getRSAKey() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(1024); final KeyPair wrapKey = keyGen.generateKeyPair(); return new RsaKey("rsaKey1", wrapKey); } public static void verifyServiceStats(ServiceStats stats) { assertNotNull(stats); if (stats.getGeoReplication().getLastSyncTime() != null) { assertEquals(GeoReplicationStatus.LIVE, stats.getGeoReplication().getStatus()); } else { assertTrue(stats.getGeoReplication().getStatus() == GeoReplicationStatus.BOOTSTRAP || stats.getGeoReplication().getStatus() == GeoReplicationStatus.UNAVAILABLE); } } private static CloudStorageAccount getAccount() throws StorageException { // Only do this the first time TestBase is called as storage account is static if (account == null) { //enable fiddler if (enableFiddler) enableFiddler(); // try to get the environment variable with the connection string String cloudAccount; try { cloudAccount = System.getenv("storageConnection"); } catch (SecurityException e) { cloudAccount = null; } // try to get the environment variable with the test configuration file path String accountConfig; try { accountConfig = System.getenv("storageTestConfiguration"); } catch (SecurityException e) { accountConfig = null; } // if storageConnection is set, use that as an account string // if storageTestConfiguration is set, use that as a path to the configurations file // if neither are set, use the local configurations file at TestConfigurations.xml try { if (cloudAccount != null) { account = CloudStorageAccount.parse(cloudAccount); } else if (accountConfig != null) { tenant = readTestConfigsFromXml(new File(accountConfig)); setAccountAndCredentials(); } else { URL localTestConfig = TestHelper.class.getClassLoader().getResource("TestConfigurations.xml"); tenant = readTestConfigsFromXml(new File(localTestConfig.getPath())); setAccountAndCredentials(); } } catch (Exception e) { throw StorageException.translateClientException(e); } } return account; } private static void setAccountAndCredentials() { if (requireSecondaryEndpoint) tenant.assertSecondaryEndpoint(); credentials = new StorageCredentialsAccountAndKey(tenant.getAccountName(), tenant.getAccountKey()); account = new CloudStorageAccount(credentials, new StorageUri(tenant.getBlobServiceEndpoint(), tenant.getBlobServiceSecondaryEndpoint()), new StorageUri(tenant.getQueueServiceEndpoint(), tenant.getQueueServiceSecondaryEndpoint()), new StorageUri(tenant.getTableServiceEndpoint(), tenant.getTableServiceSecondaryEndpoint()), new StorageUri(tenant.getFileServiceEndpoint(), tenant.getFileServiceSecondaryEndpoint())); } private static Tenant readTestConfigsFromXml(File testConfigurations) throws ParserConfigurationException, SAXException, IOException, DOMException, URISyntaxException { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document testConfigs = documentBuilder.parse(testConfigurations); testConfigs.getDocumentElement().normalize(); Node targetTenantNode = testConfigs.getElementsByTagName("TargetTestTenant").item(0); String targetTenant = null; if (targetTenantNode != null) { targetTenant = testConfigs.getElementsByTagName("TargetTestTenant").item(0).getTextContent(); } else { throw new IllegalArgumentException("No TargetTestTenant specified."); } Tenant tenant = null; final NodeList tenantNodes = testConfigs.getElementsByTagName("TenantName"); for (int i = 0; i < tenantNodes.getLength(); i++) { if (tenantNodes.item(i).getTextContent().equals(targetTenant)) { tenant = new Tenant(); Node parent = tenantNodes.item(i).getParentNode(); final NodeList childNodes = parent.getChildNodes(); for (int j = 0; j < childNodes.getLength(); j++) { final Node node = childNodes.item(j); if (node.getNodeType() != Node.ELEMENT_NODE) { // do nothing } else { final String name = node.getNodeName(); if (name.equals("TenantName")) { tenant.setTenantName(node.getTextContent()); } else if (name.equals("TenantType")) { // do nothing, we don't track this field } else if (name.equals("AccountName")) { tenant.setAccountName(node.getTextContent()); } else if (name.equals("AccountKey")) { tenant.setAccountKey(node.getTextContent()); } else if (name.equals("BlobServiceEndpoint")) { tenant.setBlobServiceEndpoint(new URI(node.getTextContent())); } else if (name.equals("QueueServiceEndpoint")) { tenant.setQueueServiceEndpoint(new URI(node.getTextContent())); } else if (name.equals("TableServiceEndpoint")) { tenant.setTableServiceEndpoint(new URI(node.getTextContent())); } else if (name.equals("FileServiceEndpoint")) { tenant.setFileServiceEndpoint(new URI(node.getTextContent())); } else if (name.equals("BlobServiceSecondaryEndpoint")) { tenant.setBlobServiceSecondaryEndpoint(new URI(node.getTextContent())); } else if (name.equals("QueueServiceSecondaryEndpoint")) { tenant.setQueueServiceSecondaryEndpoint(new URI(node.getTextContent())); } else if (name.equals("TableServiceSecondaryEndpoint")) { tenant.setTableServiceSecondaryEndpoint(new URI(node.getTextContent())); } else if (name.equals("FileServiceSecondaryEndpoint")) { tenant.setFileServiceSecondaryEndpoint(new URI(node.getTextContent())); } else if (name.equals("BlobHttpsPortOverride")) { tenant.setBlobHttpsPortOverride(Integer.parseInt(node.getTextContent())); } else if (name.equals("QueueHttpsPortOverride")) { tenant.setQueueHttpsPortOverride(Integer.parseInt(node.getTextContent())); } else if (name.equals("TableHttpsPortOverride")) { tenant.setTableHttpsPortOverride(Integer.parseInt(node.getTextContent())); } else if (name.equals("FileHttpsPortOverride")) { tenant.setFileHttpsPortOverride(Integer.parseInt(node.getTextContent())); } else { throw new IllegalArgumentException(String.format( "Invalid child of TenantConfiguration with name: %s", name)); } } } } } if (tenant == null) { throw new IllegalArgumentException("TargetTestTenant specified did not exist in TenantConfigurations."); } return tenant; } }