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");