You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by kr...@apache.org on 2010/09/22 10:18:15 UTC
svn commit: r999796 - in
/db/derby/code/trunk/java/testing/org/apache/derbyTesting:
functionTests/tests/store/OSReadOnlyTest.java
functionTests/util/PrivilegedFileOpsForTests.java junit/BaseJDBCTestCase.java
Author: kristwaa
Date: Wed Sep 22 08:18:14 2010
New Revision: 999796
URL: http://svn.apache.org/viewvc?rev=999796&view=rev
Log:
DERBY-4804: Make database used in store.OSReadOnlyTest fully read-only
Followup patch moving file operation code into PrivilegedFileOpsForTests,
since it is probably useful for other tests as well.
Also note the new assert-method in BaseJDBCTestCase, used to assert that a
directory is fully deleted.
Patch file: derby-4804-2a-common_file_ops.diff
Modified:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/OSReadOnlyTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/PrivilegedFileOpsForTests.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/OSReadOnlyTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/OSReadOnlyTest.java?rev=999796&r1=999795&r2=999796&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/OSReadOnlyTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/OSReadOnlyTest.java Wed Sep 22 08:18:14 2010
@@ -22,7 +22,6 @@
package org.apache.derbyTesting.functionTests.tests.store;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.AccessController;
@@ -36,6 +35,7 @@ import javax.sql.DataSource;
import junit.framework.Test;
import junit.framework.TestSuite;
+import org.apache.derbyTesting.functionTests.util.PrivilegedFileOpsForTests;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
import org.apache.derbyTesting.junit.JDBC;
@@ -134,7 +134,7 @@ public class OSReadOnlyTest extends Base
// so far, we were just playing. Now for the test.
String phDbName = getPhysicalDbName();
// copy the database to one called 'readOnly'
- copyDatabaseOnOS(phDbName, "readOnly");
+ moveDatabaseOnOS(phDbName, "readOnly");
// change filePermissions on readOnly, to readonly.
changeFilePermissions("readOnly");
createDummyLockFile("readOnly");
@@ -149,7 +149,7 @@ public class OSReadOnlyTest extends Base
// copy the database to one called 'readWrite'
// this will have the default read/write permissions upon
// copying
- copyDatabaseOnOS("readOnly", "readWrite");
+ moveDatabaseOnOS("readOnly", "readWrite");
ds = JDBCDataSource.getDataSource();
JDBCDataSource.setBeanProperty(ds, "databaseName", "singleUse/readWrite");
assertReadDB(ds);
@@ -157,7 +157,7 @@ public class OSReadOnlyTest extends Base
shutdownDB(ds);
// do it again...
- copyDatabaseOnOS("readWrite", "readOnly2");
+ moveDatabaseOnOS("readWrite", "readOnly2");
// change filePermissions on readOnly, to readonly.
changeFilePermissions("readOnly2");
createDummyLockFile("readOnly2");
@@ -170,7 +170,7 @@ public class OSReadOnlyTest extends Base
shutdownDB(ds);
// testharness will try to remove the original db; put it back
- copyDatabaseOnOS("readOnly2", phDbName);
+ moveDatabaseOnOS("readOnly2", phDbName);
}
/*
@@ -274,15 +274,21 @@ public class OSReadOnlyTest extends Base
stmt.close();
con.close();
}
-
- private void copyDatabaseOnOS(String fromwhere, String todir) {
+
+ /**
+ * Moves the database from one location to another location.
+ *
+ * @param fromwhere source directory
+ * @param todir destination directory
+ * @throws IOException if the copy fails
+ */
+ private void moveDatabaseOnOS(String fromwhere, String todir)
+ throws IOException {
File from_dir = constructDbPath(fromwhere);
File to_dir = constructDbPath(todir);
-
- assertTrue("Failed to copy directory from " + from_dir + " to " + to_dir,
- (copyDirectory(from_dir, to_dir)));
- assertTrue("Failed to remove directory: " + from_dir,
- (removeTemporaryDirectory(from_dir)));
+
+ PrivilegedFileOpsForTests.copy(from_dir, to_dir);
+ assertDirectoryDeleted(from_dir);
}
/**
@@ -385,169 +391,4 @@ public class OSReadOnlyTest extends Base
}
else return false;
}
-
- /**
- Remove a directory and all of its contents.
-
- The results of executing File.delete() on a File object
- that represents a directory seems to be platform
- dependent. This method removes the directory
- and all of its contents.
-
- @return true if the complete directory was removed, false if it could not be.
- If false is returned then some of the files in the directory may have been removed.
- */
- final private static boolean removeTemporaryDirectory(File directory) {
- //System.out.println("removeDirectory " + directory);
-
- if (directory == null)
- return false;
- final File sdirectory = directory;
-
- Boolean b = (Boolean)AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- if (!sdirectory.exists())
- return new Boolean(true);
- if (!sdirectory.isDirectory())
- return new Boolean(false);
- String[] list = sdirectory.list();
- // Some JVMs return null for File.list() when the
- // directory is empty.
- if (list != null) {
- for (int i = 0; i < list.length; i++) {
- File entry = new File(sdirectory, list[i]);
- if (entry.isDirectory())
- {
- if (!removeTemporaryDirectory(entry))
- return new Boolean(false);
- }
- else
- {
- if (!entry.delete())
- return new Boolean(false);
- }
- }
- }
- return new Boolean(sdirectory.delete());
- }
- });
- if (b.booleanValue())
- {
- return true;
- }
- else return false;
- }
-
- /**
- Copy a directory and all of its contents.
- */
- private static boolean copyDirectory(File from, File to)
- {
- return copyDirectory(from, to, (byte[])null);
- }
-
- private static boolean copyDirectory(String from, String to)
- {
- return copyDirectory(new File(from), new File(to));
- }
-
- private static boolean copyDirectory(File from, File to, byte[] buffer)
- {
- if (from == null)
- return false;
- final File sfrom = from;
- final File sto = to;
- if (buffer == null)
- buffer = new byte[4*4096];
- final byte[] sbuffer = buffer;
-
- Boolean b = (Boolean)AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- if (!sfrom.exists() || !sfrom.isDirectory() || sto.exists() || !sto.mkdirs())
- {
- //can't do basic stuff, returning fail from copydir method
- return new Boolean(false);
- }
- else {
- //basic stuff succeeded, incl. makind dirs, going on...
- boolean success=true;
- String[] list = sfrom.list();
-
- // Some JVMs return null for File.list() when the
- // directory is empty.
- if (list != null) {
- for (int i = 0; i < list.length; i++) {
- File entry = new File(sfrom, list[i]);
- if (entry.isDirectory())
- {
- success = copyDirectory(entry,new File(sto,list[i]),sbuffer);
- }
- else
- {
- success = copyFile(entry,new File(sto,list[i]),sbuffer);
- }
- }
- }
- return new Boolean(success);
- }
- }
- });
- if (b.booleanValue())
- {
- return true;
- }
- else return false;
- }
-
- public static boolean copyFile(File from, File to)
- {
- return copyFile(from, to, (byte[])null);
- }
-
- public static boolean copyFile(File from, File to, byte[] buf)
- {
- if (buf == null)
- buf = new byte[4096*4];
- //
- // System.out.println("Copy file ("+from+","+to+")");
- FileInputStream from_s = null;
- FileOutputStream to_s = null;
-
- try {
- from_s = new FileInputStream(from);
- to_s = new FileOutputStream(to);
-
- for (int bytesRead = from_s.read(buf);
- bytesRead != -1;
- bytesRead = from_s.read(buf))
- to_s.write(buf,0,bytesRead);
-
- from_s.close();
- from_s = null;
-
- to_s.getFD().sync();
- to_s.close();
- to_s = null;
- }
- catch (IOException ioe)
- {
- return false;
- }
- finally
- {
- if (from_s != null)
- {
- try { from_s.close(); }
- catch (IOException ioe) {}
- }
- if (to_s != null)
- {
- try { to_s.close(); }
- catch (IOException ioe) {}
- }
- }
- return true;
- }
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/PrivilegedFileOpsForTests.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/PrivilegedFileOpsForTests.java?rev=999796&r1=999795&r2=999796&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/PrivilegedFileOpsForTests.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/PrivilegedFileOpsForTests.java Wed Sep 22 08:18:14 2010
@@ -32,7 +32,8 @@ import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
-import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
/**
* A set of operations on {@link java.io.File} that wraps the
@@ -133,7 +134,7 @@ public class PrivilegedFileOpsForTests {
return ((Boolean)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
- return new Boolean(file.exists());
+ return Boolean.valueOf(file.exists());
}
})).booleanValue();
}
@@ -201,10 +202,13 @@ public class PrivilegedFileOpsForTests {
* @throws IOException
* @throws FileNotFoundException
*/
- private static void recursiveCopy(File source, File target) throws IOException, FileNotFoundException{
+ private static void recursiveCopy(File source, File target)
+ throws IOException {
+ // Share the copy buffer between all copy operations.
+ byte[] buf = new byte[32*1024];
if (source.isFile()) {
- copySingleFile(source,target);
+ copySingleFile(source, target, buf);
return;
}
@@ -219,10 +223,9 @@ public class PrivilegedFileOpsForTests {
if (entry.isDirectory()) {
copy(entry,targetEntry);
} else {
- copySingleFile(entry, targetEntry);
+ copySingleFile(entry, targetEntry, buf);
}
}
-
}
}
@@ -232,11 +235,17 @@ public class PrivilegedFileOpsForTests {
*
* @param source Source file to copy
* @param target Destination file for copy
- * @throws IOException
- * @throws FileNotFoundException
+ * @param buf buffer used for copy (may be {@code null})
+ * @throws IOException if accessing the specified files fail
+ * @throws FileNotFoundException if a specified file doesn't exist
*/
- private static void copySingleFile (File source, File target) throws IOException, FileNotFoundException {
+ private static void copySingleFile (File source, File target, byte[] buf)
+ throws IOException {
+ // Create a default buffer if necessary.
+ if (buf == null) {
+ buf = new byte[32 * 1024];
+ }
File targetParent = target.getParentFile();
if (targetParent != null && ! targetParent.exists())
target.getParentFile().mkdirs();
@@ -244,16 +253,18 @@ public class PrivilegedFileOpsForTests {
InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(target);
- byte[] buf = new byte[32 * 1024];
-
- for (;;) {
- int read = in.read(buf);
- if (read == -1)
- break;
- out.write(buf, 0, read);
+
+ try {
+ for (;;) {
+ int read = in.read(buf);
+ if (read == -1)
+ break;
+ out.write(buf, 0, read);
+ }
+ } finally {
+ in.close();
+ out.close();
}
- in.close();
- out.close();
}
@@ -301,4 +312,103 @@ public class PrivilegedFileOpsForTests {
throw (FileNotFoundException)pae.getCause();
}
}
+
+ /**
+ * Tries to delete all the files, including the specified directory, in the
+ * directory tree with the specified root.
+ * <p>
+ * If deleting one of the files fail, it will be recorded and the method
+ * will move on to the remaining files and try to delete them.
+ *
+ * @param dir the directory to delete (including subdirectories)
+ * @return A list of files which couldn't be deleted (may be empty).
+ * @see org.apache.derbyTesting.junit.BaseJDBCTestCase#assertDirectoryDeleted
+ */
+ public static File[] persistentRecursiveDelete(final File dir)
+ throws FileNotFoundException {
+ // Fail if the directory doesn't exist.
+ if (!exists(dir)) {
+ throw new FileNotFoundException(getAbsolutePath(dir));
+ }
+ final ArrayList notDeleted = new ArrayList();
+ AccessController.doPrivileged(new PrivilegedAction() {
+
+ public Object run() {
+ return Boolean.valueOf(deleteRecursively(dir, notDeleted));
+ }
+ });
+
+ File[] failedDeletes = new File[notDeleted.size()];
+ notDeleted.toArray(failedDeletes);
+ return failedDeletes;
+ }
+
+ /**
+ * Deletes the specified directory and all its files and subdirectories.
+ * <p>
+ * An attempt is made to delete all files, even if one of the delete
+ * operations fail.
+ *
+ * @param dir the root directory to start deleting from
+ * @param failedDeletes a list of failed deletes (if any)
+ * @return {@code true} is all delete operations succeeded, {@code false}
+ * otherwise.
+ */
+ private static boolean deleteRecursively(File dir, List failedDeletes) {
+ boolean allDeleted = true;
+ if (dir.isDirectory()) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (int i=0; i < files.length; i++) {
+ File f = files[i];
+ if (f.isDirectory()) {
+ allDeleted &= deleteRecursively(f, failedDeletes);
+ } else {
+ allDeleted &= internalDelete(f, failedDeletes);
+ }
+ }
+ }
+ }
+ allDeleted &= internalDelete(dir, failedDeletes);
+ return allDeleted;
+ }
+
+ /**
+ * Attempts to delete the specified file, will add it to the passed in list
+ * if the delete fails.
+ *
+ * @param f file to delete
+ * @param failedDeletes list keeping track of failed deletes
+ * @return {@code true} if the delete succeeded, {@code false} otherwise.
+ */
+ private static boolean internalDelete(File f, List failedDeletes) {
+ boolean deleted = f.delete();
+ if (!deleted) {
+ failedDeletes.add(f);
+ }
+ return deleted;
+ }
+
+ /**
+ * Obtains information about the specified file.
+ *
+ * @param f the file
+ * @return A string with file information (human-readable).
+ */
+ public static String getFileInfo(final File f) {
+ return (String)AccessController.doPrivileged(new PrivilegedAction() {
+
+ public Object run() {
+ if (!f.exists()) {
+ return "(non-existant)";
+ }
+ StringBuffer sb = new StringBuffer();
+ sb.append("(isDir=").append(f.isDirectory()).
+ append(", canRead=").append(f.canRead()).
+ append(", canWrite=").append(f.canWrite()).
+ append(", size=").append(f.length()).append(')');
+ return sb.toString();
+ }
+ });
+ }
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java?rev=999796&r1=999795&r2=999796&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseJDBCTestCase.java Wed Sep 22 08:18:14 2010
@@ -25,6 +25,8 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
@@ -41,6 +43,7 @@ import org.apache.derby.iapi.services.in
import org.apache.derby.iapi.sql.execute.RunTimeStatistics;
import org.apache.derby.impl.jdbc.EmbedConnection;
import org.apache.derby.tools.ij;
+import org.apache.derbyTesting.functionTests.util.PrivilegedFileOpsForTests;
/**
@@ -1384,7 +1387,41 @@ public abstract class BaseJDBCTestCase
conn.commit();
}
-
+
+ /**
+ * Deletes the specified directory and all its files and subdirectories.
+ * <p>
+ * This method will attempt to delete all the files inside the root
+ * directory, even if one of the delete operations fails.
+ *
+ * @param dir the root to start deleting from (root will also be deleted)
+ */
+ public static void assertDirectoryDeleted(File dir) {
+ File[] fl = null;
+ try {
+ fl = PrivilegedFileOpsForTests.persistentRecursiveDelete(dir);
+ } catch (FileNotFoundException fnfe) {
+ fail("directory doesn't exist: " +
+ PrivilegedFileOpsForTests.getAbsolutePath(dir));
+ }
+ if (fl.length == 0) {
+ return;
+ }
+
+ // If we failed to delete some of the files, list them and obtain some
+ // information about each file.
+ StringBuffer sb = new StringBuffer();
+ for (int i=0; i < fl.length; i++) {
+ File f = fl[i];
+ sb.append(PrivilegedFileOpsForTests.getAbsolutePath(f)).append(' ').
+ append(PrivilegedFileOpsForTests.getFileInfo(f)).
+ append(", ");
+ }
+ sb.deleteCharAt(sb.length() -1).deleteCharAt(sb.length() -1);
+ fail("Failed to delete " + fl.length + " files (root=" +
+ PrivilegedFileOpsForTests.getAbsolutePath(dir) + ": " +
+ sb.toString());
+ }
} // End class BaseJDBCTestCase