Repository: brooklyn-server Updated Branches: refs/heads/master 50826cbc2 -> 615c63574
SshMachineLocationTest: make non-integration * Uses RecordingSshTool * Moves integration tests into SshMachineLocationIntegrationTest * Changes SshMachineLocationIntegrationTest to extends SshMachineLocationTest. Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/e5b40cc1 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/e5b40cc1 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/e5b40cc1 Branch: refs/heads/master Commit: e5b40cc1866854d8966099c26ea44a62cd9c3196 Parents: b11c87d Author: Aled Sage <[email protected]> Authored: Thu Dec 1 08:26:56 2016 +0000 Committer: Aled Sage <[email protected]> Committed: Thu Dec 1 08:26:56 2016 +0000 ---------------------------------------------------------------------- .../ssh/SshMachineLocationIntegrationTest.java | 184 +++++++++++++++++-- .../location/ssh/SshMachineLocationTest.java | 160 +++++----------- 2 files changed, 210 insertions(+), 134 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e5b40cc1/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationIntegrationTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationIntegrationTest.java index 605d9c0..1def66f 100644 --- a/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationIntegrationTest.java +++ b/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationIntegrationTest.java @@ -19,53 +19,199 @@ package org.apache.brooklyn.location.ssh; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.OutputStream; +import java.net.InetAddress; import java.security.KeyPair; import java.util.Arrays; import java.util.Map; +import java.util.concurrent.Callable; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.location.LocationSpec; -import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.core.entity.Entities; -import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; -import org.apache.brooklyn.core.test.entity.TestApplication; +import org.apache.brooklyn.api.location.MachineDetails; +import org.apache.brooklyn.core.entity.AbstractEntity; +import org.apache.brooklyn.core.internal.BrooklynProperties; import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation; +import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.crypto.SecureKeys; +import org.apache.brooklyn.util.core.file.ArchiveUtils; +import org.apache.brooklyn.util.core.internal.ssh.SshException; import org.apache.brooklyn.util.core.internal.ssh.SshTool; import org.apache.brooklyn.util.core.internal.ssh.sshj.SshjTool; import org.apache.brooklyn.util.core.internal.ssh.sshj.SshjTool.SshjToolBuilder; +import org.apache.brooklyn.util.core.task.BasicExecutionContext; +import org.apache.brooklyn.util.core.task.BasicExecutionManager; import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.net.Networking; +import org.apache.brooklyn.util.net.Urls; +import org.apache.brooklyn.util.os.Os; +import org.apache.brooklyn.util.stream.Streams; +import org.apache.brooklyn.util.time.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testng.Assert; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.io.Files; -public class SshMachineLocationIntegrationTest { +public class SshMachineLocationIntegrationTest extends SshMachineLocationTest { - protected TestApplication app; - protected ManagementContext mgmt; + private static final Logger LOG = LoggerFactory.getLogger(AbstractEntity.class); - @BeforeMethod(alwaysRun=true) - public void setup() throws Exception { - mgmt = LocalManagementContextForTests.builder(true) - .useDefaultProperties() - .build(); - app = TestApplication.Factory.newManagedInstanceForTests(mgmt); + @Override + protected BrooklynProperties getBrooklynProperties() { + // Requires location named "localhost-passphrase", which it expects to find in local + // brooklyn.properties (or brooklyn.cfg in karaf). + return BrooklynProperties.Factory.newDefault(); + } + + @Override + protected SshMachineLocation newHost() { + return mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class) + .configure("address", Networking.getLocalHost())); + } + + // Overridden just to make it integration (because `newHost()` returns a real ssh'ing host) + @Test(groups="Integration") + @Override + public void testSshExecScript() throws Exception { + super.testSshExecScript(); + } + + // Overridden just to make it integration (because `newHost()` returns a real ssh'ing host) + @Test(groups="Integration") + @Override + public void testSshExecCommands() throws Exception { + super.testSshExecCommands(); + } + + // Overridden just to make it integration (because `newHost()` returns a real ssh'ing host) + @Test(groups="Integration") + @Override + public void testIsSshableWhenTrue() throws Exception { + super.testIsSshableWhenTrue(); } - @AfterMethod(alwaysRun=true) - public void tearDown() throws Exception { - if (mgmt != null) Entities.destroyAll(mgmt); - mgmt = null; + // Overrides super, because expect real machine details (rather than asserting our stub data) + @Test(groups = "Integration") + @Override + public void testGetMachineDetails() throws Exception { + BasicExecutionManager execManager = new BasicExecutionManager("mycontextid"); + BasicExecutionContext execContext = new BasicExecutionContext(execManager); + try { + MachineDetails details = execContext.submit(new Callable<MachineDetails>() { + public MachineDetails call() { + return host.getMachineDetails(); + }}).get(); + LOG.info("machineDetails="+details); + assertNotNull(details); + } finally { + execManager.shutdownNow(); + } + } + + @Test(groups = "Integration") + public void testCopyFileTo() throws Exception { + File dest = Os.newTempFile(getClass(), ".dest.tmp"); + File src = Os.newTempFile(getClass(), ".src.tmp"); + try { + Files.write("abc", src, Charsets.UTF_8); + host.copyTo(src, dest); + assertEquals("abc", Files.readFirstLine(dest, Charsets.UTF_8)); + } finally { + src.delete(); + dest.delete(); + } } + // Note: requires `ssh localhost` to be setup such that no password is required + @Test(groups = "Integration") + public void testCopyStreamTo() throws Exception { + String contents = "abc"; + File dest = new File(Os.tmp(), "sshMachineLocationTest_dest.tmp"); + try { + host.copyTo(Streams.newInputStreamWithContents(contents), dest.getAbsolutePath()); + assertEquals("abc", Files.readFirstLine(dest, Charsets.UTF_8)); + } finally { + dest.delete(); + } + } + + // Requires internet connectivity; on guest wifi etc can fail with things like + // "Welcome to Virgin Trains" etc. + @Test(groups = "Integration") + public void testInstallUrlTo() throws Exception { + File dest = new File(Os.tmp(), "sshMachineLocationTest_dir/"); + dest.mkdir(); + try { + int result = host.installTo("https://raw.github.com/brooklyncentral/brooklyn/master/README.md", Urls.mergePaths(dest.getAbsolutePath(), "README.md")); + assertEquals(result, 0); + String contents = ArchiveUtils.readFullyString(new File(dest, "README.md")); + assertTrue(contents.contains("http://brooklyncentral.github.com"), "contents missing expected phrase; contains:\n"+contents); + } finally { + dest.delete(); + } + } + + @Test(groups = "Integration") + public void testInstallClasspathCopyTo() throws Exception { + File dest = new File(Os.tmp(), "sshMachineLocationTest_dir/"); + dest.mkdir(); + try { + int result = host.installTo("classpath://brooklyn/config/sample.properties", Urls.mergePaths(dest.getAbsolutePath(), "sample.properties")); + assertEquals(result, 0); + String contents = ArchiveUtils.readFullyString(new File(dest, "sample.properties")); + assertTrue(contents.contains("Property 1"), "contents missing expected phrase; contains:\n"+contents); + } finally { + dest.delete(); + } + } + + // Note: on some (home/airport) networks, `ssh 123.123.123.123` hangs seemingly forever. + // Make sure we fail, waiting for longer than the 70 second TCP timeout. + // + // Times out in 2m7s on Ubuntu Vivid (syn retries set to 6) + @Test(groups = "Integration") + public void testIsSshableWhenFalse() throws Exception { + byte[] unreachableIp = new byte[] {123,123,123,123}; + final SshMachineLocation unreachableHost = new SshMachineLocation(MutableMap.of("address", InetAddress.getByAddress("unreachablename", unreachableIp))); + Asserts.assertReturnsEventually(new Runnable() { + public void run() { + assertFalse(unreachableHost.isSshable()); + }}, + Duration.minutes(3)); + } + + // For issue #230 + @Test(groups = "Integration") + public void testOverridingPropertyOnExec() throws Exception { + SshMachineLocation host = new SshMachineLocation(MutableMap.of("address", Networking.getLocalHost(), "sshPrivateKeyData", "wrongdata")); + + OutputStream outStream = new ByteArrayOutputStream(); + String expectedName = Os.user(); + host.execCommands(MutableMap.of("sshPrivateKeyData", null, "out", outStream), "my summary", ImmutableList.of("whoami")); + String outString = outStream.toString(); + + assertTrue(outString.contains(expectedName), "outString="+outString); + } + + @Test(groups = "Integration", expectedExceptions={IllegalStateException.class, SshException.class}) + public void testSshRunWithInvalidUserFails() throws Exception { + SshMachineLocation badHost = new SshMachineLocation(MutableMap.of("user", "doesnotexist", "address", Networking.getLocalHost())); + badHost.execScript("mysummary", ImmutableList.of("whoami; exit")); + } + // Note: requires `named:localhost-passphrase` set up with a key whose passphrase is "localhost" // * create the key with: // ssh-keygen -t rsa -N "brooklyn" -f ~/.ssh/id_rsa_passphrase http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e5b40cc1/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java b/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java index 2c7a78d..c09d790 100644 --- a/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java +++ b/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java @@ -26,9 +26,7 @@ import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.OutputStream; -import java.net.InetAddress; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -45,9 +43,9 @@ import org.apache.brooklyn.api.location.PortRange; import org.apache.brooklyn.core.effector.EffectorBody; import org.apache.brooklyn.core.effector.EffectorTaskTest; import org.apache.brooklyn.core.effector.Effectors; +import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.entity.BrooklynConfigKeys; import org.apache.brooklyn.core.entity.EntityInternal; -import org.apache.brooklyn.core.entity.factory.ApplicationBuilder; import org.apache.brooklyn.core.location.BasicHardwareDetails; import org.apache.brooklyn.core.location.BasicMachineDetails; import org.apache.brooklyn.core.location.BasicOsDetails; @@ -55,42 +53,40 @@ import org.apache.brooklyn.core.location.Machines; import org.apache.brooklyn.core.location.PortRanges; import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; import org.apache.brooklyn.core.test.entity.TestApplication; -import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.config.ConfigBag; -import org.apache.brooklyn.util.core.file.ArchiveUtils; import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool; -import org.apache.brooklyn.util.core.internal.ssh.SshException; +import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.CustomResponse; import org.apache.brooklyn.util.core.task.BasicExecutionContext; import org.apache.brooklyn.util.core.task.BasicExecutionManager; import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.net.Networking; -import org.apache.brooklyn.util.net.Urls; import org.apache.brooklyn.util.os.Os; import org.apache.brooklyn.util.stream.Streams; -import org.apache.brooklyn.util.time.Duration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import com.google.common.base.Charsets; +import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.io.Files; /** * Test the {@link SshMachineLocation} implementation of the {@link Location} interface. */ public class SshMachineLocationTest extends BrooklynAppUnitTestSupport { - private SshMachineLocation host; + private static final Logger LOG = LoggerFactory.getLogger(AbstractEntity.class); + + protected SshMachineLocation host; @BeforeMethod(alwaysRun=true) public void setUp() throws Exception { super.setUp(); - host = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class) - .configure("address", Networking.getLocalHost())); + host = newHost(); RecordingSshTool.clear(); } @@ -104,8 +100,22 @@ public class SshMachineLocationTest extends BrooklynAppUnitTestSupport { } } - @Test(groups = "Integration") + protected SshMachineLocation newHost() { + return mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class) + .configure("address", Networking.getLocalHost()) + .configure(SshMachineLocation.SSH_TOOL_CLASS, RecordingSshTool.class.getName())); + } + + @Test public void testGetMachineDetails() throws Exception { + String response = Joiner.on("\n").join( + "name:Test OS Y", + "version:1.2.3", + "architecture:x86_64", + "ram:1234", + "cpus:3"); + RecordingSshTool.setCustomResponse(".*uname.*", new CustomResponse(0, response, "")); + BasicExecutionManager execManager = new BasicExecutionManager("mycontextid"); BasicExecutionContext execContext = new BasicExecutionContext(execManager); try { @@ -113,12 +123,19 @@ public class SshMachineLocationTest extends BrooklynAppUnitTestSupport { public MachineDetails call() { return host.getMachineDetails(); }}).get(); + LOG.info("machineDetails="+details); assertNotNull(details); + + assertEquals(details.getOsDetails().getName(), "Test OS Y", "details="+details); + assertEquals(details.getOsDetails().getVersion(), "1.2.3", "details="+details); + assertEquals(details.getOsDetails().getArch(), "x86_64", "details="+details); + assertEquals(details.getHardwareDetails().getCpuCount(), Integer.valueOf(3), "details="+details); + assertEquals(details.getHardwareDetails().getRam(), Integer.valueOf(1234), "details="+details); } finally { execManager.shutdownNow(); } } - + @Test public void testSupplyingMachineDetails() throws Exception { MachineDetails machineDetails = new BasicMachineDetails(new BasicHardwareDetails(1, 1024), new BasicOsDetails("myname", "myarch", "myversion")); @@ -136,12 +153,14 @@ public class SshMachineLocationTest extends BrooklynAppUnitTestSupport { .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true)); assertEquals(host2.getPrivateAddresses(), ImmutableSet.of("1.2.3.4")); + assertEquals(Machines.getSubnetIp(host2).get(), "1.2.3.4"); + assertEquals(Machines.getSubnetHostname(host2).get(), "1.2.3.4"); } // Wow, this is hard to test (until I accepted creating the entity + effector)! Code smell? // Need to call getMachineDetails in a DynamicSequentialTask so that the "innessential" takes effect, // to not fail its caller. But to get one of those outside of an effector is non-obvious. - @Test(groups = "Integration") + @Test public void testGetMachineIsInessentialOnFailure() throws Exception { SshMachineLocation host2 = mgmt.getLocationManager().createLocation(LocationSpec.create(SshMachineLocation.class) .configure("address", Networking.getLocalHost()) @@ -167,7 +186,7 @@ public class SshMachineLocationTest extends BrooklynAppUnitTestSupport { ((EntityInternal)entity).getMutableEntityType().addEffector(EffectorTaskTest.DOUBLE_1); }}); - TestApplication app = ApplicationBuilder.newManagedApp(appSpec, mgmt); + TestApplication app = mgmt.getEntityManager().createEntity(appSpec); app.start(ImmutableList.of(host2)); @@ -186,124 +205,35 @@ public class SshMachineLocationTest extends BrooklynAppUnitTestSupport { } } - // Note: requires `ssh localhost` to be setup such that no password is required - @Test(groups = "Integration") + @Test public void testSshExecScript() throws Exception { - OutputStream outStream = new ByteArrayOutputStream(); String expectedName = Os.user(); + RecordingSshTool.setCustomResponse(".*whoami.*", new CustomResponse(0, expectedName, "")); + + OutputStream outStream = new ByteArrayOutputStream(); host.execScript(MutableMap.of("out", outStream), "mysummary", ImmutableList.of("whoami; exit")); String outString = outStream.toString(); assertTrue(outString.contains(expectedName), outString); } - // Note: requires `ssh localhost` to be setup such that no password is required - @Test(groups = "Integration") + @Test public void testSshExecCommands() throws Exception { - OutputStream outStream = new ByteArrayOutputStream(); String expectedName = Os.user(); - host.execCommands(MutableMap.of("out", outStream), "mysummary", ImmutableList.of("whoami; exit")); - String outString = outStream.toString(); - - assertTrue(outString.contains(expectedName), outString); - } - - // For issue #230 - @Test(groups = "Integration") - public void testOverridingPropertyOnExec() throws Exception { - SshMachineLocation host = new SshMachineLocation(MutableMap.of("address", Networking.getLocalHost(), "sshPrivateKeyData", "wrongdata")); + RecordingSshTool.setCustomResponse(".*whoami.*", new CustomResponse(0, expectedName, "")); OutputStream outStream = new ByteArrayOutputStream(); - String expectedName = Os.user(); - host.execCommands(MutableMap.of("sshPrivateKeyData", null, "out", outStream), "my summary", ImmutableList.of("whoami")); + host.execCommands(MutableMap.of("out", outStream), "mysummary", ImmutableList.of("whoami; exit")); String outString = outStream.toString(); - assertTrue(outString.contains(expectedName), "outString="+outString); - } - - @Test(groups = "Integration", expectedExceptions={IllegalStateException.class, SshException.class}) - public void testSshRunWithInvalidUserFails() throws Exception { - SshMachineLocation badHost = new SshMachineLocation(MutableMap.of("user", "doesnotexist", "address", Networking.getLocalHost())); - badHost.execScript("mysummary", ImmutableList.of("whoami; exit")); - } - - // Note: requires `ssh localhost` to be setup such that no password is required - @Test(groups = "Integration") - public void testCopyFileTo() throws Exception { - File dest = Os.newTempFile(getClass(), ".dest.tmp"); - File src = Os.newTempFile(getClass(), ".src.tmp"); - try { - Files.write("abc", src, Charsets.UTF_8); - host.copyTo(src, dest); - assertEquals("abc", Files.readFirstLine(dest, Charsets.UTF_8)); - } finally { - src.delete(); - dest.delete(); - } - } - - // Note: requires `ssh localhost` to be setup such that no password is required - @Test(groups = "Integration") - public void testCopyStreamTo() throws Exception { - String contents = "abc"; - File dest = new File(Os.tmp(), "sshMachineLocationTest_dest.tmp"); - try { - host.copyTo(Streams.newInputStreamWithContents(contents), dest.getAbsolutePath()); - assertEquals("abc", Files.readFirstLine(dest, Charsets.UTF_8)); - } finally { - dest.delete(); - } - } - - @Test(groups = "Integration") - public void testInstallUrlTo() throws Exception { - File dest = new File(Os.tmp(), "sshMachineLocationTest_dir/"); - dest.mkdir(); - try { - int result = host.installTo("https://raw.github.com/brooklyncentral/brooklyn/master/README.md", Urls.mergePaths(dest.getAbsolutePath(), "README.md")); - assertEquals(result, 0); - String contents = ArchiveUtils.readFullyString(new File(dest, "README.md")); - assertTrue(contents.contains("http://brooklyncentral.github.com"), "contents missing expected phrase; contains:\n"+contents); - } finally { - dest.delete(); - } + assertTrue(outString.contains(expectedName), outString); } - @Test(groups = "Integration") - public void testInstallClasspathCopyTo() throws Exception { - File dest = new File(Os.tmp(), "sshMachineLocationTest_dir/"); - dest.mkdir(); - try { - int result = host.installTo("classpath://brooklyn/config/sample.properties", Urls.mergePaths(dest.getAbsolutePath(), "sample.properties")); - assertEquals(result, 0); - String contents = ArchiveUtils.readFullyString(new File(dest, "sample.properties")); - assertTrue(contents.contains("Property 1"), "contents missing expected phrase; contains:\n"+contents); - } finally { - dest.delete(); - } - } - - // Note: requires `ssh localhost` to be setup such that no password is required - @Test(groups = "Integration") + @Test public void testIsSshableWhenTrue() throws Exception { assertTrue(host.isSshable()); } - // Note: on some (home/airport) networks, `ssh 123.123.123.123` hangs seemingly forever. - // Make sure we fail, waiting for longer than the 70 second TCP timeout. - // - // Times out in 2m7s on Ubuntu Vivid (syn retries set to 6) - @Test(groups = "Integration") - public void testIsSshableWhenFalse() throws Exception { - byte[] unreachableIp = new byte[] {123,123,123,123}; - final SshMachineLocation unreachableHost = new SshMachineLocation(MutableMap.of("address", InetAddress.getByAddress("unreachablename", unreachableIp))); - Asserts.assertReturnsEventually(new Runnable() { - public void run() { - assertFalse(unreachableHost.isSshable()); - }}, - Duration.minutes(3)); - } - @Test public void obtainSpecificPortGivesOutPortOnlyOnce() { int port = 2345;
