Author: umamahesh Date: Fri May 9 14:19:51 2014 New Revision: 1593547 URL: http://svn.apache.org/r1593547 Log: HDFS-6314. Test cases for XAttrs. Contributed by Yi Liu.
Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/fs/TestXAttr.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestXAttrConfigFlag.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestXAttrsWithHA.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDFSShell.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestNameNodeXAttr.java Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt?rev=1593547&r1=1593546&r2=1593547&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt Fri May 9 14:19:51 2014 @@ -25,6 +25,8 @@ HDFS-2006 (Unreleased) HDFS-6298. XML based End-to-End test for getfattr and setfattr commands. (Yi Liu via umamahesh) + HDFS-6314. Test cases for XAttrs. (Yi Liu via umamahesh) + OPTIMIZATIONS BUG FIXES Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/fs/TestXAttr.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/fs/TestXAttr.java?rev=1593547&view=auto ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/fs/TestXAttr.java (added) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/fs/TestXAttr.java Fri May 9 14:19:51 2014 @@ -0,0 +1,85 @@ +/** + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; + +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Tests for <code>XAttr</code> objects. + */ +public class TestXAttr { + private static XAttr XATTR, XATTR1, XATTR2, XATTR3, XATTR4; + + @BeforeClass + public static void setUp() throws Exception { + byte[] value = {0x31, 0x32, 0x33}; + XATTR = new XAttr.Builder() + .setName("name") + .setValue(value) + .build(); + XATTR1 = new XAttr.Builder() + .setNameSpace(XAttr.NameSpace.USER) + .setName("name") + .setValue(value) + .build(); + XATTR2 = new XAttr.Builder() + .setNameSpace(XAttr.NameSpace.TRUSTED) + .setName("name") + .setValue(value) + .build(); + XATTR3 = new XAttr.Builder() + .setNameSpace(XAttr.NameSpace.SYSTEM) + .setName("name") + .setValue(value) + .build(); + XATTR4 = new XAttr.Builder() + .setNameSpace(XAttr.NameSpace.SECURITY) + .setName("name") + .setValue(value) + .build(); + } + + @Test + public void testXAttrEquals() { + assertNotSame(XATTR1, XATTR2); + assertNotSame(XATTR2, XATTR3); + assertNotSame(XATTR3, XATTR4); + assertEquals(XATTR, XATTR1); + assertEquals(XATTR1, XATTR1); + assertEquals(XATTR2, XATTR2); + assertEquals(XATTR3, XATTR3); + assertEquals(XATTR4, XATTR4); + assertFalse(XATTR1.equals(XATTR2)); + assertFalse(XATTR2.equals(XATTR3)); + assertFalse(XATTR3.equals(XATTR4)); + } + + @Test + public void testXAttrHashCode() { + assertEquals(XATTR.hashCode(), XATTR1.hashCode()); + assertFalse(XATTR1.hashCode() == XATTR2.hashCode()); + assertFalse(XATTR2.hashCode() == XATTR3.hashCode()); + assertFalse(XATTR3.hashCode() == XATTR4.hashCode()); + } +} Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDFSShell.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDFSShell.java?rev=1593547&r1=1593546&r2=1593547&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDFSShell.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDFSShell.java Fri May 9 14:19:51 2014 @@ -1874,6 +1874,81 @@ public class TestDFSShell { cluster.shutdown(); } } + + @Test (timeout = 30000) + public void testSetXAttrPermission() throws Exception { + UserGroupInformation user = UserGroupInformation. + createUserForTesting("user", new String[] {"mygroup"}); + MiniDFSCluster cluster = null; + PrintStream bak = null; + try { + final Configuration conf = new HdfsConfiguration(); + cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build(); + cluster.waitActive(); + + FileSystem fs = cluster.getFileSystem(); + Path p = new Path("/foo"); + fs.mkdirs(p); + bak = System.err; + + final FsShell fshell = new FsShell(conf); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + System.setErr(new PrintStream(out)); + + // No permission to write xattr + fs.setPermission(p, new FsPermission((short) 0700)); + user.doAs(new PrivilegedExceptionAction<Object>() { + @Override + public Object run() throws Exception { + int ret = ToolRunner.run(fshell, new String[]{ + "-setfattr", "-n", "user.a1", "-v", "1234", "/foo"}); + assertEquals("Returned should be 1", 1, ret); + String str = out.toString(); + assertTrue("Permission denied printed", + str.indexOf("Permission denied") != -1); + out.reset(); + return null; + } + }); + + int ret = ToolRunner.run(fshell, new String[]{ + "-setfattr", "-n", "user.a1", "-v", "1234", "/foo"}); + assertEquals("Returned should be 0", 0, ret); + out.reset(); + + // No permission to read and remove + fs.setPermission(p, new FsPermission((short) 0750)); + user.doAs(new PrivilegedExceptionAction<Object>() { + @Override + public Object run() throws Exception { + // Read + int ret = ToolRunner.run(fshell, new String[]{ + "-getfattr", "-n", "user.a1", "/foo"}); + assertEquals("Returned should be 1", 1, ret); + String str = out.toString(); + assertTrue("Permission denied printed", + str.indexOf("Permission denied") != -1); + out.reset(); + // Remove + ret = ToolRunner.run(fshell, new String[]{ + "-setfattr", "-x", "user.a1", "/foo"}); + assertEquals("Returned should be 1", 1, ret); + str = out.toString(); + assertTrue("Permission denied printed", + str.indexOf("Permission denied") != -1); + out.reset(); + return null; + } + }); + } finally { + if (bak != null) { + System.setErr(bak); + } + if (cluster != null) { + cluster.shutdown(); + } + } + } /** * Test that the server trash configuration is respected when Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java?rev=1593547&r1=1593546&r2=1593547&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/FSXAttrBaseTest.java Fri May 9 14:19:51 2014 @@ -40,6 +40,7 @@ import com.google.common.collect.Lists; /** * Tests NameNode interaction for all XAttr APIs. + * This test suite covers restarting the NN, saving a new checkpoint. */ public class FSXAttrBaseTest { @@ -48,7 +49,7 @@ public class FSXAttrBaseTest { private static int pathCount = 0; private static Path path; - //xattrs + // XAttrs protected static final String name1 = "user.a1"; protected static final byte[] value1 = {0x31, 0x32, 0x33}; protected static final byte[] newValue1 = {0x31, 0x31, 0x31}; @@ -81,9 +82,10 @@ public class FSXAttrBaseTest { /** * Tests for creating xattr - * 1. create xattr using XAttrSetFlag.CREATE flag. - * 2. Assert exception of creating xattr which already exists. - * 3. Create multiple xattrs + * 1. Create an xattr using XAttrSetFlag.CREATE. + * 2. Create an xattr which already exists and expect an exception. + * 3. Create multiple xattrs. + * 4. Restart NN and save checkpoint scenarios. */ @Test public void testCreateXAttr() throws Exception { @@ -99,7 +101,7 @@ public class FSXAttrBaseTest { xattrs = fs.getXAttrs(path); Assert.assertEquals(xattrs.size(), 0); - //create xattr which already exists. + // Create xattr which already exists. fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); try { fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); @@ -108,7 +110,7 @@ public class FSXAttrBaseTest { } fs.removeXAttr(path, name1); - //create two xattrs + // Create two xattrs fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); fs.setXAttr(path, name2, null, EnumSet.of(XAttrSetFlag.CREATE)); xattrs = fs.getXAttrs(path); @@ -116,15 +118,30 @@ public class FSXAttrBaseTest { Assert.assertArrayEquals(value1, xattrs.get(name1)); Assert.assertArrayEquals(new byte[0], xattrs.get(name2)); + restart(false); + initFileSystem(); + xattrs = fs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(new byte[0], xattrs.get(name2)); + + restart(true); + initFileSystem(); + xattrs = fs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(new byte[0], xattrs.get(name2)); + fs.removeXAttr(path, name1); fs.removeXAttr(path, name2); } /** * Tests for replacing xattr - * 1. Replace xattr using XAttrSetFlag.REPLACE flag. - * 2. Assert exception of replacing xattr which does not exist. - * 3. Create multiple xattrs, and replace some. + * 1. Replace an xattr using XAttrSetFlag.REPLACE. + * 2. Replace an xattr which doesn't exist and expect an exception. + * 3. Create multiple xattrs and replace some. + * 4. Restart NN and save checkpoint scenarios. */ @Test public void testReplaceXAttr() throws Exception { @@ -138,14 +155,14 @@ public class FSXAttrBaseTest { fs.removeXAttr(path, name1); - //replace xattr which does not exist. + // Replace xattr which does not exist. try { fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.REPLACE)); Assert.fail("Replacing xattr which does not exist should fail."); } catch (IOException e) { } - //create two xattrs, then replace one + // Create two xattrs, then replace one fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); fs.setXAttr(path, name2, value2, EnumSet.of(XAttrSetFlag.CREATE)); fs.setXAttr(path, name2, null, EnumSet.of(XAttrSetFlag.REPLACE)); @@ -154,6 +171,20 @@ public class FSXAttrBaseTest { Assert.assertArrayEquals(value1, xattrs.get(name1)); Assert.assertArrayEquals(new byte[0], xattrs.get(name2)); + restart(false); + initFileSystem(); + xattrs = fs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(new byte[0], xattrs.get(name2)); + + restart(true); + initFileSystem(); + xattrs = fs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(new byte[0], xattrs.get(name2)); + fs.removeXAttr(path, name1); fs.removeXAttr(path, name2); } @@ -161,9 +192,9 @@ public class FSXAttrBaseTest { /** * Tests for setting xattr * 1. Set xattr with XAttrSetFlag.CREATE|XAttrSetFlag.REPLACE flag. - * 2. Set xattr with illegal name + * 2. Set xattr with illegal name. * 3. Set xattr without XAttrSetFlag. - * 4. Set xattr and total number exceeds max limit + * 4. Set xattr and total number exceeds max limit. */ @Test public void testSetXAttr() throws Exception { @@ -176,7 +207,7 @@ public class FSXAttrBaseTest { Assert.assertArrayEquals(value1, xattrs.get(name1)); fs.removeXAttr(path, name1); - //set xattr with null name + // Set xattr with null name try { fs.setXAttr(path, null, value1, EnumSet.of(XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE)); @@ -184,7 +215,7 @@ public class FSXAttrBaseTest { } catch (NullPointerException e) { } - //set xattr with empty name: "user." + // Set xattr with empty name: "user." try { fs.setXAttr(path, "user.", value1, EnumSet.of(XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE)); @@ -192,7 +223,7 @@ public class FSXAttrBaseTest { } catch (HadoopIllegalArgumentException e) { } - //set xattr with invalid name: "a1" + // Set xattr with invalid name: "a1" try { fs.setXAttr(path, "a1", value1, EnumSet.of(XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE)); @@ -201,14 +232,14 @@ public class FSXAttrBaseTest { } catch (HadoopIllegalArgumentException e) { } - //set xattr without XAttrSetFlag + // Set xattr without XAttrSetFlag fs.setXAttr(path, name1, value1); xattrs = fs.getXAttrs(path); Assert.assertEquals(xattrs.size(), 1); Assert.assertArrayEquals(value1, xattrs.get(name1)); fs.removeXAttr(path, name1); - //xattr exists, and replace it using CREATE|REPLACE flag. + // XAttr exists, and replace it using CREATE|REPLACE flag. fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); fs.setXAttr(path, name1, newValue1, EnumSet.of(XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE)); @@ -219,7 +250,7 @@ public class FSXAttrBaseTest { fs.removeXAttr(path, name1); - //Total number exceeds max limit + // Total number exceeds max limit fs.setXAttr(path, name1, value1); fs.setXAttr(path, name2, value2); fs.setXAttr(path, name3, null); @@ -245,7 +276,7 @@ public class FSXAttrBaseTest { fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); fs.setXAttr(path, name2, value2, EnumSet.of(XAttrSetFlag.CREATE)); - //xattr does not exist. + // XAttr does not exist. byte[] value = fs.getXAttr(path, name3); Assert.assertEquals(value, null); @@ -264,7 +295,8 @@ public class FSXAttrBaseTest { /** * Tests for removing xattr - * 1. Remove xattr + * 1. Remove xattr. + * 2. Restart NN and save checkpoint scenarios. */ @Test public void testRemoveXAttr() throws Exception { @@ -280,10 +312,65 @@ public class FSXAttrBaseTest { Assert.assertEquals(xattrs.size(), 1); Assert.assertArrayEquals(new byte[0], xattrs.get(name3)); + restart(false); + initFileSystem(); + xattrs = fs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 1); + Assert.assertArrayEquals(new byte[0], xattrs.get(name3)); + + restart(true); + initFileSystem(); + xattrs = fs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 1); + Assert.assertArrayEquals(new byte[0], xattrs.get(name3)); + fs.removeXAttr(path, name3); } /** + * Steps: + * 1) Set xattrs on a file. + * 2) Remove xattrs from that file. + * 3) Save a checkpoint and restart NN. + * 4) Set xattrs again on the same file. + * 5) Remove xattrs from that file. + * 6) Restart NN without saving a checkpoint. + * 7) Set xattrs again on the same file. + */ + @Test + public void testCleanupXAttrs() throws Exception { + FileSystem.mkdirs(fs, path, FsPermission.createImmutable((short)0750)); + fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); + fs.setXAttr(path, name2, value2, EnumSet.of(XAttrSetFlag.CREATE)); + fs.removeXAttr(path, name1); + fs.removeXAttr(path, name2); + + restart(true); + initFileSystem(); + + fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); + fs.setXAttr(path, name2, value2, EnumSet.of(XAttrSetFlag.CREATE)); + fs.removeXAttr(path, name1); + fs.removeXAttr(path, name2); + + restart(false); + initFileSystem(); + + fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); + fs.setXAttr(path, name2, value2, EnumSet.of(XAttrSetFlag.CREATE)); + fs.removeXAttr(path, name1); + fs.removeXAttr(path, name2); + + fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); + fs.setXAttr(path, name2, value2, EnumSet.of(XAttrSetFlag.CREATE)); + + Map<String, byte[]> xattrs = fs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + } + + /** * Creates a FileSystem for the super-user. * * @return FileSystem for super-user @@ -314,4 +401,20 @@ public class FSXAttrBaseTest { .build(); dfsCluster.waitActive(); } + + /** + * Restart the cluster, optionally saving a new checkpoint. + * + * @param checkpoint boolean true to save a new checkpoint + * @throws Exception if restart fails + */ + protected static void restart(boolean checkpoint) throws Exception { + NameNode nameNode = dfsCluster.getNameNode(); + if (checkpoint) { + NameNodeAdapter.enterSafeMode(nameNode, false); + NameNodeAdapter.saveNamespace(nameNode); + } + shutdown(); + initCluster(false); + } } Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestNameNodeXAttr.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestNameNodeXAttr.java?rev=1593547&r1=1593546&r2=1593547&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestNameNodeXAttr.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestNameNodeXAttr.java Fri May 9 14:19:51 2014 @@ -17,15 +17,28 @@ */ package org.apache.hadoop.hdfs.server.namenode; +import java.util.Map; + import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; import org.apache.hadoop.hdfs.DFSConfigKeys; +import org.apache.hadoop.hdfs.DFSTestUtil; +import org.junit.Assert; import org.junit.BeforeClass; +import org.junit.Test; /** * Tests NameNode interaction for all XAttr APIs. + * This test suite covers restarting NN, saving new checkpoint, + * and also includes test of xattrs for symlinks. */ public class TestNameNodeXAttr extends FSXAttrBaseTest { + private static final Path linkParent = new Path("/symdir1"); + private static final Path targetParent = new Path("/symdir2"); + private static final Path link = new Path(linkParent, "link"); + private static final Path target = new Path(targetParent, "target"); + @BeforeClass public static void init() throws Exception { conf = new Configuration(); @@ -34,4 +47,40 @@ public class TestNameNodeXAttr extends F initCluster(true); } + @Test + public void testXAttrSymlinks() throws Exception { + fs.mkdirs(linkParent); + fs.mkdirs(targetParent); + DFSTestUtil.createFile(fs, target, 1024, (short)3, 0xBEEFl); + fs.createSymlink(target, link, false); + + fs.setXAttr(target, name1, value1); + fs.setXAttr(target, name2, value2); + + Map<String, byte[]> xattrs = fs.getXAttrs(link); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + + fs.setXAttr(link, name3, null); + xattrs = fs.getXAttrs(target); + Assert.assertEquals(xattrs.size(), 3); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + Assert.assertArrayEquals(new byte[0], xattrs.get(name3)); + + fs.removeXAttr(link, name1); + xattrs = fs.getXAttrs(target); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + Assert.assertArrayEquals(new byte[0], xattrs.get(name3)); + + fs.removeXAttr(target, name3); + xattrs = fs.getXAttrs(link); + Assert.assertEquals(xattrs.size(), 1); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + + fs.delete(linkParent, true); + fs.delete(targetParent, true); + } } Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestXAttrConfigFlag.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestXAttrConfigFlag.java?rev=1593547&view=auto ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestXAttrConfigFlag.java (added) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestXAttrConfigFlag.java Fri May 9 14:19:51 2014 @@ -0,0 +1,150 @@ +/** + * 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.hdfs.server.namenode; + +import java.io.IOException; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hdfs.DFSConfigKeys; +import org.apache.hadoop.hdfs.DistributedFileSystem; +import org.apache.hadoop.hdfs.MiniDFSCluster; +import org.apache.hadoop.hdfs.server.namenode.NameNode; +import org.apache.hadoop.hdfs.server.namenode.NameNodeAdapter; +import org.apache.hadoop.io.IOUtils; +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Tests that the configuration flag that controls support for XAttrs is off + * and causes all attempted operations related to XAttrs to fail. The + * NameNode can still load XAttrs from fsimage or edits. + */ +public class TestXAttrConfigFlag { + private static final Path PATH = new Path("/path"); + + private MiniDFSCluster cluster; + private DistributedFileSystem fs; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @After + public void shutdown() throws Exception { + IOUtils.cleanup(null, fs); + if (cluster != null) { + cluster.shutdown(); + } + } + + @Test + public void testSetXAttr() throws Exception { + initCluster(true, false); + fs.mkdirs(PATH); + expectException(); + fs.setXAttr(PATH, "user.foo", null); + } + + @Test + public void testGetXAttrs() throws Exception { + initCluster(true, false); + fs.mkdirs(PATH); + expectException(); + fs.getXAttrs(PATH); + } + + @Test + public void testRemoveXAttr() throws Exception { + initCluster(true, false); + fs.mkdirs(PATH); + expectException(); + fs.removeXAttr(PATH, "user.foo"); + } + + @Test + public void testEditLog() throws Exception { + // With XAttrs enabled, set an XAttr. + initCluster(true, true); + fs.mkdirs(PATH); + fs.setXAttr(PATH, "user.foo", null); + + // Restart with XAttrs disabled. Expect successful restart. + restart(false, false); + } + + @Test + public void testFsImage() throws Exception { + // With XAttrs enabled, set an XAttr. + initCluster(true, true); + fs.mkdirs(PATH); + fs.setXAttr(PATH, "user.foo", null); + + // Save a new checkpoint and restart with XAttrs still enabled. + restart(true, true); + + // Restart with XAttrs disabled. Expect successful restart. + restart(false, false); + } + + /** + * We expect an IOException, and we want the exception text to state the + * configuration key that controls XAttr support. + */ + private void expectException() { + exception.expect(IOException.class); + exception.expectMessage(DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_KEY); + } + + /** + * Initialize the cluster, wait for it to become active, and get FileSystem. + * + * @param format if true, format the NameNode and DataNodes before starting up + * @param xattrsEnabled if true, XAttr support is enabled + * @throws Exception if any step fails + */ + private void initCluster(boolean format, boolean xattrsEnabled) + throws Exception { + Configuration conf = new Configuration(); + // not explicitly setting to false, should be false by default + conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_KEY, xattrsEnabled); + cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).format(format) + .build(); + cluster.waitActive(); + fs = cluster.getFileSystem(); + } + + /** + * Restart the cluster, optionally saving a new checkpoint. + * + * @param checkpoint boolean true to save a new checkpoint + * @param xattrsEnabled if true, XAttr support is enabled + * @throws Exception if restart fails + */ + private void restart(boolean checkpoint, boolean xattrsEnabled) + throws Exception { + NameNode nameNode = cluster.getNameNode(); + if (checkpoint) { + NameNodeAdapter.enterSafeMode(nameNode, false); + NameNodeAdapter.saveNamespace(nameNode); + } + shutdown(); + initCluster(false, xattrsEnabled); + } +} Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestXAttrsWithHA.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestXAttrsWithHA.java?rev=1593547&view=auto ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestXAttrsWithHA.java (added) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestXAttrsWithHA.java Fri May 9 14:19:51 2014 @@ -0,0 +1,114 @@ +/** + * 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.hdfs.server.namenode.ha; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.XAttr; +import org.apache.hadoop.fs.XAttrSetFlag; +import org.apache.hadoop.hdfs.DFSConfigKeys; +import org.apache.hadoop.hdfs.HAUtil; +import org.apache.hadoop.hdfs.MiniDFSCluster; +import org.apache.hadoop.hdfs.MiniDFSNNTopology; +import org.apache.hadoop.hdfs.server.namenode.NameNode; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests interaction of XAttrs with HA failover. + */ +public class TestXAttrsWithHA { + private static final Path path = new Path("/file"); + + // XAttrs + protected static final String name1 = "user.a1"; + protected static final byte[] value1 = {0x31, 0x32, 0x33}; + protected static final byte[] newValue1 = {0x31, 0x31, 0x31}; + protected static final String name2 = "user.a2"; + protected static final byte[] value2 = {0x37, 0x38, 0x39}; + protected static final String name3 = "user.a3"; + + private MiniDFSCluster cluster; + private NameNode nn0; + private NameNode nn1; + private FileSystem fs; + + @Before + public void setupCluster() throws Exception { + Configuration conf = new Configuration(); + conf.setInt(DFSConfigKeys.DFS_HA_TAILEDITS_PERIOD_KEY, 1); + HAUtil.setAllowStandbyReads(conf, true); + + cluster = new MiniDFSCluster.Builder(conf) + .nnTopology(MiniDFSNNTopology.simpleHATopology()) + .numDataNodes(1) + .waitSafeMode(false) + .build(); + cluster.waitActive(); + + nn0 = cluster.getNameNode(0); + nn1 = cluster.getNameNode(1); + fs = HATestUtil.configureFailoverFs(cluster, conf); + + cluster.transitionToActive(0); + } + + @After + public void shutdownCluster() throws IOException { + if (cluster != null) { + cluster.shutdown(); + } + } + + /** + * Test that xattrs are properly tracked by the standby + */ + @Test(timeout = 60000) + public void testXAttrsTrackedOnStandby() throws Exception { + fs.create(path).close(); + fs.setXAttr(path, name1, value1, EnumSet.of(XAttrSetFlag.CREATE)); + fs.setXAttr(path, name2, value2, EnumSet.of(XAttrSetFlag.CREATE)); + + HATestUtil.waitForStandbyToCatchUp(nn0, nn1); + List<XAttr> xAttrs = nn1.getRpcServer().getXAttrs("/file", null); + assertEquals(2, xAttrs.size()); + cluster.shutdownNameNode(0); + + // Failover the current standby to active. + cluster.shutdownNameNode(0); + cluster.transitionToActive(1); + + Map<String, byte[]> xattrs = fs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + + fs.delete(path, true); + } + +} Added: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java?rev=1593547&view=auto ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java (added) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java Fri May 9 14:19:51 2014 @@ -0,0 +1,273 @@ +/** + * 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.hdfs.server.namenode.snapshot; + +import java.util.Map; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.permission.FsPermission; +import org.apache.hadoop.hdfs.DFSConfigKeys; +import org.apache.hadoop.hdfs.DistributedFileSystem; +import org.apache.hadoop.hdfs.MiniDFSCluster; +import org.apache.hadoop.hdfs.protocol.HdfsConstants; +import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException; +import org.apache.hadoop.hdfs.protocol.SnapshotAccessControlException; +import org.apache.hadoop.hdfs.server.namenode.NameNode; +import org.apache.hadoop.hdfs.server.namenode.NameNodeAdapter; +import org.apache.hadoop.io.IOUtils; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Tests interaction of XAttrs with snapshots. + */ +public class TestXAttrWithSnapshot { + + private static MiniDFSCluster cluster; + private static Configuration conf; + private static DistributedFileSystem hdfs; + private static int pathCount = 0; + private static Path path, snapshotPath; + private static String snapshotName; + // XAttrs + private static final String name1 = "user.a1"; + private static final byte[] value1 = { 0x31, 0x32, 0x33 }; + private static final byte[] newValue1 = { 0x31, 0x31, 0x31 }; + private static final String name2 = "user.a2"; + private static final byte[] value2 = { 0x37, 0x38, 0x39 }; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @BeforeClass + public static void init() throws Exception { + conf = new Configuration(); + conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_KEY, true); + initCluster(true); + } + + @AfterClass + public static void shutdown() throws Exception { + IOUtils.cleanup(null, hdfs); + if (cluster != null) { + cluster.shutdown(); + } + } + + @Before + public void setUp() { + ++pathCount; + path = new Path("/p" + pathCount); + snapshotName = "snapshot" + pathCount; + snapshotPath = new Path(path, new Path(".snapshot", snapshotName)); + } + + /** + * 1) Save xattrs, then create snapshot. Assert that inode of original and + * snapshot have same xattrs. 2) Change the original xattrs, assert snapshot + * still has old xattrs. + */ + @Test + public void testXAttrForSnapshotRootAfterChange() throws Exception { + FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700)); + hdfs.setXAttr(path, name1, value1); + hdfs.setXAttr(path, name2, value2); + + SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName); + + // Both original and snapshot have same XAttrs. + Map<String, byte[]> xattrs = hdfs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + + xattrs = hdfs.getXAttrs(snapshotPath); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + + // Original XAttrs have changed, but snapshot still has old XAttrs. + hdfs.setXAttr(path, name1, newValue1); + + doSnapshotRootChangeAssertions(path, snapshotPath); + restart(false); + doSnapshotRootChangeAssertions(path, snapshotPath); + restart(true); + doSnapshotRootChangeAssertions(path, snapshotPath); + } + + private static void doSnapshotRootChangeAssertions(Path path, + Path snapshotPath) throws Exception { + Map<String, byte[]> xattrs = hdfs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(newValue1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + + xattrs = hdfs.getXAttrs(snapshotPath); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + } + + /** + * 1) Save xattrs, then create snapshot. Assert that inode of original and + * snapshot have same xattrs. 2) Remove some original xattrs, assert snapshot + * still has old xattrs. + */ + @Test + public void testXAttrForSnapshotRootAfterRemove() throws Exception { + FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700)); + hdfs.setXAttr(path, name1, value1); + hdfs.setXAttr(path, name2, value2); + + SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName); + + // Both original and snapshot have same XAttrs. + Map<String, byte[]> xattrs = hdfs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + + xattrs = hdfs.getXAttrs(snapshotPath); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + + // Original XAttrs have been removed, but snapshot still has old XAttrs. + hdfs.removeXAttr(path, name1); + hdfs.removeXAttr(path, name2); + + doSnapshotRootRemovalAssertions(path, snapshotPath); + restart(false); + doSnapshotRootRemovalAssertions(path, snapshotPath); + restart(true); + doSnapshotRootRemovalAssertions(path, snapshotPath); + } + + private static void doSnapshotRootRemovalAssertions(Path path, + Path snapshotPath) throws Exception { + Map<String, byte[]> xattrs = hdfs.getXAttrs(path); + Assert.assertEquals(xattrs.size(), 0); + + xattrs = hdfs.getXAttrs(snapshotPath); + Assert.assertEquals(xattrs.size(), 2); + Assert.assertArrayEquals(value1, xattrs.get(name1)); + Assert.assertArrayEquals(value2, xattrs.get(name2)); + } + + /** + * Assert exception of setting xattr on read-only snapshot. + */ + @Test + public void testSetXAttrSnapshotPath() throws Exception { + FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700)); + SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName); + exception.expect(SnapshotAccessControlException.class); + hdfs.setXAttr(snapshotPath, name1, value1); + } + + /** + * Assert exception of setting xattr when exceeding quota. + */ + @Test + public void testSetXAttrExceedsQuota() throws Exception { + Path filePath = new Path(path, "file1"); + Path fileSnapshotPath = new Path(snapshotPath, "file1"); + FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0755)); + hdfs.allowSnapshot(path); + hdfs.setQuota(path, 3, HdfsConstants.QUOTA_DONT_SET); + FileSystem.create(hdfs, filePath, + FsPermission.createImmutable((short) 0600)).close(); + hdfs.setXAttr(filePath, name1, value1); + + hdfs.createSnapshot(path, snapshotName); + + byte[] value = hdfs.getXAttr(filePath, name1); + Assert.assertArrayEquals(value, value1); + + value = hdfs.getXAttr(fileSnapshotPath, name1); + Assert.assertArrayEquals(value, value1); + + exception.expect(NSQuotaExceededException.class); + hdfs.setXAttr(filePath, name2, value2); + } + + /** + * Assert exception of removing xattr when exceeding quota. + */ + @Test + public void testRemoveXAttrExceedsQuota() throws Exception { + Path filePath = new Path(path, "file1"); + Path fileSnapshotPath = new Path(snapshotPath, "file1"); + FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0755)); + hdfs.allowSnapshot(path); + hdfs.setQuota(path, 3, HdfsConstants.QUOTA_DONT_SET); + FileSystem.create(hdfs, filePath, + FsPermission.createImmutable((short) 0600)).close(); + hdfs.setXAttr(filePath, name1, value1); + + hdfs.createSnapshot(path, snapshotName); + + byte[] value = hdfs.getXAttr(filePath, name1); + Assert.assertArrayEquals(value, value1); + + value = hdfs.getXAttr(fileSnapshotPath, name1); + Assert.assertArrayEquals(value, value1); + + exception.expect(NSQuotaExceededException.class); + hdfs.removeXAttr(filePath, name1); + } + + /** + * Initialize the cluster, wait for it to become active, and get FileSystem + * instances for our test users. + * + * @param format if true, format the NameNode and DataNodes before starting up + * @throws Exception if any step fails + */ + private static void initCluster(boolean format) throws Exception { + cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).format(format) + .build(); + cluster.waitActive(); + hdfs = cluster.getFileSystem(); + } + + /** + * Restart the cluster, optionally saving a new checkpoint. + * + * @param checkpoint boolean true to save a new checkpoint + * @throws Exception if restart fails + */ + private static void restart(boolean checkpoint) throws Exception { + NameNode nameNode = cluster.getNameNode(); + if (checkpoint) { + NameNodeAdapter.enterSafeMode(nameNode, false); + NameNodeAdapter.saveNamespace(nameNode); + } + shutdown(); + initCluster(false); + } +}