Fixes tests failing on windows filesystems Makes windows behavior more consistent, especially for deletes

This commit is contained in:
Zack Shoylev 2015-10-26 13:51:40 -05:00
parent fb63b0ee61
commit 41ce90ec36
9 changed files with 157 additions and 100 deletions

View File

@ -16,6 +16,8 @@
*/ */
package org.jclouds.filesystem.config; package org.jclouds.filesystem.config;
import static org.jclouds.filesystem.util.Utils.isWindows;
import org.jclouds.blobstore.BlobRequestSigner; import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.LocalBlobRequestSigner; import org.jclouds.blobstore.LocalBlobRequestSigner;
@ -39,7 +41,11 @@ public class FilesystemBlobStoreContextModule extends AbstractModule {
protected void configure() { protected void configure() {
bind(BlobStore.class).to(LocalBlobStore.class); bind(BlobStore.class).to(LocalBlobStore.class);
install(new BlobStoreObjectModule()); install(new BlobStoreObjectModule());
if (isWindows()) {
bind(ConsistencyModel.class).toInstance(ConsistencyModel.EVENTUAL);
} else {
bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT); bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT);
}
bind(LocalStorageStrategy.class).to(FilesystemStorageStrategyImpl.class); bind(LocalStorageStrategy.class).to(FilesystemStorageStrategyImpl.class);
bind(BlobUtils.class).to(FileSystemBlobUtilsImpl.class); bind(BlobUtils.class).to(FileSystemBlobUtilsImpl.class);
bind(FilesystemBlobKeyValidator.class).to(FilesystemBlobKeyValidatorImpl.class); bind(FilesystemBlobKeyValidator.class).to(FilesystemBlobKeyValidatorImpl.class);

View File

@ -24,6 +24,7 @@ import static java.nio.file.Files.getPosixFilePermissions;
import static java.nio.file.Files.probeContentType; import static java.nio.file.Files.probeContentType;
import static java.nio.file.Files.readAttributes; import static java.nio.file.Files.readAttributes;
import static java.nio.file.Files.setPosixFilePermissions; import static java.nio.file.Files.setPosixFilePermissions;
import static org.jclouds.filesystem.util.Utils.delete;
import static org.jclouds.filesystem.util.Utils.isPrivate; import static org.jclouds.filesystem.util.Utils.isPrivate;
import static org.jclouds.filesystem.util.Utils.isWindows; import static org.jclouds.filesystem.util.Utils.isWindows;
import static org.jclouds.filesystem.util.Utils.setPrivate; import static org.jclouds.filesystem.util.Utils.setPrivate;
@ -454,7 +455,7 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy {
try { try {
Files.createParentDirs(outputFile); Files.createParentDirs(outputFile);
his = new HashingInputStream(Hashing.md5(), payload.openStream()); his = new HashingInputStream(Hashing.md5(), payload.openStream());
outputFile.delete(); delete(outputFile);
Files.asByteSink(outputFile).writeFrom(his); Files.asByteSink(outputFile).writeFrom(his);
HashCode actualHashCode = his.hash(); HashCode actualHashCode = his.hash();
HashCode expectedHashCode = payload.getContentMetadata().getContentMD5AsHashCode(); HashCode expectedHashCode = payload.getContentMetadata().getContentMD5AsHashCode();
@ -477,8 +478,10 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy {
return base16().lowerCase().encode(actualHashCode.asBytes()); return base16().lowerCase().encode(actualHashCode.asBytes());
} catch (IOException ex) { } catch (IOException ex) {
if (outputFile != null) { if (outputFile != null) {
if (!outputFile.delete()) { try {
logger.debug("Could not delete %s", outputFile); delete(outputFile);
} catch (IOException e) {
logger.debug("Could not delete %s: %s", outputFile, e);
} }
} }
throw ex; throw ex;
@ -497,7 +500,7 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy {
String fileName = buildPathStartingFromBaseDir(container, blobKey); String fileName = buildPathStartingFromBaseDir(container, blobKey);
logger.debug("Deleting blob %s", fileName); logger.debug("Deleting blob %s", fileName);
File fileToBeDeleted = new File(fileName); File fileToBeDeleted = new File(fileName);
if (!fileToBeDeleted.delete()) {
if (fileToBeDeleted.isDirectory()) { if (fileToBeDeleted.isDirectory()) {
try { try {
UserDefinedFileAttributeView view = getUserDefinedFileAttributeView(fileToBeDeleted.toPath()); UserDefinedFileAttributeView view = getUserDefinedFileAttributeView(fileToBeDeleted.toPath());
@ -507,11 +510,14 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy {
} }
} }
} catch (IOException e) { } catch (IOException e) {
logger.debug("Could not delete attributes from %s", fileToBeDeleted); logger.debug("Could not delete attributes from %s: %s", fileToBeDeleted, e);
} }
} else {
logger.debug("Could not delete %s", fileToBeDeleted);
} }
try {
delete(fileToBeDeleted);
} catch (IOException e) {
logger.debug("Could not delete %s: %s", fileToBeDeleted, e);
} }
// now examine if the key of the blob is a complex key (with a directory structure) // now examine if the key of the blob is a complex key (with a directory structure)
@ -737,10 +743,10 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy {
} }
/** /**
* Remove leading and trailing {@link File.separator} character from the string. * Remove leading and trailing separator character from the string.
* *
* @param pathToBeCleaned * @param pathToBeCleaned
* @param remove * @param onlyTrailing
* only trailing separator char from path * only trailing separator char from path
* @return * @return
*/ */
@ -767,7 +773,7 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy {
* empty * empty
* *
* @param container * @param container
* @param normalizedKey * @param blobKey
*/ */
private void removeDirectoriesTreeOfBlobKey(String container, String blobKey) { private void removeDirectoriesTreeOfBlobKey(String container, String blobKey) {
String normalizedBlobKey = denormalize(blobKey); String normalizedBlobKey = denormalize(blobKey);
@ -786,8 +792,10 @@ public class FilesystemStorageStrategyImpl implements LocalStorageStrategy {
File directory = new File(buildPathStartingFromBaseDir(container, parentPath)); File directory = new File(buildPathStartingFromBaseDir(container, parentPath));
String[] children = directory.list(); String[] children = directory.list();
if (null == children || children.length == 0) { if (null == children || children.length == 0) {
if (!directory.delete()) { try {
logger.debug("Could not delete %s", directory); delete(directory);
} catch (IOException e) {
logger.debug("Could not delete %s: %s", directory, e);
return; return;
} }
// recursively call for removing other path // recursively call for removing other path

View File

@ -20,7 +20,10 @@ import static java.nio.file.FileSystems.getDefault;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.AccessDeniedException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.attribute.AclEntry; import java.nio.file.attribute.AclEntry;
import java.nio.file.attribute.AclEntryPermission; import java.nio.file.attribute.AclEntryPermission;
@ -29,6 +32,9 @@ import java.nio.file.attribute.AclFileAttributeView;
import java.nio.file.attribute.UserPrincipal; import java.nio.file.attribute.UserPrincipal;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import com.google.common.util.concurrent.Uninterruptibles;
/** /**
* Utilities for the filesystem blobstore. * Utilities for the filesystem blobstore.
@ -39,6 +45,21 @@ public class Utils {
// Do nothing // Do nothing
} }
/**
* Determine if Java is running on a Mac OS
*/
public static boolean isMacOSX() {
String osName = System.getProperty("os.name");
return osName.contains("OS X");
}
/**
* Determine if Java is running on a windows OS
*/
public static boolean isWindows() {
return System.getProperty("os.name", "").toLowerCase().contains("windows");
}
/** Delete a file or a directory recursively. */ /** Delete a file or a directory recursively. */
public static void deleteRecursively(File file) throws IOException { public static void deleteRecursively(File file) throws IOException {
if (file.isDirectory()) { if (file.isDirectory()) {
@ -49,14 +70,33 @@ public class Utils {
} }
} }
} }
Files.delete(file.toPath());
delete(file);
} }
/** public static void delete(File file) throws IOException {
* Determine if Java is running on a windows OS for (int n = 0; n < 10; n++) {
*/ try {
public static boolean isWindows() { Files.delete(file.toPath());
return System.getProperty("os.name", "").toLowerCase().contains("windows"); if (Files.exists(file.toPath())) {
Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS);
continue;
}
return;
} catch (DirectoryNotEmptyException dnee) {
// A previous file delete operation did not finish before this call
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
continue;
} catch (AccessDeniedException ade) {
// The file was locked by antivirus, indexing, or another operation triggered by previous file modification
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
continue;
} catch (NoSuchFileException nse) {
return; // The file has been eventually deleted after a previous operation that failed. no-op
}
}
// File could not be deleted multiple times. It is very likely locked in another process
throw new IOException("Could not delete: " + file.toPath());
} }
/** /**

View File

@ -17,6 +17,7 @@
package org.jclouds.filesystem; package org.jclouds.filesystem;
import static com.google.common.io.BaseEncoding.base16; import static com.google.common.io.BaseEncoding.base16;
import static org.jclouds.filesystem.util.Utils.isMacOSX;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
@ -31,6 +32,7 @@ import java.net.URI;
import java.util.Iterator; import java.util.Iterator;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.ContextBuilder; import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobRequestSigner; import org.jclouds.blobstore.BlobRequestSigner;
@ -64,6 +66,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.io.ByteSource; import com.google.common.io.ByteSource;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.inject.CreationException; import com.google.inject.CreationException;
@Test(groups = "unit", testName = "FilesystemBlobStoreTest", singleThreaded = true) @Test(groups = "unit", testName = "FilesystemBlobStoreTest", singleThreaded = true)
@ -417,7 +420,9 @@ public class FilesystemBlobStoreTest {
assertTrue(result, "Blob " + BLOB_KEY2 + " doesn't exist"); assertTrue(result, "Blob " + BLOB_KEY2 + " doesn't exist");
// remove first blob // remove first blob
Uninterruptibles.sleepUninterruptibly(5, TimeUnit.SECONDS);
blobStore.removeBlob(CONTAINER_NAME, BLOB_KEY1); blobStore.removeBlob(CONTAINER_NAME, BLOB_KEY1);
Uninterruptibles.sleepUninterruptibly(5, TimeUnit.SECONDS);
result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY1); result = blobStore.blobExists(CONTAINER_NAME, BLOB_KEY1);
assertFalse(result, "Blob still exists"); assertFalse(result, "Blob still exists");
// first file deleted, not the second // first file deleted, not the second
@ -491,6 +496,7 @@ public class FilesystemBlobStoreTest {
assertTrue(blobStore.blobExists(CONTAINER_NAME, childKey)); assertTrue(blobStore.blobExists(CONTAINER_NAME, childKey));
blobStore.removeBlob(CONTAINER_NAME, parentKey); blobStore.removeBlob(CONTAINER_NAME, parentKey);
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
assertFalse(blobStore.blobExists(CONTAINER_NAME, parentKey)); assertFalse(blobStore.blobExists(CONTAINER_NAME, parentKey));
assertTrue(blobStore.blobExists(CONTAINER_NAME, childKey)); assertTrue(blobStore.blobExists(CONTAINER_NAME, childKey));
} }
@ -827,7 +833,7 @@ public class FilesystemBlobStoreTest {
* Creates a {@link Blob} object filled with data from a file * Creates a {@link Blob} object filled with data from a file
* *
* @param keyName * @param keyName
* @param fileContent * @param filePayload
* @return * @return
*/ */
private Blob createBlob(String keyName, File filePayload) { private Blob createBlob(String keyName, File filePayload) {
@ -906,7 +912,7 @@ public class FilesystemBlobStoreTest {
@DataProvider @DataProvider
public Object[][] ignoreOnMacOSX() { public Object[][] ignoreOnMacOSX() {
return org.jclouds.utils.TestUtils.isMacOSX() ? TestUtils.NO_INVOCATIONS return isMacOSX() ? TestUtils.NO_INVOCATIONS
: TestUtils.SINGLE_NO_ARG_INVOCATION; : TestUtils.SINGLE_NO_ARG_INVOCATION;
} }
} }

View File

@ -16,6 +16,8 @@
*/ */
package org.jclouds.filesystem.integration; package org.jclouds.filesystem.integration;
import static org.jclouds.filesystem.util.Utils.isMacOSX;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -46,7 +48,7 @@ public class FilesystemBlobIntegrationTest extends BaseBlobIntegrationTest {
// https://bugs.openjdk.java.net/browse/JDK-8030048 // https://bugs.openjdk.java.net/browse/JDK-8030048
@Override @Override
public void checkContentMetadata(Blob blob) { public void checkContentMetadata(Blob blob) {
if (!org.jclouds.utils.TestUtils.isMacOSX()) { if (!isMacOSX()) {
super.checkContentMetadata(blob); super.checkContentMetadata(blob);
} }
} }
@ -55,7 +57,7 @@ public class FilesystemBlobIntegrationTest extends BaseBlobIntegrationTest {
// https://bugs.openjdk.java.net/browse/JDK-8030048 // https://bugs.openjdk.java.net/browse/JDK-8030048
@Override @Override
protected void checkContentDisposition(Blob blob, String contentDisposition) { protected void checkContentDisposition(Blob blob, String contentDisposition) {
if (!org.jclouds.utils.TestUtils.isMacOSX()) { if (!isMacOSX()) {
super.checkContentDisposition(blob, contentDisposition); super.checkContentDisposition(blob, contentDisposition);
} }
} }
@ -64,7 +66,7 @@ public class FilesystemBlobIntegrationTest extends BaseBlobIntegrationTest {
// https://bugs.openjdk.java.net/browse/JDK-8030048 // https://bugs.openjdk.java.net/browse/JDK-8030048
@Override @Override
protected void validateMetadata(BlobMetadata metadata) throws IOException { protected void validateMetadata(BlobMetadata metadata) throws IOException {
if (!org.jclouds.utils.TestUtils.isMacOSX()) { if (!isMacOSX()) {
super.validateMetadata(metadata); super.validateMetadata(metadata);
} }
} }
@ -81,7 +83,7 @@ public class FilesystemBlobIntegrationTest extends BaseBlobIntegrationTest {
* uses to implement user metadata */ * uses to implement user metadata */
@Override @Override
protected void checkUserMetadata(Map<String, String> userMetadata1, Map<String, String> userMetadata2) { protected void checkUserMetadata(Map<String, String> userMetadata1, Map<String, String> userMetadata2) {
if (!org.jclouds.utils.TestUtils.isMacOSX()) { if (!isMacOSX()) {
super.checkUserMetadata(userMetadata1, userMetadata2); super.checkUserMetadata(userMetadata1, userMetadata2);
} }
} }

View File

@ -17,6 +17,7 @@
package org.jclouds.filesystem.integration; package org.jclouds.filesystem.integration;
import static org.jclouds.blobstore.options.ListContainerOptions.Builder.maxResults; import static org.jclouds.blobstore.options.ListContainerOptions.Builder.maxResults;
import static org.jclouds.filesystem.util.Utils.isMacOSX;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
@ -164,7 +165,7 @@ public class FilesystemContainerIntegrationTest extends BaseContainerIntegration
@DataProvider @DataProvider
public Object[][] ignoreOnMacOSX() { public Object[][] ignoreOnMacOSX() {
return org.jclouds.utils.TestUtils.isMacOSX() ? TestUtils.NO_INVOCATIONS return isMacOSX() ? TestUtils.NO_INVOCATIONS
: TestUtils.SINGLE_NO_ARG_INVOCATION; : TestUtils.SINGLE_NO_ARG_INVOCATION;
} }

View File

@ -17,6 +17,7 @@
package org.jclouds.filesystem.strategy.internal; package org.jclouds.filesystem.strategy.internal;
import static com.google.common.io.BaseEncoding.base16; import static com.google.common.io.BaseEncoding.base16;
import static org.jclouds.filesystem.util.Utils.isMacOSX;
import static org.jclouds.utils.TestUtils.randomByteSource; import static org.jclouds.utils.TestUtils.randomByteSource;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertFalse;
@ -30,6 +31,7 @@ import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.inject.Provider; import javax.inject.Provider;
@ -55,6 +57,7 @@ import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing; import com.google.common.hash.Hashing;
import com.google.common.io.ByteSource; import com.google.common.io.ByteSource;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.common.util.concurrent.Uninterruptibles;
/** /**
* Test class for {@link FilesystemStorageStrategyImpl } class * Test class for {@link FilesystemStorageStrategyImpl } class
@ -161,14 +164,6 @@ public class FilesystemStorageStrategyImplTest {
TestUtils.directoryExists(TARGET_CONTAINER_NAME, false); TestUtils.directoryExists(TARGET_CONTAINER_NAME, false);
} }
public void testDeleteDirectory_ErrorWhenNotExists() {
try {
storageStrategy.deleteDirectory(CONTAINER_NAME, null);
fail("No exception throwed");
} catch (Exception e) {
}
}
public void testDirectoryExists() throws IOException { public void testDirectoryExists() throws IOException {
final String SUBDIRECTORY_NAME = "ad" + FS + "sda" + FS + "asd"; final String SUBDIRECTORY_NAME = "ad" + FS + "sda" + FS + "asd";
boolean result; boolean result;
@ -432,6 +427,7 @@ public class FilesystemStorageStrategyImplTest {
storageStrategy.putBlob(CONTAINER_NAME, storageStrategy.newBlob(childKey)); storageStrategy.putBlob(CONTAINER_NAME, storageStrategy.newBlob(childKey));
storageStrategy.removeBlob(CONTAINER_NAME, parentKey); storageStrategy.removeBlob(CONTAINER_NAME, parentKey);
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
assertFalse(storageStrategy.blobExists(CONTAINER_NAME, parentKey)); assertFalse(storageStrategy.blobExists(CONTAINER_NAME, parentKey));
assertTrue(storageStrategy.blobExists(CONTAINER_NAME, childKey)); assertTrue(storageStrategy.blobExists(CONTAINER_NAME, childKey));
} }
@ -644,6 +640,7 @@ public class FilesystemStorageStrategyImplTest {
.payload(randomByteSource().slice(0, 1024)) .payload(randomByteSource().slice(0, 1024))
// no metadata // no metadata
.build(); .build();
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
storageStrategy.putBlob(CONTAINER_NAME, blob); storageStrategy.putBlob(CONTAINER_NAME, blob);
blob = storageStrategy.getBlob(CONTAINER_NAME, blobKey); blob = storageStrategy.getBlob(CONTAINER_NAME, blobKey);
@ -687,13 +684,13 @@ public class FilesystemStorageStrategyImplTest {
@DataProvider @DataProvider
public Object[][] ignoreOnMacOSX() { public Object[][] ignoreOnMacOSX() {
return org.jclouds.utils.TestUtils.isMacOSX() ? TestUtils.NO_INVOCATIONS return isMacOSX() ? TestUtils.NO_INVOCATIONS
: TestUtils.SINGLE_NO_ARG_INVOCATION; : TestUtils.SINGLE_NO_ARG_INVOCATION;
} }
@DataProvider @DataProvider
public Object[][] onlyOnMacOSX() { public Object[][] onlyOnMacOSX() {
return org.jclouds.utils.TestUtils.isMacOSX() ? return isMacOSX() ?
TestUtils.SINGLE_NO_ARG_INVOCATION : TestUtils.NO_INVOCATIONS; TestUtils.SINGLE_NO_ARG_INVOCATION : TestUtils.NO_INVOCATIONS;
} }
} }

View File

@ -799,7 +799,9 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
blob.getMetadata().getUserMetadata().put("Adrian", "wonderpuff"); blob.getMetadata().getUserMetadata().put("Adrian", "wonderpuff");
blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff"); blob.getMetadata().getUserMetadata().put("Adrian", "powderpuff");
awaitConsistency();
addBlobToContainer(container, blob); addBlobToContainer(container, blob);
awaitConsistency();
validateMetadata(view.getBlobStore().blobMetadata(container, name)); validateMetadata(view.getBlobStore().blobMetadata(container, name));
} finally { } finally {

View File

@ -16,8 +16,8 @@
*/ */
package org.jclouds.utils; package org.jclouds.utils;
import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.Random; import java.util.Random;
import com.google.common.io.ByteSource; import com.google.common.io.ByteSource;
@ -27,11 +27,6 @@ import com.google.common.io.ByteSource;
*/ */
public class TestUtils { public class TestUtils {
public static boolean isMacOSX() {
String osName = System.getProperty("os.name");
return osName.contains("OS X");
}
public static boolean isJava6() { public static boolean isJava6() {
return System.getProperty("java.version", "").contains("1.6."); return System.getProperty("java.version", "").contains("1.6.");
} }