You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sqoop.apache.org by ja...@apache.org on 2015/11/05 18:57:29 UTC

sqoop git commit: SQOOP-2631: Sqoop2: Add tests for shell commands in interactive mode

Repository: sqoop
Updated Branches:
  refs/heads/sqoop2 fa3c77b6a -> c173f6a52


SQOOP-2631: Sqoop2: Add tests for shell commands in interactive mode

(Dian Fu via Jarek Jarcec Cecho)


Project: http://git-wip-us.apache.org/repos/asf/sqoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/sqoop/commit/c173f6a5
Tree: http://git-wip-us.apache.org/repos/asf/sqoop/tree/c173f6a5
Diff: http://git-wip-us.apache.org/repos/asf/sqoop/diff/c173f6a5

Branch: refs/heads/sqoop2
Commit: c173f6a52a0bf9fe5258e70e5a87eb39113d8bca
Parents: fa3c77b
Author: Jarek Jarcec Cecho <ja...@apache.org>
Authored: Thu Nov 5 09:56:57 2015 -0800
Committer: Jarek Jarcec Cecho <ja...@apache.org>
Committed: Thu Nov 5 09:56:57 2015 -0800

----------------------------------------------------------------------
 .../apache/sqoop/shell/CloneJobFunction.java    |   2 +-
 .../apache/sqoop/shell/CloneLinkFunction.java   |  24 +-
 .../apache/sqoop/shell/CreateJobFunction.java   |   2 +-
 .../apache/sqoop/shell/CreateLinkFunction.java  |   2 +-
 .../apache/sqoop/shell/ShellEnvironment.java    |  16 ++
 .../apache/sqoop/shell/UpdateJobFunction.java   |   2 +-
 .../apache/sqoop/shell/UpdateLinkFunction.java  |   2 +-
 .../apache/sqoop/shell/TestCloneCommand.java    | 227 ++++++++++++++++--
 .../apache/sqoop/shell/TestCreateCommand.java   | 231 +++++++++++++++++--
 .../apache/sqoop/shell/TestUpdateCommand.java   | 227 ++++++++++++++++--
 10 files changed, 669 insertions(+), 66 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/main/java/org/apache/sqoop/shell/CloneJobFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/CloneJobFunction.java b/shell/src/main/java/org/apache/sqoop/shell/CloneJobFunction.java
index b28ece2..ecea579 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/CloneJobFunction.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/CloneJobFunction.java
@@ -60,7 +60,7 @@ public class CloneJobFunction extends SqoopFunction {
   private Status cloneJob(String jobArg, List<String> args, boolean isInteractive) throws IOException {
     printlnResource(Constants.RES_CLONE_CLONING_JOB, jobArg);
 
-    ConsoleReader reader = new ConsoleReader();
+    ConsoleReader reader = getConsoleReader();
 
     MJob job = client.getJob(jobArg);
     job.setPersistenceId(MPersistableEntity.PERSISTANCE_ID_DEFAULT);

http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/main/java/org/apache/sqoop/shell/CloneLinkFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/CloneLinkFunction.java b/shell/src/main/java/org/apache/sqoop/shell/CloneLinkFunction.java
index b76346b..b46a19f 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/CloneLinkFunction.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/CloneLinkFunction.java
@@ -61,15 +61,15 @@ public class CloneLinkFunction extends SqoopFunction {
   private Status cloneLink(String linkArg, List<String> args, boolean isInteractive) throws IOException {
     printlnResource(Constants.RES_CLONE_CLONING_LINK, linkArg);
 
-    ConsoleReader reader = new ConsoleReader();
+    ConsoleReader reader = getConsoleReader();
 
-    MLink connection = client.getLink(linkArg);
+    MLink link = client.getLink(linkArg);
     // Remove persistent id as we're making a clone
-    connection.setPersistenceId(MPersistableEntity.PERSISTANCE_ID_DEFAULT);
+    link.setPersistenceId(MPersistableEntity.PERSISTANCE_ID_DEFAULT);
 
     Status status = Status.OK;
 
-    ResourceBundle linkConfigBundle = client.getConnectorConfigBundle(connection.getConnectorId());
+    ResourceBundle linkConfigBundle = client.getConnectorConfigBundle(link.getConnectorId());
 
     if (isInteractive) {
       printlnResource(Constants.RES_PROMPT_UPDATE_LINK_CONFIG);
@@ -81,29 +81,29 @@ public class CloneLinkFunction extends SqoopFunction {
         }
 
         // Fill in data from user
-        if(!fillLinkWithBundle(reader, connection, linkConfigBundle)) {
+        if(!fillLinkWithBundle(reader, link, linkConfigBundle)) {
           return null;
         }
 
-        status = client.saveLink(connection);
+        status = client.saveLink(link);
       } while(!status.canProceed());
     } else {
       LinkDynamicConfigOptions options = new LinkDynamicConfigOptions();
-      options.prepareOptions(connection);
+      options.prepareOptions(link);
       CommandLine line = ConfigOptions.parseOptions(options, 0, args, false);
-      if (fillLink(line, connection)) {
-        status = client.saveLink(connection);
+      if (fillLink(line, link)) {
+        status = client.saveLink(link);
         if (!status.canProceed()) {
-          printLinkValidationMessages(connection);
+          printLinkValidationMessages(link);
           return null;
         }
       } else {
-        printLinkValidationMessages(connection);
+        printLinkValidationMessages(link);
         return null;
       }
     }
 
-    printlnResource(Constants.RES_CLONE_LINK_SUCCESSFUL, status.name(), connection.getPersistenceId());
+    printlnResource(Constants.RES_CLONE_LINK_SUCCESSFUL, status.name(), link.getPersistenceId());
 
     return status;
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/main/java/org/apache/sqoop/shell/CreateJobFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/CreateJobFunction.java b/shell/src/main/java/org/apache/sqoop/shell/CreateJobFunction.java
index 4a520d7..03ceaba 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/CreateJobFunction.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/CreateJobFunction.java
@@ -73,7 +73,7 @@ public class CreateJobFunction extends  SqoopFunction {
   private Status createJob(String fromLinkArg, String toLinkArg, List<String> args, boolean isInteractive) throws IOException {
     printlnResource(Constants.RES_CREATE_CREATING_JOB, fromLinkArg, toLinkArg);
 
-    ConsoleReader reader = new ConsoleReader();
+    ConsoleReader reader = getConsoleReader();
     MJob job = getClient().createJob(fromLinkArg, toLinkArg);
 
     MConnector fromConnector = getClient().getConnector(job.getFromConnectorId());

http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/main/java/org/apache/sqoop/shell/CreateLinkFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/CreateLinkFunction.java b/shell/src/main/java/org/apache/sqoop/shell/CreateLinkFunction.java
index 224f844..e392846 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/CreateLinkFunction.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/CreateLinkFunction.java
@@ -86,7 +86,7 @@ public class CreateLinkFunction extends SqoopFunction {
       printlnResource(Constants.RES_CREATE_CREATING_LINK, connectorName);
     }
 
-    ConsoleReader reader = new ConsoleReader();
+    ConsoleReader reader = getConsoleReader();
 
     ResourceBundle connectorConfigBundle = getClient().getConnectorConfigBundle(cid);
 

http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/main/java/org/apache/sqoop/shell/ShellEnvironment.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/ShellEnvironment.java b/shell/src/main/java/org/apache/sqoop/shell/ShellEnvironment.java
index b08fdcf..55a0f27 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/ShellEnvironment.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/ShellEnvironment.java
@@ -23,12 +23,15 @@ import org.apache.sqoop.shell.core.ShellError;
 import org.apache.sqoop.shell.core.Constants;
 import org.codehaus.groovy.tools.shell.IO;
 
+import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.text.MessageFormat;
 import java.util.Locale;
 import java.util.ResourceBundle;
 
+import jline.ConsoleReader;
+
 /**
  * Static internal environment of the shell shared across all commands and
  * functions.
@@ -56,6 +59,7 @@ public final class ShellEnvironment {
   static ResourceBundle resource = ResourceBundle.getBundle(Constants.RESOURCE_NAME, Locale.getDefault());
   static SqoopClient client = new SqoopClient(getServerUrl());
   static IO io;
+  static ConsoleReader consoleReader;
 
   public static String getEnv(String variable, String defaultValue) {
     String value = System.getenv(variable);
@@ -169,6 +173,18 @@ public final class ShellEnvironment {
     return pollTimeout;
   }
 
+  public static void setConsoleReader(ConsoleReader reader) {
+    consoleReader = reader;
+  }
+
+  @edu.umd.cs.findbugs.annotations.SuppressWarnings({"LI_LAZY_INIT_STATIC"})
+  public static ConsoleReader getConsoleReader() throws IOException {
+    if (consoleReader == null) {
+      consoleReader = new ConsoleReader();
+    }
+    return consoleReader;
+  }
+
   public static String resourceString(String resourceName) {
     return resource.getString(resourceName);
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/main/java/org/apache/sqoop/shell/UpdateJobFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/UpdateJobFunction.java b/shell/src/main/java/org/apache/sqoop/shell/UpdateJobFunction.java
index ba85d63..fe6a155 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/UpdateJobFunction.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/UpdateJobFunction.java
@@ -61,7 +61,7 @@ public class UpdateJobFunction extends SqoopFunction {
   private Status updateJob(String jobArg, List<String> args, boolean isInteractive) throws IOException {
     printlnResource(Constants.RES_SQOOP_UPDATING_JOB, jobArg);
 
-    ConsoleReader reader = new ConsoleReader();
+    ConsoleReader reader = getConsoleReader();
 
     // TODO(SQOOP-1634): using from/to and driver config id, this call can be avoided
     MJob job = client.getJob(jobArg);

http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java b/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java
index e815220..c5359ce 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java
@@ -60,7 +60,7 @@ public class UpdateLinkFunction extends SqoopFunction {
   private Status updateLink(String linkArg, List<String> args, boolean isInteractive) throws IOException {
     printlnResource(Constants.RES_SQOOP_UPDATING_LINK, linkArg);
 
-    ConsoleReader reader = new ConsoleReader();
+    ConsoleReader reader = getConsoleReader();
 
     // TODO(SQOOP-1634): using link config id, this call can be avoided
     MLink link = client.getLink(linkArg);

http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/test/java/org/apache/sqoop/shell/TestCloneCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/test/java/org/apache/sqoop/shell/TestCloneCommand.java b/shell/src/test/java/org/apache/sqoop/shell/TestCloneCommand.java
index f7f44a5..c45501c 100644
--- a/shell/src/test/java/org/apache/sqoop/shell/TestCloneCommand.java
+++ b/shell/src/test/java/org/apache/sqoop/shell/TestCloneCommand.java
@@ -21,19 +21,43 @@ package org.apache.sqoop.shell;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.List;
+import java.util.ResourceBundle;
 
+import jline.ConsoleReader;
+
+import org.apache.commons.lang.StringUtils;
 import org.apache.sqoop.client.SqoopClient;
 import org.apache.sqoop.common.SqoopException;
+import org.apache.sqoop.model.InputEditable;
+import org.apache.sqoop.model.MBooleanInput;
 import org.apache.sqoop.model.MConfig;
+import org.apache.sqoop.model.MDateTimeInput;
 import org.apache.sqoop.model.MDriverConfig;
+import org.apache.sqoop.model.MEnumInput;
 import org.apache.sqoop.model.MFromConfig;
+import org.apache.sqoop.model.MInput;
+import org.apache.sqoop.model.MIntegerInput;
 import org.apache.sqoop.model.MJob;
 import org.apache.sqoop.model.MLink;
 import org.apache.sqoop.model.MLinkConfig;
+import org.apache.sqoop.model.MListInput;
+import org.apache.sqoop.model.MLongInput;
+import org.apache.sqoop.model.MMapInput;
+import org.apache.sqoop.model.MStringInput;
 import org.apache.sqoop.model.MToConfig;
 import org.apache.sqoop.model.MValidator;
 import org.apache.sqoop.shell.core.Constants;
@@ -41,22 +65,41 @@ import org.apache.sqoop.shell.core.ShellError;
 import org.apache.sqoop.utils.MapResourceBundle;
 import org.apache.sqoop.validation.Status;
 import org.codehaus.groovy.tools.shell.Groovysh;
-import org.testng.Assert;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
 public class TestCloneCommand {
   CloneCommand cloneCmd;
   SqoopClient client;
+  ConsoleReader reader;
+  ResourceBundle resourceBundle;
+  ByteArrayInputStream in;
+  byte[] data;
 
   @BeforeTest(alwaysRun = true)
-  public void setup() {
+  public void setup() throws IOException {
     Groovysh shell = new Groovysh();
     cloneCmd = new CloneCommand(shell);
     ShellEnvironment.setInteractive(false);
     ShellEnvironment.setIo(shell.getIo());
     client = mock(SqoopClient.class);
     ShellEnvironment.setClient(client);
+
+    data = new byte[1000];
+    in = new ByteArrayInputStream(data);
+    reader = new ConsoleReader(in, new OutputStreamWriter(System.out));
+    ShellEnvironment.setConsoleReader(reader);
+    resourceBundle = new ResourceBundle() {
+      @Override
+      protected Object handleGetObject(String key) {
+        return "fake_translated_value";
+      }
+
+      @Override
+      public Enumeration<String> getKeys() {
+        return Collections.emptyEnumeration();
+      }
+    };
   }
 
   @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -69,27 +112,62 @@ public class TestCloneCommand {
 
     // clone link -lid link_test
     Status status = (Status) cloneCmd.execute(Arrays.asList(Constants.FN_LINK, "-lid", "link_test"));
-    Assert.assertTrue(status != null && status == Status.OK);
+    assertTrue(status != null && status == Status.OK);
 
     // Missing argument for option lid
     try {
       cloneCmd.execute(Arrays.asList(Constants.FN_LINK, "-lid"));
-      Assert.fail("Update link should fail as parameters aren't complete!");
+      fail("Update link should fail as parameters aren't complete!");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing argument for option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing argument for option"));
     }
 
     // Missing option lid
     try {
       cloneCmd.execute(Arrays.asList(Constants.FN_LINK));
-      Assert.fail("Update link should fail as option lid is missing");
+      fail("Update link should fail as option lid is missing");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing required option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing required option"));
     }
   }
 
+  @Test
+  public void testCloneLinkInteractive() {
+    ShellEnvironment.setInteractive(true);
+    initEnv();
+    MLink link = new MLink(1, new MLinkConfig(getConfig("CONFIGFROMNAME"), new ArrayList<MValidator>()));
+    when(client.getLink("link_test")).thenReturn(link);
+    when(client.getConnectorConfigBundle(1L)).thenReturn(resourceBundle);
+    when(client.saveLink(link)).thenReturn(Status.OK);
+
+    // clone link -lid link_test
+    initData("linkname\r" +         // link name
+        "abc\r" +                   // for input with name "String"
+        "12345\r" +                 // for input with name "Integer"
+        "56789\r" +                 // for input with name "Long"
+        "true\r" +                  // for input with name "Boolean"
+        "k1=v1\rk2=v2\r\r" +        // for input with name "Map"
+        "0\r" +                     // for input with name "Enum"
+        "l1\rl2\rl3\r\r" +          // for input with name "List"
+        "12345678\r");              // for input with name "DateTime"
+    Status status = (Status) cloneCmd.execute(Arrays.asList(Constants.FN_LINK, "-lid", "link_test"));
+    assertTrue(status != null && status == Status.OK);
+    assertEquals(link.getName(), "linkname");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getStringInput("CONFIGFROMNAME.String").getValue(), "abc");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getIntegerInput("CONFIGFROMNAME.Integer").getValue().intValue(), 12345);
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getLongInput("CONFIGFROMNAME.Long").getValue().longValue(), 56789);
+    assertTrue((link.getConnectorLinkConfig("CONFIGFROMNAME").getBooleanInput("CONFIGFROMNAME.Boolean").getValue()));
+    HashMap<String, String> map = new HashMap<String, String>();
+    map.put("k1", "v1");
+    map.put("k2", "v2");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getMapInput("CONFIGFROMNAME.Map").getValue(), map);
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getEnumInput("CONFIGFROMNAME.Enum").getValue(), "YES");
+    assertEquals(StringUtils.join(link.getConnectorLinkConfig("CONFIGFROMNAME").getListInput("CONFIGFROMNAME.List").getValue(), "&"), "l1&l2&l3");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getDateTimeInput("CONFIGFROMNAME.DateTime").getValue().getMillis(), 12345678);
+  }
+
   @SuppressWarnings({ "unchecked", "rawtypes" })
   @Test
   public void testCloneJob() {
@@ -102,26 +180,141 @@ public class TestCloneCommand {
     when(client.getDriverConfigBundle()).thenReturn(new MapResourceBundle(new HashMap()));
     when(client.saveJob(job)).thenReturn(Status.OK);
 
-    // update job -jid job_test
+    // clone job -jid job_test
     Status status = (Status) cloneCmd.execute(Arrays.asList(Constants.FN_JOB, "-jid", "job_test"));
-    Assert.assertTrue(status != null && status == Status.OK);
+    assertTrue(status != null && status == Status.OK);
 
     // Missing argument for option jid
     try {
       cloneCmd.execute(Arrays.asList(Constants.FN_JOB, "-jid"));
-      Assert.fail("Update job should fail as parameters aren't complete!");
+      fail("Update job should fail as parameters aren't complete!");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing argument for option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing argument for option"));
     }
 
     // Missing option jid
     try {
       cloneCmd.execute(Arrays.asList(Constants.FN_JOB));
-      Assert.fail("Update job should fail as option jid is missing");
+      fail("Update job should fail as option jid is missing");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing required option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing required option"));
+    }
+  }
+
+  @Test
+  public void testCloneJobInteractive() {
+    ShellEnvironment.setInteractive(true);
+    initEnv();
+    MJob job = new MJob(1, 2, 1, 2, new MFromConfig(getConfig("fromJobConfig"), new ArrayList<MValidator>()),
+        new MToConfig(getConfig("toJobConfig"), new ArrayList<MValidator>()),
+        new MDriverConfig(getConfig("driverConfig"), new ArrayList<MValidator>()));
+    when(client.getJob("job_test")).thenReturn(job);
+    when(client.getConnectorConfigBundle(any(Long.class))).thenReturn(resourceBundle);
+    when(client.getDriverConfigBundle()).thenReturn(resourceBundle);
+    when(client.saveJob(job)).thenReturn(Status.OK);
+
+    // clone job -jid job_test
+    initData("jobname\r" +          // job name
+        // From job config
+        "abc\r" +                   // for input with name "String"
+        "12345\r" +                 // for input with name "Integer"
+        "56789\r" +                 // for input with name "Long"
+        "true\r" +                  // for input with name "Boolean"
+        "k1=v1\rk2=v2\r\r" +        // for input with name "Map"
+        "0\r" +                     // for input with name "Enum"
+        "l1\rl2\rl3\r\r" +          // for input with name "List"
+        "12345678\r" +              // for input with name "DateTime"
+
+        // To job config
+        "def\r" +                   // for input with name "String"
+        "11111\r" +                 // for input with name "Integer"
+        "22222\r" +                 // for input with name "Long"
+        "false\r" +                  // for input with name "Boolean"
+        "k3=v3\rk4=v4\r\r" +        // for input with name "Map"
+        "1\r" +                     // for input with name "Enum"
+        "l4\rl5\rl6\r\r" +          // for input with name "List"
+        "1234567\r" +              // for input with name "DateTime"
+
+        // Driver config
+        "hij\r" +                   // for input with name "String"
+        "33333\r" +                 // for input with name "Integer"
+        "44444\r" +                 // for input with name "Long"
+        "true\r" +                  // for input with name "Boolean"
+        "k1=v1\r\r" +               // for input with name "Map"
+        "0\r" +                     // for input with name "Enum"
+        "l1\rl2\rl3\r\r" +          // for input with name "List"
+        "7654321\r");              // for input with name "DateTime"
+    Status status = (Status) cloneCmd.execute(Arrays.asList(Constants.FN_JOB, "-jid", "job_test"));
+    assertTrue(status != null && status == Status.OK);
+    assertEquals(job.getName(), "jobname");
+    // check from job config
+    assertEquals(job.getFromJobConfig().getStringInput("fromJobConfig.String").getValue(), "abc");
+    assertEquals(job.getFromJobConfig().getIntegerInput("fromJobConfig.Integer").getValue().intValue(), 12345);
+    assertEquals((job.getFromJobConfig().getLongInput("fromJobConfig.Long").getValue()).longValue(), 56789);
+    assertTrue((job.getFromJobConfig().getBooleanInput("fromJobConfig.Boolean").getValue()));
+    HashMap<String, String> map = new HashMap<String, String>();
+    map.put("k1", "v1");
+    map.put("k2", "v2");
+    assertEquals(job.getFromJobConfig().getMapInput("fromJobConfig.Map").getValue(), map);
+    assertEquals(job.getFromJobConfig().getEnumInput("fromJobConfig.Enum").getValue(), "YES");
+    assertEquals(StringUtils.join(job.getFromJobConfig().getListInput("fromJobConfig.List").getValue(), "&"), "l1&l2&l3");
+    assertEquals(job.getFromJobConfig().getDateTimeInput("fromJobConfig.DateTime").getValue().getMillis(), 12345678);
+
+    // check to job config
+    assertEquals(job.getToJobConfig().getStringInput("toJobConfig.String").getValue(), "def");
+    assertEquals(job.getToJobConfig().getIntegerInput("toJobConfig.Integer").getValue().intValue(), 11111);
+    assertEquals(job.getToJobConfig().getLongInput("toJobConfig.Long").getValue().longValue(), 22222);
+    assertFalse(job.getToJobConfig().getBooleanInput("toJobConfig.Boolean").getValue());
+    map = new HashMap<String, String>();
+    map.put("k3", "v3");
+    map.put("k4", "v4");
+    assertEquals(job.getToJobConfig().getMapInput("toJobConfig.Map").getValue(), map);
+    assertEquals(job.getToJobConfig().getEnumInput("toJobConfig.Enum").getValue(), "NO");
+    assertEquals(StringUtils.join(job.getToJobConfig().getListInput("toJobConfig.List").getValue(), "&"), "l4&l5&l6");
+    assertEquals(job.getToJobConfig().getDateTimeInput("toJobConfig.DateTime").getValue().getMillis(), 1234567);
+
+    // check driver config
+    assertEquals(job.getDriverConfig().getStringInput("driverConfig.String").getValue(), "hij");
+    assertEquals(job.getDriverConfig().getIntegerInput("driverConfig.Integer").getValue().intValue(), 33333);
+    assertEquals(job.getDriverConfig().getLongInput("driverConfig.Long").getValue().longValue(), 44444);
+    assertTrue(job.getDriverConfig().getBooleanInput("driverConfig.Boolean").getValue());
+    map = new HashMap<String, String>();
+    map.put("k1", "v1");
+    assertEquals(job.getDriverConfig().getMapInput("driverConfig.Map").getValue(), map);
+    assertEquals(job.getDriverConfig().getEnumInput("driverConfig.Enum").getValue(), "YES");
+    assertEquals(StringUtils.join(job.getDriverConfig().getListInput("driverConfig.List").getValue(), "&"), "l1&l2&l3");
+    assertEquals(job.getDriverConfig().getDateTimeInput("driverConfig.DateTime").getValue().getMillis(), 7654321);
+  }
+
+  @SuppressWarnings("unchecked")
+  private List<MConfig> getConfig(String configName) {
+    List<MInput<?>> list = new ArrayList<MInput<?>>();
+    list.add(new MStringInput(configName + "." + "String", false, InputEditable.ANY, StringUtils.EMPTY, (short)30, Collections.EMPTY_LIST));
+    list.add(new MIntegerInput(configName + "." + "Integer", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MLongInput(configName + "." + "Long", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MBooleanInput(configName + "." + "Boolean", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MMapInput(configName + "." + "Map", false, InputEditable.ANY, StringUtils.EMPTY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MEnumInput(configName + "." + "Enum", false, InputEditable.ANY, StringUtils.EMPTY, new String[] {"YES", "NO"}, Collections.EMPTY_LIST));
+    list.add(new MListInput(configName + "." + "List", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MDateTimeInput(configName + "." + "DateTime", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+
+    List<MConfig> configs = new ArrayList<MConfig>();
+    configs.add(new MConfig(configName, list, Collections.EMPTY_LIST));
+    return configs;
+  }
+
+  private void initData(String destData) {
+    byte[] destDataBytes = destData.getBytes();
+    System.arraycopy(destDataBytes, 0, data, 0, destDataBytes.length);
+    in.reset();
+  }
+
+  private void initEnv() {
+    in.reset();
+    for (int i = 0; i < data.length; i++) {
+      data[i] = '\0';
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/test/java/org/apache/sqoop/shell/TestCreateCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/test/java/org/apache/sqoop/shell/TestCreateCommand.java b/shell/src/test/java/org/apache/sqoop/shell/TestCreateCommand.java
index e0788cc..2f91897 100644
--- a/shell/src/test/java/org/apache/sqoop/shell/TestCreateCommand.java
+++ b/shell/src/test/java/org/apache/sqoop/shell/TestCreateCommand.java
@@ -18,44 +18,88 @@
 
 package org.apache.sqoop.shell;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ResourceBundle;
 
+import jline.ConsoleReader;
+
+import org.apache.commons.lang.StringUtils;
 import org.apache.sqoop.client.SqoopClient;
 import org.apache.sqoop.common.SqoopException;
+import org.apache.sqoop.model.InputEditable;
+import org.apache.sqoop.model.MBooleanInput;
 import org.apache.sqoop.model.MConfig;
 import org.apache.sqoop.model.MConnector;
+import org.apache.sqoop.model.MDateTimeInput;
 import org.apache.sqoop.model.MDriverConfig;
+import org.apache.sqoop.model.MEnumInput;
 import org.apache.sqoop.model.MFromConfig;
+import org.apache.sqoop.model.MInput;
+import org.apache.sqoop.model.MIntegerInput;
 import org.apache.sqoop.model.MJob;
 import org.apache.sqoop.model.MLink;
 import org.apache.sqoop.model.MLinkConfig;
+import org.apache.sqoop.model.MListInput;
+import org.apache.sqoop.model.MLongInput;
+import org.apache.sqoop.model.MMapInput;
+import org.apache.sqoop.model.MStringInput;
 import org.apache.sqoop.model.MToConfig;
 import org.apache.sqoop.model.MValidator;
 import org.apache.sqoop.shell.core.Constants;
 import org.apache.sqoop.shell.core.ShellError;
 import org.apache.sqoop.validation.Status;
 import org.codehaus.groovy.tools.shell.Groovysh;
-import org.testng.Assert;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
 public class TestCreateCommand {
   CreateCommand createCmd;
   SqoopClient client;
+  ConsoleReader reader;
+  ResourceBundle resourceBundle;
+  ByteArrayInputStream in;
+  byte[] data;
 
   @BeforeTest(alwaysRun = true)
-  public void setup() {
+  public void setup() throws IOException {
     Groovysh shell = new Groovysh();
     createCmd = new CreateCommand(shell);
     ShellEnvironment.setInteractive(false);
     ShellEnvironment.setIo(shell.getIo());
     client = mock(SqoopClient.class);
     ShellEnvironment.setClient(client);
+
+    data = new byte[1000];
+    in = new ByteArrayInputStream(data);
+    reader = new ConsoleReader(in, new OutputStreamWriter(System.out));
+    ShellEnvironment.setConsoleReader(reader);
+    resourceBundle = new ResourceBundle() {
+      @Override
+      protected Object handleGetObject(String key) {
+        return "fake_translated_value";
+      }
+
+      @Override
+      public Enumeration<String> getKeys() {
+        return Collections.emptyEnumeration();
+      }
+    };
   }
 
   @Test
@@ -66,19 +110,19 @@ public class TestCreateCommand {
 
     // create link -c connector_test
     Status status = (Status) createCmd.execute(Arrays.asList(Constants.FN_LINK, "-c", "connector_test"));
-    Assert.assertTrue(status != null && status == Status.OK);
+    assertTrue(status != null && status == Status.OK);
 
     // create link -cid connector_test
     status = (Status) createCmd.execute(Arrays.asList(Constants.FN_LINK, "-cid", "connector_test"));
-    Assert.assertTrue(status != null && status == Status.OK);
+    assertTrue(status != null && status == Status.OK);
 
     // incorrect command: create link -c
     try {
       status = (Status) createCmd.execute(Arrays.asList(Constants.FN_LINK, "-c"));
-      Assert.fail("Create link should fail as connector id/name is missing!");
+      fail("Create link should fail as connector id/name is missing!");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing argument for option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing argument for option"));
     }
   }
 
@@ -89,13 +133,49 @@ public class TestCreateCommand {
 
     try {
       createCmd.execute(Arrays.asList(Constants.FN_LINK, "-c", "connector_test"));
-      Assert.fail("Create link should fail as requested connector doesn't exist!");
+      fail("Create link should fail as requested connector doesn't exist!");
     } catch (SqoopException e) {
-      Assert.assertEquals(TestShellError.TEST_SHELL_0000, e.getErrorCode());
+      assertEquals(TestShellError.TEST_SHELL_0000, e.getErrorCode());
     }
   }
 
   @Test
+  public void testCreateLinkInteractive() {
+    ShellEnvironment.setInteractive(true);
+    initEnv();
+    when(client.getConnector("connector_test")).thenReturn(new MConnector("", "", "", null, null, null));
+    MLink link = new MLink(1, new MLinkConfig(getConfig("CONFIGFROMNAME"), new ArrayList<MValidator>()));
+    when(client.createLink("connector_test")).thenReturn(link);
+    when(client.saveLink(any(MLink.class))).thenReturn(Status.OK);
+    when(client.getConnectorConfigBundle(any(Long.class))).thenReturn(resourceBundle);
+
+    // create link -c connector_test
+    initData("linkname\r" +         // link name
+        "abc\r" +                   // for input with name "String"
+        "12345\r" +                 // for input with name "Integer"
+        "56789\r" +                 // for input with name "Long"
+        "true\r" +                  // for input with name "Boolean"
+        "k1=v1\rk2=v2\r\r" +        // for input with name "Map"
+        "0\r" +                     // for input with name "Enum"
+        "l1\rl2\rl3\r\r" +          // for input with name "List"
+        "12345678\r");              // for input with name "DateTime"
+    Status status = (Status) createCmd.execute(Arrays.asList(Constants.FN_LINK, "-c", "connector_test"));
+    assertTrue(status != null && status == Status.OK);
+    assertEquals(link.getName(), "linkname");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getStringInput("CONFIGFROMNAME.String").getValue(), "abc");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getIntegerInput("CONFIGFROMNAME.Integer").getValue().intValue(), 12345);
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getLongInput("CONFIGFROMNAME.Long").getValue().longValue(), 56789);
+    assertTrue((link.getConnectorLinkConfig("CONFIGFROMNAME").getBooleanInput("CONFIGFROMNAME.Boolean").getValue()));
+    HashMap<String, String> map = new HashMap<String, String>();
+    map.put("k1", "v1");
+    map.put("k2", "v2");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getMapInput("CONFIGFROMNAME.Map").getValue(), map);
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getEnumInput("CONFIGFROMNAME.Enum").getValue(), "YES");
+    assertEquals(StringUtils.join(link.getConnectorLinkConfig("CONFIGFROMNAME").getListInput("CONFIGFROMNAME.List").getValue(), "&"), "l1&l2&l3");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getDateTimeInput("CONFIGFROMNAME.DateTime").getValue().getMillis(), 12345678);
+  }
+
+  @Test
   public void testCreateJob() {
     MConnector fromConnector = new MConnector("connector_from", "", "", null, new MFromConfig(new ArrayList<MConfig>(), new ArrayList<MValidator>()), null);
     MConnector toConnector = new MConnector("connector_to", "", "", null, null, new MToConfig(new ArrayList<MConfig>(), new ArrayList<MValidator>()));
@@ -109,15 +189,15 @@ public class TestCreateCommand {
 
     // create job -f link_from -to link_to
     Status status = (Status) createCmd.execute(Arrays.asList(Constants.FN_JOB, "-f", "link_from", "-to", "link_to"));
-    Assert.assertTrue(status != null && status == Status.OK);
+    assertTrue(status != null && status == Status.OK);
 
     // incorrect command: create job -f link_from
     try {
       status = (Status) createCmd.execute(Arrays.asList(Constants.FN_JOB, "-f", "link_from"));
-      Assert.fail("Create Job should fail as the to link id/name is missing!");
+      fail("Create Job should fail as the to link id/name is missing!");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing required option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing required option"));
     }
   }
 
@@ -127,16 +207,135 @@ public class TestCreateCommand {
 
     try {
       createCmd.execute(Arrays.asList(Constants.FN_JOB, "-f", "link_from", "-to", "link_to"));
-      Assert.fail("Create Job should fail as from link doesn't exist!");
+      fail("Create Job should fail as from link doesn't exist!");
     } catch (SqoopException e) {
-      Assert.assertEquals(TestShellError.TEST_SHELL_0000, e.getErrorCode());
+      assertEquals(TestShellError.TEST_SHELL_0000, e.getErrorCode());
     }
   }
 
   @Test
+  public void testCreateJobInteractive() {
+    ShellEnvironment.setInteractive(true);
+    initEnv();
+    MConnector fromConnector = new MConnector("connector_from", "", "", null, new MFromConfig(new ArrayList<MConfig>(), new ArrayList<MValidator>()), null);
+    MConnector toConnector = new MConnector("connector_to", "", "", null, null, new MToConfig(new ArrayList<MConfig>(), new ArrayList<MValidator>()));
+    MJob job = new MJob(1, 2, 1, 2, new MFromConfig(getConfig("fromJobConfig"), new ArrayList<MValidator>()),
+        new MToConfig(getConfig("toJobConfig"), new ArrayList<MValidator>()),
+        new MDriverConfig(getConfig("driverConfig"), new ArrayList<MValidator>()));
+    when(client.createJob("link_from", "link_to")).thenReturn(job);
+    when(client.getConnector(1)).thenReturn(fromConnector);
+    when(client.getConnector(2)).thenReturn(toConnector);
+    when(client.saveJob(any(MJob.class))).thenReturn(Status.OK);
+    when(client.getConnectorConfigBundle(any(Long.class))).thenReturn(resourceBundle);
+    when(client.getDriverConfigBundle()).thenReturn(resourceBundle);
+
+    // create job -f link_from -to link_to
+    initData("jobname\r" +          // job name
+        // From job config
+        "abc\r" +                   // for input with name "String"
+        "12345\r" +                 // for input with name "Integer"
+        "56789\r" +                 // for input with name "Long"
+        "true\r" +                  // for input with name "Boolean"
+        "k1=v1\rk2=v2\r\r" +        // for input with name "Map"
+        "0\r" +                     // for input with name "Enum"
+        "l1\rl2\rl3\r\r" +          // for input with name "List"
+        "12345678\r" +              // for input with name "DateTime"
+
+        // To job config
+        "def\r" +                   // for input with name "String"
+        "11111\r" +                 // for input with name "Integer"
+        "22222\r" +                 // for input with name "Long"
+        "false\r" +                  // for input with name "Boolean"
+        "k3=v3\rk4=v4\r\r" +        // for input with name "Map"
+        "1\r" +                     // for input with name "Enum"
+        "l4\rl5\rl6\r\r" +          // for input with name "List"
+        "1234567\r" +              // for input with name "DateTime"
+
+        // Driver config
+        "hij\r" +                   // for input with name "String"
+        "33333\r" +                 // for input with name "Integer"
+        "44444\r" +                 // for input with name "Long"
+        "true\r" +                  // for input with name "Boolean"
+        "k1=v1\r\r" +               // for input with name "Map"
+        "0\r" +                     // for input with name "Enum"
+        "l1\rl2\rl3\r\r" +          // for input with name "List"
+        "7654321\r");              // for input with name "DateTime"
+    Status status = (Status) createCmd.execute(Arrays.asList(Constants.FN_JOB, "-f", "link_from", "-to", "link_to"));
+    assertTrue(status != null && status == Status.OK);
+    assertEquals(job.getName(), "jobname");
+    // check from job config
+    assertEquals(job.getFromJobConfig().getStringInput("fromJobConfig.String").getValue(), "abc");
+    assertEquals(job.getFromJobConfig().getIntegerInput("fromJobConfig.Integer").getValue().intValue(), 12345);
+    assertEquals((job.getFromJobConfig().getLongInput("fromJobConfig.Long").getValue()).longValue(), 56789);
+    assertTrue((job.getFromJobConfig().getBooleanInput("fromJobConfig.Boolean").getValue()));
+    HashMap<String, String> map = new HashMap<String, String>();
+    map.put("k1", "v1");
+    map.put("k2", "v2");
+    assertEquals(job.getFromJobConfig().getMapInput("fromJobConfig.Map").getValue(), map);
+    assertEquals(job.getFromJobConfig().getEnumInput("fromJobConfig.Enum").getValue(), "YES");
+    assertEquals(StringUtils.join(job.getFromJobConfig().getListInput("fromJobConfig.List").getValue(), "&"), "l1&l2&l3");
+    assertEquals(job.getFromJobConfig().getDateTimeInput("fromJobConfig.DateTime").getValue().getMillis(), 12345678);
+
+    // check to job config
+    assertEquals(job.getToJobConfig().getStringInput("toJobConfig.String").getValue(), "def");
+    assertEquals(job.getToJobConfig().getIntegerInput("toJobConfig.Integer").getValue().intValue(), 11111);
+    assertEquals(job.getToJobConfig().getLongInput("toJobConfig.Long").getValue().longValue(), 22222);
+    assertFalse(job.getToJobConfig().getBooleanInput("toJobConfig.Boolean").getValue());
+    map = new HashMap<String, String>();
+    map.put("k3", "v3");
+    map.put("k4", "v4");
+    assertEquals(job.getToJobConfig().getMapInput("toJobConfig.Map").getValue(), map);
+    assertEquals(job.getToJobConfig().getEnumInput("toJobConfig.Enum").getValue(), "NO");
+    assertEquals(StringUtils.join(job.getToJobConfig().getListInput("toJobConfig.List").getValue(), "&"), "l4&l5&l6");
+    assertEquals(job.getToJobConfig().getDateTimeInput("toJobConfig.DateTime").getValue().getMillis(), 1234567);
+
+    // check driver config
+    assertEquals(job.getDriverConfig().getStringInput("driverConfig.String").getValue(), "hij");
+    assertEquals(job.getDriverConfig().getIntegerInput("driverConfig.Integer").getValue().intValue(), 33333);
+    assertEquals(job.getDriverConfig().getLongInput("driverConfig.Long").getValue().longValue(), 44444);
+    assertTrue(job.getDriverConfig().getBooleanInput("driverConfig.Boolean").getValue());
+    map = new HashMap<String, String>();
+    map.put("k1", "v1");
+    assertEquals(job.getDriverConfig().getMapInput("driverConfig.Map").getValue(), map);
+    assertEquals(job.getDriverConfig().getEnumInput("driverConfig.Enum").getValue(), "YES");
+    assertEquals(StringUtils.join(job.getDriverConfig().getListInput("driverConfig.List").getValue(), "&"), "l1&l2&l3");
+    assertEquals(job.getDriverConfig().getDateTimeInput("driverConfig.DateTime").getValue().getMillis(), 7654321);
+  }
+
+  @Test
   public void testCreateRole() {
     // create role -r role_test
     Status status = (Status) createCmd.execute(Arrays.asList(Constants.FN_ROLE, "-r", "role_test"));
-    Assert.assertTrue(status != null && status == Status.OK);
+    assertTrue(status != null && status == Status.OK);
+  }
+
+  @SuppressWarnings("unchecked")
+  private List<MConfig> getConfig(String configName) {
+    List<MInput<?>> list = new ArrayList<MInput<?>>();
+    list.add(new MStringInput(configName + "." + "String", false, InputEditable.ANY, StringUtils.EMPTY, (short)30, Collections.EMPTY_LIST));
+    list.add(new MIntegerInput(configName + "." + "Integer", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MLongInput(configName + "." + "Long", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MBooleanInput(configName + "." + "Boolean", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MMapInput(configName + "." + "Map", false, InputEditable.ANY, StringUtils.EMPTY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MEnumInput(configName + "." + "Enum", false, InputEditable.ANY, StringUtils.EMPTY, new String[] {"YES", "NO"}, Collections.EMPTY_LIST));
+    list.add(new MListInput(configName + "." + "List", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MDateTimeInput(configName + "." + "DateTime", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+
+    List<MConfig> configs = new ArrayList<MConfig>();
+    configs.add(new MConfig(configName, list, Collections.EMPTY_LIST));
+    return configs;
+  }
+
+  private void initData(String destData) {
+    byte[] destDataBytes = destData.getBytes();
+    System.arraycopy(destDataBytes, 0, data, 0, destDataBytes.length);
+    in.reset();
+  }
+
+  private void initEnv() {
+    in.reset();
+    for (int i = 0; i < data.length; i++) {
+      data[i] = '\0';
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/c173f6a5/shell/src/test/java/org/apache/sqoop/shell/TestUpdateCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/test/java/org/apache/sqoop/shell/TestUpdateCommand.java b/shell/src/test/java/org/apache/sqoop/shell/TestUpdateCommand.java
index d9618ac..d5df497 100644
--- a/shell/src/test/java/org/apache/sqoop/shell/TestUpdateCommand.java
+++ b/shell/src/test/java/org/apache/sqoop/shell/TestUpdateCommand.java
@@ -21,19 +21,44 @@ package org.apache.sqoop.shell;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.List;
+import java.util.ResourceBundle;
 
+import jline.ConsoleReader;
+
+import org.apache.commons.lang.StringUtils;
 import org.apache.sqoop.client.SqoopClient;
 import org.apache.sqoop.common.SqoopException;
+import org.apache.sqoop.model.InputEditable;
+import org.apache.sqoop.model.MBooleanInput;
 import org.apache.sqoop.model.MConfig;
+import org.apache.sqoop.model.MConnector;
+import org.apache.sqoop.model.MDateTimeInput;
 import org.apache.sqoop.model.MDriverConfig;
+import org.apache.sqoop.model.MEnumInput;
 import org.apache.sqoop.model.MFromConfig;
+import org.apache.sqoop.model.MInput;
+import org.apache.sqoop.model.MIntegerInput;
 import org.apache.sqoop.model.MJob;
 import org.apache.sqoop.model.MLink;
 import org.apache.sqoop.model.MLinkConfig;
+import org.apache.sqoop.model.MListInput;
+import org.apache.sqoop.model.MLongInput;
+import org.apache.sqoop.model.MMapInput;
+import org.apache.sqoop.model.MStringInput;
 import org.apache.sqoop.model.MToConfig;
 import org.apache.sqoop.model.MValidator;
 import org.apache.sqoop.shell.core.Constants;
@@ -41,22 +66,41 @@ import org.apache.sqoop.shell.core.ShellError;
 import org.apache.sqoop.utils.MapResourceBundle;
 import org.apache.sqoop.validation.Status;
 import org.codehaus.groovy.tools.shell.Groovysh;
-import org.testng.Assert;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
 public class TestUpdateCommand {
   UpdateCommand updateCmd;
   SqoopClient client;
+  ConsoleReader reader;
+  ResourceBundle resourceBundle;
+  ByteArrayInputStream in;
+  byte[] data;
 
   @BeforeTest(alwaysRun = true)
-  public void setup() {
+  public void setup() throws IOException {
     Groovysh shell = new Groovysh();
     updateCmd = new UpdateCommand(shell);
     ShellEnvironment.setInteractive(false);
     ShellEnvironment.setIo(shell.getIo());
     client = mock(SqoopClient.class);
     ShellEnvironment.setClient(client);
+
+    data = new byte[1000];
+    in = new ByteArrayInputStream(data);
+    reader = new ConsoleReader(in, new OutputStreamWriter(System.out));
+    ShellEnvironment.setConsoleReader(reader);
+    resourceBundle = new ResourceBundle() {
+      @Override
+      protected Object handleGetObject(String key) {
+        return "fake_translated_value";
+      }
+
+      @Override
+      public Enumeration<String> getKeys() {
+        return Collections.emptyEnumeration();
+      }
+    };
   }
 
   @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -69,27 +113,63 @@ public class TestUpdateCommand {
 
     // update link -lid link_test
     Status status = (Status) updateCmd.execute(Arrays.asList(Constants.FN_LINK, "-lid", "link_test"));
-    Assert.assertTrue(status != null && status == Status.OK);
+    assertTrue(status != null && status == Status.OK);
 
     // Missing argument for option lid
     try {
       updateCmd.execute(Arrays.asList(Constants.FN_LINK, "-lid"));
-      Assert.fail("Update link should fail as parameters aren't complete!");
+      fail("Update link should fail as parameters aren't complete!");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing argument for option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing argument for option"));
     }
 
     // Missing option lid
     try {
       updateCmd.execute(Arrays.asList(Constants.FN_LINK));
-      Assert.fail("Update link should fail as option lid is missing");
+      fail("Update link should fail as option lid is missing");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing required option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing required option"));
     }
   }
 
+  @Test
+  public void testUpdateLinkInteractive() {
+    ShellEnvironment.setInteractive(true);
+    initEnv();
+    when(client.getConnector("connector_test")).thenReturn(new MConnector("", "", "", null, null, null));
+    MLink link = new MLink(1, new MLinkConfig(getConfig("CONFIGFROMNAME"), new ArrayList<MValidator>()));
+    when(client.getLink("link_test")).thenReturn(link);
+    when(client.updateLink(link)).thenReturn(Status.OK);
+    when(client.getConnectorConfigBundle(any(Long.class))).thenReturn(resourceBundle);
+
+    // update link -lid link_test
+    initData("linkname\r" +         // link name
+        "abc\r" +                   // for input with name "String"
+        "12345\r" +                 // for input with name "Integer"
+        "56789\r" +                 // for input with name "Long"
+        "true\r" +                  // for input with name "Boolean"
+        "k1=v1\rk2=v2\r\r" +        // for input with name "Map"
+        "0\r" +                     // for input with name "Enum"
+        "l1\rl2\rl3\r\r" +          // for input with name "List"
+        "12345678\r");              // for input with name "DateTime"
+    Status status = (Status) updateCmd.execute(Arrays.asList(Constants.FN_LINK, "-lid", "link_test"));
+    assertTrue(status != null && status == Status.OK);
+    assertEquals(link.getName(), "linkname");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getStringInput("CONFIGFROMNAME.String").getValue(), "abc");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getIntegerInput("CONFIGFROMNAME.Integer").getValue().intValue(), 12345);
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getLongInput("CONFIGFROMNAME.Long").getValue().longValue(), 56789);
+    assertTrue((link.getConnectorLinkConfig("CONFIGFROMNAME").getBooleanInput("CONFIGFROMNAME.Boolean").getValue()));
+    HashMap<String, String> map = new HashMap<String, String>();
+    map.put("k1", "v1");
+    map.put("k2", "v2");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getMapInput("CONFIGFROMNAME.Map").getValue(), map);
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getEnumInput("CONFIGFROMNAME.Enum").getValue(), "YES");
+    assertEquals(StringUtils.join(link.getConnectorLinkConfig("CONFIGFROMNAME").getListInput("CONFIGFROMNAME.List").getValue(), "&"), "l1&l2&l3");
+    assertEquals(link.getConnectorLinkConfig("CONFIGFROMNAME").getDateTimeInput("CONFIGFROMNAME.DateTime").getValue().getMillis(), 12345678);
+  }
+
   @SuppressWarnings({ "unchecked", "rawtypes" })
   @Test
   public void testUpdateJob() throws InterruptedException {
@@ -104,24 +184,139 @@ public class TestUpdateCommand {
 
     // update job -jid job_test
     Status status = (Status) updateCmd.execute(Arrays.asList(Constants.FN_JOB, "-jid", "job_test"));
-    Assert.assertTrue(status != null && status == Status.OK);
+    assertTrue(status != null && status == Status.OK);
 
     // Missing argument for option jid
     try {
       updateCmd.execute(Arrays.asList(Constants.FN_JOB, "-jid"));
-      Assert.fail("Update job should fail as parameters aren't complete!");
+      fail("Update job should fail as parameters aren't complete!");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing argument for option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing argument for option"));
     }
 
     // Missing option jid
     try {
       updateCmd.execute(Arrays.asList(Constants.FN_JOB));
-      Assert.fail("Update job should fail as option jid is missing");
+      fail("Update job should fail as option jid is missing");
     } catch (SqoopException e) {
-      Assert.assertEquals(ShellError.SHELL_0003, e.getErrorCode());
-      Assert.assertTrue(e.getMessage().contains("Missing required option"));
+      assertEquals(ShellError.SHELL_0003, e.getErrorCode());
+      assertTrue(e.getMessage().contains("Missing required option"));
+    }
+  }
+
+  @Test
+  public void testUpdateJobInteractive() {
+    ShellEnvironment.setInteractive(true);
+    initEnv();
+    MJob job = new MJob(1, 2, 1, 2, new MFromConfig(getConfig("fromJobConfig"), new ArrayList<MValidator>()),
+        new MToConfig(getConfig("toJobConfig"), new ArrayList<MValidator>()),
+        new MDriverConfig(getConfig("driverConfig"), new ArrayList<MValidator>()));
+    when(client.getJob("job_test")).thenReturn(job);
+    when(client.getConnectorConfigBundle(any(Long.class))).thenReturn(resourceBundle);
+    when(client.getDriverConfigBundle()).thenReturn(resourceBundle);
+    when(client.updateJob(job)).thenReturn(Status.OK);
+
+    // update job -jid job_test
+    initData("jobname\r" +          // job name
+        // From job config
+        "abc\r" +                   // for input with name "String"
+        "12345\r" +                 // for input with name "Integer"
+        "56789\r" +                 // for input with name "Long"
+        "true\r" +                  // for input with name "Boolean"
+        "k1=v1\rk2=v2\r\r" +        // for input with name "Map"
+        "0\r" +                     // for input with name "Enum"
+        "l1\rl2\rl3\r\r" +          // for input with name "List"
+        "12345678\r" +              // for input with name "DateTime"
+
+        // To job config
+        "def\r" +                   // for input with name "String"
+        "11111\r" +                 // for input with name "Integer"
+        "22222\r" +                 // for input with name "Long"
+        "false\r" +                  // for input with name "Boolean"
+        "k3=v3\rk4=v4\r\r" +        // for input with name "Map"
+        "1\r" +                     // for input with name "Enum"
+        "l4\rl5\rl6\r\r" +          // for input with name "List"
+        "1234567\r" +              // for input with name "DateTime"
+
+        // Driver config
+        "hij\r" +                   // for input with name "String"
+        "33333\r" +                 // for input with name "Integer"
+        "44444\r" +                 // for input with name "Long"
+        "true\r" +                  // for input with name "Boolean"
+        "k1=v1\r\r" +               // for input with name "Map"
+        "0\r" +                     // for input with name "Enum"
+        "l1\rl2\rl3\r\r" +          // for input with name "List"
+        "7654321\r");              // for input with name "DateTime"
+    Status status = (Status) updateCmd.execute(Arrays.asList(Constants.FN_JOB, "-jid", "job_test"));
+    assertTrue(status != null && status == Status.OK);
+    assertEquals(job.getName(), "jobname");
+    // check from job config
+    assertEquals(job.getFromJobConfig().getStringInput("fromJobConfig.String").getValue(), "abc");
+    assertEquals(job.getFromJobConfig().getIntegerInput("fromJobConfig.Integer").getValue().intValue(), 12345);
+    assertEquals((job.getFromJobConfig().getLongInput("fromJobConfig.Long").getValue()).longValue(), 56789);
+    assertTrue((job.getFromJobConfig().getBooleanInput("fromJobConfig.Boolean").getValue()));
+    HashMap<String, String> map = new HashMap<String, String>();
+    map.put("k1", "v1");
+    map.put("k2", "v2");
+    assertEquals(job.getFromJobConfig().getMapInput("fromJobConfig.Map").getValue(), map);
+    assertEquals(job.getFromJobConfig().getEnumInput("fromJobConfig.Enum").getValue(), "YES");
+    assertEquals(StringUtils.join(job.getFromJobConfig().getListInput("fromJobConfig.List").getValue(), "&"), "l1&l2&l3");
+    assertEquals(job.getFromJobConfig().getDateTimeInput("fromJobConfig.DateTime").getValue().getMillis(), 12345678);
+
+    // check to job config
+    assertEquals(job.getToJobConfig().getStringInput("toJobConfig.String").getValue(), "def");
+    assertEquals(job.getToJobConfig().getIntegerInput("toJobConfig.Integer").getValue().intValue(), 11111);
+    assertEquals(job.getToJobConfig().getLongInput("toJobConfig.Long").getValue().longValue(), 22222);
+    assertFalse(job.getToJobConfig().getBooleanInput("toJobConfig.Boolean").getValue());
+    map = new HashMap<String, String>();
+    map.put("k3", "v3");
+    map.put("k4", "v4");
+    assertEquals(job.getToJobConfig().getMapInput("toJobConfig.Map").getValue(), map);
+    assertEquals(job.getToJobConfig().getEnumInput("toJobConfig.Enum").getValue(), "NO");
+    assertEquals(StringUtils.join(job.getToJobConfig().getListInput("toJobConfig.List").getValue(), "&"), "l4&l5&l6");
+    assertEquals(job.getToJobConfig().getDateTimeInput("toJobConfig.DateTime").getValue().getMillis(), 1234567);
+
+    // check driver config
+    assertEquals(job.getDriverConfig().getStringInput("driverConfig.String").getValue(), "hij");
+    assertEquals(job.getDriverConfig().getIntegerInput("driverConfig.Integer").getValue().intValue(), 33333);
+    assertEquals(job.getDriverConfig().getLongInput("driverConfig.Long").getValue().longValue(), 44444);
+    assertTrue(job.getDriverConfig().getBooleanInput("driverConfig.Boolean").getValue());
+    map = new HashMap<String, String>();
+    map.put("k1", "v1");
+    assertEquals(job.getDriverConfig().getMapInput("driverConfig.Map").getValue(), map);
+    assertEquals(job.getDriverConfig().getEnumInput("driverConfig.Enum").getValue(), "YES");
+    assertEquals(StringUtils.join(job.getDriverConfig().getListInput("driverConfig.List").getValue(), "&"), "l1&l2&l3");
+    assertEquals(job.getDriverConfig().getDateTimeInput("driverConfig.DateTime").getValue().getMillis(), 7654321);
+  }
+
+  @SuppressWarnings("unchecked")
+  private List<MConfig> getConfig(String configName) {
+    List<MInput<?>> list = new ArrayList<MInput<?>>();
+    list.add(new MStringInput(configName + "." + "String", false, InputEditable.ANY, StringUtils.EMPTY, (short)30, Collections.EMPTY_LIST));
+    list.add(new MIntegerInput(configName + "." + "Integer", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MLongInput(configName + "." + "Long", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MBooleanInput(configName + "." + "Boolean", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MMapInput(configName + "." + "Map", false, InputEditable.ANY, StringUtils.EMPTY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MEnumInput(configName + "." + "Enum", false, InputEditable.ANY, StringUtils.EMPTY, new String[] {"YES", "NO"}, Collections.EMPTY_LIST));
+    list.add(new MListInput(configName + "." + "List", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+    list.add(new MDateTimeInput(configName + "." + "DateTime", false, InputEditable.ANY, StringUtils.EMPTY, Collections.EMPTY_LIST));
+
+    List<MConfig> configs = new ArrayList<MConfig>();
+    configs.add(new MConfig(configName, list, Collections.EMPTY_LIST));
+    return configs;
+  }
+
+  private void initData(String destData) {
+    byte[] destDataBytes = destData.getBytes();
+    System.arraycopy(destDataBytes, 0, data, 0, destDataBytes.length);
+    in.reset();
+  }
+
+  private void initEnv() {
+    in.reset();
+    for (int i = 0; i < data.length; i++) {
+      data[i] = '\0';
     }
   }
 }