You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2015/09/23 12:23:30 UTC
[3/8] incubator-brooklyn git commit: Testing winrm exit codes
Testing winrm exit codes
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/10071a92
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/10071a92
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/10071a92
Branch: refs/heads/master
Commit: 10071a928c57aa3178442d9f72f22d47798ff7ca
Parents: 2995471
Author: Aled Sage <al...@gmail.com>
Authored: Mon Sep 21 21:36:11 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Sep 23 01:32:48 2015 +0100
----------------------------------------------------------------------
...laWindowsProcessWinrmExitStatusLiveTest.java | 291 ++++++++++
...nillaWindowsProcessWinrmStreamsLiveTest.java | 80 ++-
.../location/WinRmMachineLocationLiveTest.java | 563 ++++++++++++++++++-
.../base/test/location/WindowsTestFixture.java | 71 +++
usage/camp/pom.xml | 6 +
.../camp/brooklyn/WindowsYamlLiveTest.java | 410 ++++++++++++++
.../apache/brooklyn/camp/brooklyn/echoArg.bat | 19 +
.../camp/brooklyn/echoFreemarkerMyarg.bat | 18 +
.../camp/brooklyn/echoFreemarkerMyarg.ps1 | 18 +
.../apache/brooklyn/camp/brooklyn/echoMyArg.ps1 | 22 +
.../org/apache/brooklyn/camp/brooklyn/exit0.bat | 18 +
.../org/apache/brooklyn/camp/brooklyn/exit0.ps1 | 18 +
.../org/apache/brooklyn/camp/brooklyn/exit1.bat | 18 +
.../org/apache/brooklyn/camp/brooklyn/exit1.ps1 | 19 +
14 files changed, 1521 insertions(+), 50 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinrmExitStatusLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinrmExitStatusLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinrmExitStatusLiveTest.java
new file mode 100644
index 0000000..998d987
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinrmExitStatusLiveTest.java
@@ -0,0 +1,291 @@
+/*
+ * 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.brooklyn.entity.software.base;
+
+import static org.testng.Assert.fail;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.entity.software.base.test.location.WindowsTestFixture;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class VanillaWindowsProcessWinrmExitStatusLiveTest {
+ private static final Logger LOG = LoggerFactory.getLogger(VanillaWindowsProcessWinrmExitStatusLiveTest.class);
+
+ private static final String INVALID_CMD = "thisCommandDoesNotExistAEFafiee3d";
+
+ protected ManagementContextInternal mgmt;
+ protected TestApplication app;
+ protected MachineProvisioningLocation<WinRmMachineLocation> location;
+ protected WinRmMachineLocation machine;
+
+ @BeforeClass(alwaysRun=true)
+ public void setUpClass() throws Exception {
+ mgmt = new LocalManagementContextForTests(BrooklynProperties.Factory.newDefault());
+
+ location = WindowsTestFixture.setUpWindowsLocation(mgmt);
+ machine = location.obtain(ImmutableMap.of());
+ }
+
+ @AfterClass(alwaysRun=true)
+ public void tearDownClass() throws Exception {
+ try {
+ try {
+ if (location != null) location.release(machine);
+ } finally {
+ if (mgmt != null) Entities.destroyAll(mgmt);
+ }
+ } catch (Throwable t) {
+ LOG.error("Caught exception in tearDownClass method", t);
+ } finally {
+ mgmt = null;
+ }
+ }
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ EntitySpec<TestApplication> appSpec = EntitySpec.create(TestApplication.class)
+ .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true);
+ app = ApplicationBuilder.newManagedApp(appSpec, mgmt);
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() throws Exception {
+ try {
+ try {
+ if (app != null) Entities.destroy(app);
+ } catch (Throwable t) {
+ LOG.error("Caught exception in tearDown method", t);
+ }
+ } finally {
+ app = null;
+ }
+ }
+
+ @Test(groups = "Live")
+ public void testExecWithZeroExitCodes() {
+ VanillaWindowsProcess entity = app.createAndManageChild(EntitySpec.create(VanillaWindowsProcess.class)
+ .configure(VanillaWindowsProcess.PRE_INSTALL_COMMAND, "echo preinstall")
+ .configure(VanillaWindowsProcess.INSTALL_COMMAND, "echo install")
+ .configure(VanillaWindowsProcess.POST_INSTALL_COMMAND, "echo postinstall")
+ .configure(VanillaWindowsProcess.CUSTOMIZE_COMMAND, "echo customize")
+ .configure(VanillaWindowsProcess.PRE_LAUNCH_COMMAND, "echo prelaunch")
+ .configure(VanillaWindowsProcess.LAUNCH_COMMAND, "echo launch")
+ .configure(VanillaWindowsProcess.POST_LAUNCH_COMMAND, "echo postlaunch")
+ .configure(VanillaWindowsProcess.CHECK_RUNNING_COMMAND, "echo checkrunning")
+ .configure(VanillaWindowsProcess.STOP_COMMAND, "echo stop"));
+
+ app.start(ImmutableList.of(machine));
+ LOG.info("app started; asserting up");
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true);
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING);
+
+ entity.stop();
+ LOG.info("stopping entity");
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STOPPED);
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, false);
+ }
+
+ @Test(groups = "Live")
+ public void testExecPsWithZeroExitCodes() {
+ VanillaWindowsProcess entity = app.createAndManageChild(EntitySpec.create(VanillaWindowsProcess.class)
+ .configure(VanillaWindowsProcess.PRE_INSTALL_POWERSHELL_COMMAND, "Write-Host preinstall")
+ .configure(VanillaWindowsProcess.INSTALL_POWERSHELL_COMMAND, "Write-Host install")
+ .configure(VanillaWindowsProcess.POST_INSTALL_POWERSHELL_COMMAND, "Write-Host postinstall")
+ .configure(VanillaWindowsProcess.CUSTOMIZE_POWERSHELL_COMMAND, "Write-Host customize")
+ .configure(VanillaWindowsProcess.PRE_LAUNCH_POWERSHELL_COMMAND, "Write-Host prelaunch")
+ .configure(VanillaWindowsProcess.LAUNCH_POWERSHELL_COMMAND, "Write-Host launch")
+ .configure(VanillaWindowsProcess.POST_LAUNCH_POWERSHELL_COMMAND, "Write-Host postlaunch")
+ .configure(VanillaWindowsProcess.CHECK_RUNNING_POWERSHELL_COMMAND, "Write-Host checkrunning")
+ .configure(VanillaWindowsProcess.STOP_POWERSHELL_COMMAND, "Write-Host stop"));
+
+ app.start(ImmutableList.of(machine));
+ LOG.info("app started; asserting up");
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true);
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING);
+
+ entity.stop();
+ LOG.info("stopping entity");
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STOPPED);
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, false);
+ }
+
+ @Test(groups = "Live")
+ public void testPreInstallNonZeroExitCode() {
+ runExecNonZeroExitCode("pre-install-command");
+ }
+
+ @Test(groups = "Live")
+ public void testInstallNonZeroExitCode() {
+ runExecNonZeroExitCode("install-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPostInstallNonZeroExitCode() {
+ runExecNonZeroExitCode("post-install-command");
+ }
+
+ @Test(groups = "Live")
+ public void testCustomizeNonZeroExitCode() {
+ runExecNonZeroExitCode("customize-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPreLaunchNonZeroExitCode() {
+ runExecNonZeroExitCode("pre-launch-command");
+ }
+
+ @Test(groups = "Live")
+ public void testLaunchNonZeroExitCode() {
+ runExecNonZeroExitCode("launch-command");
+ }
+
+ @Test(groups = "Live")
+ public void testCheckRunningNonZeroExitCode() {
+ runExecNonZeroExitCode("is-running-command");
+ }
+
+ @Test(groups = "Live")
+ public void testStopNonZeroExitCode() {
+ runExecNonZeroExitCode("stop-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPsPreInstallNonZeroExitCode() {
+ runExecPsNonZeroExitCode("pre-install-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPsInstallNonZeroExitCode() {
+ runExecPsNonZeroExitCode("install-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPsPostInstallNonZeroExitCode() {
+ runExecPsNonZeroExitCode("post-install-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPsCustomizeNonZeroExitCode() {
+ runExecPsNonZeroExitCode("customize-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPsPreLaunchNonZeroExitCode() {
+ runExecPsNonZeroExitCode("pre-launch-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPsLaunchNonZeroExitCode() {
+ runExecPsNonZeroExitCode("launch-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPsCheckRunningNonZeroExitCode() {
+ runExecPsNonZeroExitCode("is-running-command");
+ }
+
+ @Test(groups = "Live")
+ public void testPsStopNonZeroExitCode() {
+ runExecPsNonZeroExitCode("stop-command");
+ }
+
+ protected void runExecNonZeroExitCode(String phase) {
+ VanillaWindowsProcess entity = app.createAndManageChild(EntitySpec.create(VanillaWindowsProcess.class)
+ .configure(VanillaWindowsProcess.PRE_INSTALL_COMMAND, phase.equals("pre-install-command") ? INVALID_CMD : "echo install")
+ .configure(VanillaWindowsProcess.INSTALL_COMMAND, phase.equals("install-command") ? INVALID_CMD : "echo install")
+ .configure(VanillaWindowsProcess.POST_INSTALL_COMMAND, phase.equals("post-install-command") ? INVALID_CMD : "echo postinstall")
+ .configure(VanillaWindowsProcess.CUSTOMIZE_COMMAND, phase.equals("customize-command") ? INVALID_CMD : "echo customize")
+ .configure(VanillaWindowsProcess.PRE_LAUNCH_COMMAND, phase.equals("pre-launch-command") ? INVALID_CMD : "echo prelaunch")
+ .configure(VanillaWindowsProcess.LAUNCH_COMMAND, phase.equals("launch-command") ? INVALID_CMD : "echo launch")
+ .configure(VanillaWindowsProcess.POST_LAUNCH_COMMAND, phase.equals("post-launch-command") ? INVALID_CMD : "echo postlaunch")
+ .configure(VanillaWindowsProcess.CHECK_RUNNING_COMMAND, phase.equals("is-running-command") ? INVALID_CMD : "echo checkrunning")
+ .configure(VanillaWindowsProcess.STOP_COMMAND, phase.equals("stop-command") ? INVALID_CMD : "echo stop")
+ .configure(BrooklynConfigKeys.START_TIMEOUT, Duration.ONE_MINUTE));
+
+ if (phase.equals("stop-command")) {
+ app.start(ImmutableList.of(machine));
+ try {
+ entity.stop();
+ fail();
+ } catch (Exception e) {
+ if (!(e.toString().contains("invalid result") && e.toString().contains("for "+phase))) throw e;
+ }
+ } else {
+ try {
+ app.start(ImmutableList.of(machine));
+ fail();
+ } catch (Exception e) {
+ if (!(e.toString().contains("invalid result") && e.toString().contains("for "+phase))) throw e;
+ }
+ }
+ }
+
+ protected void runExecPsNonZeroExitCode(String phase) {
+ VanillaWindowsProcess entity = app.createAndManageChild(EntitySpec.create(VanillaWindowsProcess.class)
+ .configure(VanillaWindowsProcess.PRE_INSTALL_POWERSHELL_COMMAND, phase.equals("pre-install-command") ? INVALID_CMD : "Write-Host install")
+ .configure(VanillaWindowsProcess.INSTALL_POWERSHELL_COMMAND, phase.equals("install-command") ? INVALID_CMD : "Write-Host install")
+ .configure(VanillaWindowsProcess.POST_INSTALL_POWERSHELL_COMMAND, phase.equals("post-install-command") ? INVALID_CMD : "Write-Host postinstall")
+ .configure(VanillaWindowsProcess.CUSTOMIZE_POWERSHELL_COMMAND, phase.equals("customize-command") ? INVALID_CMD : "Write-Host customize")
+ .configure(VanillaWindowsProcess.PRE_LAUNCH_POWERSHELL_COMMAND, phase.equals("pre-launch-command") ? INVALID_CMD : "Write-Host prelaunch")
+ .configure(VanillaWindowsProcess.LAUNCH_POWERSHELL_COMMAND, phase.equals("launch-command") ? INVALID_CMD : "Write-Host launch")
+ .configure(VanillaWindowsProcess.POST_LAUNCH_POWERSHELL_COMMAND, phase.equals("post-launch-command") ? INVALID_CMD : "Write-Host postlaunch")
+ .configure(VanillaWindowsProcess.CHECK_RUNNING_POWERSHELL_COMMAND, phase.equals("is-running-command") ? INVALID_CMD : "Write-Host checkrunning")
+ .configure(VanillaWindowsProcess.STOP_POWERSHELL_COMMAND, phase.equals("stop-command") ? INVALID_CMD : "Write-Host stop")
+ .configure(BrooklynConfigKeys.START_TIMEOUT, Duration.ONE_MINUTE));
+
+ if (phase.equals("stop-command")) {
+ app.start(ImmutableList.of(machine));
+ try {
+ entity.stop();
+ fail();
+ } catch (Exception e) {
+ if (!(e.toString().contains("invalid result") && e.toString().contains("for "+phase))) throw e;
+ }
+ } else {
+ try {
+ app.start(ImmutableList.of(machine));
+ fail();
+ } catch (Exception e) {
+ if (!(e.toString().contains("invalid result") && e.toString().contains("for "+phase))) throw e;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinrmStreamsLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinrmStreamsLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinrmStreamsLiveTest.java
index 2ee310b..fdc4c59 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinrmStreamsLiveTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaWindowsProcessWinrmStreamsLiveTest.java
@@ -18,41 +18,78 @@
*/
package org.apache.brooklyn.entity.software.base;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+
import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.entity.software.base.test.location.WindowsTestFixture;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import java.util.Map;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
public class VanillaWindowsProcessWinrmStreamsLiveTest extends AbstractSoftwareProcessStreamsTest {
- private Location location;
+
+ private static final Logger LOG = LoggerFactory.getLogger(VanillaWindowsProcessWinrmStreamsLiveTest.class);
+
+ protected MachineProvisioningLocation<WinRmMachineLocation> location;
+ protected WinRmMachineLocation machine;
+
+ // Using BeforeClass so that uses just a single VM for all tests
+ @BeforeClass(alwaysRun = true)
+ public void setUpClass() throws Exception {
+ super.setUp();
+ if (app != null) Entities.destroy(app);
+
+ location = WindowsTestFixture.setUpWindowsLocation(mgmt);
+ machine = location.obtain(ImmutableMap.of());
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void tearDownClass() throws Exception {
+ try {
+ if (location != null && machine != null) location.release(machine);
+ } catch (Throwable t) {
+ LOG.error("Caught exception in tearDownClass method", t);
+ } finally {
+ super.tearDown();
+ }
+ }
- @BeforeMethod(alwaysRun=true)
+ @BeforeMethod(alwaysRun = true)
@Override
public void setUp() throws Exception {
- super.setUp();
+ app = ApplicationBuilder.newManagedApp(TestApplication.class, mgmt);
+ }
- Map<String, Object> config = ImmutableMap.<String, Object>builder()
- .put("inboundPorts", ImmutableList.of(5985, 3389))
- .put("osFamily", "windows")
- .put("displayName", "AWS Oregon (Windows)")
- .put("imageOwner", "801119661308")
- .put("imageNameRegex", "Windows_Server-2012-R2_RTM-English-64Bit-Base-.*")
- .put("hardwareId", "m3.medium")
- .put("checkRunning.command", "echo true")
- .put("useJcloudsSshInit", false)
- .build();
- location = ((JcloudsLocation)mgmt.getLocationRegistry().resolve("jclouds:aws-ec2:us-west-1", config)).obtain();
+ @AfterMethod(alwaysRun = true)
+ @Override
+ public void tearDown() throws Exception {
+ try {
+ if (app != null) Entities.destroy(app);
+ } catch (Throwable t) {
+ LOG.error("Caught exception in tearDown method", t);
+ } finally {
+ app = null;
+ }
}
@Test(groups = "Live")
@Override
public void testGetsStreams() {
VanillaWindowsProcess entity = app.createAndManageChild(EntitySpec.create(VanillaWindowsProcess.class)
+ .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true)
.configure(VanillaSoftwareProcess.PRE_INSTALL_COMMAND, "echo " + getCommands().get("winrm: pre-install-command.*"))
.configure(VanillaSoftwareProcess.INSTALL_COMMAND, "echo " + getCommands().get("winrm: install.*"))
.configure(VanillaSoftwareProcess.POST_INSTALL_COMMAND, "echo " + getCommands().get("winrm: post-install-command.*"))
@@ -61,13 +98,14 @@ public class VanillaWindowsProcessWinrmStreamsLiveTest extends AbstractSoftwareP
.configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "echo " + getCommands().get("winrm: launch.*"))
.configure(VanillaSoftwareProcess.POST_LAUNCH_COMMAND, "echo " + getCommands().get("winrm: post-launch-command.*"))
.configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "echo true"));
- app.start(ImmutableList.of(location));
+ app.start(ImmutableList.of(machine));
assertStreams(entity);
}
@Test(groups = "Live")
public void testGetsStreamsPowerShell() {
VanillaWindowsProcess entity = app.createAndManageChild(EntitySpec.create(VanillaWindowsProcess.class)
+ .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true)
.configure(VanillaWindowsProcess.PRE_INSTALL_POWERSHELL_COMMAND, "echo " + getCommands().get("winrm: pre-install-command.*"))
.configure(VanillaWindowsProcess.INSTALL_POWERSHELL_COMMAND, "echo " + getCommands().get("winrm: install.*"))
.configure(VanillaWindowsProcess.POST_INSTALL_POWERSHELL_COMMAND, "echo " + getCommands().get("winrm: post-install-command.*"))
@@ -76,7 +114,7 @@ public class VanillaWindowsProcessWinrmStreamsLiveTest extends AbstractSoftwareP
.configure(VanillaWindowsProcess.LAUNCH_POWERSHELL_COMMAND, "echo " + getCommands().get("winrm: launch.*"))
.configure(VanillaWindowsProcess.POST_LAUNCH_POWERSHELL_COMMAND, "echo " + getCommands().get("winrm: post-launch-command.*"))
.configure(VanillaWindowsProcess.CHECK_RUNNING_POWERSHELL_COMMAND, "echo true"));
- app.start(ImmutableList.of(location));
+ app.start(ImmutableList.of(machine));
assertStreams(entity);
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WinRmMachineLocationLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WinRmMachineLocationLiveTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WinRmMachineLocationLiveTest.java
index dd4dee7..615eda7 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WinRmMachineLocationLiveTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WinRmMachineLocationLiveTest.java
@@ -19,76 +19,581 @@
package org.apache.brooklyn.entity.software.base.test.location;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.internal.BrooklynProperties;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.location.jclouds.JcloudsLocation;
-
-import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
-
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.text.Identifiers;
+import org.apache.brooklyn.util.time.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-import org.apache.brooklyn.location.jclouds.JcloudsWinRmMachineLocation;
+import com.google.api.client.util.Charsets;
+import com.google.common.base.Joiner;
+import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
+/**
+ * Tests execution of commands (batch and powershell) on Windows over WinRM, and of
+ * file upload.
+ *
+ * There are limitations with what is supported by PyWinRM. These are highlighted in
+ * tests marked as "WIP" (see individual tests).
+ *
+ * These limitations are documented in docs/guide/yaml/winrm/index.md.
+ * Please update the docs if you encountered new situations, or change the behaviuor
+ * of existing use-cases.
+ */
public class WinRmMachineLocationLiveTest {
-
- // FIXME failing locally with:
- // Caused by: Traceback (most recent call last):
- // File "__pyclasspath__/winrm/__init__.py", line 40, in run_cmd
- // File "__pyclasspath__/winrm/protocol.py", line 118, in open_shell
- // File "__pyclasspath__/winrm/protocol.py", line 190, in send_message
- // File "__pyclasspath__/winrm/transport.py", line 112, in send_message
- // winrm.exceptions.WinRMTransportError: 500 WinRMTransport. [Errno 20001] getaddrinfo failed
- // at org.python.core.PyException.doRaise(PyException.java:226)
+ private static final int MAX_EXECUTOR_THREADS = 100;
+
+ /*
+ * TODO: Deferred implementing copyFrom or environment variables.
+ */
+
private static final Logger LOG = LoggerFactory.getLogger(BrooklynAppLiveTestSupport.class);
- protected JcloudsLocation loc;
+ private static final String INVALID_CMD = "thisCommandDoesNotExistAEFafiee3d";
+ private static final String PS_ERR_ACTION_PREF_EQ_STOP = "$ErrorActionPreference = \"Stop\"";
+
+ protected MachineProvisioningLocation<WinRmMachineLocation> loc;
protected TestApplication app;
protected ManagementContextInternal mgmt;
- private JcloudsWinRmMachineLocation machine;
+ private WinRmMachineLocation machine;
+
+ private ListeningExecutorService executor;
@BeforeClass(alwaysRun=true)
public void setUpClass() throws Exception {
+ executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(MAX_EXECUTOR_THREADS));
+
mgmt = new LocalManagementContextForTests(BrooklynProperties.Factory.newDefault());
- JcloudsLocation loc = (JcloudsLocation) mgmt.getLocationRegistry().resolve("jclouds:aws-ec2:us-west-2", ImmutableMap.<String, Object>builder()
- .put("inboundPorts", ImmutableList.of(5985, 3389))
- .put("displayName", "AWS Oregon (Windows)")
- .put("imageOwner", "801119661308")
- .put("imageNameRegex", "Windows_Server-2012-R2_RTM-English-64Bit-Base-.*")
- .put("hardwareId", "m3.medium")
- .put("useJcloudsSshInit", false)
- .build());
- machine = (JcloudsWinRmMachineLocation) loc.obtain();
+
+ loc = WindowsTestFixture.setUpWindowsLocation(mgmt);
+ machine = loc.obtain(ImmutableMap.of());
}
-
+
@AfterClass(alwaysRun=true)
public void tearDownClass() throws Exception {
try {
+ if (executor != null) executor.shutdownNow();
if (machine != null) loc.release(machine);
if (mgmt != null) Entities.destroyAll(mgmt);
} catch (Throwable t) {
LOG.error("Caught exception in tearDown method", t);
} finally {
+ executor = null;
mgmt = null;
}
}
@Test(groups="Live")
+ public void testCopyTo() throws Exception {
+ String contents = "abcdef";
+ runCopyTo(contents);
+ runCopyFileTo(contents);
+ }
+
+ // Takes several minutes to upload/download!
+ @Test(groups="Live")
+ public void testLargeFileCopyTo() throws Exception {
+ String contents = Identifiers.makeRandomId(65537);
+ runCopyTo(contents);
+ runCopyFileTo(contents);
+ }
+
+ protected void runCopyTo(String contents) throws Exception {
+ String remotePath = "C:\\myfile-"+Identifiers.makeRandomId(4)+".txt";
+ machine.copyTo(new ByteArrayInputStream(contents.getBytes()), remotePath);
+
+ WinRmToolResponse response = machine.executeScript("type "+remotePath);
+ String msg = "statusCode="+response.getStatusCode()+"; out="+response.getStdOut()+"; err="+response.getStdErr();
+ assertEquals(response.getStatusCode(), 0, msg);
+ assertEquals(response.getStdOut().trim(), contents, msg);
+ }
+
+ protected void runCopyFileTo(String contents) throws Exception {
+ File localFile = File.createTempFile("winrmtest"+Identifiers.makeRandomId(4), ".txt");
+ try {
+ Files.write(contents, localFile, Charsets.UTF_8);
+ String remotePath = "C:\\myfile-"+Identifiers.makeRandomId(4)+".txt";
+ machine.copyTo(localFile, remotePath);
+
+ WinRmToolResponse response = machine.executeScript("type "+remotePath);
+ String msg = "statusCode="+response.getStatusCode()+"; out="+response.getStdOut()+"; err="+response.getStdErr();
+ assertEquals(response.getStatusCode(), 0, msg);
+ assertEquals(response.getStdOut().trim(), contents, msg);
+ } finally {
+ localFile.delete();
+ }
+ }
+
+ @Test(groups="Live")
public void testExecScript() throws Exception {
- WinRmToolResponse response = machine.executeScript("echo true");
- assertEquals(response.getStatusCode(), 0);
- assertEquals(response.getStdErr(), "");
+ assertExecSucceeds("echo myline", "myline", "");
+ }
+
+ /*
+ * TODO Not supported in PyWinRM.
+ *
+ * Executing (in python):
+ * import winrm
+ * s = winrm.Session('52.12.211.247', auth=('Administrator', 'pa55w0rd'))
+ * r = s.run_cmd("echo first \r\n echo second")
+ * gives just "first".
+ */
+ @Test(groups={"Live", "WIP"})
+ public void testExecMultiLineScript() throws Exception {
+ assertExecSucceeds("echo first" + "\r\n" + "echo second", "first"+"\r\n"+"second", "");
+ }
+
+ /*
+ * TODO Not supported in PyWinRM. Under the covers, we just concatenate the commands.
+ * See {@link #testExecMultiLineScript()}.
+ */
+ @Test(groups={"Live", "WIP"})
+ public void testExecMultiPartScript() throws Exception {
+ assertExecSucceeds(ImmutableList.of("echo first", "echo second"), "first"+"\r\n"+"second", "");
+ }
+
+ @Test(groups="Live")
+ public void testExecFailingScript() throws Exception {
+ final String INVALID_CMD = "thisCommandDoesNotExistAEFafiee3d";
+
+ // Single commands
+ assertExecFails(INVALID_CMD);
+ assertExecFails(ImmutableList.of(INVALID_CMD));
+ }
+
+ @Test(groups="Live")
+ public void testExecScriptExit0() throws Exception {
+ assertExecSucceeds("exit /B 0", "", "");
+ assertExecSucceeds(ImmutableList.of("exit /B 0"), "", "");
+ }
+
+ /*
+ * TODO Not supported in PyWinRM.
+ *
+ * Executing (in python):
+ * import winrm
+ * s = winrm.Session('52.12.211.247', auth=('Administrator', 'pa55w0rd'))
+ * r = s.run_cmd("exit /B 1")
+ * gives exit code 0.
+ */
+ @Test(groups={"Live", "WIP"})
+ public void testExecScriptExit1() throws Exception {
+ // Single commands
+ assertExecFails("exit /B 1");
+ assertExecFails(ImmutableList.of("exit /B 1"));
+ }
+
+ @Test(groups="Live")
+ public void testExecBatchFileSingleLine() throws Exception {
+ String script = "EXIT /B 0";
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".bat";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecSucceeds(scriptPath, null, "");
+ }
+
+ @Test(groups="Live")
+ public void testExecBatchFileMultiLine() throws Exception {
+ String script = Joiner.on("\n").join(
+ "@ECHO OFF",
+ "echo first",
+ "echo second",
+ "EXIT /B 0");
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".bat";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecSucceeds(scriptPath, "first"+"\r\n"+"second", "");
+ }
+
+ @Test(groups="Live")
+ public void testExecBatchFileWithArgs() throws Exception {
+ String script = Joiner.on("\n").join(
+ "@ECHO OFF",
+ "echo got %1",
+ "echo got %2",
+ "EXIT /B 0");
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".bat";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecSucceeds(scriptPath+" first second", "got first"+"\r\n"+"got second", "");
+ }
+
+ @Test(groups="Live")
+ public void testExecBatchFileWithExit1() throws Exception {
+ String script = "EXIT /B 1";
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".bat";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecFails(scriptPath);
+ }
+
+ @Test(groups="Live")
+ public void testExecCorruptExe() throws Exception {
+ String exe = "garbage";
+ String exePath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".exe";
+ machine.copyTo(new ByteArrayInputStream(exe.getBytes()), exePath);
+
+ assertExecFails(exePath);
+ }
+
+ @Test(groups="Live")
+ public void testExecFilePs() throws Exception {
+ String script = Joiner.on("\r\n").join(
+ "Write-Host myline",
+ "exit 0");
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".ps1";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecPsSucceeds(
+ "PowerShell -NonInteractive -NoProfile -Command "+scriptPath,
+ "myline",
+ "");
+ }
+
+ @Test(groups="Live")
+ public void testExecFilePsWithExit1() throws Exception {
+ String script = Joiner.on("\r\n").join(
+ "Write-Host myline",
+ "exit 1");
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".ps1";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecFails("PowerShell -NonInteractive -NoProfile -Command "+scriptPath);
+ }
+
+ /*
+ * TODO Not supported in PyWinRM - single line .ps1 file with "exit 1" gives an
+ * exit code 0 over PyWinRM, but an exit code 1 when executed locally!
+ *
+ * Executing (in python):
+ * import winrm
+ * s = winrm.Session('52.12.211.247', auth=('Administrator', 'pa55w0rd'))
+ * r = s.run_cmd("PowerShell -NonInteractive -NoProfile -Command C:\singleLineExit1.ps1")
+ * gives exit code 0.
+ */
+ @Test(groups={"Live", "WIP"})
+ public void testExecFilePsWithSingleLineExit1() throws Exception {
+ String script = "exit 1";
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".ps1";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecFails("PowerShell -NonInteractive -NoProfile -Command "+scriptPath);
+ }
+
+ @Test(groups="Live")
+ public void testExecPsScript() throws Exception {
+ assertExecPsSucceeds("Write-Host myline", "myline", "");
+ }
+
+ @Test(groups="Live")
+ public void testExecPsMultiLineScript() throws Exception {
+ // Note stdout is "\n" rather than "\r\n" (the latter is returned for run_cmd, versus run_ps)
+ assertExecPsSucceeds("Write-Host first" + "\r\n" + "Write-Host second", "first"+"\n"+"second", "");
+ }
+
+ @Test(groups="Live")
+ public void testExecPsMultiLineScriptWithoutSlashR() throws Exception {
+ assertExecPsSucceeds("Write-Host first" + "\n" + "Write-Host second", "first"+"\n"+"second", "");
+ }
+
+ @Test(groups="Live")
+ public void testExecPsMultiPartScript() throws Exception {
+ assertExecPsSucceeds(ImmutableList.of("Write-Host first", "Write-Host second"), "first"+"\n"+"second", "");
+ }
+
+ @Test(groups="Live")
+ public void testExecPsBatchFile() throws Exception {
+ String script = "EXIT /B 0";
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".bat";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecPsSucceeds("& '"+scriptPath+"'", null, "");
+ }
+
+ @Test(groups="Live")
+ public void testExecPsBatchFileExit1() throws Exception {
+ String script = "EXIT /B 1";
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".bat";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecPsFails("& '"+scriptPath+"'");
+ }
+
+ /*
+ * TODO Not supported in PyWinRM - gives exit status 1, rather than the 3 from the batch file.
+ */
+ @Test(groups={"Live", "WIP"})
+ public void testExecPsBatchFileExit3() throws Exception {
+ String script = "EXIT /B 3";
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".bat";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ WinRmToolResponse response = machine.executePsScript("& '"+scriptPath+"'");
+ String msg = "statusCode="+response.getStatusCode()+"; out="+response.getStdOut()+"; err="+response.getStdErr();
+ assertEquals(response.getStatusCode(), 3, msg);
+ }
+
+ @Test(groups="Live")
+ public void testExecPsCorruptExe() throws Exception {
+ String exe = "garbage";
+ String exePath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".exe";
+ machine.copyTo(new ByteArrayInputStream(exe.getBytes()), exePath);
+
+ assertExecPsFails("& '"+exePath+"'");
+ }
+
+ @Test(groups="Live")
+ public void testExecPsFileWithArg() throws Exception {
+ String script = Joiner.on("\r\n").join(
+ "Param(",
+ " [string]$myarg",
+ ")",
+ "Write-Host got $myarg",
+ "exit 0");
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".ps1";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecPsSucceeds("& "+scriptPath+" -myarg myval", "got myval", "");
+ }
+
+ @Test(groups="Live")
+ public void testExecPsFilePs() throws Exception {
+ String script = Joiner.on("\r\n").join(
+ "Write-Host myline",
+ "exit 0");
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".ps1";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecPsSucceeds("& "+scriptPath, "myline", "");
+ }
+
+ @Test(groups="Live")
+ public void testExecPsFilePsWithExit1() throws Exception {
+ String script = Joiner.on("\r\n").join(
+ "Write-Host myline",
+ "exit 1");
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".ps1";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+ System.out.println(scriptPath);
+
+ assertExecPsFails("& "+scriptPath);
+ }
+
+ /*
+ * TODO Not supported in PyWinRM - single line .ps1 file with "exit 1" gives an
+ * exit code 0 over PyWinRM, but an exit code 1 when executed locally!
+ *
+ * Executing (in python):
+ * import winrm
+ * s = winrm.Session('52.12.211.247', auth=('Administrator', 'pa55w0rd'))
+ * r = s.run_cmd("PowerShell -NonInteractive -NoProfile -Command C:\singleLineExit1.ps1")
+ * gives exit code 0.
+ */
+ @Test(groups={"Live", "WIP"})
+ public void testExecPsFilePsSingleLineWithExit1() throws Exception {
+ String script = "exit 1";
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".ps1";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecPsFails("& "+scriptPath);
+ }
+
+ /*
+ * TODO Not supported in PyWinRM - single line .ps1 file with "exit 1" gives an
+ * exit code 0 over PyWinRM, but an exit code 1 when executed locally!
+ *
+ * Executing (in python):
+ * import winrm
+ * s = winrm.Session('52.12.211.247', auth=('Administrator', 'pa55w0rd'))
+ * r = s.run_cmd("PowerShell -NonInteractive -NoProfile -Command C:\singleLineGarbage.ps1")
+ * gives exit code 0.
+ */
+ @Test(groups={"Live", "WIP"})
+ public void testExecPsFilePsSingleLineWithInvalidCommand() throws Exception {
+ String script = INVALID_CMD;
+ String scriptPath = "C:\\myscript-"+Identifiers.makeRandomId(4)+".ps1";
+ machine.copyTo(new ByteArrayInputStream(script.getBytes()), scriptPath);
+
+ assertExecPsFails("& "+scriptPath);
+ }
+
+ @Test(groups="Live")
+ public void testConfirmUseOfErrorActionPreferenceDoesNotCauseErr() throws Exception {
+ // Confirm that ErrorActionPreference=Stop does not itself cause a failure, and still get output on success.
+ assertExecPsSucceeds(ImmutableList.of(PS_ERR_ACTION_PREF_EQ_STOP, "Write-Host myline"), "myline", "");
+ }
+
+ /*
+ * TODO Not supported in PyWinRM
+ *
+ * Executing (in python):
+ * import winrm
+ * s = winrm.Session('52.12.211.247', auth=('Administrator', 'pa55w0rd'))
+ * r = s.run_ps("exit 1")
+ * gives exit code 0.
+ */
+ @Test(groups={"Live", "WIP"})
+ public void testExecPsExit1() throws Exception {
+ // Single commands
+ assertExecPsFails("exit 1");
+ assertExecPsFails(ImmutableList.of("exit 1"));
+
+ // Multi-part
+ assertExecPsFails(ImmutableList.of(PS_ERR_ACTION_PREF_EQ_STOP, "Write-Host myline", "exit 1"));
+
+ // Multi-line
+ assertExecPsFails(PS_ERR_ACTION_PREF_EQ_STOP + "\n" + "Write-Host myline" + "\n" + "exit 1");
+ }
+
+ @Test(groups="Live")
+ public void testExecFailingPsScript() throws Exception {
+ // Single commands
+ assertExecPsFails(INVALID_CMD);
+ assertExecPsFails(ImmutableList.of(INVALID_CMD));
+
+ // Multi-part commands
+ assertExecPsFails(ImmutableList.of(PS_ERR_ACTION_PREF_EQ_STOP, "Write-Host myline", INVALID_CMD));
+ assertExecPsFails(ImmutableList.of(PS_ERR_ACTION_PREF_EQ_STOP, INVALID_CMD, "Write-Host myline"));
+ }
+
+ @Test(groups={"Live", "Acceptance"})
+ public void testExecConcurrently() throws Exception {
+ final int NUM_RUNS = 10;
+ final int TIMEOUT_MINS = 30;
+ final AtomicInteger counter = new AtomicInteger();
+
+ // Find the test methods that are enabled, and that are not WIP
+ List<Method> methodsToRun = Lists.newArrayList();
+ Method[] allmethods = WinRmMachineLocationLiveTest.class.getMethods();
+ for (Method method : allmethods) {
+ Test annotatn = method.getAnnotation(Test.class);
+ if (method.getParameterTypes().length != 0) {
+ continue;
+ }
+ if (method.getName().equals("testExecConcurrently")) {
+ continue;
+ }
+ if (annotatn == null || !annotatn.enabled()) {
+ continue;
+ }
+ String[] groups = annotatn.groups();
+ if (groups != null && Arrays.asList(groups).contains("WIP")) {
+ continue;
+ }
+ methodsToRun.add(method);
+ }
+
+ // Execute all the methods many times
+ LOG.info("Executing "+methodsToRun.size()+" methods "+NUM_RUNS+" times each, with "+MAX_EXECUTOR_THREADS+" threads for concurrent execution; max permitted time "+TIMEOUT_MINS+"mins; methods="+methodsToRun);
+
+ List<ListenableFuture<?>> results = Lists.newArrayList();
+ for (int i = 0; i < NUM_RUNS; i++) {
+ for (final Method method : methodsToRun) {
+ results.add(executor.submit(new Callable<Void>() {
+ public Void call() throws Exception {
+ LOG.info("Executing "+method.getName()+" in thread "+Thread.currentThread());
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ try {
+ method.invoke(WinRmMachineLocationLiveTest.this);
+ LOG.info("Executed "+method.getName()+" in "+Time.makeTimeStringRounded(stopwatch)+", in thread "+Thread.currentThread()+"; total "+counter.incrementAndGet()+" methods done");
+ return null;
+ } catch (Exception e) {
+ LOG.error("Execute failed for "+method.getName()+" after "+Time.makeTimeStringRounded(stopwatch)+", in thread "+Thread.currentThread()+"; total "+counter.incrementAndGet()+" methods done");
+ throw e;
+ }
+ }}));
+ }
+ }
+
+ Futures.allAsList(results).get(TIMEOUT_MINS, TimeUnit.MINUTES);
+ }
+
+ private void assertExecFails(String cmd) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ assertFailed(cmd, machine.executeScript(cmd), stopwatch);
+ }
+
+ private void assertExecFails(List<String> cmds) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ assertFailed(cmds, machine.executeScript(cmds), stopwatch);
+ }
+
+ private void assertExecPsFails(String cmd) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ assertFailed(cmd, machine.executePsScript(cmd), stopwatch);
+ }
+
+ private void assertExecPsFails(List<String> cmds) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ assertFailed(cmds, machine.executePsScript(cmds), stopwatch);
+ }
+
+ private void assertExecSucceeds(String cmd, String stdout, String stderr) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ assertSucceeded(cmd, machine.executeScript(cmd), stdout, stderr, stopwatch);
+ }
+
+ private void assertExecSucceeds(List<String> cmds, String stdout, String stderr) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ assertSucceeded(cmds, machine.executeScript(cmds), stdout, stderr, stopwatch);
+ }
+
+ private void assertExecPsSucceeds(String cmd, String stdout, String stderr) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ assertSucceeded(cmd, machine.executePsScript(cmd), stdout, stderr, stopwatch);
+ }
+
+ private void assertExecPsSucceeds(List<String> cmds, String stdout, String stderr) {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ assertSucceeded(cmds, machine.executePsScript(cmds), stdout, stderr, stopwatch);
+ }
+
+ private void assertFailed(Object cmd, WinRmToolResponse response, Stopwatch stopwatch) {
+ String msg = "statusCode="+response.getStatusCode()+"; out="+response.getStdOut()+"; err="+response.getStdErr();
+ LOG.info("Executed in "+Time.makeTimeStringRounded(stopwatch)+" (asserting failed): "+msg+"; cmd="+cmd);
+ assertNotEquals(response.getStatusCode(), 0, msg);
+ }
+
+ private WinRmToolResponse assertSucceeded(Object cmd, WinRmToolResponse response, String stdout, String stderr, Stopwatch stopwatch) {
+ String msg = "statusCode="+response.getStatusCode()+"; out="+response.getStdOut()+"; err="+response.getStdErr();
+ LOG.info("Executed in "+Time.makeTimeStringRounded(stopwatch)+" (asserting success): "+msg+"; cmd="+cmd);
+ assertEquals(response.getStatusCode(), 0, msg);
+ if (stdout != null) assertEquals(response.getStdOut().trim(), stdout, msg);
+ if (stderr != null) assertEquals(response.getStdErr().trim(), stderr, msg);
+ return response;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WindowsTestFixture.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WindowsTestFixture.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WindowsTestFixture.java
new file mode 100644
index 0000000..10aa4b7
--- /dev/null
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/test/location/WindowsTestFixture.java
@@ -0,0 +1,71 @@
+/*
+ * 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.brooklyn.entity.software.base.test.location;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class WindowsTestFixture {
+
+ @SuppressWarnings("unchecked")
+ public static MachineProvisioningLocation<WinRmMachineLocation> setUpWindowsLocation(ManagementContext mgmt) throws Exception {
+ // Commented out / unused code included here to make it easy to supply a
+ // pre-existing Windows VM for use in a bunch of different tests.
+// return (MachineProvisioningLocation<WinRmMachineLocation>) newByonLocation((ManagementContextInternal) mgmt);
+ return (MachineProvisioningLocation<WinRmMachineLocation>) newJcloudsLocation((ManagementContextInternal) mgmt);
+ }
+
+ private static MachineProvisioningLocation<?> newJcloudsLocation(ManagementContextInternal mgmt) {
+ // Requires no userMetadata to be set, so that we use WinRmMachineLocation.getDefaultUserMetadataString()
+ mgmt.getBrooklynProperties().remove("brooklyn.location.jclouds.aws-ec2.userMetadata");
+ mgmt.getBrooklynProperties().remove("brooklyn.location.jclouds.userMetadata");
+ mgmt.getBrooklynProperties().remove("brooklyn.location.userMetadata");
+
+ return (JcloudsLocation) mgmt.getLocationRegistry().resolve("jclouds:aws-ec2:us-west-2", ImmutableMap.<String, Object>builder()
+ .put("inboundPorts", ImmutableList.of(5985, 3389))
+ .put("displayName", "AWS Oregon (Windows)")
+ .put("imageOwner", "801119661308")
+ .put("imageNameRegex", "Windows_Server-2012-R2_RTM-English-64Bit-Base-.*")
+ .put("hardwareId", "m3.medium")
+ .put("useJcloudsSshInit", false)
+ .build());
+ }
+
+ @SuppressWarnings("unused")
+ private static MachineProvisioningLocation<?> newByonLocation(ManagementContextInternal mgmt) {
+ Map<String, String> config = new LinkedHashMap<>();
+ config.put("hosts", "52.12.211.123:5985");
+ config.put("osFamily", "windows");
+ config.put("winrm", "52.12.211.123:5985");
+ config.put("user", "Administrator");
+ config.put("password", "pa55w0rd");
+ config.put("useJcloudsSshInit", "false");
+ config.put("byonIdentity", "123");
+ return (MachineProvisioningLocation<?>) mgmt.getLocationRegistry().resolve("byon", config);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/pom.xml
----------------------------------------------------------------------
diff --git a/usage/camp/pom.xml b/usage/camp/pom.xml
index 911ff6a..fb5d7ee 100644
--- a/usage/camp/pom.xml
+++ b/usage/camp/pom.xml
@@ -157,6 +157,12 @@
</dependency>
<dependency>
<groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-locations-jclouds</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
<artifactId>brooklyn-test-support</artifactId>
<version>${project.version}</version>
<scope>test</scope>
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/WindowsYamlLiveTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/WindowsYamlLiveTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/WindowsYamlLiveTest.java
new file mode 100644
index 0000000..15626db
--- /dev/null
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/WindowsYamlLiveTest.java
@@ -0,0 +1,410 @@
+/*
+ * 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.brooklyn.camp.brooklyn;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.StringReader;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.api.mgmt.HasTaskChildren;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+import org.apache.brooklyn.entity.software.base.VanillaWindowsProcess;
+import org.apache.brooklyn.entity.software.base.test.location.WindowsTestFixture;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.core.task.TaskPredicates;
+import org.apache.brooklyn.util.text.StringPredicates;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+/**
+ * Tests Windows YAML blueprint features.
+ */
+@Test
+public class WindowsYamlLiveTest extends AbstractYamlTest {
+
+ // TODO Remove duplication of assertStreams and VanillaWindowsProcessWinrmStreamsLiveTest.assertStreams
+
+ private static final Logger log = LoggerFactory.getLogger(WindowsYamlLiveTest.class);
+
+ /**
+ * Maps from the task names that are used to the names used in log/exception messages.
+ */
+ private static final Map<String, String> TASK_REGEX_TO_COMMAND = ImmutableMap.<String, String>builder()
+ .put("winrm: pre-install-command.*", "pre-install-command")
+ .put("winrm: install.*", "install-command")
+ .put("winrm: post-install-command.*", "post-install-command")
+ .put("winrm: customize.*", "customize-command")
+ .put("winrm: pre-launch-command.*", "pre-launch-command")
+ .put("winrm: launch.*", "launch-command")
+ .put("winrm: post-launch-command.*", "post-launch-command")
+ .put("winrm: stop-command.*", "stop-command")
+ .put("winrm: is-running-command.*", "is-running-command")
+ .build();
+
+ protected List<String> yamlLocation;
+ protected MachineProvisioningLocation<WinRmMachineLocation> location;
+ protected WinRmMachineLocation machine;
+ protected Entity app;
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpClass() throws Exception {
+ super.setUp();
+
+ location = WindowsTestFixture.setUpWindowsLocation(mgmt());
+ machine = (WinRmMachineLocation) location.obtain(ImmutableMap.of());
+ String ip = machine.getAddress().getHostAddress();
+ String password = machine.config().get(WinRmMachineLocation.PASSWORD);
+
+ yamlLocation = ImmutableList.of(
+ "location:",
+ " byon:",
+ " hosts:",
+ " - winrm: "+ip+":5985",
+ " password: "+password,
+ " user: Administrator",
+ " osFamily: windows");
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void tearDownClass() {
+ try {
+ if (location != null) location.release(machine);
+ } catch (Throwable t) {
+ log.error("Caught exception in tearDownClass method", t);
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ @BeforeMethod(alwaysRun = true)
+ @Override
+ public void setUp() {
+ // no-op; everything done @BeforeClass
+ }
+
+ @AfterMethod(alwaysRun = true)
+ @Override
+ public void tearDown() {
+ try {
+ if (app != null) Entities.destroy(app);
+ } catch (Throwable t) {
+ log.error("Caught exception in tearDown method", t);
+ } finally {
+ app = null;
+ }
+ }
+
+ @Override
+ protected ManagementContextInternal mgmt() {
+ return (ManagementContextInternal) super.mgmt();
+ }
+
+ @Test(groups="Live")
+ public void testPowershellMinimalist() throws Exception {
+ Map<String, String> cmds = ImmutableMap.<String, String>builder()
+ .put("myarg", "myval")
+ .put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("checkRunning.powershell.command", "\"& c:\\\\exit0.bat\"")
+ .build();
+
+ Map<String, List<String>> stdouts = ImmutableMap.of();
+
+ runWindowsApp(cmds, stdouts, null);
+ }
+
+ @Test(groups="Live")
+ public void testPowershell() throws Exception {
+ Map<String, String> cmds = ImmutableMap.<String, String>builder()
+ .put("myarg", "myval")
+ .put("pre.install.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("install.powershell.command", "\"& c:\\\\echoMyArg.ps1 -myarg myInstall\"")
+ .put("post.install.powershell.command", "\"& c:\\\\echoArg.bat myPostInstall\"")
+ .put("customize.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.bat\"")
+ .put("pre.launch.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.ps1\"")
+ .put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("post.launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("checkRunning.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("stop.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .build();
+
+ Map<String, List<String>> stdouts = ImmutableMap.<String, List<String>>builder()
+ .put("winrm: install.*", ImmutableList.of("myInstall"))
+ .put("winrm: post-install-command.*", ImmutableList.of("myPostInstall"))
+ .put("winrm: customize.*", ImmutableList.of("myval"))
+ .put("winrm: pre-launch-command.*", ImmutableList.of("myval"))
+ .build();
+
+ runWindowsApp(cmds, stdouts, null);
+ }
+
+ @Test(groups="Live")
+ public void testBatch() throws Exception {
+ Map<String, String> cmds = ImmutableMap.<String, String>builder()
+ .put("myarg", "myval")
+ .put("pre.install.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
+ .put("install.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\echoMyArg.ps1 -myarg myInstall\"")
+ .put("post.install.command", "\"c:\\\\echoArg.bat myPostInstall\"")
+ .put("customize.command", "\"c:\\\\echoFreemarkerMyarg.bat\"")
+ .put("pre.launch.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\echoFreemarkerMyarg.ps1\"")
+ .put("launch.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
+ .put("post.launch.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
+ .put("checkRunning.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
+ .put("stop.command", "\"PowerShell -NonInteractive -NoProfile -Command c:\\\\exit0.ps1\"")
+ .build();
+
+ Map<String, List<String>> stdouts = ImmutableMap.<String, List<String>>builder()
+ .put("winrm: install.*", ImmutableList.of("myInstall"))
+ .put("winrm: post-install-command.*", ImmutableList.of("myPostInstall"))
+ .put("winrm: customize.*", ImmutableList.of("myval"))
+ .put("winrm: pre-launch-command.*", ImmutableList.of("myval"))
+ .build();
+
+ runWindowsApp(cmds, stdouts, null);
+ }
+
+ @Test(groups="Live")
+ public void testPowershellExit1() throws Exception {
+ Map<String, String> cmds = ImmutableMap.<String, String>builder()
+ .put("myarg", "myval")
+ .put("pre.install.powershell.command", "\"& c:\\\\exit1.ps1\"")
+ .put("install.powershell.command", "\"& c:\\\\echoMyArg.ps1 -myarg myInstall\"")
+ .put("post.install.powershell.command", "\"& c:\\\\echoArg.bat myPostInstall\"")
+ .put("customize.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.bat\"")
+ .put("pre.launch.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.ps1\"")
+ .put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("post.launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("checkRunning.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("stop.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .build();
+
+ Map<String, List<String>> stdouts = ImmutableMap.of();
+
+ runWindowsApp(cmds, stdouts, "winrm: pre-install-command.*");
+ }
+
+ // FIXME Failing to match the expected exception, but looks fine! Needs more investigation.
+ @Test(groups="Live")
+ public void testPowershellCheckRunningExit1() throws Exception {
+ Map<String, String> cmds = ImmutableMap.<String, String>builder()
+ .put("myarg", "myval")
+ .put("pre.install.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("install.powershell.command", "\"& c:\\\\echoMyArg.ps1 -myarg myInstall\"")
+ .put("post.install.powershell.command", "\"& c:\\\\echoArg.bat myPostInstall\"")
+ .put("customize.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.bat\"")
+ .put("pre.launch.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.ps1\"")
+ .put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("post.launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("checkRunning.powershell.command", "\"& c:\\\\exit1.ps1\"")
+ .put("stop.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .build();
+
+ Map<String, List<String>> stdouts = ImmutableMap.of();
+
+ runWindowsApp(cmds, stdouts, "winrm: is-running-command.*");
+ }
+
+ // FIXME Needs more work to get the stop's task that failed, so can assert got the right error message
+ @Test(groups="Live")
+ public void testPowershellStopExit1() throws Exception {
+ Map<String, String> cmds = ImmutableMap.<String, String>builder()
+ .put("myarg", "myval")
+ .put("pre.install.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("install.powershell.command", "\"& c:\\\\echoMyArg.ps1 -myarg myInstall\"")
+ .put("post.install.powershell.command", "\"& c:\\\\echoArg.bat myPostInstall\"")
+ .put("customize.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.bat\"")
+ .put("pre.launch.powershell.command", "\"& c:\\\\echoFreemarkerMyarg.ps1\"")
+ .put("launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("post.launch.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("checkRunning.powershell.command", "\"& c:\\\\exit0.ps1\"")
+ .put("stop.powershell.command", "\"& c:\\\\exit1.ps1\"")
+ .build();
+
+ Map<String, List<String>> stdouts = ImmutableMap.of();
+
+ runWindowsApp(cmds, stdouts, "winrm: stop-command.*");
+ }
+
+ protected void runWindowsApp(Map<String, String> commands, Map<String, List<String>> stdouts, String taskRegexFailed) throws Exception {
+ String cmdFailed = (taskRegexFailed == null) ? null : TASK_REGEX_TO_COMMAND.get(taskRegexFailed);
+
+ List<String> yaml = Lists.newArrayList();
+ yaml.addAll(yamlLocation);
+ yaml.addAll(ImmutableList.of(
+ "services:",
+ "- type: org.apache.brooklyn.entity.software.base.VanillaWindowsProcess",
+ " brooklyn.config:",
+ " onbox.base.dir.skipResolution: true",
+ " templates.preinstall:",
+ " classpath://org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.bat: c:\\echoFreemarkerMyarg.bat",
+ " classpath://org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.ps1: c:\\echoFreemarkerMyarg.ps1",
+ " files.preinstall:",
+ " classpath://org/apache/brooklyn/camp/brooklyn/echoArg.bat: c:\\echoArg.bat",
+ " classpath://org/apache/brooklyn/camp/brooklyn/echoMyArg.ps1: c:\\echoMyArg.ps1",
+ " classpath://org/apache/brooklyn/camp/brooklyn/exit0.bat: c:\\exit0.bat",
+ " classpath://org/apache/brooklyn/camp/brooklyn/exit1.bat: c:\\exit1.bat",
+ " classpath://org/apache/brooklyn/camp/brooklyn/exit0.ps1: c:\\exit0.ps1",
+ " classpath://org/apache/brooklyn/camp/brooklyn/exit1.ps1: c:\\exit1.ps1",
+ ""));
+
+ for (Map.Entry<String, String> entry : commands.entrySet()) {
+ yaml.add(" "+entry.getKey()+": "+entry.getValue());
+ }
+
+ if (Strings.isBlank(cmdFailed)) {
+ app = createAndStartApplication(new StringReader(Joiner.on("\n").join(yaml)));
+ waitForApplicationTasks(app);
+ log.info("App started:");
+ Entities.dumpInfo(app);
+
+ VanillaWindowsProcess entity = (VanillaWindowsProcess) app.getChildren().iterator().next();
+
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true);
+ assertStreams(entity, stdouts);
+
+ } else if (cmdFailed.equals("stop-command")) {
+ app = createAndStartApplication(new StringReader(Joiner.on("\n").join(yaml)));
+ waitForApplicationTasks(app);
+ log.info("App started:");
+ Entities.dumpInfo(app);
+ VanillaWindowsProcess entity = (VanillaWindowsProcess) app.getChildren().iterator().next();
+ EntityTestUtils.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true);
+
+ entity.stop();
+ assertSubTaskFailures(entity, ImmutableMap.of(taskRegexFailed, StringPredicates.containsLiteral("for "+cmdFailed)));
+
+ } else {
+ try {
+ app = createAndStartApplication(new StringReader(Joiner.on("\n").join(yaml)));
+ fail("start should have failed for app="+app);
+ } catch (Exception e) {
+ if (e.toString().contains("invalid result") && e.toString().contains("for "+cmdFailed)) throw e;
+ }
+ }
+ }
+
+ protected void assertStreams(SoftwareProcess entity, Map<String, List<String>> stdouts) {
+ Set<Task<?>> tasks = BrooklynTaskTags.getTasksInEntityContext(mgmt().getExecutionManager(), entity);
+
+ for (Map.Entry<String, List<String>> entry : stdouts.entrySet()) {
+ String taskNameRegex = entry.getKey();
+ List<String> expectedOuts = entry.getValue();
+
+ Task<?> subTask = findTaskOrSubTask(tasks, TaskPredicates.displayNameMatches(StringPredicates.matchesRegex(taskNameRegex))).get();
+
+ String stdin = getStreamOrFail(subTask, BrooklynTaskTags.STREAM_STDIN);
+ String stdout = getStreamOrFail(subTask, BrooklynTaskTags.STREAM_STDOUT);
+ String stderr = getStreamOrFail(subTask, BrooklynTaskTags.STREAM_STDERR);
+ String env = getStream(subTask, BrooklynTaskTags.STREAM_ENV);
+ String msg = "stdin="+stdin+"; stdout="+stdout+"; stderr="+stderr+"; env="+env;
+
+ for (String expectedOut : expectedOuts) {
+ assertTrue(stdout.contains(expectedOut), msg);
+ }
+ }
+ }
+
+ protected void assertSubTaskFailures(SoftwareProcess entity, Map<String, Predicate<CharSequence>> taskErrs) throws Exception {
+ Set<Task<?>> tasks = BrooklynTaskTags.getTasksInEntityContext(mgmt().getExecutionManager(), entity);
+
+ for (Map.Entry<String, Predicate<CharSequence>> entry : taskErrs.entrySet()) {
+ String taskNameRegex = entry.getKey();
+ Predicate<? super String> errChecker = entry.getValue();
+ Task<?> subTask = findTaskOrSubTask(tasks, TaskPredicates.displayNameMatches(StringPredicates.matchesRegex(taskNameRegex))).get();
+ String msg = "regex="+taskNameRegex+"; task="+subTask;
+ assertNotNull(subTask, msg);
+ assertTrue(subTask.isDone(), msg);
+ assertTrue(subTask.isError(), msg);
+ try {
+ subTask.get();
+ fail();
+ } catch (Exception e) {
+ if (!errChecker.apply(e.toString())) {
+ throw e;
+ }
+ }
+ }
+ }
+
+ public static String getStreamOrFail(Task<?> task, String streamType) {
+ String msg = "task="+task+"; stream="+streamType;
+ BrooklynTaskTags.WrappedStream stream = checkNotNull(BrooklynTaskTags.stream(task, streamType), "Stream null: " + msg);
+ return checkNotNull(stream.streamContents.get(), "Contents null: "+msg);
+ }
+
+ public static String getStream(Task<?> task, String streamType) {
+ BrooklynTaskTags.WrappedStream stream = BrooklynTaskTags.stream(task, streamType);
+ return (stream != null) ? stream.streamContents.get() : null;
+ }
+
+ protected Optional<Task<?>> findTaskOrSubTask(Iterable<? extends Task<?>> tasks, Predicate<? super Task<?>> matcher) {
+ List<String> taskNames = Lists.newArrayList();
+ Optional<Task<?>> result = findTaskOrSubTaskImpl(tasks, matcher, taskNames);
+ if (!result.isPresent() && log.isDebugEnabled()) {
+ log.debug("Task not found matching "+matcher+"; contender names were "+taskNames);
+ }
+ return result;
+ }
+
+ protected Optional<Task<?>> findTaskOrSubTaskImpl(Iterable<? extends Task<?>> tasks, Predicate<? super Task<?>> matcher, List<String> taskNames) {
+ for (Task<?> task : tasks) {
+ if (matcher.apply(task)) return Optional.<Task<?>>of(task);
+
+ if (!(task instanceof HasTaskChildren)) {
+ return Optional.absent();
+ } else {
+ Optional<Task<?>> subResult = findTaskOrSubTask(((HasTaskChildren) task).getChildren(), matcher);
+ if (subResult.isPresent()) return subResult;
+ }
+ }
+
+ return Optional.<Task<?>>absent();
+ }
+
+ @Override
+ protected Logger getLogger() {
+ return log;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoArg.bat
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoArg.bat b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoArg.bat
new file mode 100644
index 0000000..dd77ba6
--- /dev/null
+++ b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoArg.bat
@@ -0,0 +1,19 @@
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements. See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership. The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License. You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied. See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+@ECHO OFF
+echo %1
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.bat
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.bat b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.bat
new file mode 100644
index 0000000..33f7b7e
--- /dev/null
+++ b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.bat
@@ -0,0 +1,18 @@
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements. See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership. The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License. You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied. See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+echo ${config['myarg']}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.ps1
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.ps1 b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.ps1
new file mode 100644
index 0000000..c2535ea
--- /dev/null
+++ b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoFreemarkerMyarg.ps1
@@ -0,0 +1,18 @@
+# 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.
+
+Write-Host ${config['myarg']}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoMyArg.ps1
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoMyArg.ps1 b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoMyArg.ps1
new file mode 100644
index 0000000..3a2d33d
--- /dev/null
+++ b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/echoMyArg.ps1
@@ -0,0 +1,22 @@
+# 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.
+
+param(
+ [string]$myarg
+)
+
+Write-Host $myarg
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit0.bat
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit0.bat b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit0.bat
new file mode 100644
index 0000000..2a926b6
--- /dev/null
+++ b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit0.bat
@@ -0,0 +1,18 @@
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements. See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership. The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License. You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied. See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+EXIT /B 0
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit0.ps1
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit0.ps1 b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit0.ps1
new file mode 100644
index 0000000..fe0e1f1
--- /dev/null
+++ b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit0.ps1
@@ -0,0 +1,18 @@
+# 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.
+
+exit 0
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit1.bat
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit1.bat b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit1.bat
new file mode 100644
index 0000000..f8b79b9
--- /dev/null
+++ b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit1.bat
@@ -0,0 +1,18 @@
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements. See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership. The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License. You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied. See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+EXIT /B 1
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/10071a92/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit1.ps1
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit1.ps1 b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit1.ps1
new file mode 100644
index 0000000..a7fc049
--- /dev/null
+++ b/usage/camp/src/test/resources/org/apache/brooklyn/camp/brooklyn/exit1.ps1
@@ -0,0 +1,19 @@
+# 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.
+
+Write-Host single line file gives exit code 0 from PyWinRM
+exit 1
\ No newline at end of file