This is an automated email from the ASF dual-hosted git repository.
kmarton pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/oozie.git
The following commit(s) were added to refs/heads/master by this push:
new 1a1a97a OOZIE-2949 Escape quotes whitespaces in Sqoop <command> field
(asalamon74 via kmarton)
1a1a97a is described below
commit 1a1a97acbab14161880c32651705e8aebe9ec8d0
Author: Julia Kinga Marton <[email protected]>
AuthorDate: Fri Feb 1 08:44:28 2019 +0100
OOZIE-2949 Escape quotes whitespaces in Sqoop <command> field (asalamon74
via kmarton)
---
core/src/main/java/org/apache/oozie/ErrorCode.java | 1 -
.../apache/oozie/action/hadoop/ShellSplitter.java | 94 +++++++++++++++
.../action/hadoop/ShellSplitterException.java | 36 ++++++
.../oozie/action/hadoop/SqoopActionExecutor.java | 39 +++++-
core/src/main/resources/oozie-default.xml | 8 ++
.../oozie/action/hadoop/TestShellSplitter.java | 134 +++++++++++++++++++++
docs/src/site/markdown/DG_SqoopActionExtension.md | 14 ++-
release-log.txt | 1 +
.../action/hadoop/TestSqoopActionExecutor.java | 59 ++++++++-
9 files changed, 373 insertions(+), 13 deletions(-)
diff --git a/core/src/main/java/org/apache/oozie/ErrorCode.java
b/core/src/main/java/org/apache/oozie/ErrorCode.java
index e274b9d..6b0ce47 100644
--- a/core/src/main/java/org/apache/oozie/ErrorCode.java
+++ b/core/src/main/java/org/apache/oozie/ErrorCode.java
@@ -67,7 +67,6 @@ public enum ErrorCode {
E0307(XLog.STD, "Runtime error [{0}]"),
E0308(XLog.STD, "Could not parse date range parameter [{0}]"),
-
E0401(XLog.STD, "Missing configuration property [{0}]"),
E0402(XLog.STD, "Invalid callback ID [{0}]"),
E0403(XLog.STD, "Invalid callback data, {0}"),
diff --git
a/core/src/main/java/org/apache/oozie/action/hadoop/ShellSplitter.java
b/core/src/main/java/org/apache/oozie/action/hadoop/ShellSplitter.java
new file mode 100644
index 0000000..69d39cf
--- /dev/null
+++ b/core/src/main/java/org/apache/oozie/action/hadoop/ShellSplitter.java
@@ -0,0 +1,94 @@
+/**
+ * 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.action.hadoop;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ShellSplitter {
+ private static final char BACKSPACE = '\\';
+ private static final char SINGLE_QUOTE = '\'';
+ private static final char DOUBLE_QUOTE = '"';
+ private static final char SPACE = ' ';
+ private boolean escaping;
+ private char quoteChar;
+ private boolean quoting;
+ private boolean addTokenEvenIfEmpty;
+ private StringBuilder current;
+ private List<String> tokens;
+
+ List<String> split(final String commandLine) throws ShellSplitterException
{
+ if (commandLine == null) {
+ return null;
+ }
+ ensureFields();
+ for (int i = 0; i < commandLine.length(); i++) {
+ char c = commandLine.charAt(i);
+ processCharacter(c);
+ }
+ addLastToken();
+ if (quoting || escaping) {
+ final String errorMessage = String.format("Unable to parse command
%s", commandLine);
+ throw new ShellSplitterException(errorMessage);
+ }
+ return tokens;
+ }
+
+ private void ensureFields() {
+ tokens = new ArrayList<>();
+ escaping = false;
+ quoteChar = SPACE;
+ quoting = false;
+ addTokenEvenIfEmpty = false;
+ current = new StringBuilder();
+ }
+
+ private void processCharacter(char c) {
+ if (escaping) {
+ current.append(c);
+ escaping = false;
+ } else if (c == BACKSPACE && !(quoting && quoteChar == SINGLE_QUOTE)) {
+ escaping = true;
+ } else if (quoting && c == quoteChar) {
+ quoting = false;
+ addTokenEvenIfEmpty = true;
+ } else if (!quoting && (c == SINGLE_QUOTE || c == DOUBLE_QUOTE)) {
+ quoting = true;
+ quoteChar = c;
+ } else if (!quoting && Character.isWhitespace(c)) {
+ if (current.length() > 0 || addTokenEvenIfEmpty ) {
+ addNewToken();
+ }
+ } else {
+ current.append(c);
+ }
+ }
+
+ private void addLastToken() {
+ if (current.length() > 0) {
+ addNewToken();
+ }
+ }
+
+ private void addNewToken() {
+ tokens.add(current.toString());
+ current = new StringBuilder();
+ addTokenEvenIfEmpty = false;
+ }
+}
diff --git
a/core/src/main/java/org/apache/oozie/action/hadoop/ShellSplitterException.java
b/core/src/main/java/org/apache/oozie/action/hadoop/ShellSplitterException.java
new file mode 100644
index 0000000..ef18d51
--- /dev/null
+++
b/core/src/main/java/org/apache/oozie/action/hadoop/ShellSplitterException.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.action.hadoop;
+
+import org.apache.oozie.ErrorCode;
+
+/**
+ * Exception thrown by {@link ShellSplitter}.
+ */
+public class ShellSplitterException extends Exception {
+
+ public ShellSplitterException(String msg) {
+ super(msg);
+ }
+
+ public ShellSplitterException(String msg, Throwable throwable) {
+ super(msg, throwable);
+ }
+
+}
diff --git
a/core/src/main/java/org/apache/oozie/action/hadoop/SqoopActionExecutor.java
b/core/src/main/java/org/apache/oozie/action/hadoop/SqoopActionExecutor.java
index 556f2cf..ffe27e3 100644
--- a/core/src/main/java/org/apache/oozie/action/hadoop/SqoopActionExecutor.java
+++ b/core/src/main/java/org/apache/oozie/action/hadoop/SqoopActionExecutor.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
@@ -42,9 +43,13 @@ import org.jdom.Namespace;
public class SqoopActionExecutor extends JavaActionExecutor {
public static final String OOZIE_ACTION_EXTERNAL_STATS_WRITE =
"oozie.action.external.stats.write";
+ @VisibleForTesting
+ static final String OOZIE_ACTION_SQOOP_SHELLSPLITTER =
"oozie.action.sqoop.shellsplitter";
+ private static final boolean SHELLSPLITTER_DEFAULT = false;
private static final String SQOOP_MAIN_CLASS_NAME =
"org.apache.oozie.action.hadoop.SqoopMain";
static final String SQOOP_ARGS = "oozie.sqoop.args";
private static final String SQOOP = "sqoop";
+ private ShellSplitter shellSplitter = new ShellSplitter();
public SqoopActionExecutor() {
super(SQOOP);
@@ -85,14 +90,11 @@ public class SqoopActionExecutor extends JavaActionExecutor
{
throw convertException(ex);
}
- final List<String> argList = new ArrayList<>();
+ List<String> argList = new ArrayList<>();
// Build a list of arguments from either a tokenized <command> string
or a list of <arg>
if (actionXml.getChild("command", ns) != null) {
String command = actionXml.getChild("command", ns).getTextTrim();
- StringTokenizer st = new StringTokenizer(command, " ");
- while (st.hasMoreTokens()) {
- argList.add(st.nextToken());
- }
+ argList = splitCommand(actionConf, command);
}
else {
@SuppressWarnings("unchecked")
@@ -113,11 +115,36 @@ public class SqoopActionExecutor extends
JavaActionExecutor {
"Found a redundant 'sqoop' prefixing the command. Removing
it.");
argList.remove(0);
}
-
setSqoopCommand(actionConf, argList.toArray(new
String[argList.size()]));
return actionConf;
}
+ private List<String> splitCommand(Configuration actionConf, String
command) throws ActionExecutorException {
+ List<String> argList;
+ boolean useShellSplitter =
actionConf.getBoolean(OOZIE_ACTION_SQOOP_SHELLSPLITTER, SHELLSPLITTER_DEFAULT);
+ if (useShellSplitter) {
+ try {
+ argList = shellSplitter.split(command);
+ } catch (ShellSplitterException e) {
+ throw new
ActionExecutorException(ActionExecutorException.ErrorType.ERROR, "SQOOP002",
+ "Cannot parse sqoop command: [{0}]", command, e);
+ }
+ }
+ else {
+ argList = splitBySpace(command);
+ }
+ return argList;
+ }
+
+ private List<String> splitBySpace(final String command) {
+ List<String> tokens = new ArrayList<>();
+ StringTokenizer st = new StringTokenizer(command, " ");
+ while (st.hasMoreTokens()) {
+ tokens.add(st.nextToken());
+ }
+ return tokens;
+ }
+
private void setSqoopCommand(Configuration conf, String[] args) {
ActionUtils.setStrings(conf, SQOOP_ARGS, args);
}
diff --git a/core/src/main/resources/oozie-default.xml
b/core/src/main/resources/oozie-default.xml
index 6c7fc9d..c7f2bec 100644
--- a/core/src/main/resources/oozie-default.xml
+++ b/core/src/main/resources/oozie-default.xml
@@ -3419,6 +3419,14 @@ will be the requeue interval for the actions which are
waiting for a long time w
</property>
<property>
+ <name>oozie.action.sqoop.shellsplitter</name>
+ <value>false</value>
+ <description>
+ Whether to use shell splitter instead of the space-based tokenizer
during sqoop command splitting.
+ </description>
+ </property>
+
+ <property>
<name>oozie.fluent-job-api.generated.path</name>
<value>/user/${user.name}/oozie-fluent-job-api-generated</value>
<description>
diff --git
a/core/src/test/java/org/apache/oozie/action/hadoop/TestShellSplitter.java
b/core/src/test/java/org/apache/oozie/action/hadoop/TestShellSplitter.java
new file mode 100644
index 0000000..e93e3fd
--- /dev/null
+++ b/core/src/test/java/org/apache/oozie/action/hadoop/TestShellSplitter.java
@@ -0,0 +1,134 @@
+/**
+ * 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.action.hadoop;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Parameterized.class)
+public class TestShellSplitter {
+ private ShellSplitter shellSplitter;
+ private String input;
+ private List<String> expectedOutput;
+ private Class<? extends Exception> expectedExceptionClass;
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> params() {
+ return Arrays.asList(new Object[][]{
+ {null,
+ null,
+ null},
+ {"",
+ Collections.<String>emptyList(),
+ null},
+ {" \t \n",
+ Collections.<String>emptyList(),
+ null},
+ {"a\tbee cee",
+ Arrays.asList("a", "bee", "cee"),
+ null},
+ {" hello world\t",
+ Arrays.asList("hello", "world"),
+ null},
+ {"\"hello world\"",
+ Collections.singletonList("hello world"),
+ null},
+ {"'hello world'",
+ Collections.singletonList("hello world"),
+ null},
+ {"\"\\\"hello world\\\"\"",
+ Collections.singletonList("\"hello world\""),
+ null},
+ {"'hello \\\" world'",
+ Collections.singletonList("hello \\\" world"),
+ null},
+ {"\"foo\"'bar'baz",
+ Collections.singletonList("foobarbaz"),
+ null},
+ {"\"three\"' 'four",
+ Collections.singletonList("three four"),
+ null},
+ {"three\\ four",
+ Collections.singletonList("three four"),
+ null},
+ {" '' one",
+ Arrays.asList("", "one"),
+ null},
+ {"command -a aa -b -c",
+ Arrays.asList("command", "-a", "aa", "-b", "-c"),
+ null},
+ {"command --longopt \"this is a single token\" --otherlongopt",
+ Arrays.asList("command", "--longopt", "this is a
single token", "--otherlongopt"),
+ null},
+ {"command --longopt 'this is a single token' --otherlongopt",
+ Arrays.asList("command", "--longopt", "this is a
single token", "--otherlongopt"),
+ null},
+ {"'",
+ null,
+ ShellSplitterException.class},
+ {"'Hello world",
+ null,
+ ShellSplitterException.class},
+ {"\"Hello world",
+ null,
+ ShellSplitterException.class},
+ {"Hellow world\\",
+ null,
+ ShellSplitterException.class},
+ {"\"Hello world'",
+ null,
+ ShellSplitterException.class},
+ });
+ }
+
+ public TestShellSplitter(String input, List<String> expectedOutput,
Class<? extends Exception> expectedException) {
+ this.input = input;
+ this.expectedOutput = expectedOutput;
+ this.expectedExceptionClass = expectedException;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ shellSplitter = new ShellSplitter();
+ }
+
+ @Test
+ public void test() throws ShellSplitterException {
+ if (expectedExceptionClass != null) {
+ expectedException.expect(expectedExceptionClass);
+ shellSplitter.split(input);
+ }
+ else {
+ assertEquals("Invalid splitting", expectedOutput,
shellSplitter.split(input));
+ }
+ }
+}
\ No newline at end of file
diff --git a/docs/src/site/markdown/DG_SqoopActionExtension.md
b/docs/src/site/markdown/DG_SqoopActionExtension.md
index b186c5a..fa0674a 100644
--- a/docs/src/site/markdown/DG_SqoopActionExtension.md
+++ b/docs/src/site/markdown/DG_SqoopActionExtension.md
@@ -91,12 +91,18 @@ properties that are passed to the Sqoop job.
The Sqoop command can be specified either using the `command` element or
multiple `arg`
elements.
-When using the `command` element, Oozie will split the command on every space
-into multiple arguments.
+When using the `command` element, Oozie will split the command into multiple
arguments. There are two command splitting algorithms
+in Oozie.
-When using the `arg` elements, Oozie will pass each argument value as an
argument to Sqoop.
+If `oozie.action.sqoop.shellsplitter` property is set to `false` Oozie will
split the command on every space.
+
+If `oozie.action.sqoop.shellsplitter` property is set to `true` Oozie will
split the command like `bash` splits the commands.
+In this case it's possible to group strings together using quotes. For
instance oozie will split `--query "select * from employee"`
+into two tokens: `--query` and `select * from employee`.
-The `arg` variant should be used when there are spaces within a single
argument.
+The default value of the `oozie.action.sqoop.shellsplitter` property is
`false`.
+
+When using the `arg` elements, Oozie will pass each argument value as an
argument to Sqoop.
Consult the Sqoop documentation for a complete list of valid Sqoop commands.
diff --git a/release-log.txt b/release-log.txt
index 9e49d2b..339b930 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -1,5 +1,6 @@
-- Oozie 5.2.0 release (trunk - unreleased)
+OOZIE-2949 Escape quotes whitespaces in Sqoop <command> field (asalamon74 via
kmarton)
OOZIE-3426 [core] V1JobsServlet should log HDFS related error when trying to
save workflow definition (asalamon74 via andras.piros)
OOZIE-3417 [FS Action] Refactor and optimize FsActionExecutor.java decision
making part (nobigo via asalamon74, kmarton)
OOZIE-3243 [tests] Flaky test
TestCoordActionsKillXCommand#testActionKillCommandDate (asalamon74 via kmarton)
diff --git
a/sharelib/sqoop/src/test/java/org/apache/oozie/action/hadoop/TestSqoopActionExecutor.java
b/sharelib/sqoop/src/test/java/org/apache/oozie/action/hadoop/TestSqoopActionExecutor.java
index edfe0c7..e230f39 100644
---
a/sharelib/sqoop/src/test/java/org/apache/oozie/action/hadoop/TestSqoopActionExecutor.java
+++
b/sharelib/sqoop/src/test/java/org/apache/oozie/action/hadoop/TestSqoopActionExecutor.java
@@ -24,6 +24,7 @@ import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.PathFilter;
import org.apache.oozie.WorkflowActionBean;
import org.apache.oozie.WorkflowJobBean;
+import org.apache.oozie.action.ActionExecutorException;
import org.apache.oozie.client.WorkflowAction;
import org.apache.oozie.service.WorkflowAppService;
import org.apache.oozie.util.IOUtils;
@@ -48,6 +49,9 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
private static final String SQOOP_IMPORT_COMMAND =
"import --connect {0} --table TT --target-dir {1} -m 1";
+ private static final String SQOOP_IMPORT_COMMAND_WITH_QUERY =
+ "import --connect {0} --username sa --password \"\" --verbose
--query {1} --target-dir {2} --split-by I";
+
private static final String SQOOP_ACTION_COMMAND_XML =
"<sqoop xmlns=\"uri:oozie:sqoop-action:0.1\">" +
"<job-tracker>{0}</job-tracker>" +
@@ -155,6 +159,20 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
"dummy", "dummyValue", command);
}
+ private String getImportWithQueryActionXml(boolean useNewShellSplitter) {
+ String command = MessageFormat.format(SQOOP_IMPORT_COMMAND_WITH_QUERY,
getActionJdbcUri(),
+ "\"select TT.I, TT.S from TT where $CONDITIONS\"",
getSqoopOutputDir());
+ return MessageFormat.format(SQOOP_ACTION_COMMAND_XML,
getJobTrackerUri(), getNameNodeUri(),
+ SqoopActionExecutor.OOZIE_ACTION_SQOOP_SHELLSPLITTER,
useNewShellSplitter, command);
+ }
+
+ private String getInvalidImportWithQueryActionXml(boolean
useNewShellSplitter) {
+ String command = MessageFormat.format(SQOOP_IMPORT_COMMAND_WITH_QUERY,
getActionJdbcUri(),
+ "\"select TT.I, TT.S from TT where $CONDITIONS'",
getSqoopOutputDir());
+ return MessageFormat.format(SQOOP_ACTION_COMMAND_XML,
getJobTrackerUri(), getNameNodeUri(),
+ SqoopActionExecutor.OOZIE_ACTION_SQOOP_SHELLSPLITTER,
useNewShellSplitter, command);
+ }
+
private String getActionXmlEval() {
String query = "select TT.I, TT.S from TT";
return MessageFormat.format(SQOOP_ACTION_EVAL_XML, getJobTrackerUri(),
getNameNodeUri(),
@@ -168,6 +186,12 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
getActionJdbcUri(), query,
getSqoopOutputDir());
}
+ private String getArgsActionXmlFreeFromQueryInQuotes(String quote) {
+ String query = "select TT.I, TT.S from TT where $CONDITIONS";
+ return MessageFormat.format(SQOOP_ACTION_ARGS_XML, getJobTrackerUri(),
getNameNodeUri(),
+ "<arg>import</arg>", getActionJdbcUri(), quote + query + quote,
getSqoopOutputDir());
+ }
+
private String getBadArgsActionXml() {
String query = "select TT.I, TT.S from TT where $CONDITIONS";
return MessageFormat.format(SQOOP_ACTION_ARGS_XML, getJobTrackerUri(),
getNameNodeUri(),
@@ -190,6 +214,7 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
/**
* Tests a bad command of 'sqoop --username ...' style.
* Test asserts that the job will fail.
+ * @throws java.lang.Exception
*/
public void testSqoopActionWithBadCommand() throws Exception {
runSqoopActionWithBadCommand(getBadCommandActionXml());
@@ -216,6 +241,7 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
/**
* Tests a normal command of 'import --username ...'.
+ * @throws java.lang.Exception
*/
public void testSqoopAction() throws Exception {
runSqoopAction(getActionXml());
@@ -224,6 +250,7 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
/**
* Tests a redundant command of 'sqoop import --username ...'.
* The test guarantees a success, since the redundant 'sqoop' must get
removed.
+ * @throws java.lang.Exception
*/
public void testSqoopActionWithRedundantPrefix() throws Exception {
runSqoopAction(getRedundantCommandActionXml());
@@ -290,6 +317,7 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
/**
* Runs a job with arg-style command of 'sqoop --username ...' form that's
invalid.
* The test ensures it fails.
+ * @throws java.lang.Exception
*/
public void testSqoopActionWithBadRedundantArgsAndFreeFormQuery() throws
Exception {
runSqoopActionWithBadCommand(getBadArgsActionXml());
@@ -298,6 +326,7 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
/**
* Runs a job with the arg-style command of 'sqoop import --username ...'.
* The test guarantees that the redundant 'sqoop' is auto-removed (job
passes).
+ * @throws java.lang.Exception
*/
public void testSqoopActionWithRedundantArgsAndFreeFormQuery() throws
Exception {
runSqoopActionFreeFormQuery(getArgsActionXmlFreeFromQuery(true));
@@ -305,11 +334,38 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
/**
* Runs a job with the normal arg-style command of 'import --username ...'.
+ * @throws java.lang.Exception
*/
public void testSqoopActionWithArgsAndFreeFormQuery() throws Exception {
runSqoopActionFreeFormQuery(getArgsActionXmlFreeFromQuery(false));
}
+ /**
+ * Runs a job with the normal arg-style command of 'import --username ...'.
+ * This is meant to be a sanity check for when --query argument has
+ * double quotes around it.
+ * @throws java.lang.Exception
+ */
+ public void testSqoopActionWithArgsAndFreeFormQueryInDoubleQuotes() throws
Exception {
+
runSqoopActionFreeFormQuery(getArgsActionXmlFreeFromQueryInQuotes("\""));
+ }
+
+ public void testSqoopActionWithCommandAndFreeFormQuery() throws Exception {
+ boolean useNewShellSplitter = true;
+
runSqoopActionFreeFormQuery(getImportWithQueryActionXml(useNewShellSplitter));
+ }
+
+ public void testInvalidSqoopActionWithCommandAndFreeFormQuery() throws
Exception {
+ try {
+ boolean useNewShellSplitter = true;
+
runSqoopActionFreeFormQuery(getInvalidImportWithQueryActionXml(useNewShellSplitter));
+ fail("Expected ActionExecutorException");
+ }
+ catch (ActionExecutorException e) {
+ assertTrue(String.format("Invalid error message: [%s]",
e.getMessage()), e.getMessage().startsWith("SQOOP002"));
+ }
+ }
+
private void runSqoopActionFreeFormQuery(String actionXml) throws
Exception {
createDB();
@@ -353,7 +409,6 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
assertEquals(3, count);
}
-
private String submitAction(Context context) throws Exception {
SqoopActionExecutor ae = new SqoopActionExecutor();
@@ -392,7 +447,7 @@ public class TestSqoopActionExecutor extends
ActionExecutorTestCase {
}
private String[] copyDbToHdfs() throws Exception {
- List<String> files = new ArrayList<String>();
+ List<String> files = new ArrayList<>();
String[] exts = {".script", ".properties"};
for (String ext : exts) {
String file = getDbPath() + ext;