geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jensde...@apache.org
Subject [26/33] incubator-geode git commit: GEODE-473: Capture status file lines in finally block
Date Wed, 30 Dec 2015 00:28:26 GMT
GEODE-473: Capture status file lines in finally block

Change FileProcessController status handler to capture lines read from
status file in finally block.

* Add new UnitTest for LocatorState

* Add new IntegrationTest for FileProcessController


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/121710cd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/121710cd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/121710cd

Branch: refs/heads/feature/GEODE-14
Commit: 121710cdd9558442ba6ee4ecdaea2fc2172a241e
Parents: 05b7ed1
Author: Kirk Lund <klund@pivotal.io>
Authored: Mon Dec 21 13:02:11 2015 -0800
Committer: Kirk Lund <klund@pivotal.io>
Committed: Tue Dec 22 14:26:28 2015 -0800

----------------------------------------------------------------------
 .../internal/process/FileProcessController.java |  39 +++-
 .../distributed/LocatorStateJUnitTest.java      | 208 +++++++++++++++++++
 ...leProcessControllerIntegrationJUnitTest.java | 155 ++++++++++++++
 3 files changed, 393 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/121710cd/gemfire-core/src/main/java/com/gemstone/gemfire/internal/process/FileProcessController.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/process/FileProcessController.java
b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/process/FileProcessController.java
index 471877f..f635bfb 100755
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/process/FileProcessController.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/process/FileProcessController.java
@@ -20,6 +20,7 @@ import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -37,28 +38,44 @@ import com.gemstone.gemfire.lang.AttachAPINotFoundException;
  * @author Kirk Lund
  * @since 8.0
  */
-public final class FileProcessController implements ProcessController {
+public class FileProcessController implements ProcessController {
   private static final Logger logger = LogService.getLogger();
 
   public static final String STATUS_TIMEOUT_PROPERTY = "gemfire.FileProcessController.STATUS_TIMEOUT";
-  private final long statusTimeout = Long.getLong(STATUS_TIMEOUT_PROPERTY, 60*1000);
   
+  private final long statusTimeoutMillis;
   private final FileControllerParameters arguments;
   private final int pid;
 
   /**
    * Constructs an instance for controlling a local process.
    * 
-   * @param pid process id identifying the process to attach to
+   * @param arguments details about the controllable process
+   * @param pid process id identifying the process to control
    * 
    * @throws IllegalArgumentException if pid is not a positive integer
    */
   public FileProcessController(final FileControllerParameters arguments, final int pid) {
+    this(arguments, pid, Long.getLong(STATUS_TIMEOUT_PROPERTY, 60*1000), TimeUnit.MILLISECONDS);
+  }
+
+  /**
+   * Constructs an instance for controlling a local process.
+   * 
+   * @param arguments details about the controllable process
+   * @param pid process id identifying the process to control
+   * @param timeout the timeout that operations must complete within
+   * @param units the units of the timeout
+   * 
+   * @throws IllegalArgumentException if pid is not a positive integer
+   */
+  public FileProcessController(final FileControllerParameters arguments, final int pid, final
long timeout, final TimeUnit units) {
     if (pid < 1) {
       throw new IllegalArgumentException("Invalid pid '" + pid + "' specified");
     }
     this.pid = pid;
     this.arguments = arguments;
+    this.statusTimeoutMillis = units.toMillis(timeout);
   }
 
   @Override
@@ -98,14 +115,14 @@ public final class FileProcessController implements ProcessController
{
       public void handleRequest() throws IOException {
         // read the statusFile
         final BufferedReader reader = new BufferedReader(new FileReader(statusFile));
+        final StringBuilder lines = new StringBuilder();
         try {
-          final StringBuilder lines = new StringBuilder();
           String line = null;
           while ((line = reader.readLine()) != null) {
             lines.append(line);
           }
-          statusRef.set(lines.toString());
         } finally {
+          statusRef.set(lines.toString());
           reader.close();
         }
       }
@@ -122,8 +139,8 @@ public final class FileProcessController implements ProcessController
{
     // if timeout invoke stop and then throw TimeoutException
     final long start = System.currentTimeMillis();
     while (statusFileWatchdog.isAlive()) {
-      Thread.sleep(100);
-      if (System.currentTimeMillis() >= start + this.statusTimeout) {
+      Thread.sleep(10);
+      if (System.currentTimeMillis() >= start + this.statusTimeoutMillis) {
         final TimeoutException te = new TimeoutException("Timed out waiting for process to
create " + statusFile);
         try {
           statusFileWatchdog.stop();
@@ -135,7 +152,11 @@ public final class FileProcessController implements ProcessController
{
         throw te;
       }
     }
-    assert statusRef.get() != null;
-    return statusRef.get();
+    
+    final String lines = statusRef.get();
+    if (null == lines || lines.trim().isEmpty()) {
+      throw new IllegalStateException("Failed to read status file");
+    }
+    return lines;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/121710cd/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/LocatorStateJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/LocatorStateJUnitTest.java
b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/LocatorStateJUnitTest.java
new file mode 100755
index 0000000..248c39f
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/LocatorStateJUnitTest.java
@@ -0,0 +1,208 @@
+/*
+ * 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 com.gemstone.gemfire.distributed;
+
+import static com.googlecode.catchexception.CatchException.*;
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.gemstone.gemfire.distributed.AbstractLauncher.ServiceState;
+import com.gemstone.gemfire.distributed.AbstractLauncher.Status;
+import com.gemstone.gemfire.distributed.LocatorLauncher.LocatorState;
+import com.gemstone.gemfire.management.internal.cli.json.GfJsonException;
+import com.gemstone.gemfire.management.internal.cli.json.GfJsonObject;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for LocatorLauncher.LocatorState
+ */
+@Category(UnitTest.class)
+public class LocatorStateJUnitTest {
+
+  @Test
+  public void fromJsonWithEmptyStringThrowsIllegalArgumentException() throws Exception {
+    // given: empty string
+    String emptyString = "";
+    
+    // when: passed to fromJson
+    verifyException(this).fromJson(emptyString);
+    
+    // then: throws IllegalArgumentException with cause of GfJsonException
+    assertThat((Exception)caughtException())
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasCauseInstanceOf(GfJsonException.class);
+    
+    assertThat(caughtException().getCause())
+        .isInstanceOf(GfJsonException.class)
+        .hasNoCause();
+  }
+  
+  @Test
+  public void fromJsonWithWhiteSpaceStringThrowsIllegalArgumentException() throws Exception
{
+    // given: white space string
+    String whiteSpaceString = "      ";
+    
+    // when: passed to fromJson
+    verifyException(this).fromJson(whiteSpaceString);
+
+    // then: throws IllegalArgumentException with cause of GfJsonException
+    assertThat((Exception)caughtException())
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasCauseInstanceOf(GfJsonException.class);
+    
+    assertThat(caughtException().getCause())
+        .isInstanceOf(GfJsonException.class)
+        .hasNoCause();
+  }
+  
+  @Test
+  public void fromJsonWithNullStringThrowsNullPointerException() throws Exception {
+    // given: null string
+    String nullString = null;
+    
+    // when: passed to fromJson
+    verifyException(this).fromJson(nullString);
+    
+    // then: throws NullPointerException
+    assertThat((Exception)caughtException())
+        .isInstanceOf(NullPointerException.class)
+        .hasNoCause();
+  }
+  
+  @Test
+  public void fromJsonWithValidJsonStringReturnsLocatorState() throws Exception {
+    // given: valid json string
+    String jsonString = createStatusJson();
+    
+    // when: passed to fromJson
+    LocatorState value = fromJson(jsonString);
+    
+    // then: return valid instance of LocatorState
+    assertThat(value).isInstanceOf(LocatorState.class);
+    
+    assertThat(value.getClasspath()).isEqualTo(getClasspath());
+    assertThat(value.getGemFireVersion()).isEqualTo(getGemFireVersion());
+    assertThat(value.getHost()).isEqualTo(getHost());
+    assertThat(value.getJavaVersion()).isEqualTo(getJavaVersion());
+    assertThat(value.getJvmArguments()).isEqualTo(getJvmArguments());
+    assertThat(value.getServiceLocation()).isEqualTo(getServiceLocation());
+    assertThat(value.getLogFile()).isEqualTo(getLogFile());
+    assertThat(value.getMemberName()).isEqualTo(getMemberName());
+    assertThat(value.getPid()).isEqualTo(getPid());
+    assertThat(value.getPort()).isEqualTo(getPort());
+    assertThat(value.getStatus().getDescription()).isEqualTo(getStatusDescription());
+    assertThat(value.getStatusMessage()).isEqualTo(getStatusMessage());
+    assertThat(value.getTimestamp().getTime()).isEqualTo(getTimestampTime());
+    assertThat(value.getUptime()).isEqualTo(getUptime());
+    assertThat(value.getWorkingDirectory()).isEqualTo(getWorkingDirectory());
+  }
+  
+  protected LocatorState fromJson(final String value) {
+    return LocatorState.fromJson(value);
+  }
+
+  private String classpath = "test_classpath";
+  private String gemFireVersion = "test_gemfireversion";
+  private String host = "test_host";
+  private String javaVersion = "test_javaversion";
+  private String jvmArguments = "test_jvmarguments";
+  private String serviceLocation = "test_location";
+  private String logFile = "test_logfile";
+  private String memberName = "test_membername";
+  private Integer pid = 6396;
+  private String port = "test_port";
+  private String statusDescription = Status.NOT_RESPONDING.getDescription();
+  private String statusMessage = "test_statusmessage";
+  private Long timestampTime = 1450728233024L;
+  private Long uptime = 1629L;
+  private String workingDirectory = "test_workingdirectory";
+  
+  private String getClasspath() {
+    return this.classpath;
+  }
+  private String getGemFireVersion() {
+    return this.gemFireVersion;
+  }
+  private String getHost() {
+    return this.host;
+  }
+  private String getJavaVersion() {
+    return this.javaVersion;
+  }
+  private List<String> getJvmArguments() {
+    List<String> list = new ArrayList<String>();
+    list.add(this.jvmArguments);
+    return list;
+  }
+  private String getServiceLocation() {
+    return this.serviceLocation;
+  }
+  private String getLogFile() {
+    return this.logFile;
+  }
+  private String getMemberName() {
+    return this.memberName;
+  }
+  private Integer getPid() {
+    return this.pid;
+  }
+  private String getPort() {
+    return this.port;
+  }
+  private String getStatusDescription() {
+    return this.statusDescription;
+  }
+  private String getStatusMessage() {
+    return this.statusMessage;
+  }
+  private Long getTimestampTime() {
+    return this.timestampTime;
+  }
+  private Long getUptime() {
+    return this.uptime;
+  }
+  private String getWorkingDirectory() {
+    return this.workingDirectory;
+  }
+
+  private String createStatusJson() {
+    final Map<String, Object> map = new HashMap<String, Object>();
+    map.put(ServiceState.JSON_CLASSPATH, getClasspath());
+    map.put(ServiceState.JSON_GEMFIREVERSION, getGemFireVersion());
+    map.put(ServiceState.JSON_HOST, getHost());
+    map.put(ServiceState.JSON_JAVAVERSION, getJavaVersion());
+    map.put(ServiceState.JSON_JVMARGUMENTS, getJvmArguments());
+    map.put(ServiceState.JSON_LOCATION, getServiceLocation());
+    map.put(ServiceState.JSON_LOGFILE, getLogFile());
+    map.put(ServiceState.JSON_MEMBERNAME, getMemberName());
+    map.put(ServiceState.JSON_PID, getPid());
+    map.put(ServiceState.JSON_PORT, getPort());
+    map.put(ServiceState.JSON_STATUS, getStatusDescription());
+    map.put(ServiceState.JSON_STATUSMESSAGE, getStatusMessage());
+    map.put(ServiceState.JSON_TIMESTAMP, getTimestampTime());
+    map.put(ServiceState.JSON_UPTIME, getUptime());
+    map.put(ServiceState.JSON_WORKINGDIRECTORY, getWorkingDirectory());
+    return new GfJsonObject(map).toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/121710cd/gemfire-core/src/test/java/com/gemstone/gemfire/internal/process/FileProcessControllerIntegrationJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/process/FileProcessControllerIntegrationJUnitTest.java
b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/process/FileProcessControllerIntegrationJUnitTest.java
new file mode 100755
index 0000000..6255af1
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/process/FileProcessControllerIntegrationJUnitTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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 com.gemstone.gemfire.internal.process;
+
+import static com.googlecode.catchexception.CatchException.*;
+import static com.jayway.awaitility.Awaitility.*;
+import static java.util.concurrent.TimeUnit.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+import static org.hamcrest.Matchers.*;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+
+import com.gemstone.gemfire.distributed.LocatorLauncher;
+import com.gemstone.gemfire.distributed.LocatorStateJUnitTest;
+import com.gemstone.gemfire.distributed.AbstractLauncher.Status;
+import com.gemstone.gemfire.distributed.LocatorLauncher.Builder;
+import com.gemstone.gemfire.distributed.LocatorLauncher.LocatorState;
+import com.gemstone.gemfire.test.junit.categories.IntegrationTest;
+
+/**
+ * Integration tests for FileProcessController.
+ */
+@Category(IntegrationTest.class)
+public class FileProcessControllerIntegrationJUnitTest {
+  
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+  
+  @Rule
+  public TestName testName = new TestName();
+  
+  private ProcessType processType;
+  private ExecutorService executor;
+  
+  @Before
+  public void setUp() throws Exception {
+    this.processType = ProcessType.LOCATOR;
+  }
+  
+  @After
+  public void tearDown() throws Exception {
+    if (this.executor != null) {
+      this.executor.shutdownNow();
+    }
+  }
+  
+  @Test
+  public void statusShouldAwaitTimeoutWhileFileIsEmpty() throws Exception {
+    // given: FileProcessController with empty pidFile
+    int pid = ProcessUtils.identifyPid();
+    File emptyPidFile = this.temporaryFolder.newFile(this.processType.getPidFileName());
+    FileControllerParameters params = mock(FileControllerParameters.class);
+    when(params.getPidFile()).thenReturn(emptyPidFile);
+    when(params.getProcessId()).thenReturn(pid);
+    when(params.getProcessType()).thenReturn(this.processType);
+    when(params.getWorkingDirectory()).thenReturn(this.temporaryFolder.getRoot());
+    
+    FileProcessController controller = new FileProcessController(params, 1, 10, MILLISECONDS);
+    
+    // when
+    verifyException(controller).status();
+
+    // then: we expect TimeoutException to be thrown
+    assertThat((Exception)caughtException())
+            .isInstanceOf(TimeoutException.class)
+            .hasMessageContaining("Timed out waiting for process to create")
+            .hasNoCause();
+  }
+  
+  @Test
+  public void statusShouldReturnJsonFromStatusFile() throws Exception {
+    // given: FileProcessController with pidFile containing real pid
+    int pid = ProcessUtils.identifyPid();
+    File pidFile = this.temporaryFolder.newFile(this.processType.getPidFileName());
+    writeToFile(pidFile, String.valueOf(pid));
+    
+    FileControllerParameters params = mock(FileControllerParameters.class);
+    when(params.getPidFile()).thenReturn(pidFile);
+    when(params.getProcessId()).thenReturn(pid);
+    when(params.getProcessType()).thenReturn(this.processType);
+    when(params.getWorkingDirectory()).thenReturn(this.temporaryFolder.getRoot());
+    
+    FileProcessController controller = new FileProcessController(params, pid, 1, MINUTES);
+    
+    // when: status is called in one thread and json is written to the file
+    AtomicReference<String> status = new AtomicReference<String>();
+    AtomicReference<Exception> exception = new AtomicReference<Exception>();
+    ExecutorService executor = Executors.newSingleThreadExecutor();
+    executor.execute(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          status.set(controller.status());
+        } catch (Exception e) {
+          exception.set(e);
+        }
+      }
+    });
+    
+    // write status
+    String statusJson = generateStatusJson();
+    File statusFile = this.temporaryFolder.newFile(this.processType.getStatusFileName());
+    writeToFile(statusFile, statusJson);
+    
+    // then: returned status should be the json in the file
+    assertThat(exception.get()).isNull();
+    with().pollInterval(10, MILLISECONDS).await().atMost(2, MINUTES).untilAtomic(status,
equalTo(statusJson));
+    assertThat(status.get()).isEqualTo(statusJson);
+    System.out.println(statusJson);
+  }
+
+  private static void writeToFile(final File file, final String value) throws IOException
{
+    final FileWriter writer = new FileWriter(file);
+    writer.write(value);
+    writer.flush();
+    writer.close();
+  }
+  
+  private static String generateStatusJson() {
+    Builder builder = new Builder();
+    LocatorLauncher defaultLauncher = builder.build();
+    Status status = Status.ONLINE;
+    LocatorState locatorState = new LocatorState(defaultLauncher, status);
+    return locatorState.toJson();
+  }
+}


Mime
View raw message