OOZIE-2748 NPE in LauncherMapper.printArgs() (pbacsko via rkanter) (cherry picked from commit c7fa12bb1abac643c60c7282626c39b690ae378b)
Project: http://git-wip-us.apache.org/repos/asf/oozie/repo Commit: http://git-wip-us.apache.org/repos/asf/oozie/commit/3b24d9dd Tree: http://git-wip-us.apache.org/repos/asf/oozie/tree/3b24d9dd Diff: http://git-wip-us.apache.org/repos/asf/oozie/diff/3b24d9dd Branch: refs/heads/branch-4.3 Commit: 3b24d9ddeb0c76be91083e2d93d70adf0b321125 Parents: a0c0ed9 Author: Robert Kanter <rkan...@cloudera.com> Authored: Fri Jan 6 10:36:26 2017 -0800 Committer: satishsaley <satishsa...@apache.org> Committed: Fri Dec 8 16:34:55 2017 -0800 ---------------------------------------------------------------------- .../action/hadoop/TestJavaActionExecutor.java | 26 ++++++ release-log.txt | 1 + sharelib/oozie/pom.xml | 6 ++ .../oozie/action/hadoop/LauncherMapper.java | 17 +++- .../oozie/action/hadoop/TestLauncherMapper.java | 88 ++++++++++++++++++++ 5 files changed, 136 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/oozie/blob/3b24d9dd/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java b/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java index 8965cdf..1c4b429 100644 --- a/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java +++ b/core/src/test/java/org/apache/oozie/action/hadoop/TestJavaActionExecutor.java @@ -2941,4 +2941,30 @@ public class TestJavaActionExecutor extends ActionExecutorTestCase { assertEquals("DEBUG", conf.get(oozieActionHiveRootLogger)); } + public void testEmptyArgs() throws Exception { + String actionXml = "<java>" + + "<job-tracker>" + getJobTrackerUri() + "</job-tracker>" + + "<name-node>" + getNameNodeUri() + "</name-node>" + + "<main-class>" + LauncherMainTester.class.getName() + "</main-class>" + + "<arg></arg>" + + "</java>"; + + Context context = createContext(actionXml, null); + final RunningJob runningJob = submitAction(context); + waitFor(60 * 1000, new Predicate() { + @Override + public boolean evaluate() throws Exception { + return runningJob.isComplete(); + } + }); + assertTrue(runningJob.isSuccessful()); + ActionExecutor ae = new JavaActionExecutor(); + ae.check(context, context.getAction()); + assertTrue(ae.isCompleted(context.getAction().getExternalStatus())); + assertEquals("SUCCEEDED", context.getAction().getExternalStatus()); + assertNull(context.getAction().getData()); + + ae.end(context, context.getAction()); + assertEquals(WorkflowAction.Status.OK, context.getAction().getStatus()); + } } http://git-wip-us.apache.org/repos/asf/oozie/blob/3b24d9dd/release-log.txt ---------------------------------------------------------------------- diff --git a/release-log.txt b/release-log.txt index 0f70852..e1026d6 100644 --- a/release-log.txt +++ b/release-log.txt @@ -1,5 +1,6 @@ -- Oozie 4.3.1 release +OOZIE-2748 NPE in LauncherMapper.printArgs() (pbacsko via rkanter) OOZIE-2654 Zookeeper dependent services should not depend on Connectionstate to be valid before cleaning up (venkatnrangan via abhishekbafna) OOZIE-2690 OOZIE NPE while executing kill() (abhishekbafna via jaydeepvishwakarma) http://git-wip-us.apache.org/repos/asf/oozie/blob/3b24d9dd/sharelib/oozie/pom.xml ---------------------------------------------------------------------- diff --git a/sharelib/oozie/pom.xml b/sharelib/oozie/pom.xml index 8dfebd4..c30e984 100644 --- a/sharelib/oozie/pom.xml +++ b/sharelib/oozie/pom.xml @@ -62,6 +62,12 @@ </dependency> <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <scope>test</scope> + </dependency> + + <dependency> <groupId>org.apache.oozie</groupId> <artifactId>oozie-hadoop-utils</artifactId> <scope>compile</scope> http://git-wip-us.apache.org/repos/asf/oozie/blob/3b24d9dd/sharelib/oozie/src/main/java/org/apache/oozie/action/hadoop/LauncherMapper.java ---------------------------------------------------------------------- diff --git a/sharelib/oozie/src/main/java/org/apache/oozie/action/hadoop/LauncherMapper.java b/sharelib/oozie/src/main/java/org/apache/oozie/action/hadoop/LauncherMapper.java index 7271486..8edebac 100644 --- a/sharelib/oozie/src/main/java/org/apache/oozie/action/hadoop/LauncherMapper.java +++ b/sharelib/oozie/src/main/java/org/apache/oozie/action/hadoop/LauncherMapper.java @@ -50,6 +50,8 @@ import org.apache.hadoop.mapred.Mapper; import org.apache.hadoop.mapred.OutputCollector; import org.apache.hadoop.mapred.Reporter; +import com.google.common.base.Strings; + public class LauncherMapper<K1, V1, K2, V2> implements Mapper<K1, V1, K2, V2>, Runnable { static final String CONF_OOZIE_ACTION_MAIN_CLASS = "oozie.launcher.action.main.class"; @@ -494,10 +496,21 @@ public class LauncherMapper<K1, V1, K2, V2> implements Mapper<K1, V1, K2, V2>, R public static String[] getMainArguments(Configuration conf) { String[] args = new String[conf.getInt(CONF_OOZIE_ACTION_MAIN_ARG_COUNT, 0)]; + + int pos = 0; for (int i = 0; i < args.length; i++) { - args[i] = conf.get(CONF_OOZIE_ACTION_MAIN_ARG_PREFIX + i); + String arg = conf.get(CONF_OOZIE_ACTION_MAIN_ARG_PREFIX + i); + if (!Strings.isNullOrEmpty(arg)) { + args[pos++] = conf.get(CONF_OOZIE_ACTION_MAIN_ARG_PREFIX + i); + } } - return args; + + // this is to skip null args, that is <arg></arg> in the workflow XML -- in this case, + // args[] might look like {"arg1", "arg2", null, null} at this point + String[] retArray = new String[pos]; + System.arraycopy(args, 0, retArray, 0, pos); + + return retArray; } private void setupHeartBeater(Reporter reporter) { http://git-wip-us.apache.org/repos/asf/oozie/blob/3b24d9dd/sharelib/oozie/src/test/java/org/apache/oozie/action/hadoop/TestLauncherMapper.java ---------------------------------------------------------------------- diff --git a/sharelib/oozie/src/test/java/org/apache/oozie/action/hadoop/TestLauncherMapper.java b/sharelib/oozie/src/test/java/org/apache/oozie/action/hadoop/TestLauncherMapper.java new file mode 100644 index 0000000..1dd8002 --- /dev/null +++ b/sharelib/oozie/src/test/java/org/apache/oozie/action/hadoop/TestLauncherMapper.java @@ -0,0 +1,88 @@ +/** + * 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 static org.apache.oozie.action.hadoop.LauncherMapper.CONF_OOZIE_ACTION_MAIN_ARG_COUNT; +import static org.apache.oozie.action.hadoop.LauncherMapper.CONF_OOZIE_ACTION_MAIN_ARG_PREFIX; +import static org.junit.Assert.assertTrue; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.eq; + +import java.util.Arrays; +import java.util.List; + +import org.apache.hadoop.conf.Configuration; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import com.google.common.collect.Lists; + +@RunWith(MockitoJUnitRunner.class) +public class TestLauncherMapper { + @Mock + private Configuration conf; // we have to use mock, because conf.set(null) throws exception + + @Test + public void testLauncherMapperArgsHandlingWithoutNulls() { + setupConf(Lists.newArrayList("a", "b", "c")); + + String args[] = LauncherMapper.getMainArguments(conf); + + assertTrue(Arrays.equals(new String[] { "a", "b", "c"}, args)); + } + + @Test + public void testLauncherMapperArgsHandlingWhenArgsContainNulls() { + setupConf(Lists.newArrayList("a", null, "b", null, "c")); + + String args[] = LauncherMapper.getMainArguments(conf); + + assertTrue(Arrays.equals(new String[] { "a", "b", "c"}, args)); + } + + @Test + public void testLauncherMapperArgsHandlingWhenArgsContainsNullsOnly() { + setupConf(Lists.<String>newArrayList(null, null, null)); + + String args[] = LauncherMapper.getMainArguments(conf); + + assertTrue(Arrays.equals(new String[] {}, args)); + } + + @Test + public void testLauncherMapperArgsHandlingWhenArgsContainsOneNull() { + setupConf(Lists.<String>newArrayList((String) null)); + + String args[] = LauncherMapper.getMainArguments(conf); + + assertTrue(Arrays.equals(new String[] {}, args)); + } + + private void setupConf(List<String> argList) { + int argCount = argList.size(); + + given(conf.getInt(eq(CONF_OOZIE_ACTION_MAIN_ARG_COUNT), eq(0))).willReturn(argCount); + + for (int i = 0; i < argCount; i++) { + given(conf.get(eq(CONF_OOZIE_ACTION_MAIN_ARG_PREFIX + i))).willReturn(argList.get(i)); + } + } +}