Refactor WindowsAclFileAttributeViews for testability.
Use Dependency Injection of various Windows APIs so that
Mock or Fake implementations may be supplied for the tests.
diff --git a/src/com/google/enterprise/adaptor/fs/WindowsAclFileAttributeViews.java b/src/com/google/enterprise/adaptor/fs/WindowsAclFileAttributeViews.java
index 199b568..37c8da4 100644
--- a/src/com/google/enterprise/adaptor/fs/WindowsAclFileAttributeViews.java
+++ b/src/com/google/enterprise/adaptor/fs/WindowsAclFileAttributeViews.java
@@ -14,6 +14,7 @@
package com.google.enterprise.adaptor.fs;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
@@ -67,12 +68,9 @@
*/
class WindowsAclFileAttributeViews {
- private static final Logger log =
+ private static final Logger log =
Logger.getLogger(WindowsAclFileAttributeViews.class.getName());
- private static final Kernel32 KERNEL32 = Kernel32.INSTANCE;
- private static final Advapi32 ADVAPI32 = Advapi32.INSTANCE;
-
/** This pattern parses a UNC path to get the host and share details. */
private static final Pattern UNC_PATTERN =
Pattern.compile("^\\\\\\\\([^\\\\]+)\\\\([^\\\\]+)");
@@ -88,7 +86,7 @@
Collections.unmodifiableSet(Sets.newHashSet(SID_NAME_USE.SidTypeUser));
/** Map of NT GENERIC permissions to NT FILE permissions. */
- private static final Map<Integer, Integer> GENERIC_PERMS_MAP =
+ private static final Map<Integer, Integer> GENERIC_PERMS_MAP =
Collections.unmodifiableMap(new HashMap<Integer, Integer>() {
{
put(WinNT.GENERIC_READ, WinNT.FILE_GENERIC_READ);
@@ -142,6 +140,28 @@
}
});
+ private final Advapi32 advapi32;
+ private final Kernel32 kernel32;
+ private final Mpr mpr;
+ private final Netapi32Ex netapi32;
+ private final Shlwapi shlwapi;
+
+ /** Constructor used for production. */
+ public WindowsAclFileAttributeViews() {
+ this(Advapi32.INSTANCE, Kernel32.INSTANCE, Mpr.INSTANCE,
+ Netapi32Ex.INSTANCE,Shlwapi.INSTANCE);
+ }
+
+ /** Constructor used by the tests. */
+ @VisibleForTesting
+ WindowsAclFileAttributeViews(Advapi32 advapi32, Kernel32 kernel32,
+ Mpr mpr, Netapi32Ex netapi32, Shlwapi shlwapi) {
+ this.advapi32 = advapi32;
+ this.kernel32 = kernel32;
+ this.mpr = mpr;
+ this.netapi32 = netapi32;
+ this.shlwapi = shlwapi;
+ }
/**
* Returns a container for the direct and inherited ACLs for
@@ -152,7 +172,7 @@
*/
public AclFileAttributeViews getAclViews(Path path) throws IOException {
String pathname = path.toRealPath(LinkOption.NOFOLLOW_LINKS).toString();
- WinNT.ACCESS_ACEStructure[] aces = getFileSecurity(pathname,
+ WinNT.ACCESS_ACEStructure[] aces = getFileSecurity(pathname,
WinNT.DACL_SECURITY_INFORMATION |
WinNT.PROTECTED_DACL_SECURITY_INFORMATION |
WinNT.UNPROTECTED_DACL_SECURITY_INFORMATION);
@@ -160,7 +180,7 @@
ImmutableList.Builder<AclEntry> direct = ImmutableList.builder();
for (WinNT.ACCESS_ACEStructure ace : aces) {
- AclEntry aclEntry = newAclEntry(ace);
+ AclEntry aclEntry = newAclEntry(ace);
if (aclEntry != null) {
if ((ace.AceFlags & WinNT.INHERITED_ACE) == WinNT.INHERITED_ACE) {
inherited.add(aclEntry);
@@ -192,23 +212,22 @@
*/
public AclFileAttributeView getShareAclView(Path path)
throws IOException, UnsupportedOperationException {
- if (Shlwapi.INSTANCE.PathIsUNC(path.toString())) {
+ if (shlwapi.PathIsUNC(path.toString())) {
log.log(Level.FINEST, "Using a UNC path.");
return getUncShareAclView(path.toString());
- } else if (Shlwapi.INSTANCE.PathIsNetworkPath(path.toString())) {
+ } else if (shlwapi.PathIsNetworkPath(path.toString())) {
log.log(Level.FINEST, "Using a mapped drive.");
- // Call WNetGetUniversalNameW with the size needed for
+ // Call WNetGetUniversalNameW with the size needed for
// UNIVERSAL_NAME_INFO. If WNetGetUniversalNameW returns ERROR_MORE_DATA
// that indicates that a larger buffer is needed. If this happens, make
// a second call to WNetGetUniversalNameW with a buffer big enough.
- Mpr mprlib = Mpr.INSTANCE;
Memory buf = new Memory(1024);
IntByReference bufSize = new IntByReference((int) buf.size());
- int result = mprlib.WNetGetUniversalNameW(path.getRoot().toString(),
+ int result = mpr.WNetGetUniversalNameW(path.getRoot().toString(),
Mpr.UNIVERSAL_NAME_INFO_LEVEL, buf, bufSize);
if (result == WinNT.ERROR_MORE_DATA) {
buf = new Memory(bufSize.getValue());
- result = Mpr.INSTANCE.WNetGetUniversalNameW(path.getRoot().toString(),
+ result = mpr.WNetGetUniversalNameW(path.getRoot().toString(),
Mpr.UNIVERSAL_NAME_INFO_LEVEL, buf, bufSize);
}
if (result != WinNT.NO_ERROR) {
@@ -239,12 +258,11 @@
new Object[] { host, share });
return getShareAclView(host, share);
}
-
+
private AclFileAttributeView getShareAclView(String host, String share)
throws IOException {
- Netapi32Ex netapi32 = Netapi32Ex.INSTANCE;
PointerByReference buf = new PointerByReference();
-
+
// Call NetShareGetInfo with a 502 to get the security descriptor of the
// share. The security descriptor contains the Acl details for the share
// that the adaptor needs.
@@ -336,7 +354,7 @@
new Object[] { accountName, accountType });
return null;
}
-
+
// Expand NT GENERIC_* permissions to their FILE_GENERIC_* equivalents.
int aceMask = ace.Mask;
for (Map.Entry<Integer, Integer> e : GENERIC_PERMS_MAP.entrySet()) {
@@ -352,7 +370,7 @@
aclPerms.add(e.getValue());
}
}
-
+
// Map the flags.
Set<AclEntryFlag> aclFlags = EnumSet.noneOf(AclEntryFlag.class);
for (Map.Entry<Byte, AclEntryFlag> e : ACL_FLAGS_MAP.entrySet()) {
@@ -408,7 +426,8 @@
}
}
- private interface Mpr extends StdCallLibrary {
+ @VisibleForTesting
+ interface Mpr extends StdCallLibrary {
Mpr INSTANCE = (Mpr) Native.loadLibrary("Mpr", Mpr.class,
W32APIOptions.UNICODE_OPTIONS);
@@ -442,21 +461,21 @@
WString wpath = new WString(pathname);
IntByReference lengthNeeded = new IntByReference();
- if (ADVAPI32.GetFileSecurity(wpath, daclType, null, 0, lengthNeeded)) {
+ if (advapi32.GetFileSecurity(wpath, daclType, null, 0, lengthNeeded)) {
throw new RuntimeException("GetFileSecurity was expected to fail with "
+ "ERROR_INSUFFICIENT_BUFFER");
}
- int rc = KERNEL32.GetLastError();
+ int rc = kernel32.GetLastError();
if (rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
throw new IOException("Failed GetFileSecurity", new Win32Exception(rc));
}
Memory memory = new Memory(lengthNeeded.getValue());
- if (!ADVAPI32.GetFileSecurity(wpath, daclType, memory, (int) memory.size(),
+ if (!advapi32.GetFileSecurity(wpath, daclType, memory, (int) memory.size(),
lengthNeeded)) {
throw new IOException("Failed GetFileSecurity",
- new Win32Exception(KERNEL32.GetLastError()));
+ new Win32Exception(kernel32.GetLastError()));
}
WinNT.SECURITY_DESCRIPTOR_RELATIVE securityDescriptor =