http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestJavaActionBuilder.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestJavaActionBuilder.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestJavaActionBuilder.java
new file mode 100644
index 0000000..c068550
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestJavaActionBuilder.java
@@ -0,0 +1,225 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestJavaActionBuilder extends TestNodeBuilderBaseImpl<JavaAction, 
JavaActionBuilder> {
+    private static final String NAME = "ssh-name";
+    private static final String NAME_NODE = "${nameNode}";
+    private static final String EXAMPLE_DIR = "/path/to/directory";
+    private static final String[] ARGS = {"arg1", "arg2", "arg3"};
+    private static final String MAPRED_JOB_QUEUE_NAME = 
"mapred.job.queue.name";
+    private static final String DEFAULT = "default";
+    private static final String RESOURCE_MANAGER = "${resourceManager}";
+    private static final String PATH_TO_DELETE = "/path/to/delete";
+    private static final String PATH_TO_MKDIR = "/path/to/mkdir";
+
+    @Override
+    protected JavaActionBuilder getBuilderInstance() {
+        return JavaActionBuilder.create();
+    }
+
+    @Override
+    protected JavaActionBuilder getBuilderInstance(final JavaAction action) {
+        return JavaActionBuilder.createFromExistingAction(action);
+    }
+
+    @Test
+    public void testResourceManagerAdded() {
+        final JavaActionBuilder builder = getBuilderInstance();
+        builder.withResourceManager(RESOURCE_MANAGER);
+
+        final JavaAction action = builder.build();
+        assertEquals(RESOURCE_MANAGER, action.getResourceManager());
+    }
+
+    @Test
+    public void testNameNodeAdded() {
+        final JavaActionBuilder builder = getBuilderInstance();
+        builder.withNameNode(NAME_NODE);
+
+        final JavaAction action = builder.build();
+        assertEquals(NAME_NODE, action.getNameNode());
+    }
+
+    @Test
+    public void testPrepareAdded() {
+        final JavaActionBuilder builder = getBuilderInstance();
+        builder.withPrepare(new 
PrepareBuilder().withDelete(EXAMPLE_DIR).build());
+
+        final JavaAction action = builder.build();
+        assertEquals(EXAMPLE_DIR, 
action.getPrepare().getDeletes().get(0).getPath());
+    }
+
+    @Test
+    public void testSameConfigPropertyAddedTwiceThrows() {
+        final JavaActionBuilder builder = getBuilderInstance();
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+    }
+
+    @Test
+    public void testSeveralArgsAdded() {
+        final JavaActionBuilder builder = getBuilderInstance();
+
+        for (final String arg : ARGS) {
+            builder.withArg(arg);
+        }
+
+        final JavaAction action = builder.build();
+
+        final List<String> argList = action.getArgs();
+        assertEquals(ARGS.length, argList.size());
+
+        for (int i = 0; i < ARGS.length; ++i) {
+            assertEquals(ARGS[i], argList.get(i));
+        }
+    }
+
+    @Test
+    public void testRemoveArgs() {
+        final JavaActionBuilder builder = getBuilderInstance();
+
+        for (final String file : ARGS) {
+            builder.withArg(file);
+        }
+
+        builder.withoutArg(ARGS[0]);
+
+        final JavaAction action = builder.build();
+
+        final List<String> argList = action.getArgs();
+        final String[] remainingArgs = Arrays.copyOfRange(ARGS, 1, 
ARGS.length);
+        assertEquals(remainingArgs.length, argList.size());
+
+        for (int i = 0; i < remainingArgs.length; ++i) {
+            assertEquals(remainingArgs[i], argList.get(i));
+        }
+    }
+
+    @Test
+    public void testClearArgs() {
+        final JavaActionBuilder builder = getBuilderInstance();
+
+        for (final String file : ARGS) {
+            builder.withArg(file);
+        }
+
+        builder.clearArgs();
+
+        final JavaAction action = builder.build();
+
+        final List<String> argList = action.getArgs();
+        assertEquals(0, argList.size());
+    }
+
+    @Test
+    public void testFromExistingJavaAction() {
+        final JavaActionBuilder builder = getBuilderInstance();
+
+        builder.withName(NAME)
+                .withResourceManager(RESOURCE_MANAGER)
+                .withNameNode(NAME_NODE)
+                .withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT)
+                .withPrepare(new PrepareBuilder()
+                        .withDelete(PATH_TO_DELETE)
+                        .withMkdir(PATH_TO_MKDIR)
+                        .build())
+                .withLauncher(new LauncherBuilder()
+                        .withMemoryMb(1024L)
+                        .withVCores(2L)
+                        .withQueue(DEFAULT)
+                        .withSharelib(DEFAULT)
+                        .withViewAcl(DEFAULT)
+                        .withModifyAcl(DEFAULT)
+                        .build())
+                .withMainClass(DEFAULT)
+                .withJavaOptsString(DEFAULT)
+                .withJavaOpt(DEFAULT)
+                .withArg(ARGS[0])
+                .withArg(ARGS[1])
+                .withArchive(DEFAULT)
+                .withFile(DEFAULT)
+                .withCaptureOutput(true);
+
+        final JavaAction action = builder.build();
+
+        final JavaActionBuilder fromExistingBuilder = 
getBuilderInstance(action);
+
+        final String newName = "fromExisting_" + NAME;
+        fromExistingBuilder.withName(newName)
+                .withoutArg(ARGS[1])
+                .withArg(ARGS[2]);
+
+        final JavaAction modifiedAction = fromExistingBuilder.build();
+
+        assertEquals(newName, modifiedAction.getName());
+        assertEquals(action.getNameNode(), modifiedAction.getNameNode());
+
+        final Map<String, String> expectedConfiguration = new 
LinkedHashMap<>();
+        expectedConfiguration.put(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+        assertEquals(expectedConfiguration, modifiedAction.getConfiguration());
+
+        assertEquals(Arrays.asList(ARGS[0], ARGS[2]), 
modifiedAction.getArgs());
+
+        assertEquals(PATH_TO_DELETE, 
modifiedAction.getPrepare().getDeletes().get(0).getPath());
+        assertEquals(PATH_TO_MKDIR, 
modifiedAction.getPrepare().getMkdirs().get(0).getPath());
+
+        assertEquals(1024L, modifiedAction.getLauncher().getMemoryMb());
+        assertEquals(2L, modifiedAction.getLauncher().getVCores());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getQueue());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getSharelib());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getViewAcl());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getModifyAcl());
+
+        assertEquals(action.getMainClass(), modifiedAction.getMainClass());
+        assertEquals(action.getJavaOptsString(), 
modifiedAction.getJavaOptsString());
+        assertEquals(action.getJavaOpts().get(0), 
modifiedAction.getJavaOpts().get(0));
+        assertEquals(action.isCaptureOutput(), 
modifiedAction.isCaptureOutput());
+    }
+
+    @Test
+    public void testFromOtherAction() {
+        final ShellAction parent = ShellActionBuilder.create()
+                .withName("parent")
+                .build();
+
+        final ShellAction otherAction = 
ShellActionBuilder.createFromExistingAction(parent)
+                .withName("shell")
+                .withParent(parent)
+                .build();
+
+        final JavaAction fromOtherAction = 
JavaActionBuilder.createFromExistingAction(otherAction)
+                .withName("java")
+                .build();
+
+        assertEquals("java", fromOtherAction.getName());
+        assertEquals(parent, 
fromOtherAction.getParentsWithoutConditions().get(0));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestLauncherBuilder.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestLauncherBuilder.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestLauncherBuilder.java
new file mode 100644
index 0000000..acf8920
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestLauncherBuilder.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestLauncherBuilder {
+    @Test
+    public void testAttributesSetOnce() {
+        final Launcher launcher = new LauncherBuilder()
+                .withMemoryMb(1024)
+                .withVCores(2)
+                .withQueue("default")
+                .withSharelib("default")
+                .withViewAcl("default")
+                .withModifyAcl("default")
+                .build();
+
+        assertEquals(1024, launcher.getMemoryMb());
+        assertEquals(2, launcher.getVCores());
+        assertEquals("default", launcher.getQueue());
+        assertEquals("default", launcher.getSharelib());
+        assertEquals("default", launcher.getViewAcl());
+        assertEquals("default", launcher.getModifyAcl());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestMapReduceActionBuilder.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestMapReduceActionBuilder.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestMapReduceActionBuilder.java
new file mode 100644
index 0000000..e6419ff
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestMapReduceActionBuilder.java
@@ -0,0 +1,392 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestMapReduceActionBuilder extends 
TestNodeBuilderBaseImpl<MapReduceAction, MapReduceActionBuilder> {
+    private static final String NAME = "map-reduce-name";
+    private static final String NAME_NODE = "${nameNode}";
+    private static final String EXAMPLE_DIR = "/path/to/directory";
+    private static final String CONFIG_CLASS = "AnyConfigClass.class";
+    private static final String[] JOB_XMLS = {"jobXml1.xml", "jobXml2.xml", 
"jobXml3.xml", "jobXml4.xml"};
+    private static final String[] FILES = {"file1.xml", "file2.xml", 
"file3.xml", "file4.xml"};
+    private static final String[] ARCHIVES = {"archive1.jar", "archive2.jar", 
"archive3.jar", "archive4.jar"};
+    private static final String RESOURCE_MANAGER = "${resourceManager}";
+
+    private static final String MAPRED_JOB_QUEUE_NAME = 
"mapred.job.queue.name";
+    private static final String DEFAULT = "default";
+
+    @Override
+    protected MapReduceActionBuilder getBuilderInstance() {
+        return MapReduceActionBuilder.create();
+    }
+
+    @Override
+    protected MapReduceActionBuilder getBuilderInstance(final MapReduceAction 
action) {
+        return MapReduceActionBuilder.createFromExistingAction(action);
+    }
+
+    @Test
+    public void testResourceManagerAdded() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withResourceManager(RESOURCE_MANAGER);
+
+        final MapReduceAction action = builder.build();
+        assertEquals(RESOURCE_MANAGER, action.getResourceManager());
+    }
+
+    @Test
+    public void testNameNodeAdded() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withNameNode(NAME_NODE);
+
+        final MapReduceAction mrAction = builder.build();
+        assertEquals(NAME_NODE, mrAction.getNameNode());
+    }
+
+    @Test
+    public void testNameNodeAddedTwiceThrows() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withNameNode(NAME_NODE);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withNameNode("any_string");
+    }
+
+    @Test
+    public void testPrepareAdded() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withPrepare(new 
PrepareBuilder().withDelete(EXAMPLE_DIR).build());
+
+        final MapReduceAction mrAction = builder.build();
+        assertEquals(EXAMPLE_DIR, 
mrAction.getPrepare().getDeletes().get(0).getPath());
+    }
+
+    @Test
+    public void testPrepareAddedTwiceThrows() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withPrepare(new 
PrepareBuilder().withDelete(EXAMPLE_DIR).build());
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withPrepare(new 
PrepareBuilder().withDelete("any_directory").build());
+    }
+
+    @Test
+    public void testStreamingAdded() {
+        final Streaming streaming = new 
StreamingBuilder().withMapper("mapper.sh").withReducer("reducer.sh").build();
+
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withStreaming(streaming);
+
+        final MapReduceAction mrAction = builder.build();
+        assertEquals(streaming, mrAction.getStreaming());
+    }
+
+    @Test
+    public void testStreamingAddedTwiceThrows() {
+        final Streaming streaming1= new 
StreamingBuilder().withMapper("mapper1.sh").withReducer("reducer1.sh").build();
+        final Streaming streaming2 = new 
StreamingBuilder().withMapper("mapper2.sh").withReducer("reducer2.sh").build();
+
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withStreaming(streaming1);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withStreaming(streaming2);
+    }
+
+    @Test
+    public void testPipesAdded() {
+        final Pipes pipes = new 
PipesBuilder().withMap("map").withReduce("reduce").build();
+
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withPipes(pipes);
+
+        final MapReduceAction mrAction = builder.build();
+        assertEquals(pipes, mrAction.getPipes());
+    }
+
+    @Test
+    public void testPipesAddedTwiceThrows() {
+        final Pipes pipes1 = new 
PipesBuilder().withMap("map1").withReduce("reduce1").build();
+        final Pipes pipes2 = new 
PipesBuilder().withMap("map2").withReduce("reduce2").build();
+
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withPipes(pipes1);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withPipes(pipes2);
+    }
+
+    @Test
+    public void testConfigClassAdded() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withConfigClass(CONFIG_CLASS);
+
+        final MapReduceAction mrAction = builder.build();
+        assertEquals(CONFIG_CLASS, mrAction.getConfigClass());
+    }
+
+    @Test
+    public void testConfigClassAddedTwiceThrows() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withConfigClass(CONFIG_CLASS);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withConfigClass("AnyClass");
+    }
+
+    @Test
+    public void testSeveralJobXmlsAdded() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        for (final String jobXml : JOB_XMLS) {
+            builder.withJobXml(jobXml);
+        }
+
+        final MapReduceAction mrAction = builder.build();
+
+        final List<String> jobXmlsList = mrAction.getJobXmls();
+        assertEquals(JOB_XMLS.length, jobXmlsList.size());
+
+        for (int i = 0; i < JOB_XMLS.length; ++i) {
+            assertEquals(JOB_XMLS[i], jobXmlsList.get(i));
+        }
+    }
+
+    @Test
+    public void testWithoutJobXmls() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        for (final String jobXml : JOB_XMLS) {
+            builder.withJobXml(jobXml);
+        }
+
+        builder.withoutJobXml(JOB_XMLS[0]);
+
+        final MapReduceAction mrAction = builder.build();
+
+        final List<String> jobXmlsList = mrAction.getJobXmls();
+        final String[] remainingJobXmls = Arrays.copyOfRange(JOB_XMLS, 1, 
JOB_XMLS.length);
+        assertEquals(remainingJobXmls.length, jobXmlsList.size());
+
+        for (int i = 0; i < remainingJobXmls.length; ++i) {
+            assertEquals(remainingJobXmls[i], jobXmlsList.get(i));
+        }
+    }
+
+    @Test
+    public void testClearJobXmls() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        for (final String jobXml : JOB_XMLS) {
+            builder.withJobXml(jobXml);
+        }
+
+        builder.clearJobXmls();
+
+        final MapReduceAction mrAction = builder.build();
+
+        final List<String> jobXmlsList = mrAction.getJobXmls();
+        assertEquals(0, jobXmlsList.size());
+    }
+
+    @Test
+    public void testSameConfigPropertyAddedTwiceThrows() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+    }
+
+    @Test
+    public void testSeveralFilesAdded() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        for (final String file : FILES) {
+            builder.withFile(file);
+        }
+
+        final MapReduceAction mrAction = builder.build();
+
+        final List<String> filesList = mrAction.getFiles();
+        assertEquals(FILES.length, filesList.size());
+
+        for (int i = 0; i < FILES.length; ++i) {
+            assertEquals(FILES[i], filesList.get(i));
+        }
+    }
+
+    @Test
+    public void testRemoveFiles() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        for (final String file : FILES) {
+            builder.withFile(file);
+        }
+
+        builder.withoutFile(FILES[0]);
+
+        final MapReduceAction mrAction = builder.build();
+
+        final List<String> filesList = mrAction.getFiles();
+        final String[] remainingFiles = Arrays.copyOfRange(FILES, 1, 
FILES.length);
+        assertEquals(remainingFiles.length, filesList.size());
+
+        for (int i = 0; i < remainingFiles.length; ++i) {
+            assertEquals(remainingFiles[i], filesList.get(i));
+        }
+    }
+
+    @Test
+    public void testClearFiles() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        for (final String file : FILES) {
+            builder.withFile(file);
+        }
+
+        builder.clearFiles();
+
+        final MapReduceAction mrAction = builder.build();
+
+        final List<String> filesList = mrAction.getFiles();
+        assertEquals(0, filesList.size());
+    }
+
+    @Test
+    public void testSeveralArchivesAdded() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        for (final String archive : ARCHIVES) {
+            builder.withArchive(archive);
+        }
+
+        final MapReduceAction mrAction = builder.build();
+
+        final List<String> filesList = mrAction.getArchives();
+        assertEquals(ARCHIVES.length, filesList.size());
+
+        for (int i = 0; i < ARCHIVES.length; ++i) {
+            assertEquals(ARCHIVES[i], filesList.get(i));
+        }
+    }
+
+    @Test
+    public void testRemoveArchives() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        for (final String archive : ARCHIVES) {
+            builder.withArchive(archive);
+        }
+
+        builder.withoutArchive(ARCHIVES[0]);
+
+        final MapReduceAction mrAction = builder.build();
+
+        final List<String> archivesList = mrAction.getArchives();
+        final String[] remainingArchives = Arrays.copyOfRange(ARCHIVES, 1, 
ARCHIVES.length);
+        assertEquals(remainingArchives.length, archivesList.size());
+
+        for (int i = 0; i < remainingArchives.length; ++i) {
+            assertEquals(remainingArchives[i], archivesList.get(i));
+        }
+    }
+
+    @Test
+    public void testClearArchives() {
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        for (final String archive : ARCHIVES) {
+            builder.withArchive(archive);
+        }
+
+        builder.clearArchives();
+
+        final MapReduceAction mrAction = builder.build();
+
+        final List<String> archivesList = mrAction.getArchives();
+        assertEquals(0, archivesList.size());
+    }
+
+    @Test
+    public void testFromExistingActionMapReduceSpecific() {
+        final Streaming streaming = new 
StreamingBuilder().withMapper("mapper.sh").withReducer("reducer.sh").build();
+        final Pipes pipes = new 
PipesBuilder().withMap("map").withReduce("reduce").build();
+
+        final MapReduceActionBuilder builder = getBuilderInstance();
+
+        builder.withName(NAME)
+                .withNameNode(NAME_NODE)
+                .withStreaming(streaming)
+                .withPipes(pipes)
+                .withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT)
+                .withFile(FILES[0])
+                .withFile(FILES[1]);
+
+        final MapReduceAction mrAction = builder.build();
+
+        final MapReduceActionBuilder fromExistingBuilder = 
getBuilderInstance(mrAction);
+
+        final String newName = "fromExisting_" + NAME;
+        fromExistingBuilder.withName(newName)
+                .withoutFile(FILES[1])
+                .withFile(FILES[2]);
+
+        final MapReduceAction modifiedMrAction = fromExistingBuilder.build();
+
+        assertEquals(newName, modifiedMrAction.getName());
+        assertEquals(mrAction.getNameNode(), modifiedMrAction.getNameNode());
+        assertEquals(streaming, modifiedMrAction.getStreaming());
+        assertEquals(pipes, modifiedMrAction.getPipes());
+
+        final Map<String, String> expectedConfiguration = new 
LinkedHashMap<>();
+        expectedConfiguration.put(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+        assertEquals(expectedConfiguration, 
modifiedMrAction.getConfiguration());
+
+        assertEquals(Arrays.asList(FILES[0], FILES[2]), 
modifiedMrAction.getFiles());
+    }
+
+    @Test
+    public void testFromOtherAction() {
+        final ShellAction parent = ShellActionBuilder.create()
+                .withName("parent")
+                .build();
+
+        final ShellAction otherAction = 
ShellActionBuilder.createFromExistingAction(parent)
+                .withName("shell")
+                .withParent(parent)
+                .build();
+
+        final MapReduceAction fromOtherAction = 
MapReduceActionBuilder.createFromExistingAction(otherAction)
+                .withName("map-reduce")
+                .build();
+
+        assertEquals("map-reduce", fromOtherAction.getName());
+        assertEquals(parent, 
fromOtherAction.getParentsWithoutConditions().get(0));
+    }
+}

http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestMove.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestMove.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestMove.java
new file mode 100644
index 0000000..629ec96
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestMove.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestMove {
+    @Test
+    public void testSourceAndTargetAreCorrect() {
+        final String source = "/path/to/source";
+        final String target = "/path/to/target";
+
+        final Move move = new Move(source, target);
+
+        assertEquals(source, move.getSource());
+        assertEquals(target, move.getTarget());
+    }
+}

http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestNodeBuilderBaseImpl.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestNodeBuilderBaseImpl.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestNodeBuilderBaseImpl.java
new file mode 100644
index 0000000..18bfa9e
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestNodeBuilderBaseImpl.java
@@ -0,0 +1,523 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.oozie.fluentjob.api.Condition;
+import org.apache.oozie.fluentjob.api.workflow.Credential;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+
+public abstract class TestNodeBuilderBaseImpl <N extends Node,
+        B extends NodeBuilderBaseImpl<B> & Builder<N>> {
+    static final String NAME = "map-reduce-name";
+
+    @Rule
+    public final ExpectedException expectedException = 
ExpectedException.none();
+
+    protected abstract B getBuilderInstance();
+    protected abstract B getBuilderInstance(N action);
+
+    @Test
+    public final void testIncorrectSubclassingThrows() {
+        class WrongBuilder extends NodeBuilderBaseImpl<MapReduceActionBuilder> 
implements Builder<MapReduceAction> {
+
+            private WrongBuilder() {
+                super();
+            }
+
+            public MapReduceActionBuilder getRuntimeSelfReference() {
+                return MapReduceActionBuilder.create();
+            }
+
+            @Override
+            public MapReduceAction build() {
+                return null;
+            }
+        }
+
+        expectedException.expect(IllegalStateException.class);
+
+        new WrongBuilder().withName("obsolete");
+    }
+
+    @Test
+    public void testErrorHandlerAdded() {
+        final ErrorHandler errorHandler = ErrorHandler.buildAsErrorHandler(
+                MapReduceActionBuilder.create().withName("error-handler"));
+
+        final B builder = getBuilderInstance();
+        builder.withErrorHandler(errorHandler);
+
+        final N node = builder.build();
+
+        assertEquals(errorHandler, node.getErrorHandler());
+    }
+
+    @Test
+    public void testErrorHandlerAddedTwiceThrows() {
+        final ErrorHandler errorHandler1 = ErrorHandler.buildAsErrorHandler(
+                MapReduceActionBuilder.create().withName("error-handler1"));
+        final ErrorHandler errorHandler2 = ErrorHandler.buildAsErrorHandler(
+                MapReduceActionBuilder.create().withName("error-handler2"));
+
+        final B builder = getBuilderInstance();
+        builder.withErrorHandler(errorHandler1);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withErrorHandler(errorHandler2);
+    }
+
+    @Test
+    public void testWithoutErrorHandler() {
+        final ErrorHandler errorHandler = ErrorHandler.buildAsErrorHandler(
+                MapReduceActionBuilder.create().withName("error-handler"));
+
+        final B builder = getBuilderInstance();
+        builder.withErrorHandler(errorHandler);
+
+        final N node = builder.build();
+
+        final B fromExistingBuilder = getBuilderInstance(node);
+
+        fromExistingBuilder.withoutErrorHandler();
+
+        final N modifiedNode = fromExistingBuilder.build();
+
+        assertEquals(null, modifiedNode.getErrorHandler());
+    }
+
+    @Test
+    public void testRemovingErrorHandlerAfterAddingItThrows() {
+        final ErrorHandler errorHandler = ErrorHandler.buildAsErrorHandler(
+                MapReduceActionBuilder.create().withName("error-handler"));
+
+        final B builder = getBuilderInstance();
+        builder.withErrorHandler(errorHandler);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withoutErrorHandler();
+    }
+
+    @Test
+    public void testAddParents() {
+        final N parent1 = Mockito.spy(getBuilderInstance().build());
+        final N parent2 = Mockito.spy(getBuilderInstance().build());
+
+        final B builder = getBuilderInstance();
+        builder.withParent(parent1)
+                .withParent(parent2);
+
+        final N child = builder.build();
+
+        assertEquals(Arrays.asList(parent1, parent2), child.getAllParents());
+
+        Mockito.verify(parent1).addChild(child);
+        Mockito.verify(parent2).addChild(child);
+
+        Mockito.verifyNoMoreInteractions(parent1);
+        Mockito.verifyNoMoreInteractions(parent2);
+    }
+
+    @Test
+    public void testWithConditionalParents() {
+        final String condition1 = "condition1";
+        final String condition2 = "condition2";
+
+        final N parent1 = Mockito.spy(getBuilderInstance().build());
+        final N parent2 = Mockito.spy(getBuilderInstance().build());
+
+        final B builder = getBuilderInstance();
+        builder.withParentWithCondition(parent1, condition1)
+                .withParentWithCondition(parent2, condition2);
+
+        final N child = builder.build();
+
+        final List<Node.NodeWithCondition> nodesWithConditions = 
child.getParentsWithConditions();
+
+        assertEquals(parent1, nodesWithConditions.get(0).getNode());
+        assertEquals(Condition.actualCondition(condition1), 
nodesWithConditions.get(0).getCondition());
+
+        assertEquals(parent2, nodesWithConditions.get(1).getNode());
+        assertEquals(Condition.actualCondition(condition2), 
nodesWithConditions.get(1).getCondition());
+
+        Mockito.verify(parent1).addChildWithCondition(child, condition1);
+        Mockito.verify(parent2).addChildWithCondition(child, condition2);
+
+        Mockito.verifyNoMoreInteractions(parent1);
+        Mockito.verifyNoMoreInteractions(parent2);
+    }
+
+    @Test
+    public void testAddingDuplicateParentBothTimesWithoutConditionThrows() {
+        final N parent = getBuilderInstance().build();
+
+        final B builder = getBuilderInstance();
+
+        builder.withParent(parent);
+
+        expectedException.expect(IllegalArgumentException.class);
+        builder.withParent(parent);
+    }
+
+    @Test
+    public void testAddingDuplicateParentBothTimesWithConditionThrows() {
+        final N parent = getBuilderInstance().build();
+
+        final B builder = getBuilderInstance();
+
+        builder.withParentWithCondition(parent, "condition1");
+
+        expectedException.expect(IllegalArgumentException.class);
+        builder.withParentWithCondition(parent, "condition2");
+    }
+
+    @Test
+    public void 
testAddingDuplicateParentFirstWithoutConditionThenWithConditionThrows() {
+        final N parent = getBuilderInstance().build();
+
+        final B builder = getBuilderInstance();
+
+        builder.withParent(parent);
+
+        expectedException.expect(IllegalArgumentException.class);
+        builder.withParentWithCondition(parent, "any_condition");
+    }
+
+    @Test
+    public void 
testAddingDuplicateParentFirstWithConditionThenWithoutConditionThrows() {
+        final N parent = getBuilderInstance().build();
+
+        final B builder = getBuilderInstance();
+
+        builder.withParentWithCondition(parent, "condition");
+
+        expectedException.expect(IllegalArgumentException.class);
+        builder.withParent(parent);
+    }
+
+    @Test
+    public void testWithoutParent() {
+        final N parent1 = Mockito.spy(getBuilderInstance().build());
+        final N parent2 = Mockito.spy(getBuilderInstance().build());
+
+        final B builder = getBuilderInstance();
+        builder.withParent(parent1)
+                .withParent(parent2);
+
+        builder.withoutParent(parent2);
+
+        final N child = builder.build();
+
+        assertEquals(Arrays.asList(parent1), child.getAllParents());
+
+        Mockito.verify(parent1).addChild(child);
+
+        Mockito.verifyNoMoreInteractions(parent1);
+        Mockito.verifyNoMoreInteractions(parent2);
+    }
+
+    @Test
+    public void testAddParentWithAndWithoutCondition() {
+        final Node parent1 = getBuilderInstance().build();
+        final Node parent2 = getBuilderInstance().build();
+
+        final String condition = "condition";
+
+        final Node child = getBuilderInstance()
+                .withParent(parent1)
+                .withParentWithCondition(parent2, condition)
+                .build();
+
+        assertEquals(Arrays.asList(parent1, parent2), child.getAllParents());
+        assertEquals(Arrays.asList(parent1), 
child.getParentsWithoutConditions());
+
+        final List<Node.NodeWithCondition> parentsWithConditions = 
child.getParentsWithConditions();
+        assertEquals(parent2, parentsWithConditions.get(0).getNode());
+        assertEquals(condition, 
parentsWithConditions.get(0).getCondition().getCondition());
+    }
+
+    @Test
+    public void testAddDuplicateDefaultParentTwiceAsDefaultThrows() {
+        final Node parent = getBuilderInstance().build();
+
+        final NodeBuilderBaseImpl<B> builder = getBuilderInstance()
+                .withParentDefaultConditional(parent);
+
+        expectedException.expect(IllegalArgumentException.class);
+        builder.withParentDefaultConditional(parent);
+    }
+
+    @Test
+    public void testAddDuplicateDefaultParentFirstAsNormalConditionalThrows() {
+        final Node parent = getBuilderInstance().build();
+
+        final NodeBuilderBaseImpl<B> builder = getBuilderInstance()
+                .withParentWithCondition(parent, "any_condition");
+
+        expectedException.expect(IllegalArgumentException.class);
+        builder.withParentDefaultConditional(parent);
+    }
+
+    @Test
+    public void testAddMultipleDefaultConditionalChildrenThrows() {
+        final N parent = getBuilderInstance().withName("parent").build();
+
+        
getBuilderInstance().withName("defaultChild1").withParentDefaultConditional(parent).build();
+
+        final B defaultChild2Builder = 
getBuilderInstance().withName("defaultChild2").withParentDefaultConditional(parent);
+
+        expectedException.expect(IllegalStateException.class);
+        defaultChild2Builder.build();
+    }
+
+    @Test
+    public void testWithoutParentWhenConditionExists() {
+        final Node parent1 = getBuilderInstance().build();
+        final Node parent2 = getBuilderInstance().build();
+        final Node parent3 = getBuilderInstance().build();
+        final Node parent4 = getBuilderInstance().build();
+
+        final String condition1 = "condition1";
+        final String condition2 = "condition2";
+
+        final B builder = getBuilderInstance()
+                .withParentWithCondition(parent1, condition1)
+                .withParentWithCondition(parent2, condition2)
+                .withParent(parent3)
+                .withParent(parent4);
+
+        builder.withoutParent(parent2);
+
+        final N child = builder.build();
+
+        assertEquals(Arrays.asList(parent3, parent4, parent1), 
child.getAllParents());
+        assertEquals(Arrays.asList(parent3, parent4), 
child.getParentsWithoutConditions());
+
+        final List<Node.NodeWithCondition> parentsWithConditions = 
child.getParentsWithConditions();
+        assertEquals(parent1, parentsWithConditions.get(0).getNode());
+        assertEquals(condition1, 
parentsWithConditions.get(0).getCondition().getCondition());
+    }
+
+    @Test
+    public void testAddedAsParentWithCondition() {
+        final N parent = getBuilderInstance().withName("parent").build();
+
+        final String condition1 = "condition1";
+        final String condition2 = "condition2";
+
+        final N child1 = 
getBuilderInstance().withName("child1").withParentWithCondition(parent, 
condition1).build();
+        final N child2 = 
getBuilderInstance().withName("child2").withParentWithCondition(parent, 
condition2).build();
+        final N defaultChild = 
getBuilderInstance().withName("defaultChild").withParentDefaultConditional(parent).build();
+
+
+        final List<Node.NodeWithCondition> childrenWithConditions = 
parent.getChildrenWithConditions();
+
+        assertEquals(3, childrenWithConditions.size());
+
+        assertEquals(child1, childrenWithConditions.get(0).getNode());
+        assertEquals(condition1, 
childrenWithConditions.get(0).getCondition().getCondition());
+
+        assertEquals(child2, childrenWithConditions.get(1).getNode());
+        assertEquals(condition2, 
childrenWithConditions.get(1).getCondition().getCondition());
+
+        assertEquals(defaultChild, childrenWithConditions.get(2).getNode());
+        assertTrue(childrenWithConditions.get(2).getCondition().isDefault());
+
+        assertEquals(defaultChild, parent.getDefaultConditionalChild());
+
+        assertEquals(Arrays.asList(child1, child2, defaultChild), 
parent.getAllChildren());
+    }
+
+    @Test
+    public void testAddedAsParentWithoutCondition() {
+        final N parent = getBuilderInstance().withName("parent").build();
+
+        final N child1 = 
getBuilderInstance().withName("child1").withParent(parent).build();
+        final N child2 = 
getBuilderInstance().withName("child2").withParent(parent).build();
+
+
+        final List<Node> childrenWithoutConditions = 
parent.getChildrenWithoutConditions();
+
+        assertEquals(Arrays.asList(child1, child2), childrenWithoutConditions);
+    }
+
+    @Test
+    public void 
testAddedAsParentWithConditionWhenChildWithoutConditionExistsThrows() {
+        final N parent = getBuilderInstance().build();
+
+        getBuilderInstance()
+                .withParent(parent)
+                .build();
+        final B child2builder = getBuilderInstance()
+                .withParentWithCondition(parent, "any_condition");
+
+        expectedException.expect(IllegalStateException.class);
+        child2builder.build();
+    }
+
+    @Test
+    public void 
testAddedAsParentWithoutConditionWhenChildWithConditionExistsThrows() {
+        final N parent = getBuilderInstance().build();
+
+        getBuilderInstance()
+                .withParentWithCondition(parent, "any_condition")
+                .build();
+        final B child2builder = getBuilderInstance()
+                .withParent(parent);
+
+        expectedException.expect(IllegalStateException.class);
+        child2builder.build();
+    }
+
+    @Test
+    public void testClearParents() {
+        final N parent1 = Mockito.spy(getBuilderInstance().build());
+        final N parent2 = Mockito.spy(getBuilderInstance().build());
+        final N parent3 = Mockito.spy(getBuilderInstance().build());
+
+        final B builder = getBuilderInstance();
+        builder.withParent(parent1)
+                .withParent(parent2)
+                .withParentWithCondition(parent3, "any_condition");
+
+        builder.clearParents();
+
+        final N child = builder.build();
+
+        assertEquals(0, child.getAllParents().size());
+
+        Mockito.verifyNoMoreInteractions(parent1);
+        Mockito.verifyNoMoreInteractions(parent2);
+        Mockito.verifyNoMoreInteractions(parent3);
+    }
+
+    @Test
+    public void testNameAdded() {
+        final B builder = getBuilderInstance();
+        builder.withName(NAME);
+
+        final N action = builder.build();
+        assertEquals(NAME, action.getName());
+    }
+
+    @Test
+    public void testNameAddedTwiceThrows() {
+        final B builder = getBuilderInstance();
+        builder.withName(NAME);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withName("any_name");
+    }
+
+    @Test
+    public void testCredentialAddedAndRemoved() {
+        final Credential first = new Credential("first name", "first type", 
ImmutableList.of());
+        final Credential second = new Credential("second name", "second type", 
ImmutableList.of());
+
+        final B builder = getBuilderInstance();
+        builder.withCredential(first);
+        builder.withCredential(second);
+
+        assertEquals(2, builder.build().getCredentials().size());
+        assertEquals(first, builder.build().getCredentials().get(0));
+        assertEquals(second, builder.build().getCredentials().get(1));
+
+        builder.withoutCredential(first);
+
+        assertEquals(1, builder.build().getCredentials().size());
+        assertEquals(second, builder.build().getCredentials().get(0));
+
+        builder.clearCredentials();
+        assertEquals(0, builder.build().getCredentials().size());
+    }
+
+    @Test
+    public void testRetryAttributesAddedTwiceThrows() {
+        final B builder = getBuilderInstance();
+
+        builder.withRetryInterval(1);
+        builder.withRetryMax(3);
+        builder.withRetryPolicy("retry-policy");
+
+        assertEquals(Integer.valueOf(1), builder.build().getRetryInterval());
+        assertEquals(Integer.valueOf(3), builder.build().getRetryMax());
+        assertEquals("retry-policy", builder.build().getRetryPolicy());
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withRetryInterval(null);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withRetryMax(null);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withRetryPolicy(null);
+    }
+
+    @Test
+    public void testFromExistingNode() {
+        final ErrorHandler errorHandler = ErrorHandler.buildAsErrorHandler(
+                MapReduceActionBuilder.create().withName("error-handler"));
+
+        final Node parent1 = 
MapReduceActionBuilder.create().withName("parent1").build();
+        final Node parent2 = 
MapReduceActionBuilder.create().withName("parent2").build();
+        final Node parent3 = 
MapReduceActionBuilder.create().withName("parent3").build();
+        final Node parent4 = 
MapReduceActionBuilder.create().withName("parent4").build();
+
+        final String condition = "condition";
+
+        final B builder = getBuilderInstance();
+
+        builder.withName(NAME)
+                .withParent(parent1)
+                .withParent(parent2)
+                .withParentWithCondition(parent4, condition)
+                .withErrorHandler(errorHandler);
+
+        final N node = builder.build();
+
+        final B fromExistingBuilder = getBuilderInstance(node);
+
+        final String newName = "fromExisting_" + NAME;
+        fromExistingBuilder.withName(newName)
+                .withoutParent(parent2)
+                .withParent(parent3);
+
+        final Node modifiedNode = fromExistingBuilder.build();
+
+        assertEquals(newName, modifiedNode.getName());
+        assertEquals(Arrays.asList(parent1, parent3, parent4), 
modifiedNode.getAllParents());
+        assertEquals(Arrays.asList(parent1, parent3), 
modifiedNode.getParentsWithoutConditions());
+        assertEquals(errorHandler, modifiedNode.getErrorHandler());
+
+        final List<Node.NodeWithCondition> parentsWithConditions = 
modifiedNode.getParentsWithConditions();
+        assertEquals(1, parentsWithConditions.size());
+        assertEquals(parent4, parentsWithConditions.get(0).getNode());
+        assertEquals(condition, 
parentsWithConditions.get(0).getCondition().getCondition());
+    }
+}

http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPigActionBuilder.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPigActionBuilder.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPigActionBuilder.java
new file mode 100644
index 0000000..d8f0918
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPigActionBuilder.java
@@ -0,0 +1,218 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestPigActionBuilder extends TestNodeBuilderBaseImpl<PigAction, 
PigActionBuilder> {
+    private static final String NAME = "pig-name";
+    private static final String NAME_NODE = "${nameNode}";
+    private static final String EXAMPLE_DIR = "/path/to/directory";
+    private static final String[] ARGS = {"arg1", "arg2", "arg3"};
+    private static final String MAPRED_JOB_QUEUE_NAME = 
"mapred.job.queue.name";
+    private static final String DEFAULT = "default";
+    private static final String RESOURCE_MANAGER = "${resourceManager}";
+    private static final String PATH_TO_DELETE = "/path/to/delete";
+    private static final String PATH_TO_MKDIR = "/path/to/mkdir";
+
+    @Override
+    protected PigActionBuilder getBuilderInstance() {
+        return PigActionBuilder.create();
+    }
+
+    @Override
+    protected PigActionBuilder getBuilderInstance(final PigAction action) {
+        return PigActionBuilder.createFromExistingAction(action);
+    }
+
+    @Test
+    public void testResourceManagerAdded() {
+        final PigActionBuilder builder = getBuilderInstance();
+        builder.withResourceManager(RESOURCE_MANAGER);
+
+        final PigAction action = builder.build();
+        assertEquals(RESOURCE_MANAGER, action.getResourceManager());
+    }
+
+    @Test
+    public void testNameNodeAdded() {
+        final PigActionBuilder builder = getBuilderInstance();
+        builder.withNameNode(NAME_NODE);
+
+        final PigAction action = builder.build();
+        assertEquals(NAME_NODE, action.getNameNode());
+    }
+
+    @Test
+    public void testPrepareAdded() {
+        final PigActionBuilder builder = getBuilderInstance();
+        builder.withPrepare(new 
PrepareBuilder().withDelete(EXAMPLE_DIR).build());
+
+        final PigAction action = builder.build();
+        assertEquals(EXAMPLE_DIR, 
action.getPrepare().getDeletes().get(0).getPath());
+    }
+
+    @Test
+    public void testSameConfigPropertyAddedTwiceThrows() {
+        final PigActionBuilder builder = getBuilderInstance();
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+    }
+
+    @Test
+    public void testSeveralArgsAdded() {
+        final PigActionBuilder builder = getBuilderInstance();
+
+        for (final String arg : ARGS) {
+            builder.withArg(arg);
+        }
+
+        final PigAction action = builder.build();
+
+        final List<String> argList = action.getArgs();
+        assertEquals(ARGS.length, argList.size());
+
+        for (int i = 0; i < ARGS.length; ++i) {
+            assertEquals(ARGS[i], argList.get(i));
+        }
+    }
+
+    @Test
+    public void testRemoveArgs() {
+        final PigActionBuilder builder = getBuilderInstance();
+
+        for (final String file : ARGS) {
+            builder.withArg(file);
+        }
+
+        builder.withoutArg(ARGS[0]);
+
+        final PigAction action = builder.build();
+
+        final List<String> argList = action.getArgs();
+        final String[] remainingArgs = Arrays.copyOfRange(ARGS, 1, 
ARGS.length);
+        assertEquals(remainingArgs.length, argList.size());
+
+        for (int i = 0; i < remainingArgs.length; ++i) {
+            assertEquals(remainingArgs[i], argList.get(i));
+        }
+    }
+
+    @Test
+    public void testClearArgs() {
+        final PigActionBuilder builder = getBuilderInstance();
+
+        for (final String file : ARGS) {
+            builder.withArg(file);
+        }
+
+        builder.clearArgs();
+
+        final PigAction action = builder.build();
+
+        final List<String> argList = action.getArgs();
+        assertEquals(0, argList.size());
+    }
+
+    @Test
+    public void testFromExistingPigAction() {
+        final PigActionBuilder builder = getBuilderInstance();
+
+        builder.withName(NAME)
+                .withResourceManager(RESOURCE_MANAGER)
+                .withNameNode(NAME_NODE)
+                .withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT)
+                .withPrepare(new PrepareBuilder()
+                        .withDelete(PATH_TO_DELETE)
+                        .withMkdir(PATH_TO_MKDIR)
+                        .build())
+                .withLauncher(new LauncherBuilder()
+                        .withMemoryMb(1024L)
+                        .withVCores(2L)
+                        .withQueue(DEFAULT)
+                        .withSharelib(DEFAULT)
+                        .withViewAcl(DEFAULT)
+                        .withModifyAcl(DEFAULT)
+                        .build())
+                .withArg(ARGS[0])
+                .withArg(ARGS[1])
+                .withArchive(DEFAULT)
+                .withFile(DEFAULT);
+
+        final PigAction action = builder.build();
+
+        final PigActionBuilder fromExistingBuilder = 
getBuilderInstance(action);
+
+        final String newName = "fromExisting_" + NAME;
+        fromExistingBuilder.withName(newName)
+                .withoutArg(ARGS[1])
+                .withArg(ARGS[2]);
+
+        final PigAction modifiedAction = fromExistingBuilder.build();
+
+        assertEquals(newName, modifiedAction.getName());
+        assertEquals(action.getNameNode(), modifiedAction.getNameNode());
+
+        final Map<String, String> expectedConfiguration = new 
LinkedHashMap<>();
+        expectedConfiguration.put(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+        assertEquals(expectedConfiguration, modifiedAction.getConfiguration());
+
+        assertEquals(Arrays.asList(ARGS[0], ARGS[2]), 
modifiedAction.getArgs());
+
+        assertEquals(PATH_TO_DELETE, 
modifiedAction.getPrepare().getDeletes().get(0).getPath());
+        assertEquals(PATH_TO_MKDIR, 
modifiedAction.getPrepare().getMkdirs().get(0).getPath());
+
+        assertEquals(1024L, modifiedAction.getLauncher().getMemoryMb());
+        assertEquals(2L, modifiedAction.getLauncher().getVCores());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getQueue());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getSharelib());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getViewAcl());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getModifyAcl());
+
+        assertEquals(action.getScript(), modifiedAction.getScript());
+    }
+
+    @Test
+    public void testFromOtherAction() {
+        final ShellAction parent = ShellActionBuilder.create()
+                .withName("parent")
+                .build();
+
+        final ShellAction otherAction = 
ShellActionBuilder.createFromExistingAction(parent)
+                .withName("shell")
+                .withParent(parent)
+                .build();
+
+        final PigAction fromOtherAction = 
PigActionBuilder.createFromExistingAction(otherAction)
+                .withName("pig")
+                .build();
+
+        assertEquals("pig", fromOtherAction.getName());
+        assertEquals(parent, 
fromOtherAction.getParentsWithoutConditions().get(0));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPipesBuilder.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPipesBuilder.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPipesBuilder.java
new file mode 100644
index 0000000..7b0ce07
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPipesBuilder.java
@@ -0,0 +1,168 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestPipesBuilder {
+    @Rule
+    public final ExpectedException expectedException = 
ExpectedException.none();
+
+    @Test
+    public void testWithMap() {
+        final String map = "map";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withMap(map);
+
+        final Pipes pipes = builder.build();
+        assertEquals(map, pipes.getMap());
+    }
+
+    @Test
+    public void testMapCalledTwiceThrows() {
+        final String map1 = "map1";
+        final String map2 = "map2";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withMap(map1);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withMap(map2);
+    }
+
+    @Test
+    public void testWithReduce() {
+        final String reduce = "reduce";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withReduce(reduce);
+
+        final Pipes pipes = builder.build();
+        assertEquals(reduce, pipes.getReduce());
+    }
+
+    @Test
+    public void testWithReduceCalledTwiceThrows() {
+        final String reduce1 = "reduce1";
+        final String reduce2= "reduce2";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withReduce(reduce1);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withReduce(reduce2);
+    }
+
+    @Test
+    public void testWithInputformat() {
+        final String inputformat = "inputformat";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withInputformat(inputformat);
+
+        final Pipes pipes = builder.build();
+        assertEquals(inputformat, pipes.getInputformat());
+    }
+
+    @Test
+    public void testWithInputformatCalledTwiceThrows() {
+        final String inputformat1 = "inputformat1";
+        final String inputformat2 = "inputformat2";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withInputformat(inputformat1);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withInputformat(inputformat2);
+    }
+
+    @Test
+    public void testWithPartitioner() {
+        final String partitioner = "partitioner";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withPartitioner(partitioner);
+
+        final Pipes pipes = builder.build();
+        assertEquals(partitioner, pipes.getPartitioner());
+    }
+
+    @Test
+    public void testWithPartitionerCalledTwiceThrows() {
+        final String partitioner1 = "partitioner1";
+        final String partitioner2 = "partitioner2";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withPartitioner(partitioner1);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withPartitioner(partitioner2);
+    }
+
+    @Test
+    public void testWithWriter() {
+        final String writer = "writer";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withWriter(writer);
+
+        final Pipes pipes = builder.build();
+        assertEquals(writer, pipes.getWriter());
+    }
+
+    @Test
+    public void testWithWriterCalledTwiceThrows() {
+        final String writer1 = "writer1";
+        final String writer2 = "writer2";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withWriter(writer1);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withWriter(writer2);
+    }
+
+    @Test
+    public void testWithProgram() {
+        final String program = "program";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withProgram(program);
+
+        final Pipes pipes = builder.build();
+        assertEquals(program, pipes.getProgram());
+    }
+
+    @Test
+    public void testWithProgramCalledTwiceThrows() {
+        final String program1 = "program1";
+        final String program2 = "program2";
+
+        final PipesBuilder builder = new PipesBuilder();
+        builder.withProgram(program1);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withProgram(program2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPrepareBuilder.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPrepareBuilder.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPrepareBuilder.java
new file mode 100644
index 0000000..37a6dbd
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestPrepareBuilder.java
@@ -0,0 +1,105 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestPrepareBuilder {
+    private static final String[] TEST_FOLDER_NAMES = {
+            "/user/testpath/testdir1",
+            "/user/testpath/testdir2",
+            "/user/testpath/testdir3"
+    };
+
+    private PrepareBuilder pb;
+
+    @Before
+    public void setUp() {
+        pb = new PrepareBuilder();
+    }
+
+    @Test
+    public void testOneDeleteIsAddedWithSkipTrashTrue() {
+        pb.withDelete(TEST_FOLDER_NAMES[0], true);
+
+        final Prepare prepare = pb.build();
+
+        assertEquals(1, prepare.getDeletes().size());
+
+        final Delete delete = prepare.getDeletes().get(0);
+        assertEquals(TEST_FOLDER_NAMES[0], delete.getPath());
+        assertEquals(true, delete.getSkipTrash());
+
+        assertEquals(0, prepare.getMkdirs().size());
+    }
+
+    @Test
+    public void testSeveralDeletesAreAddedWithSkipTrashNotSpecified() {
+        for (final String testDir : TEST_FOLDER_NAMES) {
+            pb.withDelete(testDir);
+        }
+
+        final Prepare prepare = pb.build();
+
+        assertEquals(TEST_FOLDER_NAMES.length, prepare.getDeletes().size());
+
+        for (int i = 0; i < TEST_FOLDER_NAMES.length; ++i) {
+            final Delete delete = prepare.getDeletes().get(i);
+            assertEquals(TEST_FOLDER_NAMES[i], delete.getPath());
+            assertEquals(null, delete.getSkipTrash());
+        }
+
+        assertEquals(0, prepare.getMkdirs().size());
+    }
+
+    @Test
+    public void testOneMkdirIsAdded() {
+        pb.withMkdir(TEST_FOLDER_NAMES[0]);
+
+        final Prepare prepare = pb.build();
+
+        assertEquals(1, prepare.getMkdirs().size());
+
+        final Mkdir mkdir = prepare.getMkdirs().get(0);
+        assertEquals(TEST_FOLDER_NAMES[0], mkdir.getPath());
+
+        assertEquals(0, prepare.getDeletes().size());
+    }
+
+    @Test
+    public void testSeveralMkdirsAreAdded() {
+        for (final String testDir : TEST_FOLDER_NAMES) {
+            pb.withMkdir(testDir);
+        }
+
+        final Prepare prepare = pb.build();
+
+        assertEquals(TEST_FOLDER_NAMES.length, prepare.getMkdirs().size());
+
+        for (int i = 0; i < TEST_FOLDER_NAMES.length; ++i) {
+            final Mkdir mkdir = prepare.getMkdirs().get(i);
+            assertEquals(TEST_FOLDER_NAMES[i], mkdir.getPath());
+        }
+
+        assertEquals(0, prepare.getDeletes().size());
+    }
+}

http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestShellActionBuilder.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestShellActionBuilder.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestShellActionBuilder.java
new file mode 100644
index 0000000..7ffec51
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestShellActionBuilder.java
@@ -0,0 +1,223 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestShellActionBuilder extends 
TestNodeBuilderBaseImpl<ShellAction, ShellActionBuilder> {
+    private static final String NAME = "shell-name";
+    private static final String NAME_NODE = "${nameNode}";
+    private static final String EXAMPLE_DIR = "/path/to/directory";
+    private static final String[] ARGS = {"arg1", "arg2", "arg3"};
+    private static final String MAPRED_JOB_QUEUE_NAME = 
"mapred.job.queue.name";
+    private static final String DEFAULT = "default";
+    private static final String RESOURCE_MANAGER = "${resourceManager}";
+    private static final String PATH_TO_DELETE = "/path/to/delete";
+    private static final String PATH_TO_MKDIR = "/path/to/mkdir";
+
+    @Override
+    protected ShellActionBuilder getBuilderInstance() {
+        return ShellActionBuilder.create();
+    }
+
+    @Override
+    protected ShellActionBuilder getBuilderInstance(final ShellAction action) {
+        return ShellActionBuilder.createFromExistingAction(action);
+    }
+
+    @Test
+    public void testResourceManagerAdded() {
+        final ShellActionBuilder builder = getBuilderInstance();
+        builder.withResourceManager(RESOURCE_MANAGER);
+
+        final ShellAction action = builder.build();
+        assertEquals(RESOURCE_MANAGER, action.getResourceManager());
+    }
+
+    @Test
+    public void testNameNodeAdded() {
+        final ShellActionBuilder builder = getBuilderInstance();
+        builder.withNameNode(NAME_NODE);
+
+        final ShellAction action = builder.build();
+        assertEquals(NAME_NODE, action.getNameNode());
+    }
+
+    @Test
+    public void testPrepareAdded() {
+        final ShellActionBuilder builder = getBuilderInstance();
+        builder.withPrepare(new 
PrepareBuilder().withDelete(EXAMPLE_DIR).build());
+
+        final ShellAction action = builder.build();
+        assertEquals(EXAMPLE_DIR, 
action.getPrepare().getDeletes().get(0).getPath());
+    }
+
+    @Test
+    public void testSameConfigPropertyAddedTwiceThrows() {
+        final ShellActionBuilder builder = getBuilderInstance();
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+    }
+
+    @Test
+    public void testSeveralArgumentsAdded() {
+        final ShellActionBuilder builder = getBuilderInstance();
+
+        for (final String arg : ARGS) {
+            builder.withArgument(arg);
+        }
+
+        final ShellAction action = builder.build();
+
+        final List<String> argList = action.getArguments();
+        assertEquals(ARGS.length, argList.size());
+
+        for (int i = 0; i < ARGS.length; ++i) {
+            assertEquals(ARGS[i], argList.get(i));
+        }
+    }
+
+    @Test
+    public void testRemoveArguments() {
+        final ShellActionBuilder builder = getBuilderInstance();
+
+        for (final String file : ARGS) {
+            builder.withArgument(file);
+        }
+
+        builder.withoutArgument(ARGS[0]);
+
+        final ShellAction action = builder.build();
+
+        final List<String> argList = action.getArguments();
+        final String[] remainingArgs = Arrays.copyOfRange(ARGS, 1, 
ARGS.length);
+        assertEquals(remainingArgs.length, argList.size());
+
+        for (int i = 0; i < remainingArgs.length; ++i) {
+            assertEquals(remainingArgs[i], argList.get(i));
+        }
+    }
+
+    @Test
+    public void testClearArguments() {
+        final ShellActionBuilder builder = getBuilderInstance();
+
+        for (final String file : ARGS) {
+            builder.withArgument(file);
+        }
+
+        builder.clearArguments();
+
+        final ShellAction action = builder.build();
+
+        final List<String> argList = action.getArguments();
+        assertEquals(0, argList.size());
+    }
+
+    @Test
+    public void testFromExistingShellAction() {
+        final ShellActionBuilder builder = getBuilderInstance();
+
+        builder.withName(NAME)
+                .withResourceManager(RESOURCE_MANAGER)
+                .withNameNode(NAME_NODE)
+                .withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT)
+                .withPrepare(new PrepareBuilder()
+                        .withDelete(PATH_TO_DELETE)
+                        .withMkdir(PATH_TO_MKDIR)
+                        .build())
+                .withLauncher(new LauncherBuilder()
+                        .withMemoryMb(1024L)
+                        .withVCores(2L)
+                        .withQueue(DEFAULT)
+                        .withSharelib(DEFAULT)
+                        .withViewAcl(DEFAULT)
+                        .withModifyAcl(DEFAULT)
+                        .build())
+                .withExecutable(DEFAULT)
+                .withEnvironmentVariable(DEFAULT)
+                .withArgument(ARGS[0])
+                .withArgument(ARGS[1])
+                .withArchive(DEFAULT)
+                .withFile(DEFAULT)
+                .withCaptureOutput(true);
+
+        final ShellAction action = builder.build();
+
+        final ShellActionBuilder fromExistingBuilder = 
getBuilderInstance(action);
+
+        final String newName = "fromExisting_" + NAME;
+        fromExistingBuilder.withName(newName)
+                .withoutArgument(ARGS[1])
+                .withArgument(ARGS[2]);
+
+        final ShellAction modifiedAction = fromExistingBuilder.build();
+
+        assertEquals(newName, modifiedAction.getName());
+        assertEquals(action.getNameNode(), modifiedAction.getNameNode());
+
+        final Map<String, String> expectedConfiguration = new 
LinkedHashMap<>();
+        expectedConfiguration.put(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+        assertEquals(expectedConfiguration, modifiedAction.getConfiguration());
+
+        assertEquals(Arrays.asList(ARGS[0], ARGS[2]), 
modifiedAction.getArguments());
+
+        assertEquals(PATH_TO_DELETE, 
modifiedAction.getPrepare().getDeletes().get(0).getPath());
+        assertEquals(PATH_TO_MKDIR, 
modifiedAction.getPrepare().getMkdirs().get(0).getPath());
+
+        assertEquals(1024L, modifiedAction.getLauncher().getMemoryMb());
+        assertEquals(2L, modifiedAction.getLauncher().getVCores());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getQueue());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getSharelib());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getViewAcl());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getModifyAcl());
+
+        assertEquals(action.getExecutable(), modifiedAction.getExecutable());
+        assertEquals(action.getEnvironmentVariables().get(0), 
modifiedAction.getEnvironmentVariables().get(0));
+        assertEquals(action.isCaptureOutput(), 
modifiedAction.isCaptureOutput());
+    }
+
+    @Test
+    public void testFromOtherAction() {
+        final PigAction parent = PigActionBuilder.create()
+                .withName("parent")
+                .build();
+
+        final PigAction otherAction = 
PigActionBuilder.createFromExistingAction(parent)
+                .withName("pig")
+                .withParent(parent)
+                .build();
+
+        final ShellAction fromOtherAction = 
ShellActionBuilder.createFromExistingAction(otherAction)
+                .withName("shell")
+                .build();
+
+        assertEquals("shell", fromOtherAction.getName());
+        assertEquals(parent, 
fromOtherAction.getParentsWithoutConditions().get(0));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/oozie/blob/8a0a6487/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestSparkActionBuilder.java
----------------------------------------------------------------------
diff --git 
a/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestSparkActionBuilder.java
 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestSparkActionBuilder.java
new file mode 100644
index 0000000..0572e94
--- /dev/null
+++ 
b/fluent-job/fluent-job-api/src/test/java/org/apache/oozie/fluentjob/api/action/TestSparkActionBuilder.java
@@ -0,0 +1,229 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.oozie.fluentjob.api.action;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestSparkActionBuilder extends 
TestNodeBuilderBaseImpl<SparkAction, SparkActionBuilder> {
+    private static final String NAME = "spark-name";
+    private static final String NAME_NODE = "${nameNode}";
+    private static final String EXAMPLE_DIR = "/path/to/directory";
+    private static final String[] ARGS = {"arg1", "arg2", "arg3"};
+    private static final String MAPRED_JOB_QUEUE_NAME = 
"mapred.job.queue.name";
+    private static final String DEFAULT = "default";
+    private static final String RESOURCE_MANAGER = "${resourceManager}";
+    private static final String PATH_TO_DELETE = "/path/to/delete";
+    private static final String PATH_TO_MKDIR = "/path/to/mkdir";
+
+    @Override
+    protected SparkActionBuilder getBuilderInstance() {
+        return SparkActionBuilder.create();
+    }
+
+    @Override
+    protected SparkActionBuilder getBuilderInstance(final SparkAction action) {
+        return SparkActionBuilder.createFromExistingAction(action);
+    }
+
+    @Test
+    public void testResourceManagerAdded() {
+        final SparkActionBuilder builder = getBuilderInstance();
+        builder.withResourceManager(RESOURCE_MANAGER);
+
+        final SparkAction action = builder.build();
+        assertEquals(RESOURCE_MANAGER, action.getResourceManager());
+    }
+
+    @Test
+    public void testNameNodeAdded() {
+        final SparkActionBuilder builder = getBuilderInstance();
+        builder.withNameNode(NAME_NODE);
+
+        final SparkAction action = builder.build();
+        assertEquals(NAME_NODE, action.getNameNode());
+    }
+
+    @Test
+    public void testPrepareAdded() {
+        final SparkActionBuilder builder = getBuilderInstance();
+        builder.withPrepare(new 
PrepareBuilder().withDelete(EXAMPLE_DIR).build());
+
+        final SparkAction action = builder.build();
+        assertEquals(EXAMPLE_DIR, 
action.getPrepare().getDeletes().get(0).getPath());
+    }
+
+    @Test
+    public void testSameConfigPropertyAddedTwiceThrows() {
+        final SparkActionBuilder builder = getBuilderInstance();
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+
+        expectedException.expect(IllegalStateException.class);
+        builder.withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+    }
+
+    @Test
+    public void testSeveralArgsAdded() {
+        final SparkActionBuilder builder = getBuilderInstance();
+
+        for (final String arg : ARGS) {
+            builder.withArg(arg);
+        }
+
+        final SparkAction action = builder.build();
+
+        final List<String> argList = action.getArgs();
+        assertEquals(ARGS.length, argList.size());
+
+        for (int i = 0; i < ARGS.length; ++i) {
+            assertEquals(ARGS[i], argList.get(i));
+        }
+    }
+
+    @Test
+    public void testRemoveArgs() {
+        final SparkActionBuilder builder = getBuilderInstance();
+
+        for (final String file : ARGS) {
+            builder.withArg(file);
+        }
+
+        builder.withoutArg(ARGS[0]);
+
+        final SparkAction action = builder.build();
+
+        final List<String> argList = action.getArgs();
+        final String[] remainingArgs = Arrays.copyOfRange(ARGS, 1, 
ARGS.length);
+        assertEquals(remainingArgs.length, argList.size());
+
+        for (int i = 0; i < remainingArgs.length; ++i) {
+            assertEquals(remainingArgs[i], argList.get(i));
+        }
+    }
+
+    @Test
+    public void testClearArgs() {
+        final SparkActionBuilder builder = getBuilderInstance();
+
+        for (final String file : ARGS) {
+            builder.withArg(file);
+        }
+
+        builder.clearArgs();
+
+        final SparkAction action = builder.build();
+
+        final List<String> argList = action.getArgs();
+        assertEquals(0, argList.size());
+    }
+
+    @Test
+    public void testFromExistingSparkAction() {
+        final SparkActionBuilder builder = getBuilderInstance();
+
+        builder.withName(NAME)
+                .withResourceManager(RESOURCE_MANAGER)
+                .withNameNode(NAME_NODE)
+                .withConfigProperty(MAPRED_JOB_QUEUE_NAME, DEFAULT)
+                .withPrepare(new PrepareBuilder()
+                        .withDelete(PATH_TO_DELETE)
+                        .withMkdir(PATH_TO_MKDIR)
+                        .build())
+                .withLauncher(new LauncherBuilder()
+                        .withMemoryMb(1024L)
+                        .withVCores(2L)
+                        .withQueue(DEFAULT)
+                        .withSharelib(DEFAULT)
+                        .withViewAcl(DEFAULT)
+                        .withModifyAcl(DEFAULT)
+                        .build())
+                .withArg(ARGS[0])
+                .withArg(ARGS[1])
+                .withMaster(DEFAULT)
+                .withMode(DEFAULT)
+                .withActionName(DEFAULT)
+                .withActionClass(DEFAULT)
+                .withJar(DEFAULT)
+                .withSparkOpts(DEFAULT)
+                .withArchive(DEFAULT)
+                .withFile(DEFAULT);
+
+        final SparkAction action = builder.build();
+
+        final SparkActionBuilder fromExistingBuilder = 
getBuilderInstance(action);
+
+        final String newName = "fromExisting_" + NAME;
+        fromExistingBuilder.withName(newName)
+                .withoutArg(ARGS[1])
+                .withArg(ARGS[2]);
+
+        final SparkAction modifiedAction = fromExistingBuilder.build();
+
+        assertEquals(newName, modifiedAction.getName());
+        assertEquals(action.getNameNode(), modifiedAction.getNameNode());
+
+        final Map<String, String> expectedConfiguration = new 
LinkedHashMap<>();
+        expectedConfiguration.put(MAPRED_JOB_QUEUE_NAME, DEFAULT);
+        assertEquals(expectedConfiguration, modifiedAction.getConfiguration());
+
+        assertEquals(Arrays.asList(ARGS[0], ARGS[2]), 
modifiedAction.getArgs());
+
+        assertEquals(PATH_TO_DELETE, 
modifiedAction.getPrepare().getDeletes().get(0).getPath());
+        assertEquals(PATH_TO_MKDIR, 
modifiedAction.getPrepare().getMkdirs().get(0).getPath());
+
+        assertEquals(1024L, modifiedAction.getLauncher().getMemoryMb());
+        assertEquals(2L, modifiedAction.getLauncher().getVCores());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getQueue());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getSharelib());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getViewAcl());
+        assertEquals(DEFAULT, modifiedAction.getLauncher().getModifyAcl());
+
+        assertEquals(action.getMaster(), modifiedAction.getMaster());
+        assertEquals(action.getMode(), modifiedAction.getMode());
+        assertEquals(action.getActionName(), modifiedAction.getActionName());
+        assertEquals(action.getActionClass(), modifiedAction.getActionClass());
+        assertEquals(action.getJar(), modifiedAction.getJar());
+        assertEquals(action.getSparkOpts(), modifiedAction.getSparkOpts());
+    }
+
+    @Test
+    public void testFromOtherAction() {
+        final ShellAction parent = ShellActionBuilder.create()
+                .withName("parent")
+                .build();
+
+        final ShellAction otherAction = 
ShellActionBuilder.createFromExistingAction(parent)
+                .withName("shell")
+                .withParent(parent)
+                .build();
+
+        final SparkAction fromOtherAction = 
SparkActionBuilder.createFromExistingAction(otherAction)
+                .withName("spark")
+                .build();
+
+        assertEquals("spark", fromOtherAction.getName());
+        assertEquals(parent, 
fromOtherAction.getParentsWithoutConditions().get(0));
+    }
+}
\ No newline at end of file

Reply via email to