Add FsAdaptorTest and supporting test infrastructure
This adds unit tests for the FsAdaptor class, including a bunch
of supporting test classes. The changes include:
FsAdaptorTest: 49 Unit tests for FsAdaptor class
FsAdaptor: Added a test constructor that takes a FileDelegate arg, made some
methods and inner classes VisibleForTesting
HtmlResponseWriter: Fixed array bounds exception for unix paths
MockFile: A lightweight, in-memory file system
MockFileTest: Sanity checks for MockFile
MockFileDelgate: A FileDelegate backed by MockFiles
MockFileDelegateTest: Sanity checks for MockFileDelegate
MockAdaptorContext: A AdaptorContext wrapping AccumlatingDocIdPusher
MockRequest: A trivial Request implementation
MockResponse: A Response that supports only the features used by the adaptor
AccumulatingDocIdPusher: Imported from SP adaptor and heavily modified
UnsupportedDocIdPusher: Parent class of AccumulatingDocId pusher
MockDocIdCodec: Imported from adaptor framework tests
These unit tests provide 91% code coverage for the FsAdaptor class.
Code Review: https://codereview.appspot.com/58560043/
diff --git a/src/com/google/enterprise/adaptor/fs/FsAdaptor.java b/src/com/google/enterprise/adaptor/fs/FsAdaptor.java
index f957bde..2928a61 100644
--- a/src/com/google/enterprise/adaptor/fs/FsAdaptor.java
+++ b/src/com/google/enterprise/adaptor/fs/FsAdaptor.java
@@ -132,12 +132,14 @@
/** The namespace applied to ACL Principals. */
private String namespace;
+ /** The filesystem change monitor. */
+ private FsMonitor monitor;
+
private AdaptorContext context;
private Path rootPath;
private boolean isDfsUnc;
private DocId rootPathDocId;
private FileDelegate delegate;
- private FsMonitor monitor;
public FsAdaptor() {
// At the moment, we only support Windows.
@@ -154,6 +156,26 @@
this.delegate = delegate;
}
+ @VisibleForTesting
+ Set<String> getSupportedWindowsAccounts() {
+ return supportedWindowsAccounts;
+ }
+
+ @VisibleForTesting
+ String getBuiltinPrefix() {
+ return builtinPrefix;
+ }
+
+ @VisibleForTesting
+ String getNamespace() {
+ return namespace;
+ }
+
+ @VisibleForTesting
+ BlockingQueue<Path> getFsMonitorQueue() {
+ return monitor.getQueue();
+ }
+
@Override
public void initConfig(Config config) {
config.addKey(CONFIG_SRC, null);
@@ -238,8 +260,13 @@
@Override
public void destroy() {
delegate.destroy();
- monitor.destroy();
- monitor = null;
+ // TODO (bmj): The check for null monitor is strictly for the tests,
+ // some of which may not have fully initialized the adaptor. Maybe
+ // look into handling this less obtrusively in the future.
+ if (monitor != null) {
+ monitor.destroy();
+ monitor = null;
+ }
}
@Override
@@ -414,10 +441,10 @@
// Populate the document content.
if (docIsDirectory) {
HtmlResponseWriter writer = createHtmlResponseWriter(resp);
- writer.start(id, getPathName(doc));
+ writer.start(id, getFileName(doc));
for (Path file : delegate.newDirectoryStream(doc)) {
if (isSupportedPath(file)) {
- writer.addLink(delegate.newDocId(file), getPathName(file));
+ writer.addLink(delegate.newDocId(file), getFileName(file));
}
}
writer.finish();
@@ -450,14 +477,14 @@
response.setContentType("text/html; charset=" + CHARSET.name());
// TODO(ejona): Get locale from request.
return new HtmlResponseWriter(writer, context.getDocIdEncoder(),
-
Locale.ENGLISH);
}
@VisibleForTesting
- String getPathName(Path file) {
+ String getFileName(Path file) {
// NOTE: file.getFileName() fails for UNC paths. Use file.toFile() instead.
- return file.toFile().getName();
+ String name = file.toFile().getName();
+ return name.isEmpty() ? file.getRoot().toString() : name;
}
@VisibleForTesting
@@ -505,8 +532,8 @@
Preconditions.checkNotNull(pusher, "the DocId pusher may not be null");
Preconditions.checkArgument(maxFeedSize > 0,
"the maxFeedSize must be greater than zero");
- Preconditions.checkArgument(maxLatencyMillis > 0,
- "the maxLatencyMillis must be greater than zero");
+ Preconditions.checkArgument(maxLatencyMillis >= 0,
+ "the maxLatencyMillis must be greater than or equal to zero");
this.pusher = pusher;
this.maxFeedSize = maxFeedSize;
this.maxLatencyMillis = maxLatencyMillis;
diff --git a/src/com/google/enterprise/adaptor/fs/HtmlResponseWriter.java b/src/com/google/enterprise/adaptor/fs/HtmlResponseWriter.java
index 3cf0f47..e0d50f3 100644
--- a/src/com/google/enterprise/adaptor/fs/HtmlResponseWriter.java
+++ b/src/com/google/enterprise/adaptor/fs/HtmlResponseWriter.java
@@ -15,6 +15,7 @@
package com.google.enterprise.adaptor.fs;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
import com.google.enterprise.adaptor.DocId;
import com.google.enterprise.adaptor.DocIdEncoder;
@@ -213,10 +214,10 @@
}
private String computeLabel(String label, DocId doc) {
- if (label == null || "".equals(label)) {
+ if (Strings.isNullOrEmpty(label)) {
// Use the last part of the URL if an item doesn't have a title. The last
// part of the URL will generally be a filename in this case.
- String[] parts = doc.getUniqueId().split("/");
+ String[] parts = doc.getUniqueId().split("/", 0);
label = parts[parts.length - 1];
}
return label;
diff --git a/test/com/google/enterprise/adaptor/fs/AccumulatingDocIdPusher.java b/test/com/google/enterprise/adaptor/fs/AccumulatingDocIdPusher.java
new file mode 100644
index 0000000..5c38e25
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/fs/AccumulatingDocIdPusher.java
@@ -0,0 +1,96 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// 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.google.enterprise.adaptor.fs;
+
+import com.google.enterprise.adaptor.Acl;
+import com.google.enterprise.adaptor.DocId;
+import com.google.enterprise.adaptor.ExceptionHandler;
+import com.google.enterprise.adaptor.GroupPrincipal;
+import com.google.enterprise.adaptor.Principal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+class AccumulatingDocIdPusher extends UnsupportedDocIdPusher {
+ private List<Record> records = new ArrayList<Record>();
+ private List<Map<DocId, Acl>> namedResouces
+ = new ArrayList<Map<DocId, Acl>>();
+
+ @Override
+ public DocId pushDocIds(Iterable<DocId> docIds)
+ throws InterruptedException {
+ return pushDocIds(docIds, null);
+ }
+
+ @Override
+ public DocId pushDocIds(Iterable<DocId> docIds,
+ ExceptionHandler handler)
+ throws InterruptedException {
+ List<Record> records = new ArrayList<Record>();
+ for (DocId docId : docIds) {
+ records.add(new Record.Builder(docId).build());
+ }
+ Record record = pushRecords(records, handler);
+ return record == null ? null : record.getDocId();
+ }
+
+ @Override
+ public Record pushRecords(Iterable<Record> records)
+ throws InterruptedException {
+ return pushRecords(records, null);
+ }
+
+ @Override
+ public Record pushRecords(Iterable<Record> records,
+ ExceptionHandler handler)
+ throws InterruptedException {
+ for (Record record : records) {
+ this.records.add(record);
+ }
+ return null;
+ }
+
+ @Override
+ public DocId pushNamedResources(Map<DocId, Acl> resources)
+ throws InterruptedException {
+ return pushNamedResources(resources, null);
+ }
+
+ @Override
+ public DocId pushNamedResources(Map<DocId, Acl> resources,
+ ExceptionHandler handler)
+ throws InterruptedException {
+ namedResouces.add(Collections.unmodifiableMap(
+ new TreeMap<DocId, Acl>(resources)));
+ return null;
+ }
+
+ public List<Record> getRecords() {
+ return Collections.unmodifiableList(records);
+ }
+
+ public List<Map<DocId, Acl>> getNamedResources() {
+ return Collections.unmodifiableList(namedResouces);
+ }
+
+ public void reset() {
+ records.clear();
+ namedResouces.clear();
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/fs/FsAdaptorTest.java b/test/com/google/enterprise/adaptor/fs/FsAdaptorTest.java
index 1430991..913c704 100644
--- a/test/com/google/enterprise/adaptor/fs/FsAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/fs/FsAdaptorTest.java
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All Rights Reserved.
+// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,86 +14,915 @@
package com.google.enterprise.adaptor.fs;
+import static com.google.enterprise.adaptor.fs.AclView.user;
+import static com.google.enterprise.adaptor.fs.AclView.group;
+import static com.google.enterprise.adaptor.fs.AclView.GenericPermission.*;
+
import static org.junit.Assert.*;
-import com.google.enterprise.adaptor.fs.MockDirectoryBuilder.ConfigureFile;
+import static java.nio.file.attribute.AclEntryFlag.*;
+import static java.nio.file.attribute.AclEntryPermission.*;
+import static java.nio.file.attribute.AclEntryType.*;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import com.google.enterprise.adaptor.Acl;
+import com.google.enterprise.adaptor.Acl.InheritanceType;
+import com.google.enterprise.adaptor.AdaptorContext;
+import com.google.enterprise.adaptor.Config;
+import com.google.enterprise.adaptor.DocId;
+import com.google.enterprise.adaptor.DocIdPusher.Record;
+import com.google.enterprise.adaptor.GroupPrincipal;
+import com.google.enterprise.adaptor.UserPrincipal;
import org.junit.*;
import org.junit.rules.ExpectedException;
+import java.io.File;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.file.attribute.AclFileAttributeView;
+import java.nio.file.attribute.FileTime;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
/** Test cases for {@link FsAdaptor}. */
public class FsAdaptorTest {
- private MockDirectoryBuilder builder;
- private MockFileDelegate delegate;
- private FsAdaptor adaptor;
- private Config config;
- @Override
- protected void setUp() {
- builder = new MockDirectoryBuilder();
- delegate = new MockFileDelegate(builder);
- adaptor = new FsAdaptor(delegate);
- config = new Config();
+ static final String ROOT = "/";
+ static final Path rootPath = Paths.get(ROOT);
+ static final DocId shareAclDocId = new DocId("shareAcl");
+
+ private AdaptorContext context = new MockAdaptorContext();
+ private AccumulatingDocIdPusher pusher =
+ (AccumulatingDocIdPusher) context.getDocIdPusher();
+ private Config config = context.getConfig();
+ private MockFile root = new MockFile(ROOT, true);
+ private MockFileDelegate delegate = new MockFileDelegate(root);
+ private FsAdaptor adaptor = new FsAdaptor(delegate);
+ private DocId rootDocId;
+
+ @Before
+ public void setUp() throws Exception {
+ rootDocId = delegate.newDocId(rootPath);
adaptor.initConfig(config);
+ config.overrideKey("filesystemadaptor.src", root.getPath());
+ config.overrideKey("adaptor.incrementalPollPeriodSecs", "0");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ adaptor.destroy();
}
@Rule
public ExpectedException thrown = ExpectedException.none();
+ private Path getPath(String path) {
+ return rootPath.resolve(path);
+ }
+
+ private DocId getDocId(String path) throws IOException {
+ return delegate.newDocId(getPath(path));
+ }
+
@Test
- public void testGetPathName() throws Exception {
- assertEquals("share", adaptor.getPathName(Paths.get("\\\\host/share/")));
- assertEquals("folder2",
- adaptor.getPathName(Paths.get("C:/folder1/folder2/")));
- assertEquals("foo.text",
- adaptor.getPathName(Paths.get("C:/folder1/foo.txt")));
- assertEquals("bug-test", adaptor.getPathName(Paths.get("\\\\\brwsr-xp.gdc-psl.net/bug-test/")));
+ public void testAdaptorStartupShutdown() throws Exception {
+ // Construction of Adaptor happened in setUp(), and
+ // destruction will happen in tearDown(), so the only
+ // thing left is to init the context.
+ adaptor.init(context);
+ }
+
+ @Test
+ public void testAdaptorInitNoSourcePath() throws Exception {
+ config.overrideKey("filesystemadaptor.src", "");
+ thrown.expect(IOException.class);
+ adaptor.init(context);
+ }
+
+ @Test
+ public void testAdaptorInitNonRootSourcePath() throws Exception {
+ root.addChildren(new MockFile("subdir", true));
+ config.overrideKey("filesystemadaptor.src", getPath("subdir").toString());
+ thrown.expect(IllegalStateException.class);
+ adaptor.init(context);
+ }
+
+ @Test
+ public void testAdaptorInitDfsUncActiveStorageUnc() throws Exception {
+ root.setDfsUncActiveStorageUnc(Paths.get("\\\\dfshost\\share"));
+ adaptor.init(context);
+ }
+
+ @Test
+ public void testAdaptorInitNonLinkDfsUncActiveStorageUnc() throws Exception {
+ root.setDfsUncActiveStorageUnc(rootPath);
+ thrown.expect(IOException.class);
+ adaptor.init(context);
+ }
+
+ @Test
+ public void testAdaptorInitSupportedWindowsAccounts() throws Exception {
+ String accounts = "Everyone, BUILTIN\\Users, NT AUTH\\New Users";
+ Set<String> expected =
+ ImmutableSet.of("Everyone", "BUILTIN\\Users", "NT AUTH\\New Users");
+ config.overrideKey("filesystemadaptor.supportedAccounts", accounts);
+ adaptor.init(context);
+ assertEquals(expected, adaptor.getSupportedWindowsAccounts());
+ }
+
+ @Test
+ public void testAdaptorInitBuiltinGroupPrefix() throws Exception {
+ String expected = "TestPrefix";
+ config.overrideKey("filesystemadaptor.builtinGroupPrefix", expected);
+ adaptor.init(context);
+ assertEquals(expected, adaptor.getBuiltinPrefix());
+ }
+
+ @Test
+ public void testAdaptorInitNamespace() throws Exception {
+ String expected = "TestNamespace";
+ config.overrideKey("adaptor.namespace", expected);
+ adaptor.init(context);
+ assertEquals(expected, adaptor.getNamespace());
+ }
+
+ @Test
+ public void testGetFolderName() throws Exception {
+ assertEquals("share", adaptor.getFileName(Paths.get("\\\\host/share/")));
+ assertEquals("folder2",
+ adaptor.getFileName(Paths.get("C:/folder1/folder2/")));
+ assertEquals("folder2",
+ adaptor.getFileName(Paths.get("/folder1/folder2/")));
+ assertEquals("share", adaptor.getFileName(Paths.get("\\\\host/share")));
+ assertEquals("folder1",
+ adaptor.getFileName(Paths.get("/folder1")));
+ assertEquals(File.separator, // Windows flips the '/' to '\'.
+ adaptor.getFileName(Paths.get("/")));
+ assertEquals("C:\\",
+ adaptor.getFileName(Paths.get("C:\\")));
}
@Test
public void testIsSupportedPath() throws Exception {
- ConfigureFile configureFile = new ConfigureFile() {
- public boolean configure(MockFile file) {
- if ("link".equals(file.getName())) {
- file.setIsDirectory(false);
- file.setIsRegularFile(false);
- return false;
- }
- return true;
- }
- };
- builder.addDir(configureFile, null, "/root", "foo", "link", "bar");
-
- assertTrue(adaptor.isSupportedPath(delegate.getPath("/root")));
- assertTrue(adaptor.isSupportedPath(delegate.getPath("/root/foo")));
- assertTrue(adaptor.isSupportedPath(delegate.getPath("/root/bar")));
- assertFalse(adaptor.isSupportedPath(delegate.getPath("/root/link")));
+ root.addChildren(new MockFile("foo"), new MockFile("bar", true),
+ new MockFile("link").setIsRegularFile(false));
+ assertTrue(adaptor.isSupportedPath(rootPath));
+ assertTrue(adaptor.isSupportedPath(getPath("foo")));
+ assertTrue(adaptor.isSupportedPath(getPath("bar")));
+ assertFalse(adaptor.isSupportedPath(getPath("link")));
}
- /*
+
@Test
public void testIsVisibleDescendantOfRoot() throws Exception {
- ConfigureFile configureFile = new ConfigureFile() {
- public boolean configure(MockFile file) {
- if ("hidden".equals(file.getName())) {
- file.setIsHidden(true);
- return false;
- }
- return true;
- }
- };
- MockFile root = builder.addDir(null, "/", "foo");
- builder.addDir(configureFile, root, "dir1", "bar", "hidden");
- MockFile dir2 = builder.addDir(configureFile, root, "dir2", "baz");
- builder.addDir(configureFile, dir2, "hidden", "foobar");
-
- assertTrue(adaptor.isSupportedPath(delegate.getPath("/root")));
- assertTrue(adaptor.isSupportedPath(delegate.getPath("/root/foo")));
- assertTrue(adaptor.isSupportedPath(delegate.getPath("/root/bar")));
- assertFalse(adaptor.isSupportedPath(delegate.getPath("/root/link")));
+ adaptor.init(context);
+ root.addChildren(new MockFile("foo"),
+ new MockFile("hidden.txt").setIsHidden(true),
+ new MockFile("dir1", true).addChildren(new MockFile("bar"),
+ new MockFile("hidden.pdf").setIsHidden(true)),
+ new MockFile("hidden.dir", true).setIsHidden(true).addChildren(
+ new MockFile("baz")));
+ assertTrue(adaptor.isVisibleDescendantOfRoot(rootPath));
+ assertTrue(adaptor.isVisibleDescendantOfRoot(getPath("foo")));
+ assertTrue(adaptor.isVisibleDescendantOfRoot(getPath("dir1")));
+ assertTrue(adaptor.isVisibleDescendantOfRoot(getPath("dir1/bar")));
+ assertFalse(adaptor.isVisibleDescendantOfRoot(getPath("hidden.txt")));
+ assertFalse(adaptor.isVisibleDescendantOfRoot(getPath("dir1/hidden.pdf")));
+ assertFalse(adaptor.isVisibleDescendantOfRoot(getPath("hidden.dir")));
+ assertFalse(adaptor.isVisibleDescendantOfRoot(getPath("hidden.dir/baz")));
+ assertFalse(adaptor.isVisibleDescendantOfRoot(null));
}
-
- */
+ @Test
+ public void testGetDocIds() throws Exception {
+ adaptor.init(context);
+ adaptor.getDocIds(pusher);
+
+ // We should just push the root docid.
+ List<Record> records = pusher.getRecords();
+ assertEquals(1, records.size());
+ assertEquals(delegate.newDocId(rootPath), records.get(0).getDocId());
+
+ // We should have pushed an acl for the share.
+ List<Map<DocId, Acl>> namedResources = pusher.getNamedResources();
+ Acl expected = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitGroups(Collections.singleton(new GroupPrincipal("Everyone")))
+ .setInheritanceType(InheritanceType.AND_BOTH_PERMIT).build();
+ assertEquals(1, namedResources.size());
+ assertEquals(1, namedResources.get(0).size());
+ assertEquals(expected, namedResources.get(0).get(shareAclDocId));
+ }
+
+ @Test
+ public void testGetDocIdsDfs() throws Exception {
+ Path uncPath = Paths.get("\\\\dfshost\\share");
+ root.setDfsUncActiveStorageUnc(uncPath);
+ root.setDfsShareAclView(MockFile.FULL_ACCESS_ACLVIEW);
+ adaptor.init(context);
+ adaptor.getDocIds(pusher);
+
+ // We should just push the root docid.
+ List<Record> records = pusher.getRecords();
+ assertEquals(1, records.size());
+ assertEquals(delegate.newDocId(rootPath), records.get(0).getDocId());
+
+ // We should have pushed acls for the share and the dfsShare.
+ List<Map<DocId, Acl>> namedResources = pusher.getNamedResources();
+ DocId dfsShareAcl = new DocId("dfsShareAcl");
+ Acl expectedDfsShareAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitGroups(Collections.singleton(new GroupPrincipal("Everyone")))
+ .setInheritanceType(InheritanceType.AND_BOTH_PERMIT).build();
+ Acl expectedShareAcl = new Acl.Builder(expectedDfsShareAcl)
+ .setInheritFrom(dfsShareAcl).build();
+ assertEquals(1, namedResources.size());
+ Map<DocId, Acl> acls = namedResources.get(0);
+ assertEquals(2, acls.size());
+ assertEquals(expectedDfsShareAcl, acls.get(dfsShareAcl));
+ assertEquals(expectedShareAcl, acls.get(shareAclDocId));
+ }
+
+ @Test
+ public void testGetDocIdsBrokenDfs() throws Exception {
+ Path uncPath = Paths.get("\\\\dfshost\\share");
+ root.setDfsUncActiveStorageUnc(uncPath);
+ root.setDfsShareAclView(MockFile.FULL_ACCESS_ACLVIEW);
+ adaptor.init(context);
+
+ // Now make the active storage disappear.
+ root.setDfsUncActiveStorageUnc(null);
+ thrown.expect(IOException.class);
+ adaptor.getDocIds(pusher);
+ }
+
+ @Test
+ public void testGetDocContentUnsupportedPath() throws Exception {
+ root.addChildren(new MockFile("unsupported").setIsRegularFile(false));
+ adaptor.init(context);
+ MockResponse response = new MockResponse();
+ adaptor.getDocContent(new MockRequest(getDocId("unsupported")), response);
+ assertTrue(response.notFound);
+ }
+
+ /*
+ * This test was invalidated when the check for isSupportedPath()
+ * was moved above the check for bad DocIds in the beginning of
+ * FsAdaptor.getDocumentContent(). This test still passes, but
+ * the notFound response is coming from the earlier check for
+ * isSupportedPath(), not from the bad DocId.
+ */
+ @Test
+ public void testGetDocContentBadDocId() throws Exception {
+ root.addChildren(new MockFile("badfile"));
+ adaptor.init(context);
+ MockResponse response = new MockResponse();
+ // The requested DocId is missing the root component of the path.
+ adaptor.getDocContent(new MockRequest(new DocId("badfile")), response);
+ assertTrue(response.notFound);
+ }
+
+ @Test
+ public void testGetDocContentHiddenFile() throws Exception {
+ root.addChildren(new MockFile("hidden.txt").setIsHidden(true));
+ adaptor.init(context);
+ MockResponse response = new MockResponse();
+ adaptor.getDocContent(new MockRequest(getDocId("hidden.txt")), response);
+ assertTrue(response.notFound);
+ }
+
+ @Test
+ public void testGetDocContentHiddenDirectory() throws Exception {
+ root.addChildren(new MockFile("hidden.dir", true).setIsHidden(true));
+ adaptor.init(context);
+ MockResponse response = new MockResponse();
+ adaptor.getDocContent(new MockRequest(getDocId("hidden.dir")), response);
+ assertTrue(response.notFound);
+ }
+
+ @Test
+ public void testGetDocContentRegularFile() throws Exception {
+ String fname = "test.html";
+ Date modifyDate = new Date(30000);
+ FileTime modifyTime = FileTime.fromMillis(modifyDate.getTime());
+ String content = "<html><title>Hello World</title></html>";
+ root.addChildren(new MockFile(fname).setLastModifiedTime(modifyTime)
+ .setFileContents(content).setContentType("text/html"));
+ adaptor.init(context);
+
+ MockResponse response = new MockResponse();
+ adaptor.getDocContent(new MockRequest(getDocId(fname)), response);
+ assertFalse(response.notFound);
+ assertEquals(modifyDate, response.lastModified);
+ assertEquals(getPath(fname).toUri(), response.displayUrl);
+ assertEquals("text/html", response.contentType);
+ assertEquals(content, response.content.toString("UTF-8"));
+ // TODO: check metadata.
+ assertNotNull(response.metadata.get("Creation Time"));
+ // ACL checked in other tests.
+ }
+
+ @Test
+ public void testGetDocContentRootAcl() throws Exception {
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitGroups(Collections.singleton(new GroupPrincipal("Everyone")))
+ .setInheritFrom(shareAclDocId)
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES).build();
+ adaptor.init(context);
+ MockRequest request = new MockRequest(delegate.newDocId(rootPath));
+ MockResponse response = new MockResponse();
+ adaptor.getDocContent(request, response);
+ assertEquals(expectedAcl, response.acl);
+ }
+
+ @Test
+ public void testGetDocContentEmptyAcl() throws Exception {
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setInheritFrom(rootDocId, "childFilesAcl")
+ .setInheritanceType(InheritanceType.LEAF_NODE).build();
+ testFileAcl(MockFile.EMPTY_ACLVIEW, null, expectedAcl);
+ }
+
+ @Test
+ public void testGetDocContentDirectAcl() throws Exception {
+ AclFileAttributeView aclView = new AclView((user("joe")
+ .type(ALLOW).perms(GENERIC_READ).build()));
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitUsers(Collections.singleton(new UserPrincipal("joe")))
+ .setInheritFrom(rootDocId, "childFilesAcl")
+ .setInheritanceType(InheritanceType.LEAF_NODE).build();
+ testFileAcl(aclView, null, expectedAcl);
+ }
+
+ @Test
+ public void testGetDocContentNoInheritAcl() throws Exception {
+ AclFileAttributeView aclView = new AclView((user("joe")
+ .type(ALLOW).perms(GENERIC_READ).build()));
+ // Should inherit from the share, not the parent.
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitUsers(Collections.singleton(new UserPrincipal("joe")))
+ .setInheritFrom(shareAclDocId)
+ .setInheritanceType(InheritanceType.LEAF_NODE).build();
+ testFileAcl(aclView, MockFile.EMPTY_ACLVIEW, expectedAcl);
+ }
+
+ private void testFileAcl(AclFileAttributeView aclView,
+ AclFileAttributeView inheritAclView, Acl expectedAcl) throws Exception {
+ String fname = "acltest";
+ root.addChildren(new MockFile(fname).setAclView(aclView)
+ .setInheritedAclView(inheritAclView));
+ adaptor.init(context);
+ MockResponse response = new MockResponse();
+ adaptor.getDocContent(new MockRequest(getDocId(fname)), response);
+ assertEquals(expectedAcl, response.acl);
+ }
+
+ /** Test that LastAccessTime is restored after reading the file. */
+ @Test
+ public void testPreserveFileLastAccessTime() throws Exception {
+ testPreserveFileLastAccessTime(new MockFile("test") {
+ @Override
+ InputStream newInputStream() throws IOException {
+ setLastAccessTime(FileTime.fromMillis(
+ getLastAccessTime().toMillis() + 1000));
+ return super.newInputStream();
+ }
+ });
+ }
+
+ /** Test LastAccessTime is restored even if exception opening the file. */
+ @Test
+ public void testPreserveFileLastAccessTimeException1() throws Exception {
+ thrown.expect(IOException.class);
+ testPreserveFileLastAccessTime(new MockFile("test") {
+ @Override
+ InputStream newInputStream() throws IOException {
+ setLastAccessTime(FileTime.fromMillis(
+ getLastAccessTime().toMillis() + 1000));
+ throw new IOException("newInputStream");
+ }
+ });
+ }
+
+ /** Test LastAccessTime is restored even if exception reading the file. */
+ @Test
+ public void testPreserveFileLastAccessTimeException2() throws Exception {
+ thrown.expect(IOException.class);
+ testPreserveFileLastAccessTime(new MockFile("test") {
+ @Override
+ InputStream newInputStream() throws IOException {
+ setLastAccessTime(FileTime.fromMillis(
+ getLastAccessTime().toMillis() + 1000));
+ return new FilterInputStream(super.newInputStream()) {
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ throw new IOException("read");
+ }
+ };
+ }
+ });
+ }
+
+ /** Test LastAccessTime is restored even if exception closing the file. */
+ @Test
+ public void testPreserveFileLastAccessTimeException3() throws Exception {
+ thrown.expect(IOException.class);
+ testPreserveFileLastAccessTime(new MockFile("test") {
+ @Override
+ InputStream newInputStream() throws IOException {
+ setLastAccessTime(FileTime.fromMillis(
+ getLastAccessTime().toMillis() + 1000));
+ return new FilterInputStream(super.newInputStream()) {
+ @Override
+ public void close() throws IOException {
+ throw new IOException("close");
+ }
+ };
+ }
+ });
+ }
+
+ /** Test that failure to restore LastAccessTime is not fatal. */
+ @Test
+ public void testPreserveFileLastAccessTimeException4() throws Exception {
+ testNoPreserveFileLastAccessTime(new MockFile("test") {
+ @Override
+ InputStream newInputStream() throws IOException {
+ setLastAccessTime(FileTime.fromMillis(
+ getLastAccessTime().toMillis() + 1000));
+ return super.newInputStream();
+ }
+ @Override
+ MockFile setLastAccessTime(FileTime accessTime) throws IOException {
+ if (MockFile.DEFAULT_FILETIME.equals(getLastAccessTime())) {
+ // Let the above setting from newInputStream go through.
+ return super.setLastAccessTime(accessTime);
+ } else {
+ // But fail the attempt to restore from FsAdaptor.
+ throw new IOException("Restore LastAccessTime");
+ }
+ }
+ });
+ }
+
+ private void testPreserveFileLastAccessTime(MockFile file) throws Exception {
+ testFileLastAccessTime(file, true);
+ }
+
+ private void testNoPreserveFileLastAccessTime(MockFile file)
+ throws Exception {
+ testFileLastAccessTime(file, false);
+ }
+
+ private void testFileLastAccessTime(MockFile file, boolean isPreserved)
+ throws Exception {
+ String contents = "Test contents";
+ file.setFileContents(contents);
+ root.addChildren(file);
+ adaptor.init(context);
+ MockResponse response = new MockResponse();
+ FileTime lastAccess = file.getLastAccessTime();
+ adaptor.getDocContent(new MockRequest(getDocId(file.getName())), response);
+ // Verify we indeed accessed the file
+ assertEquals(contents, response.content.toString("UTF-8"));
+ if (isPreserved) {
+ assertEquals(lastAccess, file.getLastAccessTime());
+ } else {
+ assertFalse(lastAccess.equals(file.getLastAccessTime()));
+ }
+ }
+
+ @Test
+ public void testGetDocContentRoot() throws Exception {
+ testGetDocContentDirectory(rootPath, rootPath.toString());
+ // ACLs checked in other tests.
+ }
+
+ @Test
+ public void testGetDocContentDirectory() throws Exception {
+ String fname = "test.dir";
+ root.addChildren(new MockFile(fname, true));
+ testGetDocContentDirectory(getPath(fname), fname);
+ // ACLs checked in other tests.
+ }
+
+ private void testGetDocContentDirectory(Path path, String label)
+ throws Exception {
+ MockFile dir = delegate.getFile(path);
+ FileTime modifyTime = dir.getLastModifiedTime();
+ Date modifyDate = new Date(modifyTime.toMillis());
+ dir.addChildren(new MockFile("test.txt"), new MockFile("subdir", true));
+ adaptor.init(context);
+ MockRequest request = new MockRequest(delegate.newDocId(path));
+ MockResponse response = new MockResponse();
+ adaptor.getDocContent(request, response);
+ assertFalse(response.notFound);
+ assertEquals(modifyDate, response.lastModified);
+ assertEquals(path.toUri(), response.displayUrl);
+ assertEquals("text/html; charset=UTF-8", response.contentType);
+ String expectedContent = "<!DOCTYPE html>\n<html><head><title>Folder "
+ + label + "</title></head><body><h1>Folder " + label + "</h1>"
+ + "<li><a href=\"subdir/\">subdir</a></li>"
+ + "<li><a href=\"test.txt\">test.txt</a></li></body></html>";
+ assertEquals(expectedContent, response.content.toString("UTF-8"));
+ assertNotNull(response.metadata.get("Creation Time"));
+ }
+
+ @Test
+ public void testGetDocContentDefaultRootAcls() throws Exception {
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitGroups(Collections.singleton(new GroupPrincipal("Everyone")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(shareAclDocId).build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", expectedAcl,
+ "allFilesAcl", expectedAcl,
+ "childFoldersAcl", expectedAcl,
+ "childFilesAcl", expectedAcl);
+ testGetDocContentAcls(rootPath, expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentInheritOnlyRootAcls() throws Exception {
+ AclFileAttributeView inheritOnlyAclView = new AclView(
+ user("Longfellow Deeds").type(ALLOW).perms(GENERIC_READ)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT, INHERIT_ONLY),
+ group("Administrators").type(ALLOW).perms(GENERIC_ALL)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT));
+ root.setAclView(inheritOnlyAclView);
+
+ // The root ACL should only include Administrators, not Mr. Deeds.
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitGroups(Collections.singleton(
+ new GroupPrincipal("Administrators")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(shareAclDocId).build();
+ // But the childrens' inherited ACLs should include Mr. Deeds
+ Acl expectedInheritableAcl = new Acl.Builder(expectedAcl)
+ .setPermitUsers(Collections.singleton(
+ new UserPrincipal("Longfellow Deeds")))
+ .build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", expectedInheritableAcl,
+ "allFilesAcl", expectedInheritableAcl,
+ "childFoldersAcl", expectedInheritableAcl,
+ "childFilesAcl", expectedInheritableAcl);
+ testGetDocContentAcls(rootPath, expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentNoPropagateRootAcls() throws Exception {
+ AclFileAttributeView noPropagateAclView = new AclView(
+ user("Barren von Dink").type(ALLOW).perms(GENERIC_READ)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT, NO_PROPAGATE_INHERIT),
+ group("Administrators").type(ALLOW).perms(GENERIC_ALL)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT));
+ root.setAclView(noPropagateAclView);
+
+ // The root ACL should include both Administrators and the Barren.
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitUsers(Collections.singleton(
+ new UserPrincipal("Barren von Dink")))
+ .setPermitGroups(Collections.singleton(
+ new GroupPrincipal("Administrators")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(shareAclDocId).build();
+ // The direct childrens' inherited ACLs should include both the
+ // Administrators and the Barren, but grandchildren should not
+ // inherit the Barren's NO_PROPAGATE permission.
+ Acl expectedNonChildAcl = new Acl.Builder(expectedAcl)
+ .setPermitUsers(Collections.<UserPrincipal>emptySet()).build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", expectedNonChildAcl,
+ "allFilesAcl", expectedNonChildAcl,
+ "childFoldersAcl", expectedAcl,
+ "childFilesAcl", expectedAcl);
+ testGetDocContentAcls(rootPath, expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentFilesOnlyRootAcls() throws Exception {
+ AclFileAttributeView noPropagateAclView = new AclView(
+ user("For Your Files Only").type(ALLOW).perms(GENERIC_READ)
+ .flags(FILE_INHERIT),
+ group("Administrators").type(ALLOW).perms(GENERIC_ALL)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT));
+ root.setAclView(noPropagateAclView);
+
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitUsers(Collections.singleton(
+ new UserPrincipal("For Your Files Only")))
+ .setPermitGroups(Collections.singleton(
+ new GroupPrincipal("Administrators")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(shareAclDocId).build();
+ // Folders shouldn't include the file-only permissions.
+ Acl expectedFolderAcl = new Acl.Builder(expectedAcl)
+ .setPermitUsers(Collections.<UserPrincipal>emptySet()).build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", expectedFolderAcl,
+ "allFilesAcl", expectedAcl,
+ "childFoldersAcl", expectedFolderAcl,
+ "childFilesAcl", expectedAcl);
+ testGetDocContentAcls(rootPath, expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentFoldersOnlyRootAcls() throws Exception {
+ AclFileAttributeView noPropagateAclView = new AclView(
+ user("Fluff 'n Folder").type(ALLOW).perms(GENERIC_READ)
+ .flags(DIRECTORY_INHERIT),
+ group("Administrators").type(ALLOW).perms(GENERIC_ALL)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT));
+ root.setAclView(noPropagateAclView);
+
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitUsers(Collections.singleton(
+ new UserPrincipal("Fluff 'n Folder")))
+ .setPermitGroups(Collections.singleton(
+ new GroupPrincipal("Administrators")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(shareAclDocId).build();
+ // Files shouldn't include the folder-only permissions.
+ Acl expectedFilesAcl = new Acl.Builder(expectedAcl)
+ .setPermitUsers(Collections.<UserPrincipal>emptySet()).build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", expectedAcl,
+ "allFilesAcl", expectedFilesAcl,
+ "childFoldersAcl", expectedAcl,
+ "childFilesAcl", expectedFilesAcl);
+ testGetDocContentAcls(rootPath, expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentDefaultDirectoryAcls() throws Exception {
+ String name = "subdir";
+ root.addChildren(new MockFile(name, true));
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(rootDocId, "childFoldersAcl").build();
+ Acl expectedFoldersAcl = new Acl.Builder(expectedAcl)
+ .setInheritFrom(rootDocId, "allFoldersAcl").build();
+ Acl expectedFilesAcl = new Acl.Builder(expectedAcl)
+ .setInheritFrom(rootDocId, "allFilesAcl").build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", expectedFoldersAcl,
+ "allFilesAcl", expectedFilesAcl,
+ "childFoldersAcl", expectedFoldersAcl,
+ "childFilesAcl", expectedFilesAcl);
+ testGetDocContentAcls(getPath(name), expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentNoInheritDirectoryAcls() throws Exception {
+ String name = "subdir";
+ AclFileAttributeView orphanAclView = new AclView(user("Annie").type(ALLOW)
+ .perms(GENERIC_READ).flags(FILE_INHERIT, DIRECTORY_INHERIT));
+ root.addChildren(new MockFile(name, true).setAclView(orphanAclView)
+ .setInheritedAclView(MockFile.EMPTY_ACLVIEW));
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitUsers(Collections.singleton(new UserPrincipal("Annie")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(shareAclDocId).build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", expectedAcl,
+ "allFilesAcl", expectedAcl,
+ "childFoldersAcl", expectedAcl,
+ "childFilesAcl", expectedAcl);
+ testGetDocContentAcls(getPath(name), expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentInheritOnlyDirectoryAcls() throws Exception {
+ String name = "subdir";
+ AclFileAttributeView inheritOnlyAclView = new AclView(
+ user("Longfellow Deeds").type(ALLOW).perms(GENERIC_READ)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT, INHERIT_ONLY),
+ group("Administrators").type(ALLOW).perms(GENERIC_ALL)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT));
+ root.addChildren(new MockFile(name, true).setAclView(inheritOnlyAclView));
+
+ // The root ACL should only include Administrators, not Mr. Deeds.
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitGroups(Collections.singleton(
+ new GroupPrincipal("Administrators")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(rootDocId, "childFoldersAcl").build();
+ // But the childrens' inherited ACLs should include Mr. Deeds
+ Acl expectedFoldersAcl = new Acl.Builder(expectedAcl)
+ .setPermitUsers(Collections.singleton(
+ new UserPrincipal("Longfellow Deeds")))
+ .setInheritFrom(rootDocId, "allFoldersAcl").build();
+ Acl expectedFilesAcl = new Acl.Builder(expectedFoldersAcl)
+ .setInheritFrom(rootDocId, "allFilesAcl").build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", expectedFoldersAcl,
+ "allFilesAcl", expectedFilesAcl,
+ "childFoldersAcl", expectedFoldersAcl,
+ "childFilesAcl", expectedFilesAcl);
+ testGetDocContentAcls(getPath(name), expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentNoPropagateDirectoryAcls() throws Exception {
+ String name = "subdir";
+ AclFileAttributeView noPropagateAclView = new AclView(
+ user("Barren von Dink").type(ALLOW).perms(GENERIC_READ)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT, NO_PROPAGATE_INHERIT),
+ group("Administrators").type(ALLOW).perms(GENERIC_ALL)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT));
+ root.addChildren(new MockFile(name, true).setAclView(noPropagateAclView));
+
+ // The root ACL should include both Administrators and the Barren.
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitUsers(Collections.singleton(
+ new UserPrincipal("Barren von Dink")))
+ .setPermitGroups(Collections.singleton(
+ new GroupPrincipal("Administrators")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(rootDocId, "childFoldersAcl").build();
+ // The direct childrens' inherited ACLs should include both the
+ // Administrators and the Barren, but grandchildren should not
+ // inherit the Barren's NO_PROPAGATE permission.
+ Acl expectedNonChildAcl = new Acl.Builder(expectedAcl)
+ .setPermitUsers(Collections.<UserPrincipal>emptySet()).build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", new Acl.Builder(expectedNonChildAcl)
+ .setInheritFrom(rootDocId, "allFoldersAcl").build(),
+ "allFilesAcl", new Acl.Builder(expectedNonChildAcl)
+ .setInheritFrom(rootDocId, "allFilesAcl").build(),
+ "childFoldersAcl", new Acl.Builder(expectedAcl)
+ .setInheritFrom(rootDocId, "allFoldersAcl").build(),
+ "childFilesAcl", new Acl.Builder(expectedAcl)
+ .setInheritFrom(rootDocId, "allFilesAcl").build());
+ testGetDocContentAcls(getPath(name), expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentFilesOnlyDirectoryAcls() throws Exception {
+ String name = "subdir";
+ AclFileAttributeView filesOnlyAclView = new AclView(
+ user("For Your Files Only").type(ALLOW).perms(GENERIC_READ)
+ .flags(FILE_INHERIT),
+ group("Administrators").type(ALLOW).perms(GENERIC_ALL)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT));
+ root.addChildren(new MockFile(name, true).setAclView(filesOnlyAclView));
+
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitUsers(Collections.singleton(
+ new UserPrincipal("For Your Files Only")))
+ .setPermitGroups(Collections.singleton(
+ new GroupPrincipal("Administrators")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(rootDocId, "childFoldersAcl").build();
+ // Folders shouldn't include the file-only permissions.
+ Acl expectedFolderAcl = new Acl.Builder(expectedAcl)
+ .setPermitUsers(Collections.<UserPrincipal>emptySet()).build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", new Acl.Builder(expectedFolderAcl)
+ .setInheritFrom(rootDocId, "allFoldersAcl").build(),
+ "allFilesAcl", new Acl.Builder(expectedAcl)
+ .setInheritFrom(rootDocId, "allFilesAcl").build(),
+ "childFoldersAcl", new Acl.Builder(expectedFolderAcl)
+ .setInheritFrom(rootDocId, "allFoldersAcl").build(),
+ "childFilesAcl", new Acl.Builder(expectedAcl)
+ .setInheritFrom(rootDocId, "allFilesAcl").build());
+ testGetDocContentAcls(getPath(name), expectedAcl, expectedResources);
+ }
+
+ @Test
+ public void testGetDocContentFoldersOnlyDirectoryAcls() throws Exception {
+ String name = "subdir";
+ AclFileAttributeView foldersOnlyAclView = new AclView(
+ user("Fluff 'n Folder").type(ALLOW).perms(GENERIC_READ)
+ .flags(DIRECTORY_INHERIT),
+ group("Administrators").type(ALLOW).perms(GENERIC_ALL)
+ .flags(FILE_INHERIT, DIRECTORY_INHERIT));
+ root.addChildren(new MockFile(name, true).setAclView(foldersOnlyAclView));
+
+ Acl expectedAcl = new Acl.Builder().setEverythingCaseInsensitive()
+ .setPermitUsers(Collections.singleton(
+ new UserPrincipal("Fluff 'n Folder")))
+ .setPermitGroups(Collections.singleton(
+ new GroupPrincipal("Administrators")))
+ .setInheritanceType(InheritanceType.CHILD_OVERRIDES)
+ .setInheritFrom(rootDocId, "childFoldersAcl").build();
+ // Files shouldn't include the folder-only permissions.
+ Acl expectedFilesAcl = new Acl.Builder(expectedAcl)
+ .setPermitUsers(Collections.<UserPrincipal>emptySet()).build();
+ Map<String, Acl> expectedResources = ImmutableMap.of(
+ "allFoldersAcl", new Acl.Builder(expectedAcl)
+ .setInheritFrom(rootDocId, "allFoldersAcl").build(),
+ "allFilesAcl", new Acl.Builder(expectedFilesAcl)
+ .setInheritFrom(rootDocId, "allFilesAcl").build(),
+ "childFoldersAcl", new Acl.Builder(expectedAcl)
+ .setInheritFrom(rootDocId, "allFoldersAcl").build(),
+ "childFilesAcl", new Acl.Builder(expectedFilesAcl)
+ .setInheritFrom(rootDocId, "allFilesAcl").build());
+ testGetDocContentAcls(getPath(name), expectedAcl, expectedResources);
+ }
+
+ private void testGetDocContentAcls(Path path, Acl expectedAcl,
+ Map<String, Acl> expectedAclResources) throws Exception {
+ adaptor.init(context);
+ MockRequest request = new MockRequest(delegate.newDocId(path));
+ MockResponse response = new MockResponse();
+ adaptor.getDocContent(request, response);
+ assertEquals(expectedAcl, response.acl);
+ assertEquals(expectedAclResources, response.namedResources);
+ }
+
+ @Test
+ public void testMonitorZeroFeedSize() throws Exception {
+ config.overrideKey("feed.maxUrls", "0");
+ thrown.expect(IllegalArgumentException.class);
+ adaptor.init(context);
+ }
+
+ @Test
+ public void testMonitorZeroLatency() throws Exception {
+ config.overrideKey("adaptor.incrementalPollPeriodSecs", "0");
+ adaptor.init(context);
+ }
+
+
+ @Test
+ public void testMonitorSubZeroLatency() throws Exception {
+ config.overrideKey("adaptor.incrementalPollPeriodSecs", "-1");
+ thrown.expect(IllegalArgumentException.class);
+ adaptor.init(context);
+ }
+
+ @Test
+ public void testMonitorUnsupportedPath() throws Exception {
+ root.addChildren(new MockFile("unsuppored").setIsRegularFile(false));
+ adaptor.init(context);
+ BlockingQueue<Path> queue = adaptor.getFsMonitorQueue();
+ queue.add(getPath("unsupported"));
+ Thread.sleep(100L); // Allow FsMonitor to drain the queue.
+ // Verify it has been processed, but not been fed.
+ assertEquals(0, queue.size());
+ assertEquals(0, pusher.getRecords().size());
+ assertEquals(0, pusher.getNamedResources().size());
+ }
+
+ @Test
+ public void testMonitorOneFile() throws Exception {
+ String name = "test";
+ root.addChildren(new MockFile(name));
+ adaptor.init(context);
+ testMonitor(name);
+ }
+
+ @Test
+ public void testMonitorOneDirectory() throws Exception {
+ String name = "test.dir";
+ root.addChildren(new MockFile(name, true));
+ adaptor.init(context);
+ testMonitor(name);
+ }
+
+ @Test
+ public void testMonitorMultipleItems() throws Exception {
+ String dirname = "subdir";
+ String fname = "test.txt";
+ root.addChildren(new MockFile(dirname, true), new MockFile(fname));
+ adaptor.init(context);
+ testMonitor(dirname, fname);
+ }
+
+ @Test
+ public void testMonitorMultipleBatches() throws Exception {
+ String dirname = "subdir";
+ String fname = "test.txt";
+ root.addChildren(new MockFile(dirname, true), new MockFile(fname));
+ adaptor.init(context);
+ testMonitor(dirname);
+ // Make sure the previous batch does not get fed again.
+ pusher.reset();
+ testMonitor(fname);
+ }
+
+ private void testMonitor(String... names) throws Exception {
+ BlockingQueue<Path> queue = adaptor.getFsMonitorQueue();
+ for (String name : names) {
+ queue.add(getPath(name));
+ }
+ Thread.sleep(100L); // Allow FsMonitor to drain the queue.
+ assertEquals(0, queue.size());
+ assertEquals(0, pusher.getNamedResources().size());
+ Set<Record> expected = Sets.newHashSet();
+ for (String name : names) {
+ expected.add(new Record.Builder(getDocId(name))
+ .setCrawlImmediately(true).build());
+ }
+ assertEquals(expected, Sets.newHashSet(pusher.getRecords()));
+ }
}
diff --git a/test/com/google/enterprise/adaptor/fs/MockAdaptorContext.java b/test/com/google/enterprise/adaptor/fs/MockAdaptorContext.java
new file mode 100644
index 0000000..adba37b
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/fs/MockAdaptorContext.java
@@ -0,0 +1,111 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// 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.google.enterprise.adaptor.fs;
+
+import com.google.enterprise.adaptor.AdaptorContext;
+import com.google.enterprise.adaptor.AuthnAuthority;
+import com.google.enterprise.adaptor.AuthzAuthority;
+import com.google.enterprise.adaptor.Config;
+import com.google.enterprise.adaptor.DocIdEncoder;
+import com.google.enterprise.adaptor.DocIdPusher;
+import com.google.enterprise.adaptor.ExceptionHandler;
+import com.google.enterprise.adaptor.PollingIncrementalLister;
+import com.google.enterprise.adaptor.SensitiveValueDecoder;
+import com.google.enterprise.adaptor.Session;
+import com.google.enterprise.adaptor.StatusSource;
+
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+
+/**
+ * Mock of {@link AdaptorContext}.
+ */
+class MockAdaptorContext implements AdaptorContext {
+ private final Config config = new Config();
+ private final DocIdPusher docIdPusher = new AccumulatingDocIdPusher();
+ private final DocIdEncoder docIdEncoder = new MockDocIdCodec();
+
+ @Override
+ public Config getConfig() {
+ return config;
+ }
+
+ @Override
+ public DocIdPusher getDocIdPusher() {
+ return docIdPusher;
+ }
+
+ @Override
+ public DocIdEncoder getDocIdEncoder() {
+ return docIdEncoder;
+ }
+
+ @Override
+ public void addStatusSource(StatusSource source) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setGetDocIdsFullErrorHandler(ExceptionHandler handler) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ExceptionHandler getGetDocIdsFullErrorHandler() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setGetDocIdsIncrementalErrorHandler(
+ ExceptionHandler handler) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ExceptionHandler getGetDocIdsIncrementalErrorHandler() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SensitiveValueDecoder getSensitiveValueDecoder() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public HttpContext createHttpContext(String path, HttpHandler handler) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Session getUserSession(HttpExchange ex, boolean create) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPollingIncrementalLister(PollingIncrementalLister lister) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAuthnAuthority(AuthnAuthority authnAuthority) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAuthzAuthority(AuthzAuthority authzAuthority) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/fs/MockDocIdCodec.java b/test/com/google/enterprise/adaptor/fs/MockDocIdCodec.java
new file mode 100644
index 0000000..e669083
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/fs/MockDocIdCodec.java
@@ -0,0 +1,37 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// 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.google.enterprise.adaptor.fs;
+
+import com.google.enterprise.adaptor.DocId;
+import com.google.enterprise.adaptor.DocIdEncoder;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Mock of {@link DocIdCodec}.
+ */
+class MockDocIdCodec implements DocIdEncoder {
+ @Override
+ public URI encodeDocId(DocId docId) {
+ try {
+ String id = docId.getUniqueId();
+ return new URI("http", "localhost",
+ id.startsWith("/") ? id : "/" + id, null);
+ } catch (URISyntaxException ex) {
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/fs/MockFile.java b/test/com/google/enterprise/adaptor/fs/MockFile.java
index 5cb2461..eb97926 100644
--- a/test/com/google/enterprise/adaptor/fs/MockFile.java
+++ b/test/com/google/enterprise/adaptor/fs/MockFile.java
@@ -42,16 +42,15 @@
class MockFile {
static final String SEPARATOR = "/";
- static final FileTime defaultFileTime = FileTime.fromMillis(10000);
- static final AclFileAttributeView fullAccessAclView =
+ static final FileTime DEFAULT_FILETIME = FileTime.fromMillis(10000);
+ static final AclFileAttributeView FULL_ACCESS_ACLVIEW =
new AclView(group("Everyone").type(ALLOW)
.perms(READ_DATA, READ_ATTRIBUTES, READ_NAMED_ATTRS, READ_ACL)
.flags(FILE_INHERIT, DIRECTORY_INHERIT));
- static final AclFileAttributeView emptyAclView = new AclView();
+ static final AclFileAttributeView EMPTY_ACLVIEW = new AclView();
private MockFile parent;
private String name;
- private boolean exists = true;
private boolean isHidden = false;
private boolean isRegularFile;
private boolean isDirectory;
@@ -61,9 +60,9 @@
private AclFileAttributeView shareAclView;
private AclFileAttributeView aclView;
private AclFileAttributeView inheritedAclView;
- private FileTime creationTime = defaultFileTime;
- private FileTime lastAccessTime = defaultFileTime;
- private FileTime lastModifiedTime = defaultFileTime;
+ private FileTime creationTime = DEFAULT_FILETIME;
+ private FileTime lastModifiedTime = DEFAULT_FILETIME;
+ private FileTime lastAccessTime = DEFAULT_FILETIME;
private String contentType;
private byte[] fileContents;
@@ -100,6 +99,7 @@
* MockFile, and registers this file as the parent of all the children.
*/
MockFile addChildren(MockFile... children) {
+ Preconditions.checkState(isDirectory, "not a directory %s", getPath());
for (MockFile child : children) {
child.parent = this;
directoryContents.add(child);
@@ -112,6 +112,7 @@
*/
MockFile getChild(String name) throws FileNotFoundException {
Preconditions.checkNotNull(name, "name cannot be null");
+ Preconditions.checkState(isDirectory, "not a directory %s", getPath());
Iterator<MockFile> it = directoryContents.iterator();
while (it.hasNext()) {
MockFile f = it.next();
@@ -124,37 +125,15 @@
}
/**
- * Remove this file.
- */
- void delete() {
- if (parent != null) {
- // Unlink from parent.
- Iterator<MockFile> it = parent.directoryContents.iterator();
- while (it.hasNext()) {
- if (it.next() == this) {
- it.remove();
- break;
- }
- }
- }
- if (isDirectory) {
- // TODO: If this is insufficient, delete recursively.
- // But after this, getChild() will fail, so we should be OK.
- directoryContents.clear();
- }
- exists = isDirectory = isRegularFile = isHidden = false;
- parent = null;
- name = null;
- }
-
- /**
* Return the path to this file or directory.
*/
String getPath() {
if (parent == null) {
return name;
} else {
- return parent.getPath() + SEPARATOR + name;
+ String parentPath = parent.getPath();
+ return (parentPath.endsWith(SEPARATOR))
+ ? parentPath + name : parentPath + SEPARATOR + name;
}
}
@@ -193,15 +172,6 @@
return isRegularFile;
}
- MockFile setExists(boolean exists) {
- this.exists = exists;
- return this;
- }
-
- boolean exists() throws IOException {
- return this.exists;
- }
-
MockFile setIsHidden(boolean isHidden) {
this.isHidden = isHidden;
return this;
@@ -217,7 +187,7 @@
return this;
}
- FileTime getCreateTime() throws IOException {
+ FileTime getCreationTime() throws IOException {
return creationTime;
}
@@ -259,7 +229,7 @@
this.dfsShareAclView = aclView;
return this;
}
-
+
AclFileAttributeView getDfsShareAclView() throws IOException {
return dfsShareAclView;
}
@@ -270,7 +240,7 @@
}
AclFileAttributeView getShareAclView() throws IOException {
- return (shareAclView == null) ? fullAccessAclView : shareAclView;
+ return (shareAclView == null) ? FULL_ACCESS_ACLVIEW : shareAclView;
}
MockFile setAclView(AclFileAttributeView aclView) {
@@ -280,7 +250,7 @@
AclFileAttributeView getAclView() throws IOException {
if (aclView == null) {
- return (parent == null) ? fullAccessAclView : emptyAclView;
+ return (parent == null) ? FULL_ACCESS_ACLVIEW : EMPTY_ACLVIEW;
} else {
return aclView;
}
@@ -295,10 +265,10 @@
if (inheritedAclView == null) {
if (parent == null) {
// root has no inherited ACL
- return emptyAclView;
+ return EMPTY_ACLVIEW;
} else if (parent.parent == null) {
// root's children inherit its ACL
- return parent.getAclView();
+ return parent.getAclView();
} else {
// all other children inherit from their parent
return parent.getInheritedAclView();
@@ -314,7 +284,7 @@
}
String getContentType() throws IOException {
- return contentType;
+ return isRegularFile ? contentType : null;
}
MockFile setFileContents(String fileContents) {
@@ -339,7 +309,9 @@
}
DirectoryStream<Path> newDirectoryStream() throws IOException {
- Preconditions.checkState(isDirectory, "not a directory %s", getPath());
+ if (!isDirectory) {
+ throw new NotDirectoryException("not a directory " + getPath());
+ }
return new MockDirectoryStream(directoryContents);
}
diff --git a/test/com/google/enterprise/adaptor/fs/MockFileDelegate.java b/test/com/google/enterprise/adaptor/fs/MockFileDelegate.java
index 2c85a6b..9a4c6f8 100644
--- a/test/com/google/enterprise/adaptor/fs/MockFileDelegate.java
+++ b/test/com/google/enterprise/adaptor/fs/MockFileDelegate.java
@@ -44,14 +44,27 @@
*/
MockFile getFile(Path doc) throws FileNotFoundException {
Preconditions.checkNotNull(doc, "doc cannot be null");
- Iterator<Path> iter = doc.iterator();
MockFile file = root;
+ Iterator<Path> iter = doc.iterator();
+ if (doc.getRoot() != null) {
+ // Using startsWith because Path adds a trailing backslash to
+ // UNC roots. The second check accounts for Windows Path
+ // implementation flipping slashes on Unix paths.
+ if (!(doc.getRoot().toString().startsWith(root.getPath()) ||
+ root.getPath().equals(doc.getRoot().toString().replace('\\', '/')))) {
+ throw new FileNotFoundException("not found: " + doc.toString());
+ }
+ } else if (iter.hasNext()) {
+ if (!(root.getPath().equals(iter.next().toString()))) {
+ throw new FileNotFoundException("not found: " + doc.toString());
+ }
+ }
while (iter.hasNext()) {
file = file.getChild(iter.next().toString());
}
return file;
}
-
+
@Override
public Path getPath(String pathname) throws IOException {
Preconditions.checkNotNull(pathname, "pathname cannot be null");
@@ -60,17 +73,29 @@
@Override
public boolean isDirectory(Path doc) throws IOException {
- return getFile(doc).isDirectory();
+ try {
+ return getFile(doc).isDirectory();
+ } catch (FileNotFoundException e) {
+ return false;
+ }
}
@Override
public boolean isRegularFile(Path doc) throws IOException {
- return getFile(doc).isRegularFile();
+ try {
+ return getFile(doc).isRegularFile();
+ } catch (FileNotFoundException e) {
+ return false;
+ }
}
@Override
public boolean isHidden(Path doc) throws IOException {
- return getFile(doc).isHidden();
+ try {
+ return getFile(doc).isHidden();
+ } catch (FileNotFoundException e) {
+ return false;
+ }
}
@Override
@@ -100,10 +125,16 @@
@Override
public DocId newDocId(Path doc) throws IOException {
- String id = doc.toString();
+ String id = doc.toString().replace('\\', '/');
if (isDirectory(doc) && !id.endsWith("/")) {
id += "/";
}
+ if (id.startsWith("//")) {
+ // String.replaceFirst uses regular expression string and replacement
+ // so they need to be escaped appropriately. The above String.replace
+ // does NOT use expressions so regex escaping is not needed.
+ id = id.replaceFirst("//", "\\\\\\\\");
+ }
return new DocId(id);
}
diff --git a/test/com/google/enterprise/adaptor/fs/MockFileDelegateTest.java b/test/com/google/enterprise/adaptor/fs/MockFileDelegateTest.java
new file mode 100644
index 0000000..91f85f8
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/fs/MockFileDelegateTest.java
@@ -0,0 +1,222 @@
+// Copyright 2014 Google Inc.
+//
+// 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.google.enterprise.adaptor.fs;
+
+import static org.junit.Assert.*;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.CharStreams;
+import com.google.enterprise.adaptor.DocId;
+
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Iterator;
+
+/**
+ * Test cases for {@link MockFileDelegate}.
+ */
+public class MockFileDelegateTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testConstructorNullRoot() throws Exception {
+ thrown.expect(NullPointerException.class);
+ new MockFileDelegate(null);
+ }
+
+ @Test
+ public void testGetPathNullPathname() throws Exception {
+ thrown.expect(NullPointerException.class);
+ new MockFileDelegate(new MockFile("root", true)).getPath(null);
+ }
+
+ @Test
+ public void testGetPath() throws Exception {
+ String delim = File.separator;
+ FileDelegate delegate = new MockFileDelegate(new MockFile("root", true));
+ assertEquals("root", delegate.getPath("root").toString());
+ assertEquals("root" + delim + "foo" + delim + "bar",
+ delegate.getPath("root/foo/bar").toString());
+ assertEquals(delim + "foo" + delim + "bar" + delim + "baz",
+ delegate.getPath("/foo/bar/baz").toString());
+ assertEquals("\\\\server\\share\\dir\\file.txt",
+ delegate.getPath("\\\\server\\share\\dir\\file.txt").toString());
+ }
+
+ @Test
+ public void testGetFileNotFound() throws Exception {
+ MockFile root = new MockFile("root", true).addChildren(new MockFile("foo"));
+ MockFileDelegate delegate = new MockFileDelegate(root);
+ thrown.expect(FileNotFoundException.class);
+ delegate.getFile(delegate.getPath("root/nonExistent"));
+ }
+
+ @Test
+ public void testGetFileRelativeRoot() throws Exception {
+ testGetFile("root");
+ }
+
+ @Test
+ public void testGetFileUncRoot() throws Exception {
+ testGetFile("\\\\host\\share");
+ testGetFile("\\\\host\\share\\");
+ }
+
+ @Test
+ public void testGetFileUnixRoot() throws Exception {
+ testGetFile("/");
+ }
+
+ @Test
+ public void testGetFileDosRoot() throws Exception {
+ testGetFile("C:\\");
+ }
+
+ private void testGetFile(String rootPath) throws Exception {
+ MockFile root = new MockFile(rootPath, true).addChildren(
+ new MockFile("dir1", true).addChildren(new MockFile("foo")),
+ new MockFile("dir2", true).addChildren(new MockFile("bar")),
+ new MockFile("test.txt"));
+ MockFileDelegate delegate = new MockFileDelegate(root);
+
+ assertSame(root, delegate.getFile(delegate.getPath(rootPath)));
+ testGetFile(delegate, getPath(rootPath, "test.txt"));
+ testGetFile(delegate, getPath(rootPath, "dir1"));
+ testGetFile(delegate, getPath(rootPath, "dir2"));
+ testGetFile(delegate, getPath(rootPath, "dir1/foo"));
+ testGetFile(delegate, getPath(rootPath, "dir2/bar"));
+ }
+
+ private String getPath(String parent, String child) {
+ return (parent.endsWith("/")) ? parent + child : parent + "/" + child;
+ }
+
+ private void testGetFile(MockFileDelegate delegate, String pathname)
+ throws Exception {
+ Path path = delegate.getPath(pathname);
+ MockFile file = delegate.getFile(path);
+ assertEquals(pathname, file.getPath());
+ MockFile parent = file.getParent();
+ if (parent != null) {
+ assertSame(parent, delegate.getFile(path.getParent()));
+ }
+ }
+
+ @Test
+ public void testNewDocId() throws Exception {
+ MockFile root = new MockFile("root", true).addChildren(
+ new MockFile("dir1", true).addChildren(new MockFile("foo")));
+ FileDelegate delegate = new MockFileDelegate(root);
+ assertEquals(new DocId("root/"), getDocId(delegate, "root"));
+ assertEquals(new DocId("root/dir1/"), getDocId(delegate, "root/dir1"));
+ assertEquals(new DocId("root/dir1/foo"),
+ getDocId(delegate, "root/dir1/foo"));
+ }
+
+ private DocId getDocId(FileDelegate delegate, String pathname)
+ throws Exception {
+ return delegate.newDocId(delegate.getPath(pathname));
+ }
+
+ @Test
+ public void testSetLastAccessTime() throws Exception {
+ MockFile root = new MockFile("root", true)
+ .addChildren(new MockFile("test.txt"));
+ FileDelegate delegate = new MockFileDelegate(root);
+ Path path = delegate.getPath("root/test.txt");
+
+ BasicFileAttributes attrs = delegate.readBasicAttributes(path);
+ assertEquals(MockFile.DEFAULT_FILETIME, attrs.lastAccessTime());
+
+ FileTime accessTime = FileTime.fromMillis(40000);
+ delegate.setLastAccessTime(path, accessTime);
+ attrs = delegate.readBasicAttributes(path);
+ assertEquals(accessTime, attrs.lastAccessTime());
+ }
+
+ /**
+ * Most of the MockDelegate methods are simple passthrough calls to the
+ * MockFile methods. This is a sanity check to make sure I'm calling the
+ * right ones.
+ */
+ @Test
+ public void testPassthroughGetters() throws Exception {
+ FileTime createTime = FileTime.fromMillis(20000);
+ FileTime modifyTime = FileTime.fromMillis(30000);
+ FileTime accessTime = FileTime.fromMillis(40000);
+ String content = "<html><title>Hello World</title></html>";
+ MockFile root = new MockFile("root", true)
+ .addChildren(
+ new MockFile("test.html").setCreationTime(createTime)
+ .setLastModifiedTime(modifyTime).setLastAccessTime(accessTime)
+ .setFileContents(content).setContentType("text/html"));
+
+ FileDelegate delegate = new MockFileDelegate(root);
+ Path path = delegate.getPath("root");
+ assertTrue(delegate.isDirectory(path));
+ assertFalse(delegate.isRegularFile(path));
+ assertNull(delegate.getDfsUncActiveStorageUnc(path));
+ Path uncPath = delegate.getPath("\\\\server\\share");
+ root.setDfsUncActiveStorageUnc(uncPath);
+ assertEquals(uncPath, delegate.getDfsUncActiveStorageUnc(path));
+ assertNull(delegate.getDfsShareAclView(path));
+ root.setDfsShareAclView(MockFile.FULL_ACCESS_ACLVIEW);
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW,
+ delegate.getDfsShareAclView(path));
+ AclFileAttributeViews aclViews = delegate.getAclViews(path);
+ assertNotNull(aclViews);
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, aclViews.getDirectAclView());
+ assertEquals(MockFile.EMPTY_ACLVIEW, aclViews.getInheritedAclView());
+
+ path = delegate.getPath("root/test.html");
+ assertTrue(delegate.isRegularFile(path));
+ assertFalse(delegate.isDirectory(path));
+ assertFalse(delegate.isHidden(path));
+ assertEquals("text/html", delegate.probeContentType(path));
+ assertEquals(content, readContents(delegate, path));
+ aclViews = delegate.getAclViews(path);
+ assertNotNull(aclViews);
+ assertEquals(MockFile.EMPTY_ACLVIEW, aclViews.getDirectAclView());
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, aclViews.getInheritedAclView());
+
+ BasicFileAttributes attrs = delegate.readBasicAttributes(path);
+ assertTrue(attrs.isRegularFile());
+ assertFalse(attrs.isDirectory());
+ assertFalse(attrs.isOther());
+ assertEquals(createTime, attrs.creationTime());
+ assertEquals(modifyTime, attrs.lastModifiedTime());
+ assertEquals(accessTime, attrs.lastAccessTime());
+ assertEquals(content.getBytes(Charsets.UTF_8).length, attrs.size());
+ }
+
+ private String readContents(FileDelegate delegate, Path path)
+ throws IOException {
+ return CharStreams.toString(
+ new InputStreamReader(delegate.newInputStream(path), Charsets.UTF_8));
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/fs/MockFileTest.java b/test/com/google/enterprise/adaptor/fs/MockFileTest.java
new file mode 100644
index 0000000..c65992b
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/fs/MockFileTest.java
@@ -0,0 +1,309 @@
+// Copyright 2014 Google Inc.
+//
+// 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.google.enterprise.adaptor.fs;
+
+import static org.junit.Assert.*;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.CharStreams;
+
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Iterator;
+
+/**
+ * Test cases for {@link MockFile}.
+ */
+public class MockFileTest {
+
+ private static final FileTime createTime = FileTime.fromMillis(20000);
+ private static final FileTime modifyTime = FileTime.fromMillis(30000);
+ private static final FileTime accessTime = FileTime.fromMillis(40000);
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testConstructorNullName() throws Exception {
+ thrown.expect(NullPointerException.class);
+ new MockFile(null);
+ }
+
+ /** Test constructor for regular files. */
+ @Test
+ public void testFileConstructor() throws Exception {
+ MockFile f = new MockFile("test");
+ checkDefaultConfig(f, "test", false);
+ assertEquals("Contents of test", readContents(f));
+ assertEquals("text/plain", f.getContentType());
+ }
+
+ /** Test constructor for directories . */
+ @Test
+ public void testDirectoryConstructor() throws Exception {
+ MockFile f = new MockFile("test", true);
+ checkDefaultConfig(f, "test", true);
+ DirectoryStream<Path> ds = f.newDirectoryStream();
+ assertNotNull(ds);
+ assertFalse(ds.iterator().hasNext());
+ ds.close();
+ }
+
+ /**
+ * Verifies some of the default file attributes (no explicit setters called).
+ */
+ private void checkDefaultConfig(MockFile file, String name, boolean isDir)
+ throws Exception {
+ assertEquals(name, file.getName());
+ assertEquals(isDir, file.isDirectory());
+ assertEquals(!isDir, file.isRegularFile());
+ assertFalse(file.isHidden());
+ assertNull(file.getParent());
+ assertEquals(MockFile.DEFAULT_FILETIME, file.getCreationTime());
+ assertEquals(MockFile.DEFAULT_FILETIME, file.getLastModifiedTime());
+ assertEquals(MockFile.DEFAULT_FILETIME, file.getLastAccessTime());
+ }
+
+ private String readContents(MockFile file) throws IOException {
+ return CharStreams.toString(
+ new InputStreamReader(file.newInputStream(), Charsets.UTF_8));
+ }
+
+ @Test
+ public void testSetName() throws Exception {
+ assertEquals("foo", new MockFile("test").setName("foo").getName());
+ }
+
+ @Test
+ public void testSetIsRegularFile() throws Exception {
+ MockFile f = new MockFile("test").setIsRegularFile(false);
+ assertFalse(f.isRegularFile());
+ assertFalse(f.isDirectory());
+
+ f.setIsRegularFile(true);
+ assertTrue(f.isRegularFile());
+ assertFalse(f.isDirectory());
+ }
+
+ @Test
+ public void testSetIsHidden() throws Exception {
+ MockFile f = new MockFile("test");
+ assertFalse(f.isHidden()); // default is false.
+ assertTrue(f.setIsHidden(true).isHidden());
+ assertFalse(f.setIsHidden(false).isHidden());
+ }
+
+ @Test
+ public void testSetFileTimes() throws Exception {
+ MockFile f = new MockFile("test").setCreationTime(createTime)
+ .setLastModifiedTime(modifyTime).setLastAccessTime(accessTime);
+ assertEquals(createTime, f.getCreationTime());
+ assertEquals(modifyTime, f.getLastModifiedTime());
+ assertEquals(accessTime, f.getLastAccessTime());
+ }
+
+ @Test
+ public void testReadBasicAttributesRegularFile() throws Exception {
+ MockFile f = new MockFile("test").setCreationTime(createTime)
+ .setLastModifiedTime(modifyTime).setLastAccessTime(accessTime);
+
+ BasicFileAttributes bfa = f.readBasicAttributes();
+ assertNotNull(bfa);
+ assertSame(f, bfa.fileKey());
+ assertEquals(createTime, bfa.creationTime());
+ assertEquals(modifyTime, bfa.lastModifiedTime());
+ assertEquals(accessTime, bfa.lastAccessTime());
+ assertTrue(bfa.isRegularFile());
+ assertFalse(bfa.isDirectory());
+ assertFalse(bfa.isSymbolicLink());
+ assertFalse(bfa.isOther());
+ assertEquals(readContents(f).length(), bfa.size());
+ }
+
+ @Test
+ public void testReadBasicAttributesDirectory() throws Exception {
+ MockFile f = new MockFile("test", true).setCreationTime(createTime)
+ .setLastModifiedTime(modifyTime).setLastAccessTime(accessTime);
+
+ BasicFileAttributes bfa = f.readBasicAttributes();
+ assertNotNull(bfa);
+ assertSame(f, bfa.fileKey());
+ assertEquals(createTime, bfa.creationTime());
+ assertEquals(modifyTime, bfa.lastModifiedTime());
+ assertEquals(accessTime, bfa.lastAccessTime());
+ assertFalse(bfa.isRegularFile());
+ assertTrue(bfa.isDirectory());
+ assertFalse(bfa.isSymbolicLink());
+ assertFalse(bfa.isOther());
+ assertEquals(0L, bfa.size());
+ }
+
+ @Test
+ public void testReadBasicAttributesSpecialFile() throws Exception {
+ // If neither file, nor directory, then it is "special".
+ MockFile f = new MockFile("test", false).setIsRegularFile(false);
+ BasicFileAttributes bfa = f.readBasicAttributes();
+ assertFalse(bfa.isRegularFile());
+ assertFalse(bfa.isDirectory());
+ assertFalse(bfa.isSymbolicLink());
+ assertTrue(bfa.isOther());
+ assertEquals(0L, bfa.size());
+ }
+
+ @Test
+ public void testSetFileContents() throws Exception {
+ String expected = "Hello World";
+ MockFile f = new MockFile("test.txt").setFileContents(expected);
+ assertEquals(expected, readContents(f));
+ }
+
+ @Test
+ public void testSetFileContentsBytes() throws Exception {
+ String expected = "<html><title>Hello World</title></html>";
+ MockFile f = new MockFile("test.html")
+ .setFileContents(expected.getBytes(Charsets.UTF_8))
+ .setContentType("text/html");
+ assertEquals(expected, readContents(f));
+ assertEquals("text/html", f.getContentType());
+ }
+
+ @Test
+ public void testChildren() throws Exception {
+ MockFile root = new MockFile("root", true);
+ MockFile dir1 = new MockFile("dir1", true);
+ MockFile dir2 = new MockFile("dir2", true);
+ MockFile test = new MockFile("test.txt");
+ root.addChildren(test, dir1, dir2);
+ assertNull(root.getParent());
+ assertSame(root, dir1.getParent());
+ assertSame(root, dir2.getParent());
+ assertSame(root, test.getParent());
+ checkDirectoryListing(root, dir1, dir2, test);
+
+ // Test getChild().
+ assertSame(dir1, root.getChild("dir1"));
+ assertSame(dir2, root.getChild("dir2"));
+ assertSame(test, root.getChild("test.txt"));
+
+ // Add another file.
+ MockFile newer = new MockFile("newer.txt");
+ root.addChildren(newer);
+ checkDirectoryListing(root, dir1, dir2, newer, test);
+ }
+
+ private void checkDirectoryListing(MockFile parent, MockFile... children)
+ throws IOException {
+ DirectoryStream<Path> ds = parent.newDirectoryStream();
+ assertNotNull(ds);
+ Iterator<Path> iter = ds.iterator();
+ assertNotNull(iter);
+ for (MockFile child : children) {
+ assertEquals(child.getName(), iter.next().getFileName().toString());
+ }
+ assertFalse(iter.hasNext());
+ ds.close();
+ }
+
+ @Test
+ public void testGetPath() throws Exception {
+ MockFile root = new MockFile("root", true);
+ MockFile dir1 = new MockFile("dir1", true);
+ MockFile test = new MockFile("test.txt");
+ MockFile test1 = new MockFile("test.txt");
+ root.addChildren(test, dir1);
+ dir1.addChildren(test1);
+ assertEquals("root", root.getPath());
+ assertEquals("root/dir1", dir1.getPath());
+ assertEquals("root/test.txt", test.getPath());
+ assertEquals("root/dir1/test.txt", test1.getPath());
+ }
+
+ @Test
+ public void testGetChildNullName() throws Exception {
+ thrown.expect(NullPointerException.class);
+ new MockFile("root", true).getChild(null);
+ }
+
+ @Test
+ public void testGetChildNotFound() throws Exception {
+ thrown.expect(FileNotFoundException.class);
+ new MockFile("root", true).getChild("nonExistent");
+ }
+
+ @Test
+ public void testGetDfsUncActiveStorageUnc() throws Exception {
+ MockFile root = new MockFile("root", true);
+ assertNull(root.getDfsUncActiveStorageUnc());
+ Path uncPath = Paths.get("\\\\server\\share");
+ root.setDfsUncActiveStorageUnc(uncPath);
+ assertEquals(uncPath, root.getDfsUncActiveStorageUnc());
+ }
+
+ @Test
+ public void testGetDfsShareAclView() throws Exception {
+ MockFile root = new MockFile("root", true);
+ assertNull(root.getDfsShareAclView());
+ root.setDfsShareAclView(MockFile.FULL_ACCESS_ACLVIEW);
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, root.getDfsShareAclView());
+ }
+
+ @Test
+ public void testDefaultRootAclViews() throws Exception {
+ MockFile root = new MockFile("root", true);
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, root.getShareAclView());
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, root.getAclView());
+ assertEquals(MockFile.EMPTY_ACLVIEW, root.getInheritedAclView());
+ }
+
+ @Test
+ public void testDefaultNonRootAclViews() throws Exception {
+ MockFile root = new MockFile("root", true);
+ MockFile dir1 = new MockFile("dir1", true);
+ MockFile foo = new MockFile("foo");
+ MockFile bar = new MockFile("bar");
+ root.addChildren(dir1, foo);
+ dir1.addChildren(bar);
+ assertEquals(MockFile.EMPTY_ACLVIEW, dir1.getAclView());
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, dir1.getInheritedAclView());
+ assertEquals(MockFile.EMPTY_ACLVIEW, foo.getAclView());
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, foo.getInheritedAclView());
+ assertEquals(MockFile.EMPTY_ACLVIEW, bar.getAclView());
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, bar.getInheritedAclView());
+ }
+
+ @Test
+ public void testSetAclViews() throws Exception {
+ MockFile root = new MockFile("root", true);
+ MockFile foo = new MockFile("foo");
+ root.addChildren(foo);
+ assertEquals(MockFile.EMPTY_ACLVIEW, foo.getAclView());
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, foo.getInheritedAclView());
+
+ foo.setAclView(MockFile.FULL_ACCESS_ACLVIEW);
+ foo.setInheritedAclView(MockFile.EMPTY_ACLVIEW);
+ assertEquals(MockFile.FULL_ACCESS_ACLVIEW, foo.getAclView());
+ assertEquals(MockFile.EMPTY_ACLVIEW, foo.getInheritedAclView());
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/fs/MockRequest.java b/test/com/google/enterprise/adaptor/fs/MockRequest.java
new file mode 100644
index 0000000..850d2fa
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/fs/MockRequest.java
@@ -0,0 +1,50 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// 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.google.enterprise.adaptor.fs;
+
+import com.google.enterprise.adaptor.DocId;
+import com.google.enterprise.adaptor.Request;
+
+import java.util.Date;
+
+/** A trivial implemenation of {@link Request} */
+class MockRequest implements Request {
+ private final DocId docid;
+ private final Date lastAccess;
+
+ MockRequest(DocId docid) {
+ this(docid, null);
+ }
+
+ MockRequest(DocId docid, Date lastAccess) {
+ this.docid = docid;
+ this.lastAccess = lastAccess;
+ }
+
+ @Override
+ public boolean hasChangedSinceLastAccess(Date lastModified) {
+ return lastModified.after(lastAccess);
+ }
+
+ @Override
+ public Date getLastAccessTime() {
+ return lastAccess;
+ }
+
+ @Override
+ public DocId getDocId() {
+ return docid;
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/fs/MockResponse.java b/test/com/google/enterprise/adaptor/fs/MockResponse.java
new file mode 100644
index 0000000..edbbaaa
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/fs/MockResponse.java
@@ -0,0 +1,124 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// 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.google.enterprise.adaptor.fs;
+
+import com.google.enterprise.adaptor.Acl;
+import com.google.enterprise.adaptor.Response;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An implementation of {@link Response} that implements only those items that
+ * the adaptor uses.
+ */
+class MockResponse implements Response {
+
+ boolean notModified = false;
+ boolean notFound = false;
+ String contentType;
+ Date lastModified;
+ URI displayUrl;
+ Acl acl;
+ Map<String, String> metadata = new HashMap<String, String>();
+ Map<String, Acl> namedResources = new HashMap<String, Acl>();
+ ByteArrayOutputStream content;
+
+ @Override
+ public void respondNotModified() throws IOException {
+ notModified = true;
+ }
+
+ @Override
+ public void respondNotFound() throws IOException {
+ notFound = true;
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ content = new ByteArrayOutputStream();
+ return content;
+ }
+
+ @Override
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ @Override
+ public void setLastModified(Date lastModified) {
+ this.lastModified = lastModified;
+ }
+
+ @Override
+ public void addMetadata(String key, String value) {
+ metadata.put(key, value);
+ }
+
+ @Override
+ public void setAcl(Acl acl) {
+ this.acl = acl;
+ }
+
+ @Override
+ public void putNamedResource(String fragment, Acl acl) {
+ namedResources.put(fragment, acl);
+ }
+
+ @Override
+ public void setDisplayUrl(URI displayUrl) {
+ this.displayUrl = displayUrl;
+ }
+
+ @Override
+ public void setSecure(boolean secure) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addAnchor(URI uri, String text) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNoIndex(boolean noIndex) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNoFollow(boolean noFollow) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNoArchive(boolean noArchive) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setCrawlOnce(boolean crawlOnce) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setLock(boolean lock) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/fs/UnsupportedDocIdPusher.java b/test/com/google/enterprise/adaptor/fs/UnsupportedDocIdPusher.java
new file mode 100644
index 0000000..e9b3439
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/fs/UnsupportedDocIdPusher.java
@@ -0,0 +1,83 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// 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.google.enterprise.adaptor.fs;
+
+import com.google.enterprise.adaptor.Acl;
+import com.google.enterprise.adaptor.DocId;
+import com.google.enterprise.adaptor.DocIdPusher;
+import com.google.enterprise.adaptor.ExceptionHandler;
+import com.google.enterprise.adaptor.GroupPrincipal;
+import com.google.enterprise.adaptor.Principal;
+
+import java.util.Collection;
+import java.util.Map;
+
+/** Throws UnsupportedOperationException for all calls. */
+class UnsupportedDocIdPusher implements DocIdPusher {
+
+ @Override
+ public DocId pushDocIds(Iterable<DocId> docIds)
+ throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DocId pushDocIds(Iterable<DocId> docIds,
+ ExceptionHandler handler)
+ throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Record pushRecords(Iterable<Record> records)
+ throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Record pushRecords(Iterable<Record> records,
+ ExceptionHandler handler)
+ throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DocId pushNamedResources(Map<DocId, Acl> resources)
+ throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DocId pushNamedResources(Map<DocId, Acl> resources,
+ ExceptionHandler handler)
+ throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public GroupPrincipal pushGroupDefinitions(
+ Map<GroupPrincipal, ? extends Collection<Principal>> defs,
+ boolean caseSensitive) throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public GroupPrincipal pushGroupDefinitions(
+ Map<GroupPrincipal, ? extends Collection<Principal>> defs,
+ boolean caseSensitive, ExceptionHandler handler)
+ throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+}