/** * 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.file; import com.microsoft.azure.storage.NameValidator; import com.microsoft.azure.storage.OperationContext; import com.microsoft.azure.storage.SendingRequestEvent; import com.microsoft.azure.storage.StorageErrorCodeStrings; import com.microsoft.azure.storage.StorageEvent; import com.microsoft.azure.storage.StorageException; 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.core.SR; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URISyntaxException; import java.util.Calendar; import java.util.Date; import java.util.EnumSet; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.TimeZone; import static org.junit.Assert.*; /** * File Share Tests */ @Category({ DevFabricTests.class, DevStoreTests.class, CloudTests.class }) public class CloudFileShareTests { protected static CloudFileClient client; protected CloudFileShare share; @Before public void fileShareTestMethodSetUp() throws StorageException, URISyntaxException { this.share = FileTestHelper.getRandomShareReference(); } @After public void fileShareTestMethodTearDown() throws StorageException { this.share.deleteIfExists(); } /** * Test share name validation. */ @Test public void testCloudShareNameValidation() { NameValidator.validateShareName("alpha"); NameValidator.validateShareName("4lphanum3r1c"); NameValidator.validateShareName("middle-dash"); invalidShareTestHelper(null, "Null not allowed.", "Invalid share name. The name may not be null, empty, or whitespace only."); invalidShareTestHelper("$root", "Alphanumeric or dashes only.", "Invalid share name. Check MSDN for more information about valid naming."); invalidShareTestHelper("double--dash", "No double dash.", "Invalid share name. Check MSDN for more information about valid naming."); invalidShareTestHelper("CapsLock", "Lowercase only.", "Invalid share name. Check MSDN for more information about valid naming."); invalidShareTestHelper("illegal$char", "Alphanumeric or dashes only.", "Invalid share name. Check MSDN for more information about valid naming."); invalidShareTestHelper("illegal!char", "Alphanumeric or dashes only.", "Invalid share name. Check MSDN for more information about valid naming."); invalidShareTestHelper("white space", "Alphanumeric or dashes only.", "Invalid share name. Check MSDN for more information about valid naming."); invalidShareTestHelper("2c", "Between 3 and 63 characters.", "Invalid share name length. The name must be between 3 and 63 characters long."); invalidShareTestHelper(new String(new char[64]).replace("\0", "n"), "Between 3 and 63 characters.", "Invalid share name length. The name must be between 3 and 63 characters long."); } private void invalidShareTestHelper(String shareName, String failMessage, String exceptionMessage) { try { NameValidator.validateShareName(shareName); fail(failMessage); } catch (IllegalArgumentException e) { assertEquals(exceptionMessage, e.getMessage()); } } /** * Validate share references * * @throws StorageException * @throws URISyntaxException */ @Test public void testCloudFileShareReference() throws StorageException, URISyntaxException { CloudFileClient client = FileTestHelper.createCloudFileClient(); CloudFileShare share = client.getShareReference("share"); CloudFileDirectory directory = share.getRootDirectoryReference().getDirectoryReference("directory3"); CloudFileDirectory directory2 = directory.getDirectoryReference("directory4"); assertEquals(share.getStorageUri().toString(), directory.getShare().getStorageUri().toString()); assertEquals(share.getStorageUri().toString(), directory2.getShare().getStorageUri().toString()); assertEquals(share.getStorageUri().toString(), directory2.getParent().getShare().getStorageUri().toString()); } /** * Try to create a share after it is created * * @throws StorageException */ @Test public void testCloudFileShareCreate() throws StorageException { this.share.create(); assertTrue(this.share.exists()); try { this.share.create(); fail("Share already existed but was created anyway."); } catch (StorageException e) { assertEquals(e.getErrorCode(), "ShareAlreadyExists"); assertEquals(e.getHttpStatusCode(), 409); assertEquals(e.getMessage(), "The specified share already exists."); } } /** * CreateIfNotExists test. * * @throws StorageException */ @Test public void testCloudFileShareCreateIfNotExists() throws StorageException { assertTrue(this.share.createIfNotExists()); assertTrue(this.share.exists()); assertFalse(this.share.createIfNotExists()); } /** * DeleteIfExists test. * * @throws StorageException */ @Test public void testCloudFileShareDeleteIfExists() throws StorageException { assertFalse(this.share.deleteIfExists()); this.share.create(); assertTrue(this.share.deleteIfExists()); assertFalse(this.share.exists()); assertFalse(this.share.deleteIfExists()); } /** * Check a share's existence * * @throws StorageException */ @Test public void testCloudFileShareExists() throws StorageException { assertFalse(this.share.exists()); this.share.create(); assertTrue(this.share.exists()); assertNotNull(this.share.getProperties().getEtag()); this.share.delete(); assertFalse(this.share.exists()); } /** * Set and delete share permissions * * @throws URISyntaxException * @throws StorageException * @throws InterruptedException */ @Test @Category({ SlowTests.class, DevFabricTests.class, DevStoreTests.class }) public void testCloudFileShareSetPermissions() throws StorageException, InterruptedException, URISyntaxException { CloudFileClient client = FileTestHelper.createCloudFileClient(); this.share.create(); FileSharePermissions permissions = this.share.downloadPermissions(); assertEquals(0, permissions.getSharedAccessPolicies().size()); final Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); final Date start = cal.getTime(); cal.add(Calendar.MINUTE, 30); final Date expiry = cal.getTime(); SharedAccessFilePolicy policy = new SharedAccessFilePolicy(); policy.setPermissions(EnumSet.of(SharedAccessFilePermissions.LIST, SharedAccessFilePermissions.CREATE)); policy.setSharedAccessStartTime(start); policy.setSharedAccessExpiryTime(expiry); permissions.getSharedAccessPolicies().put("key1", policy); // Set permissions and wait for them to propagate this.share.uploadPermissions(permissions); Thread.sleep(30000); // Check if permissions were set CloudFileShare share2 = client.getShareReference(this.share.getName()); assertPermissionsEqual(permissions, share2.downloadPermissions()); // Clear permissions and wait for them to propagate permissions.getSharedAccessPolicies().clear(); this.share.uploadPermissions(permissions); Thread.sleep(30000); // Check if permissions were cleared assertPermissionsEqual(permissions, share2.downloadPermissions()); } /** * Get permissions from string */ @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testCloudFileSharePermissionsFromString() { SharedAccessFilePolicy policy = new SharedAccessFilePolicy(); policy.setPermissionsFromString("rcwdl"); assertEquals(EnumSet.of(SharedAccessFilePermissions.READ, SharedAccessFilePermissions.CREATE, SharedAccessFilePermissions.WRITE, SharedAccessFilePermissions.DELETE, SharedAccessFilePermissions.LIST), policy.getPermissions()); policy.setPermissionsFromString("rwdl"); assertEquals(EnumSet.of(SharedAccessFilePermissions.READ, SharedAccessFilePermissions.WRITE, SharedAccessFilePermissions.DELETE, SharedAccessFilePermissions.LIST), policy.getPermissions()); policy.setPermissionsFromString("rwl"); assertEquals(EnumSet.of(SharedAccessFilePermissions.READ, SharedAccessFilePermissions.WRITE, SharedAccessFilePermissions.LIST), policy.getPermissions()); policy.setPermissionsFromString("wr"); assertEquals(EnumSet.of(SharedAccessFilePermissions.WRITE, SharedAccessFilePermissions.READ), policy.getPermissions()); policy.setPermissionsFromString("d"); assertEquals(EnumSet.of(SharedAccessFilePermissions.DELETE), policy.getPermissions()); } /** * Write permission to string */ @Test @Category({ DevFabricTests.class, DevStoreTests.class }) public void testCloudFileSharePermissionsToString() { SharedAccessFilePolicy policy = new SharedAccessFilePolicy(); policy.setPermissions(EnumSet.of(SharedAccessFilePermissions.READ, SharedAccessFilePermissions.CREATE, SharedAccessFilePermissions.WRITE, SharedAccessFilePermissions.DELETE, SharedAccessFilePermissions.LIST)); assertEquals("rcwdl", policy.permissionsToString()); policy.setPermissions(EnumSet.of(SharedAccessFilePermissions.READ, SharedAccessFilePermissions.WRITE, SharedAccessFilePermissions.DELETE, SharedAccessFilePermissions.LIST)); assertEquals("rwdl", policy.permissionsToString()); policy.setPermissions(EnumSet.of(SharedAccessFilePermissions.READ, SharedAccessFilePermissions.WRITE, SharedAccessFilePermissions.LIST)); assertEquals("rwl", policy.permissionsToString()); policy.setPermissions(EnumSet.of(SharedAccessFilePermissions.WRITE, SharedAccessFilePermissions.READ)); assertEquals("rw", policy.permissionsToString()); policy.setPermissions(EnumSet.of(SharedAccessFilePermissions.DELETE)); assertEquals("d", policy.permissionsToString()); } /** * Check uploading/downloading share metadata. * * @throws StorageException * @throws URISyntaxException */ @Test public void testCloudFileShareUploadMetadata() throws StorageException, URISyntaxException { this.share.getMetadata().put("key1", "value1"); this.share.create(); assertEquals(1, this.share.getMetadata().size()); assertEquals("value1", this.share.getMetadata().get("key1")); CloudFileShare share2 = this.share.getServiceClient().getShareReference(this.share.getName()); share2.downloadAttributes(); assertEquals(1, share2.getMetadata().size()); assertEquals("value1", share2.getMetadata().get("key1")); this.share.getMetadata().put("key2", "value2"); assertEquals(2, this.share.getMetadata().size()); assertEquals("value1", this.share.getMetadata().get("key1")); assertEquals("value2", this.share.getMetadata().get("key2")); this.share.uploadMetadata(); assertEquals(2, this.share.getMetadata().size()); assertEquals("value1", this.share.getMetadata().get("key1")); assertEquals("value2", this.share.getMetadata().get("key2")); share2.downloadAttributes(); assertEquals(2, this.share.getMetadata().size()); assertEquals("value1", this.share.getMetadata().get("key1")); assertEquals("value2", this.share.getMetadata().get("key2")); Iterable<CloudFileShare> shares = this.share.getServiceClient().listShares(this.share.getName(), ShareListingDetails.METADATA, null, null); for (CloudFileShare share3 : shares) { assertEquals(2, share3.getMetadata().size()); assertEquals("value1", share3.getMetadata().get("key1")); assertEquals("value2", this.share.getMetadata().get("key2")); } this.share.getMetadata().clear(); this.share.uploadMetadata(); share2.downloadAttributes(); assertEquals(0, share2.getMetadata().size()); } /** * Check uploading/downloading invalid share metadata. */ @Test public void testCloudFileShareInvalidMetadata() { // test client-side fails correctly testMetadataFailures(this.share, null, "value1", true); testMetadataFailures(this.share, "", "value1", true); testMetadataFailures(this.share, " ", "value1", true); testMetadataFailures(this.share, "\n \t", "value1", true); testMetadataFailures(this.share, "key1", null, false); testMetadataFailures(this.share, "key1", "", false); testMetadataFailures(this.share, "key1", " ", false); testMetadataFailures(this.share, "key1", "\n \t", false); } private static void testMetadataFailures(CloudFileShare share, String key, String value, boolean badKey) { share.getMetadata().put(key, value); try { share.uploadMetadata(); fail(SR.METADATA_KEY_INVALID); } catch (StorageException e) { if (badKey) { assertEquals(SR.METADATA_KEY_INVALID, e.getMessage()); } else { assertEquals(SR.METADATA_VALUE_INVALID, e.getMessage()); } } share.getMetadata().remove(key); } /** * Tests whether Share Stats can be updated and downloaded. * * @throws StorageException * @throws IOException * @throws URISyntaxException */ @Test @Category({ CloudTests.class }) public void testGetShareStats() throws StorageException, IOException, URISyntaxException { share.createIfNotExists(); ShareStats stats = share.getStats(); assertNotNull(stats); assertEquals(0, stats.getUsage()); FileTestHelper.uploadNewFile(share, 512, null); stats = share.getStats(); assertNotNull(stats); assertEquals(1, stats.getUsage()); } /** * Test that Share Quota can be set, but only to allowable values. * * @throws StorageException * @throws URISyntaxException */ @Test public void testCloudFileShareQuota() throws StorageException, URISyntaxException { // Share quota defaults to 5120 this.share.createIfNotExists(); this.share.downloadAttributes(); assertNotNull(this.share.getProperties().getShareQuota()); int shareQuota = FileConstants.MAX_SHARE_QUOTA; assertEquals(shareQuota, this.share.getProperties().getShareQuota().intValue()); // Upload new share quota shareQuota = 8; this.share.getProperties().setShareQuota(shareQuota); this.share.uploadProperties(); this.share.downloadAttributes(); assertNotNull(this.share.getProperties().getShareQuota()); assertEquals(shareQuota, this.share.getProperties().getShareQuota().intValue()); this.share.delete(); // Create a share with quota already set shareQuota = 16; this.share = FileTestHelper.getRandomShareReference(); this.share.getProperties().setShareQuota(shareQuota); this.share.create(); assertNotNull(this.share.getProperties().getShareQuota()); assertEquals(shareQuota, this.share.getProperties().getShareQuota().intValue()); this.share.downloadAttributes(); assertNotNull(this.share.getProperties().getShareQuota()); assertEquals(shareQuota, this.share.getProperties().getShareQuota().intValue()); // Attempt to set illegal share quota try { shareQuota = FileConstants.MAX_SHARE_QUOTA + 1; this.share.getProperties().setShareQuota(shareQuota); fail(); } catch (IllegalArgumentException e) { assertEquals(String.format(SR.PARAMETER_NOT_IN_RANGE, "Share Quota", 1, FileConstants.MAX_SHARE_QUOTA), e.getMessage()); } } /** * Test that Share Quota can be set, but only to allowable values. * * @throws StorageException * @throws URISyntaxException */ @Test public void testCloudFileShareQuotaListing() throws StorageException, URISyntaxException { int shareQuota = 16; this.share.getProperties().setShareQuota(shareQuota); this.share.createIfNotExists(); Iterable<CloudFileShare> shares = this.share.getServiceClient().listShares(this.share.getName()); for (CloudFileShare fileShare : shares) { assertEquals(shareQuota, fileShare.getProperties().getShareQuota().intValue()); } } /** * Test specific deleteIfExists case. * * @throws StorageException */ @Test public void testCloudFileShareDeleteIfExistsErrorCode() throws StorageException { try { this.share.delete(); fail("Share should not already exist."); } catch (StorageException e) { assertEquals(StorageErrorCodeStrings.SHARE_NOT_FOUND, e.getErrorCode()); } OperationContext ctx = new OperationContext(); ctx.getSendingRequestEventHandler().addListener(new StorageEvent<SendingRequestEvent>() { @Override public void eventOccurred(SendingRequestEvent eventArg) { if (((HttpURLConnection) eventArg.getConnectionObject()).getRequestMethod().equals("DELETE")) { try { CloudFileShareTests.this.share.delete(); assertFalse(CloudFileShareTests.this.share.exists()); } catch (StorageException e) { fail("Delete should succeed."); } } } }); this.share.create(); // Share deletes succeed before garbage collection occurs. assertTrue(this.share.deleteIfExists(null, null, ctx)); } private static void assertPermissionsEqual(FileSharePermissions expected, FileSharePermissions actual) { HashMap<String, SharedAccessFilePolicy> expectedPolicies = expected.getSharedAccessPolicies(); HashMap<String, SharedAccessFilePolicy> actualPolicies = actual.getSharedAccessPolicies(); assertEquals("SharedAccessPolicies.Count", expectedPolicies.size(), actualPolicies.size()); for (String name : expectedPolicies.keySet()) { assertTrue("Key" + name + " doesn't exist", actualPolicies.containsKey(name)); SharedAccessFilePolicy expectedPolicy = expectedPolicies.get(name); SharedAccessFilePolicy actualPolicy = actualPolicies.get(name); assertEquals("Policy: " + name + "\tPermissions\n", expectedPolicy.getPermissions().toString(), actualPolicy.getPermissions().toString()); assertEquals("Policy: " + name + "\tStartDate\n", expectedPolicy.getSharedAccessStartTime().toString(), actualPolicy.getSharedAccessStartTime().toString()); assertEquals("Policy: " + name + "\tExpireDate\n", expectedPolicy.getSharedAccessExpiryTime().toString(), actualPolicy.getSharedAccessExpiryTime().toString()); } } }