/**
* 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.assertTrue;
import java.util.HashMap;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Tests that WASB handles things gracefully when users add blobs to the Azure
* Storage container from outside WASB's control.
*/
public class TestOutOfBandAzureBlobOperations {
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 void createEmptyBlobOutOfBand(String path) {
backingStore.setContent(
AzureBlobStorageTestAccount.toMockUri(path),
new byte[] { 1, 2 },
new HashMap<String, String>(),
false, 0);
}
@SuppressWarnings("deprecation")
@Test
public void testImplicitFolderListed() throws Exception {
createEmptyBlobOutOfBand("root/b");
// List the blob itself.
FileStatus[] obtained = fs.listStatus(new Path("/root/b"));
assertNotNull(obtained);
assertEquals(1, obtained.length);
assertFalse(obtained[0].isDir());
assertEquals("/root/b", obtained[0].getPath().toUri().getPath());
// List the directory
obtained = fs.listStatus(new Path("/root"));
assertNotNull(obtained);
assertEquals(1, obtained.length);
assertFalse(obtained[0].isDir());
assertEquals("/root/b", obtained[0].getPath().toUri().getPath());
// Get the directory's file status
FileStatus dirStatus = fs.getFileStatus(new Path("/root"));
assertNotNull(dirStatus);
assertTrue(dirStatus.isDir());
assertEquals("/root", dirStatus.getPath().toUri().getPath());
}
@Test
public void testImplicitFolderDeleted() throws Exception {
createEmptyBlobOutOfBand("root/b");
assertTrue(fs.exists(new Path("/root")));
assertTrue(fs.delete(new Path("/root"), true));
assertFalse(fs.exists(new Path("/root")));
}
@Test
public void testFileInImplicitFolderDeleted() throws Exception {
createEmptyBlobOutOfBand("root/b");
assertTrue(fs.exists(new Path("/root")));
assertTrue(fs.delete(new Path("/root/b"), true));
assertTrue(fs.exists(new Path("/root")));
}
@SuppressWarnings("deprecation")
@Test
public void testFileAndImplicitFolderSameName() throws Exception {
createEmptyBlobOutOfBand("root/b");
createEmptyBlobOutOfBand("root/b/c");
FileStatus[] listResult = fs.listStatus(new Path("/root/b"));
// File should win.
assertEquals(1, listResult.length);
assertFalse(listResult[0].isDir());
try {
// Trying to delete root/b/c would cause a dilemma for WASB, so
// it should throw.
fs.delete(new Path("/root/b/c"), true);
assertTrue("Should've thrown.", false);
} catch (AzureException e) {
assertEquals("File /root/b/c has a parent directory /root/b"
+ " which is also a file. Can't resolve.", e.getMessage());
}
}
private static enum DeepCreateTestVariation {
File, Folder
};
/**
* Tests that when we create the file (or folder) x/y/z, we also create
* explicit folder blobs for x and x/y
*/
@Test
public void testCreatingDeepFileCreatesExplicitFolder() throws Exception {
for (DeepCreateTestVariation variation : DeepCreateTestVariation.values()) {
switch (variation) {
case File:
assertTrue(fs.createNewFile(new Path("/x/y/z")));
break;
case Folder:
assertTrue(fs.mkdirs(new Path("/x/y/z")));
break;
}
assertTrue(backingStore
.exists(AzureBlobStorageTestAccount.toMockUri("x")));
assertTrue(backingStore.exists(AzureBlobStorageTestAccount
.toMockUri("x/y")));
fs.delete(new Path("/x"), true);
}
}
@Test
public void testSetPermissionOnImplicitFolder() throws Exception {
createEmptyBlobOutOfBand("root/b");
FsPermission newPermission = new FsPermission((short) 0600);
fs.setPermission(new Path("/root"), newPermission);
FileStatus newStatus = fs.getFileStatus(new Path("/root"));
assertNotNull(newStatus);
assertEquals(newPermission, newStatus.getPermission());
}
@Test
public void testSetOwnerOnImplicitFolder() throws Exception {
createEmptyBlobOutOfBand("root/b");
fs.setOwner(new Path("/root"), "newOwner", null);
FileStatus newStatus = fs.getFileStatus(new Path("/root"));
assertNotNull(newStatus);
assertEquals("newOwner", newStatus.getOwner());
}
}