azkaban-developers

Issue #256, #257 - Fix unit tests part 1. Tests in azkaban-common

6/23/2014 3:43:07 PM

Details

diff --git a/azkaban-common/src/test/java/azkaban/database/AzkabanDatabaseSetupTest.java b/azkaban-common/src/test/java/azkaban/database/AzkabanDatabaseSetupTest.java
index a3b18cc..9e04ace 100644
--- a/azkaban-common/src/test/java/azkaban/database/AzkabanDatabaseSetupTest.java
+++ b/azkaban-common/src/test/java/azkaban/database/AzkabanDatabaseSetupTest.java
@@ -16,8 +16,12 @@
 
 package azkaban.database;
 
+import com.google.common.io.Resources;
+
 import java.io.File;
 import java.io.IOException;
+import java.net.URL;
+import java.net.URISyntaxException;
 import java.sql.SQLException;
 
 import javax.sql.DataSource;
@@ -26,90 +30,94 @@ import org.apache.commons.dbutils.QueryRunner;
 import org.apache.commons.io.FileUtils;
 
 import org.junit.AfterClass;
-import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import azkaban.utils.Props;
 
-@Ignore
 public class AzkabanDatabaseSetupTest {
-  @BeforeClass
-  public static void setupDB() throws IOException, SQLException {
-    File dbDir = new File("h2dbtest");
-    if (dbDir.exists()) {
-      FileUtils.deleteDirectory(dbDir);
-    }
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
 
-    dbDir.mkdir();
+  private static String sqlScriptsDir;
 
-    clearUnitTestDB();
+  @BeforeClass
+  public static void setupDB() throws IOException, URISyntaxException {
+    URL resourceUrl = Resources.getResource("sql");
+    assertNotNull(resourceUrl);
+    sqlScriptsDir = new File(resourceUrl.toURI()).getCanonicalPath();
   }
 
   @AfterClass
   public static void teardownDB() {
   }
 
-  @Test
+  @Ignore @Test
   public void testH2Query() throws Exception {
-    Props h2Props = getH2Props();
+    File dbDir = temp.newFolder("h2dbtest");
+    Props h2Props = getH2Props(dbDir.getCanonicalPath(), sqlScriptsDir);
     AzkabanDatabaseSetup setup = new AzkabanDatabaseSetup(h2Props);
 
     // First time will create the tables
     setup.loadTableInfo();
     setup.printUpgradePlan();
     setup.updateDatabase(true, true);
-    Assert.assertTrue(setup.needsUpdating());
+    assertTrue(setup.needsUpdating());
 
     // Second time will update some tables. This is only for testing purpose and
-    // obviously we
-    // wouldn't set things up this way.
+    // obviously we wouldn't set things up this way.
     setup.loadTableInfo();
     setup.printUpgradePlan();
     setup.updateDatabase(true, true);
-    Assert.assertTrue(setup.needsUpdating());
+    assertTrue(setup.needsUpdating());
 
     // Nothing to be done
     setup.loadTableInfo();
     setup.printUpgradePlan();
-    Assert.assertFalse(setup.needsUpdating());
+    assertFalse(setup.needsUpdating());
   }
 
-  @Test
+  @Ignore @Test
   public void testMySQLQuery() throws Exception {
-    Props mysqlProps = getMySQLProps();
+    clearMySQLTestDB();
+    Props mysqlProps = getMySQLProps(sqlScriptsDir);
     AzkabanDatabaseSetup setup = new AzkabanDatabaseSetup(mysqlProps);
 
     // First time will create the tables
     setup.loadTableInfo();
     setup.printUpgradePlan();
     setup.updateDatabase(true, true);
-    Assert.assertTrue(setup.needsUpdating());
+    assertTrue(setup.needsUpdating());
 
     // Second time will update some tables. This is only for testing purpose
     // and obviously we wouldn't set things up this way.
     setup.loadTableInfo();
     setup.printUpgradePlan();
     setup.updateDatabase(true, true);
-    Assert.assertTrue(setup.needsUpdating());
+    assertTrue(setup.needsUpdating());
 
     // Nothing to be done
     setup.loadTableInfo();
     setup.printUpgradePlan();
-    Assert.assertFalse(setup.needsUpdating());
+    assertFalse(setup.needsUpdating());
   }
 
-  private static Props getH2Props() {
+  private static Props getH2Props(String dbDir, String sqlScriptsDir) {
     Props props = new Props();
     props.put("database.type", "h2");
-    props.put("h2.path", "h2dbtest/h2db");
-    props.put("database.sql.scripts.dir", "unit/sql");
-
+    props.put("h2.path", dbDir);
+    props.put("database.sql.scripts.dir", sqlScriptsDir);
     return props;
   }
 
-  private static Props getMySQLProps() {
+  private static Props getMySQLProps(String sqlScriptsDir) {
     Props props = new Props();
 
     props.put("database.type", "mysql");
@@ -117,16 +125,15 @@ public class AzkabanDatabaseSetupTest {
     props.put("mysql.host", "localhost");
     props.put("mysql.database", "azkabanunittest");
     props.put("mysql.user", "root");
-    props.put("database.sql.scripts.dir", "unit/sql");
+    props.put("database.sql.scripts.dir", sqlScriptsDir);
     props.put("mysql.password", "");
     props.put("mysql.numconnections", 10);
 
     return props;
   }
 
-  private static void clearUnitTestDB() throws SQLException {
+  private static void clearMySQLTestDB() throws SQLException {
     Props props = new Props();
-
     props.put("database.type", "mysql");
     props.put("mysql.host", "localhost");
     props.put("mysql.port", "3306");
diff --git a/azkaban-common/src/test/java/azkaban/database/AzkabanDatabaseUpdaterTest.java b/azkaban-common/src/test/java/azkaban/database/AzkabanDatabaseUpdaterTest.java
index 4efc11b..7ba67c4 100644
--- a/azkaban-common/src/test/java/azkaban/database/AzkabanDatabaseUpdaterTest.java
+++ b/azkaban-common/src/test/java/azkaban/database/AzkabanDatabaseUpdaterTest.java
@@ -16,8 +16,11 @@
 
 package azkaban.database;
 
+import com.google.common.io.Resources;
+
 import java.io.File;
 import java.io.IOException;
+import java.net.URL;
 import java.sql.SQLException;
 
 import javax.sql.DataSource;
@@ -30,29 +33,20 @@ import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import static org.junit.Assert.assertNotNull;
+
 import azkaban.utils.Props;
 
-@Ignore
 public class AzkabanDatabaseUpdaterTest {
-  @BeforeClass
-  public static void setupDB() throws IOException, SQLException {
-    File dbDir = new File("h2dbtest");
-    if (dbDir.exists()) {
-      FileUtils.deleteDirectory(dbDir);
-    }
-
-    dbDir.mkdir();
-
-    clearUnitTestDB();
-  }
+  @Ignore @Test
+  public void testMySQLAutoCreate() throws Exception {
+    clearMySQLTestDb();
 
-  @AfterClass
-  public static void teardownDB() {
-  }
+    URL resourceUrl = Resources.getResource("conf/dbtestmysql");
+    assertNotNull(resourceUrl);
+    File resource = new File(resourceUrl.toURI());
+    String confDir = resource.getParent();
 
-  @Test
-  public void testMySQLAutoCreate() throws Exception {
-    String confDir = "unit/conf/dbtestmysql";
     System.out.println("1.***Now testing check");
     AzkabanDatabaseUpdater.main(new String[] { "-c", confDir });
 
@@ -71,7 +65,11 @@ public class AzkabanDatabaseUpdaterTest {
 
   @Test
   public void testH2AutoCreate() throws Exception {
-    String confDir = "unit/conf/dbtesth2";
+    URL resourceUrl = Resources.getResource("conf/dbtesth2");
+    assertNotNull(resourceUrl);
+    File resource = new File(resourceUrl.toURI());
+    String confDir = resource.getParent();
+
     System.out.println("1.***Now testing check");
     AzkabanDatabaseUpdater.main(new String[] { "-c", confDir });
 
@@ -88,7 +86,7 @@ public class AzkabanDatabaseUpdaterTest {
     AzkabanDatabaseUpdater.main(new String[] { "-c", confDir });
   }
 
-  private static void clearUnitTestDB() throws SQLException {
+  private static void clearMySQLTestDb() throws SQLException {
     Props props = new Props();
 
     props.put("database.type", "mysql");
diff --git a/azkaban-common/src/test/java/azkaban/jobExecutor/JavaProcessJobTest.java b/azkaban-common/src/test/java/azkaban/jobExecutor/JavaProcessJobTest.java
index 11c799c..05a0a28 100644
--- a/azkaban-common/src/test/java/azkaban/jobExecutor/JavaProcessJobTest.java
+++ b/azkaban-common/src/test/java/azkaban/jobExecutor/JavaProcessJobTest.java
@@ -17,26 +17,35 @@
 package azkaban.jobExecutor;
 
 import java.io.IOException;
+import java.io.File;
 import java.util.Date;
 import java.util.Properties;
 
 import org.apache.log4j.Logger;
 
+import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
+import org.junit.ClassRule;
 import org.junit.Test;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
 
 import azkaban.utils.Props;
 
 public class JavaProcessJobTest {
+  @ClassRule
+  public static TemporaryFolder classTemp = new TemporaryFolder();
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
 
   private JavaProcessJob job = null;
-  // private JobDescriptor descriptor = null;
   private Props props = null;
   private Logger log = Logger.getLogger(JavaProcessJob.class);
+
   private static String classPaths;
 
   private static final String inputContent =
@@ -63,17 +72,19 @@ public class JavaProcessJobTest {
   private static String outputFile;
 
   @BeforeClass
-  public static void init() {
-    // get the classpath
+  public static void init() throws IOException {
+    // Get the classpath
     Properties prop = System.getProperties();
     classPaths =
         String.format("'%s'", prop.getProperty("java.class.path", null));
 
     long time = (new Date()).getTime();
-    inputFile = "/tmp/azkaban_input_" + time;
-    errorInputFile = "/tmp/azkaban_input_error_" + time;
-    outputFile = "/tmp/azkaban_output_" + time;
-    // dump input files
+    inputFile = classTemp.newFile("azkaban_input_" + time).getCanonicalPath();
+    errorInputFile =
+        classTemp.newFile("azkaban_input_error_" + time).getCanonicalPath();
+    outputFile = classTemp.newFile("azkaban_output_" + time).getCanonicalPath();
+
+    // Dump input files
     try {
       Utils.dumpFile(inputFile, inputContent);
       Utils.dumpFile(errorInputFile, errorInputContent);
@@ -81,57 +92,47 @@ public class JavaProcessJobTest {
       e.printStackTrace(System.err);
       Assert.fail("error in creating input file:" + e.getLocalizedMessage());
     }
-
   }
 
   @AfterClass
   public static void cleanup() {
-    // remove the input file and error input file
-    Utils.removeFile(inputFile);
-    Utils.removeFile(errorInputFile);
-    // Utils.removeFile(outputFile);
+    classTemp.delete();
   }
 
   @Before
-  public void setUp() {
-
-    /* initialize job */
-    // descriptor = EasyMock.createMock(JobDescriptor.class);
+  public void setUp() throws IOException {
+    File workingDir = temp.newFolder("testJavaProcess");
 
+    // Initialize job
     props = new Props();
-    props.put(AbstractProcessJob.WORKING_DIR, ".");
+    props.put(AbstractProcessJob.WORKING_DIR, workingDir.getCanonicalPath());
     props.put("type", "java");
     props.put("fullPath", ".");
-
-    // EasyMock.expect(descriptor.getId()).andReturn("java").times(1);
-    // EasyMock.expect(descriptor.getProps()).andReturn(props).times(1);
-    // EasyMock.expect(descriptor.getFullPath()).andReturn(".").times(1);
-    //
-    // EasyMock.replay(descriptor);
-
     job = new JavaProcessJob("testJavaProcess", props, props, log);
+  }
 
-    // EasyMock.verify(descriptor);
+  @After
+  public void tearDown() {
+    temp.delete();
   }
 
-  @Ignore @Test
+  @Test
   public void testJavaJob() throws Exception {
-    /* initialize the Props */
+    // initialize the Props
     props.put(JavaProcessJob.JAVA_CLASS,
-        "azkaban.test.jobExecutor.WordCountLocal");
-    props.put(ProcessJob.WORKING_DIR, ".");
+        "azkaban.jobExecutor.WordCountLocal");
     props.put("input", inputFile);
     props.put("output", outputFile);
     props.put("classpath", classPaths);
     job.run();
   }
 
-  @Ignore @Test
+  @Test
   public void testJavaJobHashmap() throws Exception {
-    /* initialize the Props */
-    props.put(JavaProcessJob.JAVA_CLASS, "azkaban.test.executor.SleepJavaJob");
+    // initialize the Props
+    props.put(JavaProcessJob.JAVA_CLASS,
+        "azkaban.executor.SleepJavaJob");
     props.put("seconds", 1);
-    props.put(ProcessJob.WORKING_DIR, ".");
     props.put("input", inputFile);
     props.put("output", outputFile);
     props.put("classpath", classPaths);
@@ -141,8 +142,7 @@ public class JavaProcessJobTest {
   @Test
   public void testFailedJavaJob() throws Exception {
     props.put(JavaProcessJob.JAVA_CLASS,
-        "azkaban.test.jobExecutor.WordCountLocal");
-    props.put(ProcessJob.WORKING_DIR, ".");
+        "azkaban.jobExecutor.WordCountLocal");
     props.put("input", errorInputFile);
     props.put("output", outputFile);
     props.put("classpath", classPaths);
@@ -153,5 +153,4 @@ public class JavaProcessJobTest {
       Assert.assertTrue(true);
     }
   }
-
 }
diff --git a/azkaban-common/src/test/java/azkaban/jobExecutor/ProcessJobTest.java b/azkaban-common/src/test/java/azkaban/jobExecutor/ProcessJobTest.java
index 26b86d5..974895b 100644
--- a/azkaban-common/src/test/java/azkaban/jobExecutor/ProcessJobTest.java
+++ b/azkaban-common/src/test/java/azkaban/jobExecutor/ProcessJobTest.java
@@ -16,56 +16,57 @@
 
 package azkaban.jobExecutor;
 
+import java.io.File;
+import java.io.IOException;
+
 import org.apache.log4j.Logger;
 
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
 
 import azkaban.utils.Props;
 
 public class ProcessJobTest {
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
   private ProcessJob job = null;
-  // private JobDescriptor descriptor = null;
   private Props props = null;
   private Logger log = Logger.getLogger(ProcessJob.class);
 
   @Before
-  public void setUp() {
-
-    /* initialize job */
-    // props = EasyMock.createMock(Props.class);
+  public void setUp() throws IOException {
+    File workingDir = temp.newFolder("TestProcess");
 
     props = new Props();
-    props.put(AbstractProcessJob.WORKING_DIR, ".");
+    props.put(AbstractProcessJob.WORKING_DIR, workingDir.getCanonicalPath());
     props.put("type", "command");
     props.put("fullPath", ".");
 
-    // EasyMock.expect(props.getString("type")).andReturn("command").times(1);
-    // EasyMock.expect(props.getProps()).andReturn(props).times(1);
-    // EasyMock.expect(props.getString("fullPath")).andReturn(".").times(1);
-    //
-    // EasyMock.replay(props);
-
     job = new ProcessJob("TestProcess", props, props, log);
+  }
 
+  @After
+  public void tearDown() {
+    temp.delete();
   }
 
   @Test
   public void testOneUnixCommand() throws Exception {
-    /* initialize the Props */
+    // Initialize the Props
     props.put(ProcessJob.COMMAND, "ls -al");
-    props.put(ProcessJob.WORKING_DIR, ".");
-
     job.run();
 
   }
 
   @Test
   public void testFailedUnixCommand() throws Exception {
-    /* initialize the Props */
+    // Initialize the Props
     props.put(ProcessJob.COMMAND, "xls -al");
-    props.put(ProcessJob.WORKING_DIR, ".");
 
     try {
       job.run();
@@ -77,8 +78,7 @@ public class ProcessJobTest {
 
   @Test
   public void testMultipleUnixCommands() throws Exception {
-    /* initialize the Props */
-    props.put(ProcessJob.WORKING_DIR, ".");
+    // Initialize the Props
     props.put(ProcessJob.COMMAND, "pwd");
     props.put("command.1", "date");
     props.put("command.2", "whoami");
diff --git a/azkaban-common/src/test/java/azkaban/jobtype/JobTypeManagerTest.java b/azkaban-common/src/test/java/azkaban/jobtype/JobTypeManagerTest.java
index 7a42262..0433214 100644
--- a/azkaban-common/src/test/java/azkaban/jobtype/JobTypeManagerTest.java
+++ b/azkaban-common/src/test/java/azkaban/jobtype/JobTypeManagerTest.java
@@ -16,16 +16,20 @@
 
 package azkaban.jobtype;
 
+import com.google.common.io.Resources;
+
 import java.io.File;
 import java.io.IOException;
+import java.net.URL;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.log4j.Logger;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
 
 import static org.junit.Assert.*;
 
@@ -38,8 +42,13 @@ import azkaban.utils.Props;
  *
  */
 public class JobTypeManagerTest {
-  public static String TEST_PLUGIN_DIR = "jobtypes_test";
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  public final static String TEST_PLUGIN_DIR = "jobtypes_test";
+
   private Logger logger = Logger.getLogger(JobTypeManagerTest.class);
+  private String testPluginDirPath;
   private JobTypeManager manager;
 
   public JobTypeManagerTest() {
@@ -47,18 +56,19 @@ public class JobTypeManagerTest {
 
   @Before
   public void setUp() throws Exception {
-    File jobTypeDir = new File(TEST_PLUGIN_DIR);
-    jobTypeDir.mkdirs();
-
-    FileUtils.copyDirectory(new File("unit/plugins/jobtypes"), jobTypeDir);
-    manager =
-        new JobTypeManager(TEST_PLUGIN_DIR, null, this.getClass()
-            .getClassLoader());
+    File jobTypeDir = temp.newFolder(TEST_PLUGIN_DIR);
+    testPluginDirPath = jobTypeDir.getCanonicalPath();
+
+    URL resourceUrl = Resources.getResource("plugins/jobtypes");
+    assertNotNull(resourceUrl);
+    FileUtils.copyDirectory(new File(resourceUrl.toURI()), jobTypeDir);
+    manager = new JobTypeManager(testPluginDirPath, null,
+        this.getClass().getClassLoader());
   }
 
   @After
   public void tearDown() throws IOException {
-    FileUtils.deleteDirectory(new File(TEST_PLUGIN_DIR));
+    temp.delete();
   }
 
   /**
@@ -66,7 +76,7 @@ public class JobTypeManagerTest {
    *
    * @throws Exception
    */
-  @Ignore @Test
+  @Test
   public void testCommonPluginProps() throws Exception {
     JobTypePluginSet pluginSet = manager.getJobTypePluginSet();
 
@@ -88,7 +98,7 @@ public class JobTypeManagerTest {
    *
    * @throws Exception
    */
-  @Ignore @Test
+  @Test
   public void testLoadedClasses() throws Exception {
     JobTypePluginSet pluginSet = manager.getJobTypePluginSet();
 
@@ -107,13 +117,13 @@ public class JobTypeManagerTest {
     // Testing the anothertestjobtype
     Class<? extends Job> aPluginClass =
         pluginSet.getPluginClass("anothertestjob");
-    assertEquals("azkaban.test.jobtype.FakeJavaJob", aPluginClass.getName());
+    assertEquals("azkaban.jobtype.FakeJavaJob", aPluginClass.getName());
     Props ajobProps = pluginSet.getPluginJobProps("anothertestjob");
     Props aloadProps = pluginSet.getPluginLoaderProps("anothertestjob");
 
     // Loader props
     assertEquals("lib/*", aloadProps.get("jobtype.classpath"));
-    assertEquals("azkaban.test.jobtype.FakeJavaJob",
+    assertEquals("azkaban.jobtype.FakeJavaJob",
         aloadProps.get("jobtype.class"));
     assertEquals("commonprivate1", aloadProps.get("commonprivate1"));
     assertEquals("commonprivate2", aloadProps.get("commonprivate2"));
@@ -125,13 +135,13 @@ public class JobTypeManagerTest {
     assertNull(ajobProps.get("commonprivate1"));
 
     Class<? extends Job> tPluginClass = pluginSet.getPluginClass("testjob");
-    assertEquals("azkaban.test.jobtype.FakeJavaJob2", tPluginClass.getName());
+    assertEquals("azkaban.jobtype.FakeJavaJob2", tPluginClass.getName());
     Props tjobProps = pluginSet.getPluginJobProps("testjob");
     Props tloadProps = pluginSet.getPluginLoaderProps("testjob");
 
     // Loader props
     assertNull(tloadProps.get("jobtype.classpath"));
-    assertEquals("azkaban.test.jobtype.FakeJavaJob2",
+    assertEquals("azkaban.jobtype.FakeJavaJob2",
         tloadProps.get("jobtype.class"));
     assertEquals("commonprivate1", tloadProps.get("commonprivate1"));
     assertEquals("commonprivate2", tloadProps.get("commonprivate2"));
@@ -154,7 +164,7 @@ public class JobTypeManagerTest {
    *
    * @throws Exception
    */
-  @Ignore @Test
+  @Test
   public void testBuildClass() throws Exception {
     Props jobProps = new Props();
     jobProps.put("type", "anothertestjob");
@@ -180,7 +190,7 @@ public class JobTypeManagerTest {
    *
    * @throws Exception
    */
-  @Ignore @Test
+  @Test
   public void testBuildClass2() throws Exception {
     Props jobProps = new Props();
     jobProps.put("type", "testjob");
@@ -207,10 +217,10 @@ public class JobTypeManagerTest {
    *
    * @throws Exception
    */
-  @Ignore @Test
+  @Test
   public void testResetPlugins() throws Exception {
     // Add a plugins file to the anothertestjob folder
-    File anothertestfolder = new File(TEST_PLUGIN_DIR + "/anothertestjob");
+    File anothertestfolder = new File(testPluginDirPath + "/anothertestjob");
     Props pluginProps = new Props();
     pluginProps.put("test1", "1");
     pluginProps.put("test2", "2");
@@ -219,36 +229,34 @@ public class JobTypeManagerTest {
         .storeFlattened(new File(anothertestfolder, "plugin.properties"));
 
     // clone the testjob folder
-    File testFolder = new File(TEST_PLUGIN_DIR + "/testjob");
-    FileUtils.copyDirectory(testFolder, new File(TEST_PLUGIN_DIR
+    File testFolder = new File(testPluginDirPath + "/testjob");
+    FileUtils.copyDirectory(testFolder, new File(testPluginDirPath
         + "/newtestjob"));
 
     // change the common properties
     Props commonPlugin =
-        new Props(null, TEST_PLUGIN_DIR + "/common.properties");
+        new Props(null, testPluginDirPath + "/common.properties");
     commonPlugin.put("commonprop1", "1");
     commonPlugin.put("newcommonprop1", "2");
     commonPlugin.removeLocal("commonprop2");
     commonPlugin
-        .storeFlattened(new File(TEST_PLUGIN_DIR + "/common.properties"));
+        .storeFlattened(new File(testPluginDirPath + "/common.properties"));
 
     // change the common properties
     Props commonPrivate =
-        new Props(null, TEST_PLUGIN_DIR + "/commonprivate.properties");
+        new Props(null, testPluginDirPath + "/commonprivate.properties");
     commonPrivate.put("commonprivate1", "1");
     commonPrivate.put("newcommonprivate1", "2");
     commonPrivate.removeLocal("commonprivate2");
-    commonPrivate.storeFlattened(new File(TEST_PLUGIN_DIR
+    commonPrivate.storeFlattened(new File(testPluginDirPath
         + "/commonprivate.properties"));
 
     // change testjob private property
     Props loadProps =
-        new Props(null, TEST_PLUGIN_DIR + "/testjob/private.properties");
+        new Props(null, testPluginDirPath + "/testjob/private.properties");
     loadProps.put("privatetest", "test");
 
-    /*
-     * Reload the plugins here!!
-     */
+    // Reload the plugins here!!
     manager.loadPlugins();
 
     // Checkout common props
@@ -268,7 +276,7 @@ public class JobTypeManagerTest {
 
     // Verify anothertestjob changes
     Class<? extends Job> atjClass = pluginSet.getPluginClass("anothertestjob");
-    assertEquals("azkaban.test.jobtype.FakeJavaJob", atjClass.getName());
+    assertEquals("azkaban.jobtype.FakeJavaJob", atjClass.getName());
     Props ajobProps = pluginSet.getPluginJobProps("anothertestjob");
     assertEquals("1", ajobProps.get("test1"));
     assertEquals("2", ajobProps.get("test2"));
@@ -282,7 +290,7 @@ public class JobTypeManagerTest {
 
     // Verify testjob changes
     Class<? extends Job> tjClass = pluginSet.getPluginClass("testjob");
-    assertEquals("azkaban.test.jobtype.FakeJavaJob2", tjClass.getName());
+    assertEquals("azkaban.jobtype.FakeJavaJob2", tjClass.getName());
     Props tjobProps = pluginSet.getPluginJobProps("testjob");
     assertEquals("1", tjobProps.get("commonprop1"));
     assertEquals("2", tjobProps.get("newcommonprop1"));
@@ -294,7 +302,7 @@ public class JobTypeManagerTest {
 
     Props tloadProps = pluginSet.getPluginLoaderProps("testjob");
     assertNull(tloadProps.get("jobtype.classpath"));
-    assertEquals("azkaban.test.jobtype.FakeJavaJob2",
+    assertEquals("azkaban.jobtype.FakeJavaJob2",
         tloadProps.get("jobtype.class"));
     assertEquals("1", tloadProps.get("commonprivate1"));
     assertNull(tloadProps.get("commonprivate2"));
@@ -302,13 +310,13 @@ public class JobTypeManagerTest {
 
     // Verify newtestjob
     Class<? extends Job> ntPluginClass = pluginSet.getPluginClass("newtestjob");
-    assertEquals("azkaban.test.jobtype.FakeJavaJob2", ntPluginClass.getName());
+    assertEquals("azkaban.jobtype.FakeJavaJob2", ntPluginClass.getName());
     Props ntjobProps = pluginSet.getPluginJobProps("newtestjob");
     Props ntloadProps = pluginSet.getPluginLoaderProps("newtestjob");
 
     // Loader props
     assertNull(ntloadProps.get("jobtype.classpath"));
-    assertEquals("azkaban.test.jobtype.FakeJavaJob2",
+    assertEquals("azkaban.jobtype.FakeJavaJob2",
         ntloadProps.get("jobtype.class"));
     assertEquals("1", ntloadProps.get("commonprivate1"));
     assertNull(ntloadProps.get("commonprivate2"));
diff --git a/azkaban-common/src/test/java/azkaban/utils/FileIOUtilsTest.java b/azkaban-common/src/test/java/azkaban/utils/FileIOUtilsTest.java
index 99c6464..16da204 100644
--- a/azkaban-common/src/test/java/azkaban/utils/FileIOUtilsTest.java
+++ b/azkaban-common/src/test/java/azkaban/utils/FileIOUtilsTest.java
@@ -16,35 +16,52 @@
 
 package azkaban.utils;
 
+import com.google.common.io.Resources;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.net.URL;
 
 import org.apache.commons.io.FileUtils;
 
 import org.junit.After;
-import org.junit.Assert;
 import org.junit.Before;
-import org.junit.Ignore;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
 
 public class FileIOUtilsTest {
-  File sourceDir = new File("unit/project/testjob");
-  File destDir = new File("unit/executions/unixsymlink");
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  private static File sourceDir;
+
+  private File destDir;
+
+  @BeforeClass
+  public static void createSourceDir() throws Exception {
+    URL resourceUrl = Resources.getResource("project/testjob");
+    assertNotNull(resourceUrl);
+    sourceDir = new File(resourceUrl.toURI());
+  }
 
   @Before
   public void setUp() throws Exception {
-    if (destDir.exists()) {
-      FileUtils.deleteDirectory(destDir);
-    }
-    destDir.mkdirs();
+    destDir = temp.newFolder("unixsymlink");
   }
 
   @After
   public void tearDown() throws Exception {
+    temp.delete();
   }
 
-  @Ignore @Test
+  @Test
   public void testSymlinkCopy() throws IOException {
     FileIOUtils.createDeepSymlink(sourceDir, destDir);
   }
@@ -60,7 +77,7 @@ public class FileIOUtilsTest {
       exception = true;
     }
 
-    Assert.assertTrue(exception);
+    assertTrue(exception);
   }
 
   @Test
@@ -83,9 +100,9 @@ public class FileIOUtilsTest {
         pair.getSecond(), "UTF-8");
     System.out.println("correctString:" + correctString);
 
-    Assert.assertEquals(pair, new Pair<Integer,Integer>(1, 20));
+    assertEquals(pair, new Pair<Integer,Integer>(1, 20));
     // Two characters stripped from this.
-    Assert.assertEquals(correctString.length(), foreignText.length() - 6);
+    assertEquals(correctString.length(), foreignText.length() - 6);
 
   }
 
@@ -109,9 +126,9 @@ public class FileIOUtilsTest {
         pair.getSecond(), "UTF-8");
     System.out.println("correctString:" + correctString);
 
-    Assert.assertEquals(pair, new Pair<Integer,Integer>(3, 40));
+    assertEquals(pair, new Pair<Integer,Integer>(3, 40));
     // Two characters stripped from this.
-    Assert.assertEquals(correctString.length(), foreignText.length() - 3);
+    assertEquals(correctString.length(), foreignText.length() - 3);
 
 
     // Testing mixed bytes
@@ -122,10 +139,9 @@ public class FileIOUtilsTest {
     correctString = new String(mixedBytes, pair2.getFirst(), pair2.getSecond(),
         "UTF-8");
     System.out.println("correctString:" + correctString);
-    Assert.assertEquals(pair2, new Pair<Integer,Integer>(1, 45));
+    assertEquals(pair2, new Pair<Integer,Integer>(1, 45));
     // Two characters stripped from this.
-    Assert.assertEquals(correctString.length(), mixedText.length() - 3);
-
+    assertEquals(correctString.length(), mixedText.length() - 3);
   }
 
   private byte[] createUTF8ByteArray(String text) {
diff --git a/azkaban-common/src/test/resources/plugins/jobtypes/anothertestjob/private.properties b/azkaban-common/src/test/resources/plugins/jobtypes/anothertestjob/private.properties
index 8e95c94..9764ca7 100644
--- a/azkaban-common/src/test/resources/plugins/jobtypes/anothertestjob/private.properties
+++ b/azkaban-common/src/test/resources/plugins/jobtypes/anothertestjob/private.properties
@@ -1,2 +1,2 @@
 jobtype.classpath=lib/*
-jobtype.class=azkaban.test.jobtype.FakeJavaJob
+jobtype.class=azkaban.jobtype.FakeJavaJob
diff --git a/azkaban-common/src/test/resources/plugins/jobtypes/testjob/private.properties b/azkaban-common/src/test/resources/plugins/jobtypes/testjob/private.properties
index 2bba593..9146ec1 100644
--- a/azkaban-common/src/test/resources/plugins/jobtypes/testjob/private.properties
+++ b/azkaban-common/src/test/resources/plugins/jobtypes/testjob/private.properties
@@ -1,3 +1,3 @@
-jobtype.class=azkaban.test.jobtype.FakeJavaJob2
+jobtype.class=azkaban.jobtype.FakeJavaJob2
 commonprivate3=private3
-testprivate=0
\ No newline at end of file
+testprivate=0

build.gradle 77(+77 -0)

diff --git a/build.gradle b/build.gradle
index 88bc05e..9d6a9b7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -399,6 +399,83 @@ project(':azkaban-sql') {
   }
 }
 
+project(':azkaban-test') {
+  apply plugin: 'distribution'
+
+  distributions {
+    animal {
+      baseName = 'test-animal'
+      contents {
+        from { 'src/test/resources/executions/animal' }
+      }
+    }
+
+    embedded {
+      baseName = 'test-embedded'
+      contents {
+        from { 'src/test/resources/executions/embedded' }
+      }
+    }
+
+    embedded2 {
+      baseName = 'test-embedded2'
+      contents {
+        from { 'src/test/resources/executions/embedded2' }
+      }
+    }
+
+    embedded3 {
+      baseName = 'test-embedded3'
+      contents {
+        from { 'src/test/resources/executions/embedded3' }
+      }
+    }
+
+    embeddedBad {
+      baseName = 'test-embedded-bad'
+      contents {
+        from { 'src/test/resources/executions/embeddedBad' }
+      }
+    }
+
+    execpropstest {
+      baseName = 'test-execpropstest'
+      contents {
+        from { 'src/test/resources/executions/execpropstest' }
+      }
+    }
+
+    exectest1 {
+      baseName = 'test-exectest1'
+      contents {
+        from { 'src/test/resources/executions/exectest1' }
+      }
+    }
+
+    exectest2 {
+      baseName = 'test-exectest2'
+      contents {
+        from { 'src/test/resources/executions/exectest2' }
+      }
+    }
+
+    logtest {
+      baseName = 'test-logtest'
+      contents {
+        from { 'src/test/resources/executions/logtest' }
+      }
+    }
+  }
+
+  distZip.dependsOn build, animalDistZip, embeddedDistZip, embedded2DistZip,
+      embedded3DistZip, embeddedBadDistZip, execpropstestDistZip,
+      exectest1DistZip, exectest2DistZip, logtestDistZip
+
+  distTar.dependsOn build, animalDistTar, embeddedDistTar, embedded2DistTar,
+      embedded3DistTar, embeddedBadDistTar, execpropstestDistTar,
+      exectest1DistTar, exectest2DistTar, logtestDistTar
+}
+
 distributions {
   migration {
     baseName = 'azkaban-migration'

settings.gradle 1(+1 -0)

diff --git a/settings.gradle b/settings.gradle
index dcfd8d0..7917a49 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,3 +4,4 @@ include 'azkaban-migration'
 include 'azkaban-soloserver'
 include 'azkaban-sql'
 include 'azkaban-webserver'
+include 'azkaban-test'