@Test
 public void testRemoveAclSnapshotPath() throws Exception {
   FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700));
   SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
   exception.expect(SnapshotAccessControlException.class);
   hdfs.removeAcl(snapshotPath);
 }
  @Test
  public void testModifyReadsCurrentState() throws Exception {
    FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700));

    SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);

    List<AclEntry> aclSpec = Lists.newArrayList(aclEntry(ACCESS, USER, "bruce", ALL));
    hdfs.modifyAclEntries(path, aclSpec);

    aclSpec = Lists.newArrayList(aclEntry(ACCESS, USER, "diana", READ_EXECUTE));
    hdfs.modifyAclEntries(path, aclSpec);

    AclEntry[] expected =
        new AclEntry[] {
          aclEntry(ACCESS, USER, "bruce", ALL),
          aclEntry(ACCESS, USER, "diana", READ_EXECUTE),
          aclEntry(ACCESS, GROUP, NONE)
        };
    AclStatus s = hdfs.getAclStatus(path);
    AclEntry[] returned = s.getEntries().toArray(new AclEntry[0]);
    assertArrayEquals(expected, returned);
    assertPermission((short) 010770, path);
    assertDirPermissionGranted(fsAsBruce, BRUCE, path);
    assertDirPermissionGranted(fsAsDiana, DIANA, path);
  }
 @Test
 public void testGetAclStatusDotSnapshotPath() throws Exception {
   hdfs.mkdirs(path);
   SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
   AclStatus s = hdfs.getAclStatus(new Path(path, ".snapshot"));
   AclEntry[] returned = s.getEntries().toArray(new AclEntry[0]);
   assertArrayEquals(new AclEntry[] {}, returned);
 }
 @Test
 public void testSetAclSnapshotPath() throws Exception {
   FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700));
   SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
   List<AclEntry> aclSpec = Lists.newArrayList(aclEntry(DEFAULT, USER, "bruce"));
   exception.expect(SnapshotAccessControlException.class);
   hdfs.setAcl(snapshotPath, aclSpec);
 }
  @Test
  public void testOriginalAclEnforcedForSnapshotRootAfterChange() throws Exception {
    FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700));
    List<AclEntry> aclSpec =
        Lists.newArrayList(
            aclEntry(ACCESS, USER, ALL),
            aclEntry(ACCESS, USER, "bruce", READ_EXECUTE),
            aclEntry(ACCESS, GROUP, NONE),
            aclEntry(ACCESS, OTHER, NONE));
    hdfs.setAcl(path, aclSpec);

    assertDirPermissionGranted(fsAsBruce, BRUCE, path);
    assertDirPermissionDenied(fsAsDiana, DIANA, path);

    SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);

    // Both original and snapshot still have same ACL.
    AclStatus s = hdfs.getAclStatus(path);
    AclEntry[] returned = s.getEntries().toArray(new AclEntry[0]);
    assertArrayEquals(
        new AclEntry[] {
          aclEntry(ACCESS, USER, "bruce", READ_EXECUTE), aclEntry(ACCESS, GROUP, NONE)
        },
        returned);
    assertPermission((short) 010750, path);

    s = hdfs.getAclStatus(snapshotPath);
    returned = s.getEntries().toArray(new AclEntry[0]);
    assertArrayEquals(
        new AclEntry[] {
          aclEntry(ACCESS, USER, "bruce", READ_EXECUTE), aclEntry(ACCESS, GROUP, NONE)
        },
        returned);
    assertPermission((short) 010750, snapshotPath);

    assertDirPermissionGranted(fsAsBruce, BRUCE, snapshotPath);
    assertDirPermissionDenied(fsAsDiana, DIANA, snapshotPath);

    aclSpec =
        Lists.newArrayList(
            aclEntry(ACCESS, USER, READ_EXECUTE),
            aclEntry(ACCESS, USER, "diana", READ_EXECUTE),
            aclEntry(ACCESS, GROUP, NONE),
            aclEntry(ACCESS, OTHER, NONE));
    hdfs.setAcl(path, aclSpec);

    // Original has changed, but snapshot still has old ACL.
    doSnapshotRootChangeAssertions(path, snapshotPath);
    restart(false);
    doSnapshotRootChangeAssertions(path, snapshotPath);
    restart(true);
    doSnapshotRootChangeAssertions(path, snapshotPath);
  }
  @Test
  public void testDefaultAclNotCopiedToAccessAclOfNewSnapshot() throws Exception {
    FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700));
    List<AclEntry> aclSpec = Lists.newArrayList(aclEntry(DEFAULT, USER, "bruce", READ_EXECUTE));
    hdfs.modifyAclEntries(path, aclSpec);

    SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);

    AclStatus s = hdfs.getAclStatus(path);
    AclEntry[] returned = s.getEntries().toArray(new AclEntry[0]);
    assertArrayEquals(
        new AclEntry[] {
          aclEntry(DEFAULT, USER, ALL),
          aclEntry(DEFAULT, USER, "bruce", READ_EXECUTE),
          aclEntry(DEFAULT, GROUP, NONE),
          aclEntry(DEFAULT, MASK, READ_EXECUTE),
          aclEntry(DEFAULT, OTHER, NONE)
        },
        returned);
    assertPermission((short) 010700, path);

    s = hdfs.getAclStatus(snapshotPath);
    returned = s.getEntries().toArray(new AclEntry[0]);
    assertArrayEquals(
        new AclEntry[] {
          aclEntry(DEFAULT, USER, ALL),
          aclEntry(DEFAULT, USER, "bruce", READ_EXECUTE),
          aclEntry(DEFAULT, GROUP, NONE),
          aclEntry(DEFAULT, MASK, READ_EXECUTE),
          aclEntry(DEFAULT, OTHER, NONE)
        },
        returned);
    assertPermission((short) 010700, snapshotPath);

    assertDirPermissionDenied(fsAsBruce, BRUCE, snapshotPath);
  }
  @Test
  public void testDeDuplication() throws Exception {
    int startSize = AclStorage.getUniqueAclFeatures().getUniqueElementsSize();
    // unique default AclEntries for this test
    List<AclEntry> aclSpec =
        Lists.newArrayList(
            aclEntry(ACCESS, USER, "testdeduplicateuser", ALL),
            aclEntry(ACCESS, GROUP, "testdeduplicategroup", ALL));
    hdfs.mkdirs(path);
    hdfs.modifyAclEntries(path, aclSpec);
    assertEquals(
        "One more ACL feature should be unique",
        startSize + 1,
        AclStorage.getUniqueAclFeatures().getUniqueElementsSize());
    Path subdir = new Path(path, "sub-dir");
    hdfs.mkdirs(subdir);
    Path file = new Path(path, "file");
    hdfs.create(file).close();
    AclFeature aclFeature;
    {
      // create the snapshot with root directory having ACLs should refer to
      // same ACLFeature without incrementing the reference count
      aclFeature = FSAclBaseTest.getAclFeature(path, cluster);
      assertEquals("Reference count should be one before snapshot", 1, aclFeature.getRefCount());
      Path snapshotPath = SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
      AclFeature snapshotAclFeature = FSAclBaseTest.getAclFeature(snapshotPath, cluster);
      assertSame(aclFeature, snapshotAclFeature);
      assertEquals("Reference count should be increased", 2, snapshotAclFeature.getRefCount());
    }
    {
      // deleting the snapshot with root directory having ACLs should not alter
      // the reference count of the ACLFeature
      deleteSnapshotWithAclAndVerify(aclFeature, path, startSize);
    }
    {
      hdfs.modifyAclEntries(subdir, aclSpec);
      aclFeature = FSAclBaseTest.getAclFeature(subdir, cluster);
      assertEquals("Reference count should be 1", 1, aclFeature.getRefCount());
      Path snapshotPath = SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
      Path subdirInSnapshot = new Path(snapshotPath, "sub-dir");
      AclFeature snapshotAcl = FSAclBaseTest.getAclFeature(subdirInSnapshot, cluster);
      assertSame(aclFeature, snapshotAcl);
      assertEquals("Reference count should remain same", 1, aclFeature.getRefCount());

      // Delete the snapshot with sub-directory containing the ACLs should not
      // alter the reference count for AclFeature
      deleteSnapshotWithAclAndVerify(aclFeature, subdir, startSize);
    }
    {
      hdfs.modifyAclEntries(file, aclSpec);
      aclFeature = FSAclBaseTest.getAclFeature(file, cluster);
      assertEquals("Reference count should be 1", 1, aclFeature.getRefCount());
      Path snapshotPath = SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
      Path fileInSnapshot = new Path(snapshotPath, file.getName());
      AclFeature snapshotAcl = FSAclBaseTest.getAclFeature(fileInSnapshot, cluster);
      assertSame(aclFeature, snapshotAcl);
      assertEquals("Reference count should remain same", 1, aclFeature.getRefCount());

      // Delete the snapshot with contained file having ACLs should not
      // alter the reference count for AclFeature
      deleteSnapshotWithAclAndVerify(aclFeature, file, startSize);
    }
    {
      // Modifying the ACLs of root directory of the snapshot should refer new
      // AclFeature. And old AclFeature should be referenced by snapshot
      hdfs.modifyAclEntries(path, aclSpec);
      Path snapshotPath = SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
      AclFeature snapshotAcl = FSAclBaseTest.getAclFeature(snapshotPath, cluster);
      aclFeature = FSAclBaseTest.getAclFeature(path, cluster);
      assertEquals(
          "Before modification same ACL should be referenced twice", 2, aclFeature.getRefCount());
      List<AclEntry> newAcl = Lists.newArrayList(aclEntry(ACCESS, USER, "testNewUser", ALL));
      hdfs.modifyAclEntries(path, newAcl);
      aclFeature = FSAclBaseTest.getAclFeature(path, cluster);
      AclFeature snapshotAclPostModification = FSAclBaseTest.getAclFeature(snapshotPath, cluster);
      assertSame(snapshotAcl, snapshotAclPostModification);
      assertNotSame(aclFeature, snapshotAclPostModification);
      assertEquals("Old ACL feature reference count should be same", 1, snapshotAcl.getRefCount());
      assertEquals("New ACL feature reference should be used", 1, aclFeature.getRefCount());
      deleteSnapshotWithAclAndVerify(aclFeature, path, startSize);
    }
    {
      // Modifying the ACLs of sub directory of the snapshot root should refer
      // new AclFeature. And old AclFeature should be referenced by snapshot
      hdfs.modifyAclEntries(subdir, aclSpec);
      Path snapshotPath = SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
      Path subdirInSnapshot = new Path(snapshotPath, "sub-dir");
      AclFeature snapshotAclFeature = FSAclBaseTest.getAclFeature(subdirInSnapshot, cluster);
      List<AclEntry> newAcl = Lists.newArrayList(aclEntry(ACCESS, USER, "testNewUser", ALL));
      hdfs.modifyAclEntries(subdir, newAcl);
      aclFeature = FSAclBaseTest.getAclFeature(subdir, cluster);
      assertNotSame(aclFeature, snapshotAclFeature);
      assertEquals("Reference count should remain same", 1, snapshotAclFeature.getRefCount());
      assertEquals("New AclFeature should be used", 1, aclFeature.getRefCount());

      deleteSnapshotWithAclAndVerify(aclFeature, subdir, startSize);
    }
    {
      // Modifying the ACLs of file inside the snapshot root should refer new
      // AclFeature. And old AclFeature should be referenced by snapshot
      hdfs.modifyAclEntries(file, aclSpec);
      Path snapshotPath = SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
      Path fileInSnapshot = new Path(snapshotPath, file.getName());
      AclFeature snapshotAclFeature = FSAclBaseTest.getAclFeature(fileInSnapshot, cluster);
      List<AclEntry> newAcl = Lists.newArrayList(aclEntry(ACCESS, USER, "testNewUser", ALL));
      hdfs.modifyAclEntries(file, newAcl);
      aclFeature = FSAclBaseTest.getAclFeature(file, cluster);
      assertNotSame(aclFeature, snapshotAclFeature);
      assertEquals("Reference count should remain same", 1, snapshotAclFeature.getRefCount());
      deleteSnapshotWithAclAndVerify(aclFeature, file, startSize);
    }
    {
      // deleting the original directory containing dirs and files with ACLs
      // with snapshot
      hdfs.delete(path, true);
      Path dir = new Path(subdir, "dir");
      hdfs.mkdirs(dir);
      hdfs.modifyAclEntries(dir, aclSpec);
      file = new Path(subdir, "file");
      hdfs.create(file).close();
      aclSpec.add(aclEntry(ACCESS, USER, "testNewUser", ALL));
      hdfs.modifyAclEntries(file, aclSpec);
      AclFeature fileAcl = FSAclBaseTest.getAclFeature(file, cluster);
      AclFeature dirAcl = FSAclBaseTest.getAclFeature(dir, cluster);
      Path snapshotPath = SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);
      Path dirInSnapshot = new Path(snapshotPath, "sub-dir/dir");
      AclFeature snapshotDirAclFeature = FSAclBaseTest.getAclFeature(dirInSnapshot, cluster);
      Path fileInSnapshot = new Path(snapshotPath, "sub-dir/file");
      AclFeature snapshotFileAclFeature = FSAclBaseTest.getAclFeature(fileInSnapshot, cluster);
      assertSame(fileAcl, snapshotFileAclFeature);
      assertSame(dirAcl, snapshotDirAclFeature);
      hdfs.delete(subdir, true);
      assertEquals(
          "Original ACLs references should be maintained for snapshot",
          1,
          snapshotFileAclFeature.getRefCount());
      assertEquals(
          "Original ACLs references should be maintained for snapshot",
          1,
          snapshotDirAclFeature.getRefCount());
      hdfs.deleteSnapshot(path, snapshotName);
      assertEquals(
          "ACLs should be deleted from snapshot",
          startSize,
          AclStorage.getUniqueAclFeatures().getUniqueElementsSize());
    }
  }
  @Test
  public void testOriginalAclEnforcedForSnapshotContentsAfterRemoval() throws Exception {
    Path filePath = new Path(path, "file1");
    Path subdirPath = new Path(path, "subdir1");
    Path fileSnapshotPath = new Path(snapshotPath, "file1");
    Path subdirSnapshotPath = new Path(snapshotPath, "subdir1");
    FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0777));
    FileSystem.create(hdfs, filePath, FsPermission.createImmutable((short) 0600)).close();
    FileSystem.mkdirs(hdfs, subdirPath, FsPermission.createImmutable((short) 0700));
    List<AclEntry> aclSpec =
        Lists.newArrayList(
            aclEntry(ACCESS, USER, READ_EXECUTE),
            aclEntry(ACCESS, USER, "bruce", READ_EXECUTE),
            aclEntry(ACCESS, GROUP, NONE),
            aclEntry(ACCESS, OTHER, NONE));
    hdfs.setAcl(filePath, aclSpec);
    hdfs.setAcl(subdirPath, aclSpec);

    assertFilePermissionGranted(fsAsBruce, BRUCE, filePath);
    assertFilePermissionDenied(fsAsDiana, DIANA, filePath);
    assertDirPermissionGranted(fsAsBruce, BRUCE, subdirPath);
    assertDirPermissionDenied(fsAsDiana, DIANA, subdirPath);

    SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName);

    // Both original and snapshot still have same ACL.
    AclEntry[] expected =
        new AclEntry[] {
          aclEntry(ACCESS, USER, "bruce", READ_EXECUTE), aclEntry(ACCESS, GROUP, NONE)
        };
    AclStatus s = hdfs.getAclStatus(filePath);
    AclEntry[] returned = s.getEntries().toArray(new AclEntry[0]);
    assertArrayEquals(expected, returned);
    assertPermission((short) 010550, filePath);

    s = hdfs.getAclStatus(subdirPath);
    returned = s.getEntries().toArray(new AclEntry[0]);
    assertArrayEquals(expected, returned);
    assertPermission((short) 010550, subdirPath);

    s = hdfs.getAclStatus(fileSnapshotPath);
    returned = s.getEntries().toArray(new AclEntry[0]);
    assertArrayEquals(expected, returned);
    assertPermission((short) 010550, fileSnapshotPath);
    assertFilePermissionGranted(fsAsBruce, BRUCE, fileSnapshotPath);
    assertFilePermissionDenied(fsAsDiana, DIANA, fileSnapshotPath);

    s = hdfs.getAclStatus(subdirSnapshotPath);
    returned = s.getEntries().toArray(new AclEntry[0]);
    assertArrayEquals(expected, returned);
    assertPermission((short) 010550, subdirSnapshotPath);
    assertDirPermissionGranted(fsAsBruce, BRUCE, subdirSnapshotPath);
    assertDirPermissionDenied(fsAsDiana, DIANA, subdirSnapshotPath);

    hdfs.removeAcl(filePath);
    hdfs.removeAcl(subdirPath);

    // Original has changed, but snapshot still has old ACL.
    doSnapshotContentsRemovalAssertions(filePath, fileSnapshotPath, subdirPath, subdirSnapshotPath);
    restart(false);
    doSnapshotContentsRemovalAssertions(filePath, fileSnapshotPath, subdirPath, subdirSnapshotPath);
    restart(true);
    doSnapshotContentsRemovalAssertions(filePath, fileSnapshotPath, subdirPath, subdirSnapshotPath);
  }