/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.fs.azure; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.io.Closeable; import java.io.IOException; import java.net.URI; import java.util.HashMap; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.security.UserGroupInformation; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Tests that we put the correct metadata on blobs created through WASB. */ public class TestBlobMetadata { private AzureBlobStorageTestAccount testAccount; private FileSystem fs; private InMemoryBlockBlobStore backingStore; @Before public void setUp() throws Exception { testAccount = AzureBlobStorageTestAccount.createMock(); fs = testAccount.getFileSystem(); backingStore = testAccount.getMockStorage().getBackingStore(); } @After public void tearDown() throws Exception { testAccount.cleanup(); fs = null; backingStore = null; } private static String getExpectedOwner() throws Exception { return UserGroupInformation.getCurrentUser().getShortUserName(); } private static String getExpectedPermissionString(String permissionString) throws Exception { return String.format( "{\"owner\":\"%s\",\"group\":\"%s\",\"permissions\":\"%s\"}", getExpectedOwner(), NativeAzureFileSystem.AZURE_DEFAULT_GROUP_DEFAULT, permissionString); } /** * Tests that WASB stamped the version in the container metadata. */ @Test public void testContainerVersionMetadata() throws Exception { // Do a write operation to trigger version stamp fs.createNewFile(new Path("/foo")); HashMap<String, String> containerMetadata = backingStore.getContainerMetadata(); assertNotNull(containerMetadata); assertEquals(AzureNativeFileSystemStore.CURRENT_WASB_VERSION, containerMetadata.get(AzureNativeFileSystemStore.VERSION_METADATA_KEY)); } private static final class FsWithPreExistingContainer implements Closeable { private final MockStorageInterface mockStorage; private final NativeAzureFileSystem fs; private FsWithPreExistingContainer(MockStorageInterface mockStorage, NativeAzureFileSystem fs) { this.mockStorage = mockStorage; this.fs = fs; } public NativeAzureFileSystem getFs() { return fs; } public HashMap<String, String> getContainerMetadata() { return mockStorage.getBackingStore().getContainerMetadata(); } public static FsWithPreExistingContainer create() throws Exception { return create(null); } public static FsWithPreExistingContainer create( HashMap<String, String> containerMetadata) throws Exception { AzureNativeFileSystemStore store = new AzureNativeFileSystemStore(); MockStorageInterface mockStorage = new MockStorageInterface(); store.setAzureStorageInteractionLayer(mockStorage); NativeAzureFileSystem fs = new NativeAzureFileSystem(store); Configuration conf = new Configuration(); AzureBlobStorageTestAccount.setMockAccountKey(conf); mockStorage.addPreExistingContainer( AzureBlobStorageTestAccount.getMockContainerUri(), containerMetadata); fs.initialize(new URI(AzureBlobStorageTestAccount.MOCK_WASB_URI), conf); return new FsWithPreExistingContainer(mockStorage, fs); } @Override public void close() throws IOException { fs.close(); } } /** * Tests that WASB stamped the version in the container metadata if it does a * write operation to a pre-existing container. */ @Test public void testPreExistingContainerVersionMetadata() throws Exception { // Create a mock storage with a pre-existing container that has no // WASB version metadata on it. FsWithPreExistingContainer fsWithContainer = FsWithPreExistingContainer .create(); // Now, do some read operations (should touch the metadata) assertFalse(fsWithContainer.getFs().exists(new Path("/IDontExist"))); assertEquals(0, fsWithContainer.getFs().listStatus(new Path("/")).length); // Check that no container metadata exists yet assertNull(fsWithContainer.getContainerMetadata()); // Now do a write operation - should stamp the version fsWithContainer.getFs().mkdirs(new Path("/dir")); // Check that now we have the version stamp assertNotNull(fsWithContainer.getContainerMetadata()); assertEquals( AzureNativeFileSystemStore.CURRENT_WASB_VERSION, fsWithContainer.getContainerMetadata().get( AzureNativeFileSystemStore.VERSION_METADATA_KEY)); fsWithContainer.close(); } /** * Tests that WASB works well with an older version container with ASV-era * version and metadata. */ @Test public void testFirstContainerVersionMetadata() throws Exception { // Create a mock storage with a pre-existing container that has // ASV version metadata on it. HashMap<String, String> containerMetadata = new HashMap<String, String>(); containerMetadata.put(AzureNativeFileSystemStore.OLD_VERSION_METADATA_KEY, AzureNativeFileSystemStore.FIRST_WASB_VERSION); FsWithPreExistingContainer fsWithContainer = FsWithPreExistingContainer .create(containerMetadata); // Now, do some read operations (should touch the metadata) assertFalse(fsWithContainer.getFs().exists(new Path("/IDontExist"))); assertEquals(0, fsWithContainer.getFs().listStatus(new Path("/")).length); // Check that no container metadata exists yet assertEquals( AzureNativeFileSystemStore.FIRST_WASB_VERSION, fsWithContainer.getContainerMetadata().get( AzureNativeFileSystemStore.OLD_VERSION_METADATA_KEY)); assertNull(fsWithContainer.getContainerMetadata().get( AzureNativeFileSystemStore.VERSION_METADATA_KEY)); // Now do a write operation - should stamp the version fsWithContainer.getFs().mkdirs(new Path("/dir")); // Check that now we have the version stamp assertEquals( AzureNativeFileSystemStore.CURRENT_WASB_VERSION, fsWithContainer.getContainerMetadata().get( AzureNativeFileSystemStore.VERSION_METADATA_KEY)); assertNull(fsWithContainer.getContainerMetadata().get( AzureNativeFileSystemStore.OLD_VERSION_METADATA_KEY)); fsWithContainer.close(); } @SuppressWarnings("deprecation") @Test public void testPermissionMetadata() throws Exception { FsPermission justMe = new FsPermission(FsAction.READ_WRITE, FsAction.NONE, FsAction.NONE); Path selfishFile = new Path("/noOneElse"); fs.create(selfishFile, justMe, true, 4096, fs.getDefaultReplication(), fs.getDefaultBlockSize(), null).close(); HashMap<String, String> metadata = backingStore .getMetadata(AzureBlobStorageTestAccount.toMockUri(selfishFile)); assertNotNull(metadata); String storedPermission = metadata.get("hdi_permission"); assertEquals(getExpectedPermissionString("rw-------"), storedPermission); FileStatus retrievedStatus = fs.getFileStatus(selfishFile); assertNotNull(retrievedStatus); assertEquals(justMe, retrievedStatus.getPermission()); assertEquals(getExpectedOwner(), retrievedStatus.getOwner()); assertEquals(NativeAzureFileSystem.AZURE_DEFAULT_GROUP_DEFAULT, retrievedStatus.getGroup()); } /** * Tests that WASB understands the old-style ASV metadata and changes it when * it gets the chance. */ @Test public void testOldPermissionMetadata() throws Exception { Path selfishFile = new Path("/noOneElse"); HashMap<String, String> metadata = new HashMap<String, String>(); metadata.put("asv_permission", getExpectedPermissionString("rw-------")); backingStore.setContent( AzureBlobStorageTestAccount.toMockUri(selfishFile), new byte[] { }, metadata, false, 0); FsPermission justMe = new FsPermission( FsAction.READ_WRITE, FsAction.NONE, FsAction.NONE); FileStatus retrievedStatus = fs.getFileStatus(selfishFile); assertNotNull(retrievedStatus); assertEquals(justMe, retrievedStatus.getPermission()); assertEquals(getExpectedOwner(), retrievedStatus.getOwner()); assertEquals(NativeAzureFileSystem.AZURE_DEFAULT_GROUP_DEFAULT, retrievedStatus.getGroup()); FsPermission meAndYou = new FsPermission( FsAction.READ_WRITE, FsAction.READ_WRITE, FsAction.NONE); fs.setPermission(selfishFile, meAndYou); metadata = backingStore.getMetadata( AzureBlobStorageTestAccount.toMockUri(selfishFile)); assertNotNull(metadata); String storedPermission = metadata.get("hdi_permission"); assertEquals(getExpectedPermissionString("rw-rw----"), storedPermission); assertNull(metadata.get("asv_permission")); } @Test public void testFolderMetadata() throws Exception { Path folder = new Path("/folder"); FsPermission justRead = new FsPermission(FsAction.READ, FsAction.READ, FsAction.READ); fs.mkdirs(folder, justRead); HashMap<String, String> metadata = backingStore .getMetadata(AzureBlobStorageTestAccount.toMockUri(folder)); assertNotNull(metadata); assertEquals("true", metadata.get("hdi_isfolder")); assertEquals(getExpectedPermissionString("r--r--r--"), metadata.get("hdi_permission")); } }