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