commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ozeigerm...@apache.org
Subject cvs commit: jakarta-commons-sandbox/transaction/src/test/org/apache/commons/transaction/file FileResourceManagerTest.java
Date Mon, 17 May 2004 13:26:42 GMT
ozeigermann    2004/05/17 06:26:42

  Added:       transaction/src/test/org/apache/commons/transaction/file
                        FileResourceManagerTest.java
  Log:
  Added test for FileResourceManager
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/transaction/src/test/org/apache/commons/transaction/file/FileResourceManagerTest.java
  
  Index: FileResourceManagerTest.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons-sandbox/transaction/src/test/org/apache/commons/transaction/file/FileResourceManagerTest.java,v
1.1 2004/05/17 13:26:42 ozeigermann Exp $
   * $Revision: 1.1 $
   * $Date: 2004/05/17 13:26:42 $
   *
   * ====================================================================
   *
   * Copyright 1999-2002 The Apache Software Foundation 
   *
   * 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 org.apache.commons.transaction.file;
  
  import junit.framework.*;
  
  import java.io.*;
  import java.util.*;
  import java.util.logging.*;
  
  import javax.transaction.Status;
  
  import org.apache.commons.transaction.util.FileHelper;
  import org.apache.commons.transaction.util.Jdk14Logger;
  import org.apache.commons.transaction.util.LoggerFacade;
  
  /**
   * Tests for FileResourceManager. 
   *
   * @author <a href="mailto:ozeigermann@apache.org">Oliver Zeigermann</a>
   */
  public class FileResourceManagerTest extends TestCase {
  
      private static final Logger logger = Logger.getLogger("Test");
      private static final LoggerFacade sLogger = new Jdk14Logger(logger); 
  
      private static final String STORE = "E:/tmp/rm/store";
      private static final String WORK = "E:/tmp/rm/work";
      private static final String ENCODING = "ISO-8859-15";
      private static final long BARRIER_TIMEOUT = 2000;
  
      private static final String[] INITIAL_FILES = new String[] { STORE + "/olli/Hubert6",
STORE + "/olli/Hubert" };
  
      private static final String STATUS_COMMITTING_CONTEXT =
          "E:/tmp/rm/work\nE:/tmp/rm/store\n8\n10\n2000\n1063099404687\n";
      private static final String[] STATUS_COMMITTING_CONTEXT_CHANGE_FILES =
          new String[] { "olli/Hubert40", "olli/Hubert50" };
      private static final String[] STATUS_COMMITTING_CONTEXT_DELETE_FILES = new String[]
{ "/olli/Hubert" };
      private static final String[] STATUS_COMMITTING_CONTEXT_RESULT_FILES =
          new String[] { "Hubert6", "Hubert50", "Hubert40" };
  
      private static void initCommittingRecovery() throws Throwable {
          String txId = "COMMITTING";
          createTxContextFile(txId, STATUS_COMMITTING_CONTEXT);
          createTxDeleteFiles(txId, STATUS_COMMITTING_CONTEXT_DELETE_FILES);
          createTxChangeFiles(txId, STATUS_COMMITTING_CONTEXT_CHANGE_FILES);
      }
  
      private static final String STATUS_COMMITTED_CONTEXT =
          "E:/tmp/rm/work\nE:/tmp/rm/store\n3\n10\n2000\n1063099404687\n";
      private static final String[] STATUS_COMMITTED_CONTEXT_CHANGE_FILES =
          new String[] { "olli/Hubert4", "olli/Hubert5" };
      private static final String[] STATUS_COMMITTED_CONTEXT_DELETE_FILES = new String[] {
      };
      private static final String[] STATUS_COMMITTED_CONTEXT_RESULT_FILES = new String[] {
"Hubert6", "Hubert" };
  
      private static void initCommittedRecovery() throws Throwable {
          String txId = "COMMITTED";
          createTxContextFile(txId, STATUS_COMMITTED_CONTEXT);
          createTxDeleteFiles(txId, STATUS_COMMITTED_CONTEXT_DELETE_FILES);
          createTxChangeFiles(txId, STATUS_COMMITTED_CONTEXT_CHANGE_FILES);
      }
  
      private static final String STATUS_ROLLING_BACK_CONTEXT =
          "E:/tmp/rm/work\nE:/tmp/rm/store\n9\n10\n2000\n1063099404687\n";
      private static final String[] STATUS_ROLLING_BACK_CONTEXT_CHANGE_FILES =
          new String[] { "olli/Hubert4", "olli/Hubert5" };
      private static final String[] STATUS_ROLLING_BACK_CONTEXT_DELETE_FILES = new String[]
{
      };
      private static final String[] STATUS_ROLLING_BACK_CONTEXT_RESULT_FILES = new String[]
{ "Hubert6", "Hubert" };
  
      private static void initRollingBackRecovery() throws Throwable {
          String txId = "ROLLING_BACK";
          createTxContextFile(txId, STATUS_ROLLING_BACK_CONTEXT);
          createTxDeleteFiles(txId, STATUS_ROLLING_BACK_CONTEXT_DELETE_FILES);
          createTxChangeFiles(txId, STATUS_ROLLING_BACK_CONTEXT_CHANGE_FILES);
      }
  
      private static final String STATUS_ROLLEDBACK_CONTEXT =
          "E:/tmp/rm/work\nE:/tmp/rm/store\n4\n10\n2000\n1063099404687\n";
      private static final String[] STATUS_ROLLEDBACK_CONTEXT_CHANGE_FILES =
          new String[] { "olli/Hubert4", "olli/Hubert5" };
      private static final String[] STATUS_ROLLEDBACK_CONTEXT_DELETE_FILES = new String[]
{
      };
      private static final String[] STATUS_ROLLEDBACK_CONTEXT_RESULT_FILES = new String[]
{ "Hubert6", "Hubert" };
  
      private static void initRolledBackRecovery() throws Throwable {
          String txId = "ROLLEDBACK";
          createTxContextFile(txId, STATUS_ROLLEDBACK_CONTEXT);
          createTxDeleteFiles(txId, STATUS_ROLLEDBACK_CONTEXT_DELETE_FILES);
          createTxChangeFiles(txId, STATUS_ROLLEDBACK_CONTEXT_CHANGE_FILES);
      }
  
      private static final String STATUS_ACTIVE_CONTEXT = "E:/tmp/rm/work\nE:/tmp/rm/store\n0\n10\n2000\n1063099404687\n";
      private static final String[] STATUS_ACTIVE_CONTEXT_CHANGE_FILES = new String[] { "olli/Hubert4",
"olli/Hubert5" };
      private static final String[] STATUS_ACTIVE_CONTEXT_DELETE_FILES = new String[] {
      };
      private static final String[] STATUS_ACTIVE_CONTEXT_RESULT_FILES = new String[] { "Hubert6",
"Hubert" };
  
      private static void initActiveRecovery() throws Throwable {
          String txId = "ACTIVE";
          createTxContextFile(txId, STATUS_ACTIVE_CONTEXT);
          createTxDeleteFiles(txId, STATUS_ACTIVE_CONTEXT_DELETE_FILES);
          createTxChangeFiles(txId, STATUS_ACTIVE_CONTEXT_CHANGE_FILES);
      }
  
      private static void removeRec(String dirPath) {
          FileHelper.removeRec(new File(dirPath));
      }
  
      private static final void createFiles(String[] filePaths) {
          createFiles(filePaths, null, null);
      }
  
      private static final void createFiles(String[] filePaths, String dirPath) {
          createFiles(filePaths, null, dirPath);
      }
  
      private static final void createFiles(String[] filePaths, String[] contents) {
          createFiles(filePaths, contents, null);
      }
  
      private static final void createFiles(String[] filePaths, String[] contents, String
dirPath) {
          for (int i = 0; i < filePaths.length; i++) {
              String filePath = filePaths[i];
              File file;
              if (dirPath != null) {
                  file = new File(new File(dirPath), filePath);
              } else {
                  file = new File(filePath);
              }
              file.getParentFile().mkdirs();
              try {
                  file.delete();
                  file.createNewFile();
                  String content = null;
                  if (contents != null && contents.length > i) {
                      content = contents[i];
                  }
                  if (content != null) {
                      FileOutputStream stream = new FileOutputStream(file);
                      stream.write(contents[i].getBytes(ENCODING));
                      stream.close();
                  }
              } catch (IOException e) {
              }
          }
      }
  
      private static final void deleteInDir(String dirPath, String[] fileNames) {
          File dir = new File(dirPath);
  
          if (dir.isDirectory()) {
              for (int i = 0; i < fileNames.length; i++) {
                  String fileName = fileNames[i];
                  File file = new File(dir, fileName);
                  file.delete();
              }
          }
      }
  
      private static final void checkIsEmpty(String dirPath) {
          checkExactlyContains(dirPath, null);
      }
      private static final void checkExactlyContains(String dirPath, String[] fileNames) {
          checkExactlyContains(dirPath, fileNames, null);
      }
  
      private static final void checkExactlyContains(String dirPath, String[] fileNames, String[]
contents) {
          File dir = new File(dirPath);
  
          if (dir.isDirectory()) {
              File[] files = dir.listFiles();
              if (fileNames == null) {
                  if (files.length != 0) {
                      fail(dirPath + " must be empty");
                  } else {
                      return;
                  }
              }
  
              List fileNameList = new ArrayList(Arrays.asList(fileNames));
  
              for (int i = 0; i < files.length; i++) {
                  File file = files[i];
                  String fileName = file.getName();
                  if (!fileNameList.contains(fileName)) {
                      fail(dirPath + " does not contain required " + fileName);
                  } else {
                      fileNameList.remove(fileName);
                      String content = null;
                      if (contents != null && contents.length > i) {
                          content = contents[i];
                      }
                      if (content != null && !compare(file, content)) {
                          fail(
                              "Contents of "
                                  + fileName
                                  + " in "
                                  + dirPath
                                  + " does not contain required content '"
                                  + content
                                  + "'");
                      }
                  }
              }
  
              if (fileNameList.size() != 0) {
                  StringBuffer missingFiles = new StringBuffer("Missing files: ");
                  for (Iterator it = fileNameList.iterator(); it.hasNext();) {
                      String fileName = (String) it.next();
                      missingFiles.append(fileName + (it.hasNext() ? ", " : ""));
                  }
                  fail(missingFiles.toString());
              }
  
          } else {
              fail(dirPath + " is not directoy");
          }
      }
  
      private static boolean compare(FileInputStream stream, byte[] bytes) {
          int read;
          int count = 0;
          try {
              while ((read = stream.read()) != -1) {
                  if (bytes[count++] != read) {
                      return false;
                  }
              }
          } catch (IOException e) {
              return false;
          }
          return true;
      }
  
      private static boolean compare(File file, String content) {
          FileInputStream stream = null;
          try {
              byte[] bytes = content.getBytes(ENCODING);
              stream = new FileInputStream(file);
              return compare(stream, bytes);
          } catch (Throwable t) {
              return false;
          } finally {
              if (stream != null) {
                  try {
                      stream.close();
                  } catch (IOException e) {
                  }
              }
          }
      }
  
      private static String workForTx(Object txId) {
          return WORK + "/" + txId;
      }
  
      private static String changeForTx(Object txId) {
          return workForTx(txId) + "/change";
      }
  
      private static String deleteForTx(Object txId) {
          return workForTx(txId) + "/delete";
      }
  
      private static String logForTx(Object txId) {
          return workForTx(txId) + "/transaction.log";
      }
  
      private static void reset() {
          removeRec(STORE);
          removeRec(WORK);
          new File(STORE).mkdirs();
          new File(WORK).mkdirs();
      }
  
      private static void createInitialFiles() {
          createFiles(INITIAL_FILES);
      }
  
      private static void createTxContextFile(Object txId, String content) {
          createFiles(new String[] { logForTx(txId)}, new String[] { txId + "\n" + content
});
      }
  
      private static void createTxDeleteFiles(Object txId, String[] files) {
          createFiles(files, deleteForTx(txId));
      }
  
      private static void createTxChangeFiles(Object txId, String[] files) {
          createFiles(files, changeForTx(txId));
      }
  
      // XXX need this, as JUnit seems to print only part of these strings
      private static void report(String should, String is) {
          if (!is.equals(should)) {
              fail("\nWrong output:\n'" + is + "'\nShould be:\n'" + should + "'\n");
          }
      }
  
      public static FileResourceManager createFRM() {
          return new FileResourceManager(STORE, WORK, false, sLogger, true);
      }
  
      public static Test suite() {
          TestSuite suite = new TestSuite(FileResourceManagerTest.class);
          return suite;
      }
  
      public static void main(java.lang.String[] args) {
          junit.textui.TestRunner.run(suite());
      }
  
      public FileResourceManagerTest(String testName) {
          super(testName);
      }
  
      public void testGlobal() throws Throwable {
          reset();
          createInitialFiles();
          
          final FileResourceManager rm = createFRM(); 
          
          rm.start();
  
          final RendezvousBarrier shutdownBarrier = new RendezvousBarrier("Shutdown", 3);
          final RendezvousBarrier start2Barrier = new RendezvousBarrier("Start2");
          final RendezvousBarrier commit1Barrier = new RendezvousBarrier("Commit1");
  
          final Object txId1 = "Create";
  
          Thread create = new Thread(new Runnable() {
              public void run() {
                  try {
                      rm.startTransaction(txId1);
  
                      shutdownBarrier.call();
                      start2Barrier.call();
  
                      rm.createResource(txId1, "/olli/Hubert4");
                      rm.createResource(txId1, "/olli/Hubert5");
                      String msg = "Greetings from " + txId1 + "\n";
                      OutputStream out = rm.writeResource(txId1, "/olli/Hubert6");
                      out.write(msg.getBytes(ENCODING));
  
                      commit1Barrier.meet();
  
                      checkExactlyContains(
                          changeForTx(txId1) + "/olli",
                          new String[] { "Hubert4", "Hubert5", "Hubert6" },
                          new String[] { "", "", "Greetings from " + txId1 + "\n" });
  
                      rm.commitTransaction(txId1);
  
                      checkExactlyContains(
                          STORE + "/olli",
                          new String[] { "Hubert", "Hubert4", "Hubert5", "Hubert6" },
                          new String[] { "", "", "", "Greetings from " + txId1 + "\n" });
  
                  } catch (Throwable e) {
                      System.err.println("Error: " + e);
                      e.printStackTrace();
                  }
              }
          }, "Create Thread");
  
          Thread modify = new Thread(new Runnable() {
              public void run() {
                  Object txId = null;
                  try {
  
                      {
                          InputStream in = rm.readResource("/olli/Hubert6");
                          BufferedReader reader = new BufferedReader(new InputStreamReader(in,
ENCODING));
                          String line = reader.readLine();
                          assertEquals(line, null);
                          in.close();
                      }
  
                      txId = "Modify";
                      rm.startTransaction(txId);
                      rm.setIsolationLevel(txId, ResourceManager.ISOLATION_LEVEL_READ_COMMITTED);
  
                      {
                          InputStream in = rm.readResource(txId, "/olli/Hubert6");
                          BufferedReader reader = new BufferedReader(new InputStreamReader(in,
ENCODING));
                          String line = reader.readLine();
                          assertEquals(line, null);
                          in.close();
                      }
  
                      shutdownBarrier.call();
  
                      rm.createResource(txId, "/olli/Hubert1");
                      rm.createResource(txId, "/olli/Hubert2");
                      rm.createResource(txId, "/olli/Hubert3");
  
                      // wait until tx commits, so there already are Hubert4 and Hubert5 and
                      // Hubert6 changes 
                      commit1Barrier.meet();
  
                      rm.createResource(txId, "/olli/Hubert4");
                      rm.createResource(txId, "/olli/Hubert5");
  
                      rm.createResource(txId, "/olli/Hubert6");
                      InputStream in = rm.readResource(txId, "/olli/Hubert6");
                      BufferedReader reader = new BufferedReader(new InputStreamReader(in,
ENCODING));
                      String line = reader.readLine();
                      // allow for update while in tx as this is READ_COMMITED
                      report("Greetings from " + txId1, line);
                      in.close();
  
                      rm.deleteResource(txId, "/olli/Hubert");
                      rm.deleteResource(txId, "/olli/Hubert2");
                      rm.deleteResource(txId, "/olli/Hubert3");
                      rm.deleteResource(txId, "/olli/Hubert4");
                      rm.deleteResource(txId, "/olli/Hubert5");
  
                      checkExactlyContains(deleteForTx(txId) + "/olli", new String[] { "Hubert",
"Hubert4", "Hubert5" });
  
                      checkExactlyContains(changeForTx(txId) + "/olli", new String[] { "Hubert1"
});
  
                      rm.commitTransaction(txId);
                  } catch (Throwable e) {
                      System.err.println("Error: " + e);
                      e.printStackTrace();
                  }
              }
          }, "Modify Thread");
  
          create.start();
          // be sure first thread is started before trying next
          start2Barrier.meet();
          modify.start();
  
          // let both transaction start before trying to shut down
          shutdownBarrier.meet();
  
          assertTrue(rm.stop(ResourceManager.SHUTDOWN_MODE_NORMAL, 5000));
  
          checkExactlyContains(
              STORE + "/olli",
              new String[] { "Hubert1", "Hubert6" },
              new String[] { "", "Greetings from " + txId1 + "\n" });
          checkIsEmpty(WORK);
      }
  
      public void testCombinedRecovery() throws Throwable {
          reset();
          createInitialFiles();
          initCommittingRecovery();
          initCommittedRecovery();
          initActiveRecovery();
          initRolledBackRecovery();
          initRollingBackRecovery();
  
          FileResourceManager rm =createFRM();
  
          // do nothing, just start and stop to check recovery of tx
          rm.start();
          assertTrue(rm.stop(ResourceManager.SHUTDOWN_MODE_NORMAL, 5000));
  
          // all but committing should be rolled back
          checkExactlyContains(STORE + "/olli", STATUS_COMMITTING_CONTEXT_RESULT_FILES);
          checkIsEmpty(WORK);
      }
  
      public void testCommittingRecovery() throws Throwable {
          reset();
          createInitialFiles();
          initCommittingRecovery();
  
          FileResourceManager rm = createFRM();
  
          // do nothing, just start and stop to check recovery of tx
          rm.start();
          assertTrue(rm.stop(ResourceManager.SHUTDOWN_MODE_NORMAL, 5000));
  
          checkExactlyContains(STORE + "/olli", STATUS_COMMITTING_CONTEXT_RESULT_FILES);
          checkIsEmpty(WORK);
      }
  
      public void testActiveRecovery() throws Throwable {
          reset();
          createInitialFiles();
          initActiveRecovery();
  
          FileResourceManager rm = createFRM();
  
          // do nothing, just start and stop to check recovery of tx
          rm.start();
          assertTrue(rm.stop(ResourceManager.SHUTDOWN_MODE_NORMAL, 5000));
  
          checkExactlyContains(STORE + "/olli", STATUS_ACTIVE_CONTEXT_RESULT_FILES);
          checkIsEmpty(WORK);
      }
  
      public void testRolledbackRecovery() throws Throwable {
          reset();
          createInitialFiles();
          initRolledBackRecovery();
  
          FileResourceManager rm = createFRM();
  
          // do nothing, just start and stop to check recovery of tx
          rm.start();
          assertTrue(rm.stop(ResourceManager.SHUTDOWN_MODE_NORMAL, 5000));
  
          checkExactlyContains(STORE + "/olli", STATUS_ROLLEDBACK_CONTEXT_RESULT_FILES);
          checkIsEmpty(WORK);
      }
  
      public void testRollingBackRecovery() throws Throwable {
          reset();
          createInitialFiles();
          initRollingBackRecovery();
  
          FileResourceManager rm = createFRM();
  
          // do nothing, just start and stop to check recovery of tx
          rm.start();
          assertTrue(rm.stop(ResourceManager.SHUTDOWN_MODE_NORMAL, 5000));
  
          checkExactlyContains(STORE + "/olli", STATUS_ROLLING_BACK_CONTEXT_RESULT_FILES);
          checkIsEmpty(WORK);
      }
  
      public void testCommittedRecovery() throws Throwable {
          reset();
          createInitialFiles();
          initCommittedRecovery();
  
          FileResourceManager rm = createFRM();
  
          // do nothing, just start and stop to check recovery of tx
          rm.start();
          assertTrue(rm.stop(ResourceManager.SHUTDOWN_MODE_NORMAL, 5000));
  
          checkExactlyContains(STORE + "/olli", STATUS_COMMITTED_CONTEXT_RESULT_FILES);
          checkIsEmpty(WORK);
      }
  
      public void testInteractiveDirtyRecovery() throws Throwable {
          reset();
          createInitialFiles();
  
          FileResourceManager rm = createFRM();
  
          rm.start();
  
          String txId = "DIRTY";
          rm.startTransaction(txId);
          rm.createResource(txId, "/olli/Hubert100");
  
          // fake a failed commit
          FileResourceManager.TransactionContext context = rm.getContext(txId);
          // needing synchronization in order not to interfer with shutdown thread
          synchronized (context) {
              logger.fine("Committing Tx " + txId);
  
              context.status = Status.STATUS_COMMITTING;
              context.saveState();
              rm.dirty = true;
              context.finalCleanUp();
              context.notifyFinish();
          }
  
          // should be allowed
          rm.readResource(txId, "/olli/Hubert");
  
          // should be disallowed
          boolean writeDeniedByDirty = false;
          try {
              rm.createResource(txId, "/olli/Hubert10");
          } catch (ResourceManagerSystemException rmse) {
              writeDeniedByDirty = true;
          }
          assertTrue(writeDeniedByDirty);
  
          // on success (expected) resets dirty flag
          rm.recover();
  
          // should all be allowed again
          txId = "DIRTYTEST";
          rm.startTransaction(txId);
          rm.readResource(txId, "/olli/Hubert");
          rm.createResource(txId, "/olli/Hubert10");
          rm.commitTransaction(txId);
  
          assertTrue(rm.stop(ResourceManager.SHUTDOWN_MODE_NORMAL, 5000));
  
          // tx rolled forward created "/olli/Hubert100", so it should be here as well
          checkExactlyContains(STORE + "/olli", new String[] { "Hubert", "Hubert100", "Hubert6",
"Hubert10" });
          checkIsEmpty(WORK);
      }
  
      public static class RendezvousBarrier {
  
          private final int parties;
          private final String name;
          private int count = 0;
          private long timeout;
  
          public RendezvousBarrier(String name) {
              this(name, 2);
          }
  
          public RendezvousBarrier(String name, int parties) {
              this(name, parties, BARRIER_TIMEOUT);
          }
  
          public RendezvousBarrier(String name, int parties, long timeout) {
              this.parties = parties;
              this.name = name;
              this.timeout = timeout;
          }
  
          public synchronized void call() throws InterruptedException {
              count++;
              if (count >= parties) {
                  logger.fine("Thread " + Thread.currentThread().getName() + " by CALL COMLETING
barrier " + name);
                  notifyAll();
              }
          }
  
          public synchronized void meet() throws InterruptedException {
              count++;
              if (count >= parties) {
                  logger.fine("Thread " + Thread.currentThread().getName() + " by MEET COMLETING
barrier " + name);
                  notifyAll();
              } else {
                  logger.fine(
                      "At barrier "
                          + name
                          + " thread "
                          + Thread.currentThread().getName()
                          + " WAITING for "
                          + (parties - count)
                          + " of "
                          + parties
                          + " parties");
                  wait(timeout);
                  if (count >= parties) {
                      logger.fine("Thread " + Thread.currentThread().getName() + " CONTINUING
at barrier " + name);
                  } else {
                      logger.fine("Thread " + Thread.currentThread().getName() + " FAILING
at barrier " + name);
                      notifyAll();
                  }
              }
          }
  
          public synchronized void reset() {
              count = 0;
              notifyAll();
          }
  
      }
      
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message