[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] [metrics-db/master] Add unit tests and refactor some classes to make them easier to test.



commit ec3956b3b98a043f469c0a1abf560af6d2138179
Author: Karsten Loesing <karsten.loesing@xxxxxxx>
Date:   Fri Jan 28 16:12:46 2011 +0100

    Add unit tests and refactor some classes to make them easier to test.
---
 build.xml                                          |   51 ++++++++++---------
 lib/junit-4.8.2.jar                                |  Bin 0 -> 237344 bytes
 src/org/torproject/ernie/db/ArchiveReader.java     |   26 ++++++----
 src/org/torproject/ernie/db/ArchiveWriter.java     |   18 +++++--
 .../torproject/ernie/db/BridgeSnapshotReader.java  |   12 ++++-
 .../ernie/db/CachedRelayDescriptorReader.java      |   11 ++++-
 src/org/torproject/ernie/db/Main.java              |   28 +++++++----
 .../ernie/db/SanitizedBridgesReader.java           |   13 ++++--
 .../ernie/db/SanitizedBridgesWriter.java           |   40 +++++++++++-----
 src/org/torproject/ernie/db/TorperfProcessor.java  |   17 ++++--
 .../torproject/ernie/test/ArchiveReaderTest.java   |   33 +++++++++++++
 .../torproject/ernie/test/ArchiveWriterTest.java   |   30 ++++++++++++
 .../ernie/test/BridgeSnapshotReaderTest.java       |   33 +++++++++++++
 .../test/CachedRelayDescriptorReaderTest.java      |   32 ++++++++++++
 .../ernie/test/SanitizedBridgesReaderTest.java     |   33 +++++++++++++
 .../ernie/test/SanitizedBridgesWriterTest.java     |   38 +++++++++++++++
 .../ernie/test/TorperfProcessorTest.java           |   37 ++++++++++++++
 17 files changed, 377 insertions(+), 75 deletions(-)

diff --git a/build.xml b/build.xml
index 187787d..678a088 100644
--- a/build.xml
+++ b/build.xml
@@ -1,25 +1,15 @@
 <project default="run" name="ERNIE" basedir=".">
-  <!-- ERNIE specific build properties -->
   <property name="sources" value="src/"/>
   <property name="classes" value="bin/"/>
   <property name="docs" value="javadoc/"/>
   <property name="name" value="ERNIE"/>
-
-<!-- Usage target -->
-  <target name="usage">
-    <echo message=""/>
-    <echo message="${name} build file"/>
-    <echo message="-----------------------------------"/>
-    <echo message=""/>
-
-    <echo message="init      --> Initialize ERNIE directories"/>
-    <echo message="compile   --> Compile ERNIE"/>
-    <echo message="run       --> Run ERNIE"/>
-    <echo message="docs      --> Generate ERNIE javadoc tree to javadoc/"/>
-    <echo message=""/>
-  </target>
-
-<!--ERNIE-specific targets -->
+  <path id="classpath">
+    <pathelement path="${classes}"/>
+    <pathelement location="lib/commons-codec-1.4.jar"/>
+    <pathelement location="lib/commons-compress-1.0.jar"/>
+    <pathelement location="lib/postgresql-8.4-701.jdbc4.jar"/>
+    <pathelement location="lib/junit-4.8.2.jar"/>
+  </path>
   <target name="init">
     <mkdir dir="${classes}"/>
     <copy file="config.template" tofile="config"/>
@@ -29,20 +19,33 @@
            destdir="${classes}"
            excludes="org/torproject/ernie/web/"
            debug="true" debuglevel="lines,source"
-           classpath="lib/commons-codec-1.4.jar;lib/commons-compress-1.0.jar;lib/postgresql-8.4-701.jdbc4.jar"
-           includeantruntime="false"/>
+           includeantruntime="false">
+      <classpath refid="classpath"/>
+    </javac>
   </target>
   <target name="run" depends="compile">
-    <java classpath="${classes};lib/commons-codec-1.4.jar:lib/commons-compress-1.0.jar;lib/postgresql-8.4-701.jdbc4.jar"
-          fork="true"
+    <java fork="true"
           maxmemory="1024m"
-          classname="org.torproject.ernie.db.Main"/>
+          classname="org.torproject.ernie.db.Main">
+      <classpath refid="classpath"/>
+    </java>
   </target>
   <target name="docs">
     <mkdir dir="${docs}"/>
-    <javadoc destdir="${docs}"
-             classpath="lib/commons-codec-1.4.jar;lib/commons-compress-1.0.jar">
+    <javadoc destdir="${docs}">
+      <classpath refid="classpath"/>
       <fileset dir="${sources}/" includes="**/*.java" />
     </javadoc>
   </target>
+  <target name="test" depends="compile">
+    <junit haltonfailure="true" printsummary="off">
+      <classpath refid="classpath"/>
+      <formatter type="plain" usefile="false"/>
+      <batchtest>
+        <fileset dir="${classes}"
+                 includes="**/*Test.class"/>
+      </batchtest>
+    </junit>
+  </target>
 </project>
+
diff --git a/lib/junit-4.8.2.jar b/lib/junit-4.8.2.jar
new file mode 100644
index 0000000..5b4bb84
Binary files /dev/null and b/lib/junit-4.8.2.jar differ
diff --git a/src/org/torproject/ernie/db/ArchiveReader.java b/src/org/torproject/ernie/db/ArchiveReader.java
index 10721b4..edf04c3 100644
--- a/src/org/torproject/ernie/db/ArchiveReader.java
+++ b/src/org/torproject/ernie/db/ArchiveReader.java
@@ -12,13 +12,19 @@ import org.apache.commons.compress.compressors.bzip2.*;
  * them to the relay descriptor parser.
  */
 public class ArchiveReader {
-  public ArchiveReader(RelayDescriptorParser rdp, String archivesDir,
-      boolean keepImportHistory) {
+  public ArchiveReader(RelayDescriptorParser rdp, File archivesDirectory,
+      File statsDirectory, boolean keepImportHistory) {
+
+    if (rdp == null || archivesDirectory == null ||
+        statsDirectory == null) {
+      throw new IllegalArgumentException();
+    }
+
     int parsedFiles = 0, ignoredFiles = 0;
     Logger logger = Logger.getLogger(ArchiveReader.class.getName());
     SortedSet<String> archivesImportHistory = new TreeSet<String>();
-    File archivesImportHistoryFile =
-        new File("stats/archives-import-history");
+    File archivesImportHistoryFile = new File(statsDirectory,
+        "archives-import-history");
     if (keepImportHistory && archivesImportHistoryFile.exists()) {
       try {
         BufferedReader br = new BufferedReader(new FileReader(
@@ -33,11 +39,11 @@ public class ArchiveReader {
             + "history file. Skipping.");
       }
     }
-    if (new File(archivesDir).exists()) {
-      logger.fine("Importing files in directory " + archivesDir
+    if (archivesDirectory.exists()) {
+      logger.fine("Importing files in directory " + archivesDirectory
           + "/...");
       Stack<File> filesInInputDir = new Stack<File>();
-      filesInInputDir.add(new File(archivesDir));
+      filesInInputDir.add(archivesDirectory);
       List<File> problems = new ArrayList<File>();
       while (!filesInInputDir.isEmpty()) {
         File pop = filesInInputDir.pop();
@@ -89,11 +95,11 @@ public class ArchiveReader {
         }
       }
       if (problems.isEmpty()) {
-        logger.fine("Finished importing files in directory " + archivesDir
-            + "/.");
+        logger.fine("Finished importing files in directory "
+            + archivesDirectory + "/.");
       } else {
         StringBuilder sb = new StringBuilder("Failed importing files in "
-            + "directory " + archivesDir + "/:");
+            + "directory " + archivesDirectory + "/:");
         int printed = 0;
         for (File f : problems) {
           sb.append("\n  " + f.getAbsolutePath());
diff --git a/src/org/torproject/ernie/db/ArchiveWriter.java b/src/org/torproject/ernie/db/ArchiveWriter.java
index afafdfe..68cdbaa 100644
--- a/src/org/torproject/ernie/db/ArchiveWriter.java
+++ b/src/org/torproject/ernie/db/ArchiveWriter.java
@@ -11,11 +11,16 @@ import org.apache.commons.codec.binary.*;
 
 public class ArchiveWriter {
   private Logger logger;
-  private String outputDirectory;
+  private File outputDirectory;
   private int storedConsensuses = 0, storedVotes = 0,
       storedServerDescriptors = 0, storedExtraInfoDescriptors = 0;
 
-  public ArchiveWriter(String outputDirectory) {
+  public ArchiveWriter(File outputDirectory) {
+
+    if (outputDirectory == null) {
+      throw new IllegalArgumentException();
+    }
+
     this.logger = Logger.getLogger(ArchiveWriter.class.getName());
     this.outputDirectory = outputDirectory;
   }
@@ -192,7 +197,8 @@ public class ArchiveWriter {
                         String extraInfoDigest = line2.startsWith("opt ") ?
                             line2.split(" ")[2].toLowerCase() :
                             line2.split(" ")[1].toLowerCase();
-                        String filename2 = outputDirectory
+                        String filename2 =
+                            outputDirectory.getAbsolutePath()
                             + "/extra-info/"
                             + descriptorFormat.format(new Date(published))
                             + extraInfoDigest.substring(0, 1) + "/"
@@ -224,7 +230,8 @@ public class ArchiveWriter {
                 line.split(" ")[3] + "=")).toLowerCase();
             long published = validAfterFormat.parse(
                 line.split(" ")[4] + " " + line.split(" ")[5]).getTime();
-            String filename = outputDirectory + "/server-descriptor/"
+            String filename = outputDirectory.getAbsolutePath()
+                + "/server-descriptor/"
                 + descriptorFormat.format(new Date(published))
                 + digest.substring(0, 1) + "/"
                 + digest.substring(1, 2) + "/" + digest;
@@ -239,7 +246,8 @@ public class ArchiveWriter {
                   String extraInfoDigest = line2.startsWith("opt ") ?
                       line2.split(" ")[2].toLowerCase() :
                       line2.split(" ")[1].toLowerCase();
-                  String filename2 = outputDirectory + "/extra-info/"
+                  String filename2 = outputDirectory.getAbsolutePath()
+                      + "/extra-info/"
                       + descriptorFormat.format(new Date(published))
                       + extraInfoDigest.substring(0, 1) + "/"
                       + extraInfoDigest.substring(1, 2) + "/"
diff --git a/src/org/torproject/ernie/db/BridgeSnapshotReader.java b/src/org/torproject/ernie/db/BridgeSnapshotReader.java
index 28ece2a..13ab58d 100644
--- a/src/org/torproject/ernie/db/BridgeSnapshotReader.java
+++ b/src/org/torproject/ernie/db/BridgeSnapshotReader.java
@@ -17,12 +17,18 @@ import org.apache.commons.compress.archivers.tar.*;
  */
 public class BridgeSnapshotReader {
   public BridgeSnapshotReader(BridgeDescriptorParser bdp,
-      String bridgeDirectoriesDir) {
+      File bridgeDirectoriesDir, File statsDirectory) {
+
+    if (bdp == null || bridgeDirectoriesDir == null ||
+        statsDirectory == null) {
+      throw new IllegalArgumentException();
+    }
+
     Logger logger =
         Logger.getLogger(BridgeSnapshotReader.class.getName());
     SortedSet<String> parsed = new TreeSet<String>();
-    File bdDir = new File(bridgeDirectoriesDir);
-    File pbdFile = new File("stats/parsed-bridge-directories");
+    File bdDir = bridgeDirectoriesDir;
+    File pbdFile = new File(statsDirectory, "parsed-bridge-directories");
     boolean modified = false;
     if (bdDir.exists()) {
       if (pbdFile.exists()) {
diff --git a/src/org/torproject/ernie/db/CachedRelayDescriptorReader.java b/src/org/torproject/ernie/db/CachedRelayDescriptorReader.java
index 098038b..29390b7 100644
--- a/src/org/torproject/ernie/db/CachedRelayDescriptorReader.java
+++ b/src/org/torproject/ernie/db/CachedRelayDescriptorReader.java
@@ -16,7 +16,13 @@ import org.apache.commons.codec.digest.*;
  */
 public class CachedRelayDescriptorReader {
   public CachedRelayDescriptorReader(RelayDescriptorParser rdp,
-      List<String> inputDirectories) {
+      List<String> inputDirectories, File statsDirectory) {
+
+    if (rdp == null || inputDirectories == null ||
+        inputDirectories.isEmpty() || statsDirectory == null) {
+      throw new IllegalArgumentException();
+    }
+
     StringBuilder dumpStats = new StringBuilder("Finished importing "
         + "relay descriptors from local Tor data directories:");
     Logger logger = Logger.getLogger(
@@ -26,7 +32,8 @@ public class CachedRelayDescriptorReader {
      * statuses and descriptors, so that we can skip them in this run. */
     Set<String> lastImportHistory = new HashSet<String>(),
         currentImportHistory = new HashSet<String>();
-    File importHistoryFile = new File("stats/cacheddesc-import-history");
+    File importHistoryFile = new File(statsDirectory,
+        "cacheddesc-import-history");
     if (importHistoryFile.exists()) {
       try {
         BufferedReader br = new BufferedReader(new FileReader(
diff --git a/src/org/torproject/ernie/db/Main.java b/src/org/torproject/ernie/db/Main.java
index ab214f2..e3d04b1 100644
--- a/src/org/torproject/ernie/db/Main.java
+++ b/src/org/torproject/ernie/db/Main.java
@@ -2,6 +2,7 @@
  * See LICENSE for licensing information */
 package org.torproject.ernie.db;
 
+import java.io.*;
 import java.util.*;
 import java.util.logging.*;
 
@@ -29,6 +30,9 @@ public class Main {
       System.exit(1);
     }
 
+    // Define stats directory for temporary files
+    File statsDirectory = new File("stats");
+
     // Prepare bridge stats file handler
     BridgeStatsFileHandler bsfh = config.getWriteBridgeStats() ?
         new BridgeStatsFileHandler(
@@ -41,8 +45,8 @@ public class Main {
 
     // Prepare writing relay descriptor archive to disk
     ArchiveWriter aw = config.getWriteDirectoryArchives() ?
-        new ArchiveWriter(config.getDirectoryArchivesOutputDirectory())
-        : null;
+        new ArchiveWriter(
+        new File(config.getDirectoryArchivesOutputDirectory())) : null;
 
     // Prepare writing relay descriptors to database
     RelayDescriptorDatabaseImporter rddi =
@@ -82,14 +86,16 @@ public class Main {
       }
       if (config.getImportCachedRelayDescriptors()) {
         new CachedRelayDescriptorReader(rdp,
-            config.getCachedRelayDescriptorDirectory());
+            config.getCachedRelayDescriptorDirectory(), statsDirectory);
         if (aw != null) {
           aw.intermediateStats("importing relay descriptors from local "
               + "Tor data directories");
         }
       }
       if (config.getImportDirectoryArchives()) {
-        new ArchiveReader(rdp, config.getDirectoryArchivesDirectory(),
+        new ArchiveReader(rdp,
+            new File(config.getDirectoryArchivesDirectory()),
+            statsDirectory,
             config.getKeepDirectoryArchiveImportHistory());
         if (aw != null) {
           aw.intermediateStats("importing relay descriptors from local "
@@ -131,7 +137,8 @@ public class Main {
     // Prepare sanitized bridge descriptor writer
     SanitizedBridgesWriter sbw = config.getWriteSanitizedBridges() ?
         new SanitizedBridgesWriter(
-        config.getSanitizedBridgesWriteDirectory()) : null;
+        new File(config.getSanitizedBridgesWriteDirectory()),
+        statsDirectory) : null;
 
     // Prepare bridge descriptor parser
     BridgeDescriptorParser bdp = config.getWriteConsensusStats() ||
@@ -141,11 +148,13 @@ public class Main {
     // Import bridge descriptors
     if (bdp != null && config.getImportSanitizedBridges()) {
       new SanitizedBridgesReader(bdp,
-          config.getSanitizedBridgesDirectory(),
-          config.getKeepSanitizedBridgesImportHistory());
+          new File(config.getSanitizedBridgesDirectory()),
+          statsDirectory, config.getKeepSanitizedBridgesImportHistory());
     }
     if (bdp != null && config.getImportBridgeSnapshots()) {
-      new BridgeSnapshotReader(bdp, config.getBridgeSnapshotsDirectory());
+      new BridgeSnapshotReader(bdp,
+          new File(config.getBridgeSnapshotsDirectory()),
+          statsDirectory);
     }
 
     // Finish writing sanitized bridge descriptors to disk
@@ -166,7 +175,8 @@ public class Main {
 
     // Import and process torperf stats
     if (config.getImportWriteTorperfStats()) {
-      new TorperfProcessor(config.getTorperfDirectory(),
+      new TorperfProcessor(new File(config.getTorperfDirectory()),
+          statsDirectory,
           config.getWriteAggregateStatsDatabase() ?
           config.getRelayDescriptorDatabaseJDBC() : null);
     }
diff --git a/src/org/torproject/ernie/db/SanitizedBridgesReader.java b/src/org/torproject/ernie/db/SanitizedBridgesReader.java
index efca2c1..2ddf1dd 100644
--- a/src/org/torproject/ernie/db/SanitizedBridgesReader.java
+++ b/src/org/torproject/ernie/db/SanitizedBridgesReader.java
@@ -8,12 +8,17 @@ import java.util.logging.*;
 
 public class SanitizedBridgesReader {
   public SanitizedBridgesReader(BridgeDescriptorParser bdp,
-      String bridgesDir, boolean keepImportHistory) {
+      File bridgesDir, File statsDirectory, boolean keepImportHistory) {
+
+    if (bdp == null || bridgesDir == null || statsDirectory == null) {
+      throw new IllegalArgumentException();
+    }
+
     Logger logger =
         Logger.getLogger(SanitizedBridgesReader.class.getName());
     SortedSet<String> bridgesImportHistory = new TreeSet<String>();
     File bridgesImportHistoryFile =
-        new File("stats/bridges-import-history");
+        new File(statsDirectory, "bridges-import-history");
     if (keepImportHistory && bridgesImportHistoryFile.exists()) {
       try {
         BufferedReader br = new BufferedReader(new FileReader(
@@ -28,10 +33,10 @@ public class SanitizedBridgesReader {
             + "import history file. Skipping.");
       }
     }
-    if (new File(bridgesDir).exists()) {
+    if (bridgesDir.exists()) {
       logger.fine("Importing files in directory " + bridgesDir + "/...");
       Stack<File> filesInInputDir = new Stack<File>();
-      filesInInputDir.add(new File(bridgesDir));
+      filesInInputDir.add(bridgesDir);
       List<File> problems = new ArrayList<File>();
       while (!filesInInputDir.isEmpty()) {
         File pop = filesInInputDir.pop();
diff --git a/src/org/torproject/ernie/db/SanitizedBridgesWriter.java b/src/org/torproject/ernie/db/SanitizedBridgesWriter.java
index 0b504a9..dc5d0dc 100644
--- a/src/org/torproject/ernie/db/SanitizedBridgesWriter.java
+++ b/src/org/torproject/ernie/db/SanitizedBridgesWriter.java
@@ -161,16 +161,24 @@ public class SanitizedBridgesWriter {
   /**
    * Output directory for writing sanitized bridge descriptors.
    */
-  private String sanitizedBridgesDir;
+  private File sanitizedBridgesDirectory;
+
+  private File statsDirectory;
 
   /**
    * Initializes this class, including reading in the known descriptor
    * mapping.
    */
-  public SanitizedBridgesWriter(String dir) {
+  public SanitizedBridgesWriter(File sanitizedBridgesDirectory,
+      File statsDirectory) {
+
+    if (sanitizedBridgesDirectory == null || statsDirectory == null) {
+      throw new IllegalArgumentException();
+    }
 
     /* Memorize argument values. */
-    this.sanitizedBridgesDir = dir;
+    this.sanitizedBridgesDirectory = sanitizedBridgesDirectory;
+    this.statsDirectory = statsDirectory;
 
     /* Initialize logger. */
     this.logger = Logger.getLogger(
@@ -307,7 +315,8 @@ public class SanitizedBridgesWriter {
       String stime = publicationTime.substring(11, 13)
           + publicationTime.substring(14, 16)
           + publicationTime.substring(17, 19);
-      File statusFile = new File(this.sanitizedBridgesDir + "/" + syear
+      File statusFile = new File(
+          this.sanitizedBridgesDirectory.getAbsolutePath() + "/" + syear
           + "/" + smonth + "/statuses/" + sday + "/" + syear + smonth
           + sday + "-" + stime + "-"
           + "4A0CCD2DDC7995083D73F5D667100C8A5831F16D");
@@ -496,7 +505,8 @@ public class SanitizedBridgesWriter {
     /* Determine filename of sanitized server descriptor. */
     String dyear = mapping.published.substring(0, 4);
     String dmonth = mapping.published.substring(5, 7);
-    File newFile = new File(this.sanitizedBridgesDir + "/"
+    File newFile = new File(
+        this.sanitizedBridgesDirectory.getAbsolutePath() + "/"
         + dyear + "/" + dmonth + "/server-descriptors/"
         + "/" + scrubbedHash.charAt(0) + "/"
         + scrubbedHash.charAt(1) + "/"
@@ -627,7 +637,8 @@ public class SanitizedBridgesWriter {
     /* Determine filename of sanitized server descriptor. */
     String dyear = mapping.published.substring(0, 4);
     String dmonth = mapping.published.substring(5, 7);
-    File newFile = new File(this.sanitizedBridgesDir + "/"
+    File newFile = new File(
+        this.sanitizedBridgesDirectory.getAbsolutePath() + "/"
         + dyear + "/" + dmonth + "/extra-infos/"
         + scrubbedDescHash.charAt(0) + "/"
         + scrubbedDescHash.charAt(1) + "/"
@@ -708,7 +719,8 @@ public class SanitizedBridgesWriter {
       String stime = published.substring(11, 13)
           + published.substring(14, 16)
           + published.substring(17, 19);
-      File statusFile = new File(this.sanitizedBridgesDir + "/" + syear
+      File statusFile = new File(
+          this.sanitizedBridgesDirectory.getAbsolutePath() + "/" + syear
           + "/" + smonth + "/statuses/" + sday + "/" + syear + smonth
           + sday + "-" + stime + "-"
           + "4A0CCD2DDC7995083D73F5D667100C8A5831F16D");
@@ -775,7 +787,8 @@ public class SanitizedBridgesWriter {
       mapping.serverDescriptorIdentifier = scrubbedHash;
       String dyear = published.substring(0, 4);
       String dmonth = published.substring(5, 7);
-      File newFile = new File(this.sanitizedBridgesDir + "/"
+      File newFile = new File(
+          this.sanitizedBridgesDirectory.getAbsolutePath() + "/"
           + dyear + "/" + dmonth + "/server-descriptors/"
           + scrubbedHash.substring(0, 1) + "/"
           + scrubbedHash.substring(1, 2) + "/"
@@ -832,7 +845,8 @@ public class SanitizedBridgesWriter {
       mapping.extraInfoDescriptorIdentifier = scrubbedHash;
       String dyear = published.substring(0, 4);
       String dmonth = published.substring(5, 7);
-      File newFile = new File(this.sanitizedBridgesDir + "/"
+      File newFile = new File(
+          this.sanitizedBridgesDirectory.getAbsolutePath() + "/"
           + dyear + "/" + dmonth + "/extra-infos/"
           + scrubbedHash.substring(0, 1) + "/"
           + scrubbedHash.substring(1, 2) + "/"
@@ -874,7 +888,7 @@ public class SanitizedBridgesWriter {
       String dyear = mapping.published.substring(0, 4);
       String dmonth = mapping.published.substring(5, 7);
       File serverDescriptorFile = new File(
-          this.sanitizedBridgesDir + "/"
+          this.sanitizedBridgesDirectory.getAbsolutePath() + "/"
           + dyear + "/" + dmonth + "/server-descriptors/"
           + mapping.serverDescriptorIdentifier.substring(0, 1) + "/"
           + mapping.serverDescriptorIdentifier.substring(1, 2) + "/"
@@ -942,7 +956,8 @@ public class SanitizedBridgesWriter {
       }
       String[] dayOne = dateFormat.format(publishedTime).split("-");
 
-      File publishedDayOne = new File(this.sanitizedBridgesDir + "/"
+      File publishedDayOne = new File(
+          this.sanitizedBridgesDirectory.getAbsolutePath() + "/"
           + dayOne[0] + "/" + dayOne[1] + "/statuses/" + dayOne[2]);
       if (publishedDayOne.exists()) {
         statusesToRewrite.addAll(Arrays.asList(publishedDayOne.
@@ -951,7 +966,8 @@ public class SanitizedBridgesWriter {
       long plus24Hours = publishedTime + 24L * 60L * 60L * 1000L;
       lastDescriptorPublishedPlus24Hours = dateFormat.format(plus24Hours);
       String[] dayTwo = dateFormat.format(plus24Hours).split("-");
-      File publishedDayTwo = new File(this.sanitizedBridgesDir + "/"
+      File publishedDayTwo = new File(
+          this.sanitizedBridgesDirectory.getAbsolutePath() + "/"
           + dayTwo[0] + "/" + dayTwo[1] + "/statuses/" + dayTwo[2]);
       if (publishedDayTwo.exists()) {
         statusesToRewrite.addAll(Arrays.asList(publishedDayTwo.
diff --git a/src/org/torproject/ernie/db/TorperfProcessor.java b/src/org/torproject/ernie/db/TorperfProcessor.java
index b27f702..d6d2e53 100644
--- a/src/org/torproject/ernie/db/TorperfProcessor.java
+++ b/src/org/torproject/ernie/db/TorperfProcessor.java
@@ -9,11 +9,16 @@ import java.util.*;
 import java.util.logging.*;
 
 public class TorperfProcessor {
-  public TorperfProcessor(String torperfDirectory, String connectionURL) {
+  public TorperfProcessor(File torperfDirectory, File statsDirectory,
+      String connectionURL) {
+
+    if (torperfDirectory == null || statsDirectory == null) {
+      throw new IllegalArgumentException();
+    }
+
     Logger logger = Logger.getLogger(TorperfProcessor.class.getName());
-    File rawFile = new File("stats/torperf-raw");
-    File statsFile = new File("stats/torperf-stats");
-    File torperfDir = new File(torperfDirectory);
+    File rawFile = new File(statsDirectory, "torperf-raw");
+    File statsFile = new File(statsDirectory, "torperf-stats");
     SortedMap<String, String> rawObs = new TreeMap<String, String>();
     SortedMap<String, String> stats = new TreeMap<String, String>();
     int addedRawObs = 0;
@@ -48,10 +53,10 @@ public class TorperfProcessor {
         logger.fine("Finished reading file " + statsFile.getAbsolutePath()
             + ".");
       }
-      if (torperfDir.exists()) {
+      if (torperfDirectory.exists()) {
         logger.fine("Importing files in " + torperfDirectory + "/...");
         Stack<File> filesInInputDir = new Stack<File>();
-        filesInInputDir.add(torperfDir);
+        filesInInputDir.add(torperfDirectory);
         while (!filesInInputDir.isEmpty()) {
           File pop = filesInInputDir.pop();
           if (pop.isDirectory()) {
diff --git a/src/org/torproject/ernie/test/ArchiveReaderTest.java b/src/org/torproject/ernie/test/ArchiveReaderTest.java
new file mode 100644
index 0000000..4099ee3
--- /dev/null
+++ b/src/org/torproject/ernie/test/ArchiveReaderTest.java
@@ -0,0 +1,33 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.ernie.test;
+
+import org.torproject.ernie.db.*;
+
+import java.io.*;
+
+import org.junit.*;
+import org.junit.rules.*;
+import static org.junit.Assert.*;
+
+public class ArchiveReaderTest {
+
+  private File tempArchivesDirectory;
+  private File tempStatsDirectory;
+
+  @Rule
+  public TemporaryFolder folder = new TemporaryFolder();
+
+  @Before
+  public void createTempDirectories() {
+    this.tempArchivesDirectory = folder.newFolder("sanitized-bridges");
+    this.tempStatsDirectory = folder.newFolder("stats");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testRelayDescriptorParserNull() {
+    new ArchiveReader(null, this.tempArchivesDirectory,
+        this.tempStatsDirectory, false);
+  }
+}
+
diff --git a/src/org/torproject/ernie/test/ArchiveWriterTest.java b/src/org/torproject/ernie/test/ArchiveWriterTest.java
new file mode 100644
index 0000000..fb34f65
--- /dev/null
+++ b/src/org/torproject/ernie/test/ArchiveWriterTest.java
@@ -0,0 +1,30 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.ernie.test;
+
+import org.torproject.ernie.db.*;
+
+import java.io.*;
+
+import org.junit.*;
+import org.junit.rules.*;
+import static org.junit.Assert.*;
+
+public class ArchiveWriterTest {
+
+  private File tempArchivesDirectory;
+
+  @Rule
+  public TemporaryFolder folder = new TemporaryFolder();
+
+  @Before
+  public void createTempDirectories() {
+    this.tempArchivesDirectory = folder.newFolder("archives");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testArchivesDirectoryNull() {
+    new ArchiveWriter(null);
+  }
+}
+
diff --git a/src/org/torproject/ernie/test/BridgeSnapshotReaderTest.java b/src/org/torproject/ernie/test/BridgeSnapshotReaderTest.java
new file mode 100644
index 0000000..93d1642
--- /dev/null
+++ b/src/org/torproject/ernie/test/BridgeSnapshotReaderTest.java
@@ -0,0 +1,33 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.ernie.test;
+
+import org.torproject.ernie.db.*;
+
+import java.io.*;
+
+import org.junit.*;
+import org.junit.rules.*;
+import static org.junit.Assert.*;
+
+public class BridgeSnapshotReaderTest {
+
+  private File tempBridgeDirectoriesDirectory;
+  private File tempStatsDirectory;
+
+  @Rule
+  public TemporaryFolder folder = new TemporaryFolder();
+
+  @Before
+  public void createTempDirectories() {
+    this.tempBridgeDirectoriesDirectory = folder.newFolder("bridges");
+    this.tempStatsDirectory = folder.newFolder("stats");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testBridgeDescriptorParserNull() {
+    new BridgeSnapshotReader(null, this.tempBridgeDirectoriesDirectory,
+        this.tempStatsDirectory);
+  }
+}
+
diff --git a/src/org/torproject/ernie/test/CachedRelayDescriptorReaderTest.java b/src/org/torproject/ernie/test/CachedRelayDescriptorReaderTest.java
new file mode 100644
index 0000000..22b2018
--- /dev/null
+++ b/src/org/torproject/ernie/test/CachedRelayDescriptorReaderTest.java
@@ -0,0 +1,32 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.ernie.test;
+
+import org.torproject.ernie.db.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.junit.*;
+import org.junit.rules.*;
+import static org.junit.Assert.*;
+
+public class CachedRelayDescriptorReaderTest {
+
+  private File tempStatsDirectory;
+
+  @Rule
+  public TemporaryFolder folder = new TemporaryFolder();
+
+  @Before
+  public void createTempDirectories() {
+    this.tempStatsDirectory = folder.newFolder("stats");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testRelayDescriptorParserNull() {
+    new CachedRelayDescriptorReader(null, new ArrayList<String>(),
+        this.tempStatsDirectory);
+  }
+}
+
diff --git a/src/org/torproject/ernie/test/SanitizedBridgesReaderTest.java b/src/org/torproject/ernie/test/SanitizedBridgesReaderTest.java
new file mode 100644
index 0000000..dd5f31e
--- /dev/null
+++ b/src/org/torproject/ernie/test/SanitizedBridgesReaderTest.java
@@ -0,0 +1,33 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.ernie.test;
+
+import org.torproject.ernie.db.*;
+
+import java.io.*;
+
+import org.junit.*;
+import org.junit.rules.*;
+import static org.junit.Assert.*;
+
+public class SanitizedBridgesReaderTest {
+
+  private File tempSanitizedBridgesDirectory;
+  private File tempStatsDirectory;
+
+  @Rule
+  public TemporaryFolder folder = new TemporaryFolder();
+
+  @Before
+  public void createTempDirectories() {
+    this.tempSanitizedBridgesDirectory = folder.newFolder("bridges");
+    this.tempStatsDirectory = folder.newFolder("stats");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testBridgeDescriptorParserNull() {
+    new SanitizedBridgesReader(null, this.tempSanitizedBridgesDirectory,
+        this.tempStatsDirectory, false);
+  }
+}
+
diff --git a/src/org/torproject/ernie/test/SanitizedBridgesWriterTest.java b/src/org/torproject/ernie/test/SanitizedBridgesWriterTest.java
new file mode 100644
index 0000000..0a3b0d7
--- /dev/null
+++ b/src/org/torproject/ernie/test/SanitizedBridgesWriterTest.java
@@ -0,0 +1,38 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.ernie.test;
+
+import org.torproject.ernie.db.*;
+
+import java.io.*;
+
+import org.junit.*;
+import org.junit.rules.*;
+import static org.junit.Assert.*;
+
+public class SanitizedBridgesWriterTest {
+
+  private File tempSanitizedBridgesDirectory;
+  private File tempStatsDirectory;
+
+  @Rule
+  public TemporaryFolder folder = new TemporaryFolder();
+
+  @Before
+  public void createTempDirectories() {
+    this.tempSanitizedBridgesDirectory =
+        folder.newFolder("sanitized-bridges");
+    this.tempStatsDirectory = folder.newFolder("stats");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testSanitizedBridgesDirectoryNull() {
+    new SanitizedBridgesWriter(null, this.tempStatsDirectory);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testStatsDirectoryNull() {
+    new SanitizedBridgesWriter(this.tempSanitizedBridgesDirectory, null);
+  }
+}
+
diff --git a/src/org/torproject/ernie/test/TorperfProcessorTest.java b/src/org/torproject/ernie/test/TorperfProcessorTest.java
new file mode 100644
index 0000000..015eec3
--- /dev/null
+++ b/src/org/torproject/ernie/test/TorperfProcessorTest.java
@@ -0,0 +1,37 @@
+/* Copyright 2011 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.ernie.test;
+
+import org.torproject.ernie.db.*;
+
+import java.io.*;
+
+import org.junit.*;
+import org.junit.rules.*;
+import static org.junit.Assert.*;
+
+public class TorperfProcessorTest {
+
+  private File tempTorperfDirectory;
+  private File tempStatsDirectory;
+
+  @Rule
+  public TemporaryFolder folder = new TemporaryFolder();
+
+  @Before
+  public void createTempDirectories() {
+    this.tempTorperfDirectory = folder.newFolder("torperf");
+    this.tempStatsDirectory = folder.newFolder("stats");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testTorperfDirectoryNull() {
+    new TorperfProcessor(null, this.tempStatsDirectory, null);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testStatsDirectoryNull() {
+    new TorperfProcessor(this.tempTorperfDirectory, null, null);
+  }
+}
+