You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@slider.apache.org by st...@apache.org on 2014/06/02 20:11:54 UTC
[3/8] git commit: SLIDER-94: tests for LongLivedProcess -caught a
regression in the switch to ExecutorService based execution
SLIDER-94: tests for LongLivedProcess -caught a regression in the switch to ExecutorService based execution
Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/0f1ab84a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/0f1ab84a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/0f1ab84a
Branch: refs/heads/develop
Commit: 0f1ab84a596ffa0192236399267002d38b9e2f84
Parents: bd20dc6
Author: Steve Loughran <st...@apache.org>
Authored: Mon Jun 2 13:47:55 2014 +0100
Committer: Steve Loughran <st...@apache.org>
Committed: Mon Jun 2 13:47:55 2014 +0100
----------------------------------------------------------------------
.../services/workflow/ForkedProcessService.java | 2 +-
.../services/workflow/LongLivedProcess.java | 15 +-
.../workflow/ProcessCommandFactory.java | 75 +++++++++
.../services/workflow/TestLongLivedProcess.java | 164 +++++++++++++++++++
.../workflow/WorkflowServiceTestBase.java | 5 +-
5 files changed, 252 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/0f1ab84a/slider-core/src/main/java/org/apache/slider/server/services/workflow/ForkedProcessService.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/server/services/workflow/ForkedProcessService.java b/slider-core/src/main/java/org/apache/slider/server/services/workflow/ForkedProcessService.java
index c3744f8..a5c042a 100644
--- a/slider-core/src/main/java/org/apache/slider/server/services/workflow/ForkedProcessService.java
+++ b/slider-core/src/main/java/org/apache/slider/server/services/workflow/ForkedProcessService.java
@@ -71,7 +71,7 @@ public class ForkedProcessService extends AbstractWorkflowExecutorService implem
throw new ServiceStateException("Process not yet configured");
}
//now spawn the process -expect updates via callbacks
- process.spawnApplication();
+ process.start();
}
@Override //AbstractService
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/0f1ab84a/slider-core/src/main/java/org/apache/slider/server/services/workflow/LongLivedProcess.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/server/services/workflow/LongLivedProcess.java b/slider-core/src/main/java/org/apache/slider/server/services/workflow/LongLivedProcess.java
index 8293255..9efbe9f 100644
--- a/slider-core/src/main/java/org/apache/slider/server/services/workflow/LongLivedProcess.java
+++ b/slider-core/src/main/java/org/apache/slider/server/services/workflow/LongLivedProcess.java
@@ -105,7 +105,6 @@ public class LongLivedProcess implements Runnable {
* @param lifecycleCallback callback to notify on application exit
*/
public void setLifecycleCallback(LongLivedProcessLifecycleEvent lifecycleCallback) {
- Preconditions.checkArgument(lifecycleCallback != null, "lifecycleCallback");
this.lifecycleCallback = lifecycleCallback;
}
@@ -114,7 +113,7 @@ public class LongLivedProcess implements Runnable {
* @param envVar envVar -must not be null
* @param val value
*/
- public void putEnv(String envVar, String val) {
+ public void setEnv(String envVar, String val) {
Preconditions.checkArgument(envVar != null, "envVar");
Preconditions.checkArgument(val != null, "val");
processBuilder.environment().put(envVar, val);
@@ -130,7 +129,7 @@ public class LongLivedProcess implements Runnable {
for (Map.Entry<String, String> entry : map.entrySet()) {
String val = entry.getValue();
String key = entry.getKey();
- putEnv(key, val);
+ setEnv(key, val);
}
}
@@ -210,7 +209,7 @@ public class LongLivedProcess implements Runnable {
* Dump the environment to a string builder
* @param buffer the buffer to append to
*/
- private void dumpEnv(StringBuilder buffer) {
+ public void dumpEnv(StringBuilder buffer) {
buffer.append("\nEnvironment\n-----------");
Map<String, String> env = processBuilder.environment();
Set<String> keys = env.keySet();
@@ -261,8 +260,10 @@ public class LongLivedProcess implements Runnable {
if (lifecycleCallback != null) {
lifecycleCallback.onProcessExited(this, exitCode);
}
+ // shut down the threads
+ logExecutor.shutdown();
try {
- logExecutor.awaitTermination(60, TimeUnit.MINUTES);
+ logExecutor.awaitTermination(60, TimeUnit.SECONDS);
} catch (InterruptedException ignored) {
//ignored
}
@@ -273,7 +274,7 @@ public class LongLivedProcess implements Runnable {
* Spawn the application
* @throws IOException IO problems
*/
- public void spawnApplication() throws IOException {
+ public void start() throws IOException {
spawnChildProcess();
processExecutor.submit(this);
@@ -406,7 +407,7 @@ public class LongLivedProcess implements Runnable {
outLine.setLength(0);
processed |= true;
}
- if (!processed) {
+ if (!processed && !finished) {
//nothing processed: wait a bit for data.
try {
Thread.sleep(sleepTime);
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/0f1ab84a/slider-core/src/test/java/org/apache/slider/server/services/workflow/ProcessCommandFactory.java
----------------------------------------------------------------------
diff --git a/slider-core/src/test/java/org/apache/slider/server/services/workflow/ProcessCommandFactory.java b/slider-core/src/test/java/org/apache/slider/server/services/workflow/ProcessCommandFactory.java
new file mode 100644
index 0000000..8521d0d
--- /dev/null
+++ b/slider-core/src/test/java/org/apache/slider/server/services/workflow/ProcessCommandFactory.java
@@ -0,0 +1,75 @@
+/*
+ * 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.slider.server.services.workflow;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A source of commands, with the goal being to allow for adding different
+ * implementations for different platforms
+ */
+public class ProcessCommandFactory {
+
+ protected ProcessCommandFactory() {
+ }
+
+ /**
+ * The command to list a directory
+ * @param dir directory
+ * @return commands
+ */
+ public List<String> ls(File dir) {
+ List<String> commands = new ArrayList<String>(5);
+ commands.add("ls");
+ commands.add("-1");
+ commands.add(dir.getAbsolutePath());
+ return commands;
+ }
+
+ /**
+ * Echo some text to stdout
+ * @param text text
+ * @return commands
+ */
+ public List<String> echo(String text) {
+ List<String> commands = new ArrayList<String>(5);
+ commands.add("echo");
+ commands.add(text);
+ return commands;
+ }
+ /**
+ * print env variables
+ * @return commands
+ */
+ public List<String> env() {
+ List<String> commands = new ArrayList<String>(1);
+ commands.add("env");
+ return commands;
+ }
+
+ /**
+ * Create a process command factory for this OS
+ * @return
+ */
+ public static ProcessCommandFactory createProcessCommandFactory() {
+ return new ProcessCommandFactory();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/0f1ab84a/slider-core/src/test/java/org/apache/slider/server/services/workflow/TestLongLivedProcess.java
----------------------------------------------------------------------
diff --git a/slider-core/src/test/java/org/apache/slider/server/services/workflow/TestLongLivedProcess.java b/slider-core/src/test/java/org/apache/slider/server/services/workflow/TestLongLivedProcess.java
new file mode 100644
index 0000000..ab37e6a
--- /dev/null
+++ b/slider-core/src/test/java/org/apache/slider/server/services/workflow/TestLongLivedProcess.java
@@ -0,0 +1,164 @@
+/*
+ * 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.slider.server.services.workflow;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Test the long lived process by executing a command that works and a command
+ * that fails
+ */
+public class TestLongLivedProcess extends WorkflowServiceTestBase implements
+ LongLivedProcessLifecycleEvent {
+ private static final Logger
+ log = LoggerFactory.getLogger(TestLongLivedProcess.class);
+
+ private static final Logger
+ processLog =
+ LoggerFactory.getLogger("org.apache.hadoop.services.workflow.Process");
+
+
+ private LongLivedProcess process;
+ private File testDir = new File("target");
+ private ProcessCommandFactory commandFactory;
+ private volatile boolean started, stopped;
+ private volatile int exitCode;
+
+ @Before
+ public void setupProcesses() {
+ commandFactory = ProcessCommandFactory.createProcessCommandFactory();
+ }
+
+ @After
+ public void stopProcesses() {
+ if (process != null) {
+ process.stop();
+ }
+ }
+
+ @Test
+ public void testLs() throws Throwable {
+
+ initProcess(commandFactory.ls(testDir));
+ process.start();
+ //in-thread wait
+ process.run();
+
+ //here stopped
+ assertTrue("process start callback not received", started);
+ assertTrue("process stop callback not received", stopped);
+ assertEquals(0, process.getExitCode().intValue());
+
+ assertStringInOutput("test-classes", getFinalOutput());
+ }
+
+ @Test
+ public void testEcho() throws Throwable {
+
+ String echoText = "hello, world";
+ initProcess(commandFactory.echo(echoText));
+ process.start();
+ //in-thread wait
+ process.run();
+
+ //here stopped
+ assertTrue("process stop callback not received", stopped);
+ assertEquals(0, process.getExitCode().intValue());
+ assertStringInOutput(echoText, getFinalOutput());
+ }
+
+ @Test
+ public void testSetenv() throws Throwable {
+
+ String var = "TEST_RUN";
+ String val = "TEST-RUN-ENV-VALUE";
+ String echoText = "${TEST_RUN}";
+ initProcess(commandFactory.env());
+ process.setEnv(var, val);
+ process.start();
+ //in-thread wait
+ process.run();
+
+ //here stopped
+ assertTrue("process stop callback not received", stopped);
+ assertEquals(0, process.getExitCode().intValue());
+ assertStringInOutput(val, getFinalOutput());
+ }
+
+ /**
+ * Get the final output. includes a quick sleep for the tail output
+ * @return the last output
+ * @throws InterruptedException
+ */
+ private List<String> getFinalOutput() throws InterruptedException {
+ return process.getRecentOutput();
+ }
+
+ public void assertStringInOutput(String text, List<String> output) {
+ boolean found = false;
+ StringBuilder builder = new StringBuilder();
+ for (String s : output) {
+ builder.append(s).append('\n');
+ if (s.contains(text)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ String message =
+ "Text \"" + text + "\" not found in " + output.size() + " lines\n";
+ fail(message + builder.toString());
+ }
+
+ }
+
+
+ private LongLivedProcess initProcess(List<String> commands) {
+ process = new LongLivedProcess(name.getMethodName(), log, commands);
+ process.setLifecycleCallback(this);
+ return process;
+ }
+
+ /**
+ * Handler for callback events on the process
+ */
+
+
+ @Override
+ public void onProcessStarted(LongLivedProcess process) {
+ started = true;
+ }
+
+ /**
+ * Handler for callback events on the process
+ */
+ @Override
+ public void onProcessExited(LongLivedProcess process, int exitCode) {
+ this.exitCode = exitCode;
+ stopped = true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/0f1ab84a/slider-core/src/test/java/org/apache/slider/server/services/workflow/WorkflowServiceTestBase.java
----------------------------------------------------------------------
diff --git a/slider-core/src/test/java/org/apache/slider/server/services/workflow/WorkflowServiceTestBase.java b/slider-core/src/test/java/org/apache/slider/server/services/workflow/WorkflowServiceTestBase.java
index d485148..ab57644 100644
--- a/slider-core/src/test/java/org/apache/slider/server/services/workflow/WorkflowServiceTestBase.java
+++ b/slider-core/src/test/java/org/apache/slider/server/services/workflow/WorkflowServiceTestBase.java
@@ -23,6 +23,7 @@ import org.apache.hadoop.service.Service;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
+import org.junit.rules.TestName;
import org.junit.rules.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,13 +32,15 @@ public abstract class WorkflowServiceTestBase extends Assert {
private static final Logger
log = LoggerFactory.getLogger(WorkflowServiceTestBase.class);
-
/**
* Set the timeout for every test
*/
@Rule
public Timeout testTimeout = new Timeout(15000);
+ @Rule
+ public TestName name = new TestName();
+
@Before
public void nameThread() {
Thread.currentThread().setName("JUnit");