You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/17 21:17:44 UTC
[13/42] incubator-brooklyn git commit: [BROOKLYN-162] Refactor
package in ./core/util
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveBuilderTest.java b/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveBuilderTest.java
new file mode 100644
index 0000000..0ce8298
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveBuilderTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.core.util.file;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.core.util.file.ArchiveBuilder;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.os.Os;
+import brooklyn.util.text.Identifiers;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+
+/**
+ * Test the operation of the {@link ArchiveBuilder} class.
+ */
+@Test
+public class ArchiveBuilderTest {
+
+ private File parentDir, tmpDir, tmpDir2;
+ private Predicate<ZipEntry> isDirectory = new Predicate<ZipEntry>() {
+ @Override
+ public boolean apply(@Nullable ZipEntry input) {
+ return input.isDirectory();
+ }
+ };
+
+ @BeforeClass
+ public void createTmpDirAndFiles() throws IOException {
+ parentDir = Os.newTempDir(getClass().getSimpleName());
+ Os.deleteOnExitRecursively(parentDir);
+ tmpDir = new File(parentDir, Identifiers.makeRandomId(4));
+ Os.mkdirs(tmpDir);
+ Files.write("abcdef", new File(tmpDir, "data01.txt"), Charsets.US_ASCII);
+ Files.write("123456", new File(tmpDir, "data02.txt"), Charsets.US_ASCII);
+ Files.write("qqqqqq", new File(tmpDir, "data03.txt"), Charsets.US_ASCII);
+
+ tmpDir2 = new File(parentDir, Identifiers.makeRandomId(4));
+ Os.mkdirs(tmpDir2);
+ Files.write("zzzzzz", new File(tmpDir2, "data04.txt"), Charsets.US_ASCII);
+ }
+
+ @Test
+ public void testCreateZipFromDir() throws Exception {
+ File archive = ArchiveBuilder.zip().addDirContentsAt(tmpDir, ".").create();
+ archive.deleteOnExit();
+
+ List<ZipEntry> entries = Lists.newArrayList();
+ ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
+ ZipEntry entry = input.getNextEntry();
+ while (entry != null) {
+ entries.add(entry);
+ entry = input.getNextEntry();
+ }
+ assertEquals(entries.size(), 4);
+ Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
+ Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
+ assertEquals(Iterables.size(directories), 1);
+ assertEquals(Iterables.size(files), 3);
+ String dirName = Iterables.getOnlyElement(directories).getName();
+ assertEquals(dirName, "./");
+
+ Set<String> names = MutableSet.of();
+ for (ZipEntry file : files) {
+ assertTrue(file.getName().startsWith(dirName));
+ names.add(file.getName());
+ }
+ assertTrue(names.contains("./data01.txt"));
+ assertFalse(names.contains("./data04.txt"));
+ input.close();
+ }
+
+ @Test
+ public void testCreateZipFromTwoDirs() throws Exception {
+ File archive = ArchiveBuilder.zip().addDirContentsAt(tmpDir, ".").addDirContentsAt(tmpDir2, ".").create();
+ archive.deleteOnExit();
+
+ List<ZipEntry> entries = Lists.newArrayList();
+ ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
+ ZipEntry entry = input.getNextEntry();
+ while (entry != null) {
+ entries.add(entry);
+ entry = input.getNextEntry();
+ }
+ assertEquals(entries.size(), 5);
+ Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
+ Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
+ assertEquals(Iterables.size(directories), 1);
+ assertEquals(Iterables.size(files), 4);
+ String dirName = Iterables.getOnlyElement(directories).getName();
+ assertEquals(dirName, "./");
+
+ Set<String> names = MutableSet.of();
+ for (ZipEntry file : files) {
+ assertTrue(file.getName().startsWith(dirName));
+ names.add(file.getName());
+ }
+ assertTrue(names.contains("./data01.txt"));
+ assertTrue(names.contains("./data04.txt"));
+ input.close();
+ }
+ @Test
+ public void testCreateZipFromFiles() throws Exception {
+ ArchiveBuilder builder = ArchiveBuilder.zip();
+ for (String fileName : Arrays.asList("data01.txt", "data02.txt", "data03.txt")) {
+ builder.addAt(new File(tmpDir, fileName), ".");
+ }
+ File archive = builder.create();
+ archive.deleteOnExit();
+
+ List<ZipEntry> entries = Lists.newArrayList();
+ ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
+ ZipEntry entry = input.getNextEntry();
+ while (entry != null) {
+ entries.add(entry);
+ entry = input.getNextEntry();
+ }
+ assertEquals(entries.size(), 3);
+ Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
+ Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
+ assertTrue(Iterables.isEmpty(directories));
+ assertEquals(Iterables.size(files), 3);
+ for (ZipEntry file : files) {
+ assertTrue(file.getName().startsWith(Os.mergePathsUnix(".", "data")));
+ }
+ input.close();
+ }
+
+ @Test
+ public void testCreateZipFromFilesWithBaseDir() throws Exception {
+ ArchiveBuilder builder = ArchiveBuilder.zip();
+ String baseDir = tmpDir.getName();
+ for (String fileName : Arrays.asList("data01.txt", "data02.txt", "data03.txt")) {
+ builder.addFromLocalBaseDir(parentDir, Os.mergePaths(baseDir, fileName));
+ }
+ File archive = builder.create();
+ archive.deleteOnExit();
+
+ List<ZipEntry> entries = Lists.newArrayList();
+ ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
+ ZipEntry entry = input.getNextEntry();
+ while (entry != null) {
+ entries.add(entry);
+ entry = input.getNextEntry();
+ }
+ assertEquals(entries.size(), 3);
+ Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
+ Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
+ assertTrue(Iterables.isEmpty(directories));
+ assertEquals(Iterables.size(files), 3);
+ for (ZipEntry file : files) {
+ assertTrue(file.getName().startsWith(Os.mergePathsUnix(".", baseDir)));
+ }
+ input.close();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveUtilsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveUtilsTest.java
new file mode 100644
index 0000000..a13ef63
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveUtilsTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.core.util.file;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.util.Map;
+
+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 brooklyn.entity.BrooklynAppUnitTestSupport;
+
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.file.ArchiveBuilder;
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.os.Os;
+
+import com.google.api.client.repackaged.com.google.common.base.Joiner;
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.Files;
+
+// Test are integration, because relies on ssh/scp via SshMachineLocation
+public class ArchiveUtilsTest extends BrooklynAppUnitTestSupport {
+
+ private SshMachineLocation machine;
+ private ResourceUtils resourceUtils;
+
+ private Map<String, String> archiveContents = ImmutableMap.of("a.txt", "mya");
+ private File destDir;
+ private File origZip;
+ private File origJar;
+
+ @BeforeClass(alwaysRun=true)
+ public void setUpClass() throws Exception {
+ origZip = newZip(archiveContents);
+ origJar = Os.newTempFile(ArchiveUtilsTest.class, ".jar");
+ Files.copy(origZip, origJar);
+ }
+
+ @AfterClass(alwaysRun=true)
+ public void tearDownClass() throws Exception {
+ if (origZip != null) origZip.delete();
+ if (origJar != null) origJar.delete();
+ }
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ machine = app.newLocalhostProvisioningLocation().obtain();
+ resourceUtils = ResourceUtils.create(ArchiveUtilsTest.class);
+ destDir = Os.newTempDir(getClass().getSimpleName());
+ }
+
+ @AfterMethod(alwaysRun=true)
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (destDir != null) Os.deleteRecursively(destDir);
+ }
+
+ @Test(groups="Integration")
+ public void testDeployZipWithNoOptionalArgsSupplied() throws Exception {
+ boolean result = ArchiveUtils.deploy(resourceUtils, ImmutableMap.<String, Object>of(), origZip.getAbsolutePath(), machine, destDir.getAbsolutePath(), true, null, null);
+ assertTrue(result);
+ assertFilesEqual(new File(destDir, origZip.getName()), origZip);
+ assertSubFilesEqual(destDir, archiveContents);
+ }
+
+ @Test(groups="Integration")
+ public void testDeployZipDeletingArchiveAfterUnpack() throws Exception {
+ boolean result = ArchiveUtils.deploy(resourceUtils, ImmutableMap.<String, Object>of(), origZip.getAbsolutePath(), machine, destDir.getAbsolutePath(), false, null, null);
+ assertTrue(result);
+ assertFalse(new File(destDir, origZip.getName()).exists());
+ assertSubFilesEqual(destDir, archiveContents);
+ }
+
+ @Test(groups="Integration")
+ public void testDeployJarNotUnpacked() throws Exception {
+ ArchiveUtils.deploy(origJar.getAbsolutePath(), machine, destDir.getAbsolutePath());
+ assertFilesEqual(new File(destDir, origJar.getName()), origJar);
+ }
+
+ @Test(groups="Integration")
+ public void testDeployExplicitDestFile() throws Exception {
+ String destFile = "custom-destFile.jar";
+ ArchiveUtils.deploy(origJar.getAbsolutePath(), machine, destDir.getAbsolutePath(), destFile);
+ assertFilesEqual(new File(destDir, destFile), origJar);
+ }
+
+ private File newZip(Map<String, String> files) throws Exception {
+ File parentDir = Os.newTempDir(getClass().getSimpleName()+"-archive");
+ for (Map.Entry<String, String> entry : files.entrySet()) {
+ File subFile = new File(Os.mergePaths(parentDir.getAbsolutePath(), entry.getKey()));
+ subFile.getParentFile().mkdirs();
+ Files.write(entry.getValue(), subFile, Charsets.UTF_8);
+ }
+ return ArchiveBuilder.zip().addDirContentsAt(parentDir, ".").create();
+ }
+
+ private void assertFilesEqual(File f1, File f2) throws Exception {
+ byte[] bytes1 = Files.asByteSource(f1).read();
+ byte[] bytes2 = Files.asByteSource(f1).read();
+ assertEquals(bytes1, bytes2, "f1="+f1+"; f2="+f2);
+ }
+
+ private void assertSubFilesEqual(File parentDir, Map<String, String> files) throws Exception {
+ for (Map.Entry<String, String> entry : archiveContents.entrySet()) {
+ File subFile = new File(Os.mergePaths(parentDir.getAbsolutePath(), entry.getKey()));
+ assertEquals(Joiner.on("\n").join(Files.readLines(subFile, Charsets.UTF_8)), entry.getValue());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/test/java/org/apache/brooklyn/core/util/flags/MethodCoercionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/flags/MethodCoercionsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/flags/MethodCoercionsTest.java
new file mode 100644
index 0000000..2d1efa3
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/flags/MethodCoercionsTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.core.util.flags;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+
+import org.apache.brooklyn.core.util.flags.MethodCoercions;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static org.testng.Assert.*;
+
+public class MethodCoercionsTest {
+
+ private Method singleParameterMethod;
+ private Method multiParameterMethod;
+ private Method singleCollectionParameterMethod;
+
+ @BeforeClass
+ public void testFixtureSetUp() {
+ try {
+ singleParameterMethod = TestClass.class.getMethod("singleParameterMethod", int.class);
+ multiParameterMethod = TestClass.class.getMethod("multiParameterMethod", boolean.class, int.class);
+ singleCollectionParameterMethod = TestClass.class.getMethod("singleCollectionParameterMethod", List.class);
+ } catch (NoSuchMethodException e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+
+ @Test
+ public void testMatchSingleParameterMethod() throws Exception {
+ Predicate<Method> predicate = MethodCoercions.matchSingleParameterMethod("singleParameterMethod", "42");
+ assertTrue(predicate.apply(singleParameterMethod));
+ assertFalse(predicate.apply(multiParameterMethod));
+ assertFalse(predicate.apply(singleCollectionParameterMethod));
+ }
+
+ @Test
+ public void testTryFindAndInvokeSingleParameterMethod() throws Exception {
+ TestClass instance = new TestClass();
+ Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleParameterMethod(instance, "singleParameterMethod", "42");
+ assertTrue(maybe.isPresent());
+ assertTrue(instance.wasSingleParameterMethodCalled());
+ }
+
+ @Test
+ public void testMatchMultiParameterMethod() throws Exception {
+ Predicate<Method> predicate = MethodCoercions.matchMultiParameterMethod("multiParameterMethod", ImmutableList.of("true", "42"));
+ assertFalse(predicate.apply(singleParameterMethod));
+ assertTrue(predicate.apply(multiParameterMethod));
+ assertFalse(predicate.apply(singleCollectionParameterMethod));
+ }
+
+ @Test
+ public void testTryFindAndInvokeMultiParameterMethod() throws Exception {
+ TestClass instance = new TestClass();
+ Maybe<?> maybe = MethodCoercions.tryFindAndInvokeMultiParameterMethod(instance, "multiParameterMethod", ImmutableList.of("true", "42"));
+ assertTrue(maybe.isPresent());
+ assertTrue(instance.wasMultiParameterMethodCalled());
+ }
+
+ @Test
+ public void testTryFindAndInvokeBestMatchingMethod() throws Exception {
+ TestClass instance = new TestClass();
+ Maybe<?> maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "singleParameterMethod", "42");
+ assertTrue(maybe.isPresent());
+ assertTrue(instance.wasSingleParameterMethodCalled());
+
+ instance = new TestClass();
+ maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "multiParameterMethod", ImmutableList.of("true", "42"));
+ assertTrue(maybe.isPresent());
+ assertTrue(instance.wasMultiParameterMethodCalled());
+
+ instance = new TestClass();
+ maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("fred", "joe"));
+ assertTrue(maybe.isPresent());
+ assertTrue(instance.wasSingleCollectionParameterMethodCalled());
+ }
+/*
+ @Test
+ public void testMatchSingleCollectionParameterMethod() throws Exception {
+ Predicate<Method> predicate = MethodCoercions.matchSingleCollectionParameterMethod("singleCollectionParameterMethod", ImmutableList.of("42"));
+ assertFalse(predicate.apply(singleParameterMethod));
+ assertFalse(predicate.apply(multiParameterMethod));
+ assertTrue(predicate.apply(singleCollectionParameterMethod));
+ }
+
+ @Test
+ public void testTryFindAndInvokeSingleCollectionParameterMethod() throws Exception {
+ TestClass instance = new TestClass();
+ Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleCollectionParameterMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("42"));
+ assertTrue(maybe.isPresent());
+ assertTrue(instance.wasSingleCollectionParameterMethodCalled());
+ }
+*/
+ public static class TestClass {
+
+ private boolean singleParameterMethodCalled;
+ private boolean multiParameterMethodCalled;
+ private boolean singleCollectionParameterMethodCalled;
+
+ public void singleParameterMethod(int parameter) {
+ singleParameterMethodCalled = true;
+ }
+
+ public void multiParameterMethod(boolean parameter1, int parameter2) {
+ multiParameterMethodCalled = true;
+ }
+
+ public void singleCollectionParameterMethod(List<String> parameter) {
+ singleCollectionParameterMethodCalled = true;
+ }
+
+ public boolean wasSingleParameterMethodCalled() {
+ return singleParameterMethodCalled;
+ }
+
+ public boolean wasMultiParameterMethodCalled() {
+ return multiParameterMethodCalled;
+ }
+
+ public boolean wasSingleCollectionParameterMethodCalled() {
+ return singleCollectionParameterMethodCalled;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/test/java/org/apache/brooklyn/core/util/http/BetterMockWebServer.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/http/BetterMockWebServer.java b/core/src/test/java/org/apache/brooklyn/core/util/http/BetterMockWebServer.java
new file mode 100644
index 0000000..f02689b
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/http/BetterMockWebServer.java
@@ -0,0 +1,138 @@
+/*
+ * 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.core.util.http;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.URL;
+
+import javax.net.ssl.SSLSocketFactory;
+
+import com.google.common.base.Throwables;
+import com.google.mockwebserver.Dispatcher;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.MockWebServer;
+import com.google.mockwebserver.RecordedRequest;
+
+/** like MockWebServer (and delegating) but:
+ * <li> allows subclassing
+ * <li> easy way to create instance which returns localhost for {@link #getHostName()}
+ * (since otherwise you can get failures on networks which misconfigure hostname)
+ * */
+public class BetterMockWebServer {
+
+ final MockWebServer delegate = new MockWebServer();
+ String hostname = null;
+ boolean isHttps = false;
+
+ public static BetterMockWebServer newInstanceLocalhost() {
+ return new BetterMockWebServer().setHostName("localhost");
+ }
+
+ /** use {@link #newInstanceLocalhost()} or subclass */
+ protected BetterMockWebServer() {}
+
+ public BetterMockWebServer setHostName(String hostname) {
+ this.hostname = hostname;
+ return this;
+ }
+
+
+ // --- delegate methods (unchanged)
+
+ public void enqueue(MockResponse response) {
+ delegate.enqueue(response);
+ }
+
+ public boolean equals(Object obj) {
+ return delegate.equals(obj);
+ }
+
+ public String getCookieDomain() {
+ return delegate.getCookieDomain();
+ }
+
+ public String getHostName() {
+ if (hostname!=null) return hostname;
+ return delegate.getHostName();
+ }
+
+ public int getPort() {
+ return delegate.getPort();
+ }
+
+ public int getRequestCount() {
+ return delegate.getRequestCount();
+ }
+
+ public URL getUrl(String path) {
+ try {
+ return isHttps
+ ? new URL("https://" + getHostName() + ":" + getPort() + path)
+ : new URL("http://" + getHostName() + ":" + getPort() + path);
+ } catch (MalformedURLException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+
+ public void play() throws IOException {
+ delegate.play();
+ }
+
+ public void play(int port) throws IOException {
+ delegate.play(port);
+ }
+
+ public void setBodyLimit(int maxBodyLength) {
+ delegate.setBodyLimit(maxBodyLength);
+ }
+
+ public void setDispatcher(Dispatcher dispatcher) {
+ delegate.setDispatcher(dispatcher);
+ }
+
+ public void shutdown() throws IOException {
+ delegate.shutdown();
+ }
+
+ public RecordedRequest takeRequest() throws InterruptedException {
+ return delegate.takeRequest();
+ }
+
+ public Proxy toProxyAddress() {
+ return delegate.toProxyAddress();
+ }
+
+ public String toString() {
+ return delegate.toString();
+ }
+
+ public void useHttps(SSLSocketFactory sslSocketFactory, boolean tunnelProxy) {
+ isHttps = true;
+ delegate.useHttps(sslSocketFactory, tunnelProxy);
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/test/java/org/apache/brooklyn/core/util/http/HttpToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/http/HttpToolIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/util/http/HttpToolIntegrationTest.java
new file mode 100644
index 0000000..f557955
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/http/HttpToolIntegrationTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.core.util.http;
+
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+
+import org.apache.http.client.HttpClient;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+import org.apache.brooklyn.location.basic.PortRanges;
+
+import brooklyn.test.HttpService;
+
+import com.google.common.collect.ImmutableMap;
+
+public class HttpToolIntegrationTest {
+
+ // TODO Expand test coverage for credentials etc
+
+ private HttpService httpService;
+ private HttpService httpsService;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ httpService = new HttpService(PortRanges.fromString("9000+"), false).start();
+ httpsService = new HttpService(PortRanges.fromString("9000+"), true).start();
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() throws Exception {
+ if (httpService != null) httpService.shutdown();
+ if (httpsService != null) httpsService.shutdown();
+ }
+
+ @Test(groups = {"Integration"})
+ public void testHttpGet() throws Exception {
+ URI baseUri = new URI(httpService.getUrl());
+
+ HttpClient client = HttpTool.httpClientBuilder().build();
+ HttpToolResponse result = HttpTool.httpGet(client, baseUri, ImmutableMap.<String,String>of());
+ assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+ }
+
+ @Test(groups = {"Integration"})
+ public void testHttpRedirect() throws Exception {
+ URI baseUri = new URI(httpService.getUrl() + "hello/redirectAbsolute");
+
+ HttpClient client = HttpTool.httpClientBuilder().laxRedirect(true).build();
+ HttpToolResponse result = HttpTool.httpGet(client, baseUri, ImmutableMap.<String,String>of());
+ assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+ }
+
+ @Test(groups = {"Integration"})
+ public void testHttpPost() throws Exception {
+ URI baseUri = new URI(httpService.getUrl());
+
+ HttpClient client = HttpTool.httpClientBuilder().build();
+ HttpToolResponse result = HttpTool.httpPost(client, baseUri, ImmutableMap.<String,String>of(), new byte[0]);
+ assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+ }
+
+ @Test(groups = {"Integration"})
+ public void testHttpsGetWithTrustAll() throws Exception {
+ URI baseUri = new URI(httpsService.getUrl());
+
+ HttpClient client = HttpTool.httpClientBuilder().https(true).trustAll().build();
+ HttpToolResponse result = HttpTool.httpGet(client, baseUri, ImmutableMap.<String,String>of());
+ assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+ }
+
+ @Test(groups = {"Integration"})
+ public void testHttpsPostWithTrustSelfSigned() throws Exception {
+ URI baseUri = new URI(httpsService.getUrl());
+
+ HttpClient client = HttpTool.httpClientBuilder().https(true).trustSelfSigned().build();
+ HttpToolResponse result = HttpTool.httpPost(client, baseUri, ImmutableMap.<String,String>of(), new byte[0]);
+ assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/test/java/org/apache/brooklyn/core/util/internal/FlagUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/FlagUtilsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/FlagUtilsTest.java
new file mode 100644
index 0000000..02becf6
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/FlagUtilsTest.java
@@ -0,0 +1,314 @@
+/*
+ * 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.core.util.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.lang.reflect.Field;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.trait.Configurable;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.ConfigKey.HasConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+public class FlagUtilsTest {
+
+ public static final Logger log = LoggerFactory.getLogger(FlagUtilsTest.class);
+
+ @Test
+ public void testGetAllFields() {
+ log.info("types {}", FlagUtils.getAllAssignableTypes(Baz.class));
+ assertEquals(FlagUtils.getAllAssignableTypes(Baz.class), ImmutableList.of(Baz.class, Foo.class, Bar.class));
+ List<Field> fs = FlagUtils.getAllFields(Baz.class);
+ for (Field f : fs) {
+ log.info("field {} {}", f.getName(), f);
+ }
+ List<String> fsn = ImmutableList.copyOf(Iterables.transform(fs, new Function<Field, String>() {
+ @Override public String apply(Field f) {
+ return f.getName();
+ }}));
+ assertTrue(fsn.indexOf("A") >= 0);
+ assertTrue(fsn.indexOf("w") > fsn.indexOf("A"));
+ assertTrue(fsn.indexOf("x") > fsn.indexOf("A") );
+ assertTrue(fsn.indexOf("yNotY") > fsn.indexOf("A"));
+ assertTrue(fsn.indexOf("Z") > fsn.indexOf("yNotY") );
+ }
+
+ @Test
+ public void testSetFieldsFromFlags() {
+ Foo f = new Foo();
+ Map<?,?> m = MutableMap.of("w", 3, "x", 1, "y", 7, "z", 9);
+ Map<?, ?> unused = FlagUtils.setFieldsFromFlags(m, f);
+ assertEquals(f.w, 3);
+ assertEquals(f.x, 1);
+ assertEquals(f.yNotY, 7);
+ assertEquals(unused, ImmutableMap.of("z", 9));
+ Map<?,?> m2 = FlagUtils.getFieldsWithValues(f);
+ m.remove("z");
+ assertEquals(m2, m);
+ }
+
+ @Test
+ public void testCollectionCoercionOnSetFromFlags() {
+ WithSpecialFieldTypes s = new WithSpecialFieldTypes();
+ Map<?,?> m = ImmutableMap.of("set", ImmutableSet.of(1));
+ FlagUtils.setFieldsFromFlags(m, s);
+ assertEquals(s.set, ImmutableSet.of(1));
+ }
+
+ @Test
+ public void testInetAddressCoercionOnSetFromFlags() {
+ WithSpecialFieldTypes s = new WithSpecialFieldTypes();
+ Map<?,?> m = ImmutableMap.of("inet", "127.0.0.1");
+ FlagUtils.setFieldsFromFlags(m, s);
+ assertEquals(s.inet.getHostAddress(), "127.0.0.1");
+ }
+
+ @Test
+ public void testNonImmutableField() {
+ Foo f = new Foo();
+ FlagUtils.setFieldsFromFlags(ImmutableMap.of("w", 8), f);
+ assertEquals(f.w, 8);
+ FlagUtils.setFieldsFromFlags(ImmutableMap.of("w", 9), f);
+ assertEquals(f.w, 9);
+ }
+
+ @Test
+ public void testImmutableIntField() {
+ Foo f = new Foo();
+ FlagUtils.setFieldsFromFlags(ImmutableMap.of("x", 8), f);
+ assertEquals(f.x, 8);
+ boolean succeededWhenShouldntHave = false;
+ try {
+ FlagUtils.setFieldsFromFlags(ImmutableMap.of("x", 9), f);
+ succeededWhenShouldntHave = true;
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ assertFalse(succeededWhenShouldntHave);
+ assertEquals(f.x, 8);
+ }
+
+ @Test
+ public void testImmutableObjectField() {
+ WithImmutableNonNullableObject o = new WithImmutableNonNullableObject();
+ FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a", "b", "b"), o);
+ assertEquals(o.a, "a");
+ assertEquals(o.b, "b");
+
+ FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a2"), o);
+ assertEquals(o.a, "a2");
+
+ boolean succeededWhenShouldntHave = false;
+ try {
+ FlagUtils.setFieldsFromFlags(ImmutableMap.of("b", "b2"), o);
+ succeededWhenShouldntHave = true;
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ assertFalse(succeededWhenShouldntHave);
+ assertEquals(o.b, "b");
+ }
+
+ @Test
+ public void testNonNullable() {
+ WithImmutableNonNullableObject o = new WithImmutableNonNullableObject();
+ //allowed
+ FlagUtils.setFieldsFromFlags(MutableMap.of("a", null), o);
+ assertEquals(o.a, null);
+ assertEquals(o.b, null);
+ //not allowed
+ boolean succeededWhenShouldntHave = false;
+ try {
+ FlagUtils.setFieldsFromFlags(MutableMap.of("b", null), o);
+ succeededWhenShouldntHave = true;
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+ assertFalse(succeededWhenShouldntHave);
+ assertEquals(o.b, null);
+ }
+
+ @Test
+ public void testGetAnnotatedFields() throws Exception {
+ Map<Field, SetFromFlag> fm = FlagUtils.getAnnotatedFields(WithImmutableNonNullableObject.class);
+ assertEquals(fm.keySet().size(), 2);
+ assertTrue(fm.get(WithImmutableNonNullableObject.class.getDeclaredField("b")).immutable());
+ }
+
+ @Test
+ public void testCheckRequired() {
+ WithImmutableNonNullableObject f = new WithImmutableNonNullableObject();
+ FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a is a"), f);
+ assertEquals(f.a, "a is a");
+ assertEquals(f.b, null);
+ int exceptions = 0;
+ try {
+ FlagUtils.checkRequiredFields(f);
+ } catch (IllegalStateException e) {
+ exceptions++;
+ }
+ assertEquals(exceptions, 1);
+ }
+
+ @Test
+ public void testSetConfigKeys() {
+ FooCK f = new FooCK();
+ Map<?,?> unused = FlagUtils.setFieldsFromFlags(ImmutableMap.of("f1", 9, "ck1", "do-set", "ck2", "dont-set", "c3", "do-set"), f);
+ assertEquals(f.bag.get(FooCK.CK1), "do-set");
+ assertEquals(f.bag.get(FooCK.CK3), "do-set");
+ assertEquals(f.f1, 9);
+ assertEquals(f.bag.containsKey(FooCK.CK2), false);
+ assertEquals(unused, ImmutableMap.of("ck2", "dont-set"));
+ }
+
+ @Test
+ public void testSetAllConfigKeys() {
+ FooCK f = new FooCK();
+ Map<?,?> unused = FlagUtils.setAllConfigKeys(ImmutableMap.of("f1", 9, "ck1", "do-set", "ck2", "do-set-2", "c3", "do-set"), f, true);
+ assertEquals(f.bag.get(FooCK.CK1), "do-set");
+ assertEquals(f.bag.get(FooCK.CK3), "do-set");
+ assertEquals(f.bag.containsKey(FooCK.CK2), true);
+ assertEquals(f.bag.get(FooCK.CK2), "do-set-2");
+ assertEquals(unused, ImmutableMap.of("f1", 9));
+ }
+
+ @Test
+ public void testSetFromConfigKeys() {
+ FooCK f = new FooCK();
+ Map<?, ?> unused = FlagUtils.setFieldsFromFlags(ImmutableMap.of(new BasicConfigKey<Integer>(Integer.class, "f1"), 9, "ck1", "do-set", "ck2", "dont-set"), f);
+ assertEquals(f.bag.get(FooCK.CK1), "do-set");
+ assertEquals(f.f1, 9);
+ assertEquals(f.bag.containsKey(FooCK.CK2), false);
+ assertEquals(unused, ImmutableMap.of("ck2", "dont-set"));
+ }
+
+ public static class Foo {
+ @SetFromFlag
+ int w;
+
+ @SetFromFlag(immutable=true)
+ private int x;
+
+ @SetFromFlag("y")
+ public int yNotY;
+ }
+
+ public static interface Bar {
+ static final String Z = "myzval";
+ }
+
+ public static class Baz extends Foo implements Bar {
+ @SuppressWarnings("unused") //inspected by reflection
+ private static int A;
+ }
+
+ public static class WithImmutableNonNullableObject {
+ @SetFromFlag
+ Object a;
+ @SetFromFlag(immutable=true, nullable=false)
+ public Object b;
+ }
+
+ public static class WithSpecialFieldTypes {
+ @SetFromFlag Set<?> set;
+ @SetFromFlag InetAddress inet;
+ }
+
+ public static class FooCK implements Configurable {
+ @SetFromFlag
+ public static ConfigKey<String> CK1 = ConfigKeys.newStringConfigKey("ck1");
+
+ public static ConfigKey<String> CK2 = ConfigKeys.newStringConfigKey("ck2");
+
+ @SetFromFlag("c3")
+ public static ConfigKey<String> CK3 = ConfigKeys.newStringConfigKey("ck3");
+
+ @SetFromFlag
+ int f1;
+
+ ConfigBag bag = new ConfigBag();
+ BasicConfigurationSupport configSupport = new BasicConfigurationSupport();
+
+ @Override
+ public ConfigurationSupport config() {
+ return configSupport;
+ }
+
+ public <T> T setConfig(ConfigKey<T> key, T val) {
+ return config().set(key, val);
+ }
+
+ private class BasicConfigurationSupport implements ConfigurationSupport {
+ @Override
+ public <T> T get(ConfigKey<T> key) {
+ return bag.get(key);
+ }
+
+ @Override
+ public <T> T get(HasConfigKey<T> key) {
+ return get(key.getConfigKey());
+ }
+
+ @Override
+ public <T> T set(ConfigKey<T> key, T val) {
+ T old = bag.get(key);
+ bag.configure(key, val);
+ return old;
+ }
+
+ @Override
+ public <T> T set(HasConfigKey<T> key, T val) {
+ return set(key.getConfigKey(), val);
+ }
+
+ @Override
+ public <T> T set(ConfigKey<T> key, Task<T> val) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T set(HasConfigKey<T> key, Task<T> val) {
+ return set(key.getConfigKey(), val);
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/test/java/org/apache/brooklyn/core/util/internal/RepeaterTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/RepeaterTest.groovy b/core/src/test/java/org/apache/brooklyn/core/util/internal/RepeaterTest.groovy
new file mode 100644
index 0000000..08ef0da
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/RepeaterTest.groovy
@@ -0,0 +1,257 @@
+/*
+ * 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.core.util.internal
+
+import static java.util.concurrent.TimeUnit.*
+import static org.testng.Assert.*
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit
+
+import org.apache.brooklyn.core.util.internal.Repeater;
+import org.testng.annotations.Test
+
+import brooklyn.util.internal.TimeExtras;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Stopwatch
+
+public class RepeaterTest {
+ static { TimeExtras.init() }
+
+ @Test
+ public void sanityTest() {
+ new Repeater("Sanity test")
+ .repeat()
+ .until { true }
+ .every(10 * MILLISECONDS);
+ }
+
+ @Test
+ public void sanityTestDescription() {
+ new Repeater()
+ .repeat()
+ .until { true }
+ .every(10 * MILLISECONDS);
+ }
+
+ @Test
+ public void sanityTestBuilder() {
+ Repeater.create("Sanity test")
+ .repeat()
+ .until { true }
+ .every(10 * MILLISECONDS);
+ }
+
+ @Test
+ public void sanityTestBuilderDescription() {
+ Repeater.create()
+ .repeat()
+ .until { true }
+ .every(10 * MILLISECONDS);
+ }
+
+ @Test(expectedExceptions = [ NullPointerException.class ])
+ public void repeatFailsIfClosureIsNull() {
+ new Repeater("repeatFailsIfClosureIsNull").repeat((Callable<?>)null);
+ fail "Expected exception was not thrown"
+ }
+
+ @Test
+ public void repeatSucceedsIfClosureIsNonNull() {
+ new Repeater("repeatSucceedsIfClosureIsNonNull").repeat { true };
+ }
+
+ @Test(expectedExceptions = [ NullPointerException.class ])
+ public void untilFailsIfClosureIsNull() {
+ new Repeater("untilFailsIfClosureIsNull").until(null);
+ fail "Expected exception was not thrown"
+ }
+
+ @Test
+ public void untilSucceedsIfClosureIsNonNull() {
+ new Repeater("untilSucceedsIfClosureIsNonNull").until { true };
+ }
+
+ @Test(expectedExceptions = [ IllegalArgumentException.class ])
+ public void everyFailsIfPeriodIsZero() {
+ new Repeater("everyFailsIfPeriodIsZero").every(0 * MILLISECONDS);
+ fail "Expected exception was not thrown"
+ }
+
+ @Test(expectedExceptions = [ IllegalArgumentException.class ])
+ public void everyFailsIfPeriodIsNegative() {
+ new Repeater("everyFailsIfPeriodIsNegative").every(-1 * MILLISECONDS);
+ fail "Expected exception was not thrown"
+ }
+
+ @Test(expectedExceptions = [ NullPointerException.class ])
+ public void everyFailsIfUnitsIsNull() {
+ new Repeater("everyFailsIfUnitsIsNull").every(10, null);
+ fail "Expected exception was not thrown"
+ }
+
+ @Test
+ public void everySucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
+ new Repeater("repeatSucceedsIfClosureIsNonNull").every(10 * MILLISECONDS);
+ }
+
+ @Test(expectedExceptions = [ IllegalArgumentException.class ])
+ public void limitTimeToFailsIfPeriodIsZero() {
+ new Repeater("limitTimeToFailsIfPeriodIsZero").limitTimeTo(0, TimeUnit.MILLISECONDS);
+ fail "Expected exception was not thrown"
+ }
+
+ @Test(expectedExceptions = [ IllegalArgumentException.class ])
+ public void limitTimeToFailsIfPeriodIsNegative() {
+ new Repeater("limitTimeToFailsIfPeriodIsNegative").limitTimeTo(-1, TimeUnit.MILLISECONDS);
+ fail "Expected exception was not thrown"
+ }
+
+ @Test(expectedExceptions = [ NullPointerException.class ])
+ public void limitTimeToFailsIfUnitsIsNull() {
+ new Repeater("limitTimeToFailsIfUnitsIsNull").limitTimeTo(10, null);
+ fail "Expected exception was not thrown"
+ }
+
+ @Test
+ public void limitTimeToSucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
+ new Repeater("limitTimeToSucceedsIfClosureIsNonNull").limitTimeTo(10, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void everyAcceptsDuration() {
+ new Repeater("everyAcceptsDuration").every(Duration.ONE_SECOND);
+ }
+
+ @Test
+ public void everyAcceptsLong() {
+ new Repeater("everyAcceptsLong").every(1000L);
+ }
+
+ @Test
+ public void everyAcceptsTimeUnit() {
+ new Repeater("everyAcceptsTimeUnit").every(1000000L, TimeUnit.MICROSECONDS);
+ }
+
+ @Test
+ public void runReturnsTrueIfExitConditionIsTrue() {
+ assertTrue new Repeater("runReturnsTrueIfExitConditionIsTrue")
+ .repeat()
+ .every(1 * MILLISECONDS)
+ .until { true }
+ .run();
+ }
+
+ @Test
+ public void runRespectsMaximumIterationLimitAndReturnsFalseIfReached() {
+ int iterations = 0;
+ assertFalse new Repeater("runRespectsMaximumIterationLimitAndReturnsFalseIfReached")
+ .repeat { iterations++ }
+ .every(1 * MILLISECONDS)
+ .until { false }
+ .limitIterationsTo(5)
+ .run();
+ assertEquals 5, iterations;
+ }
+
+ /**
+ * Check that the {@link Repeater} will stop after a time limit.
+ *
+ * The repeater is configured to run every 100ms and never stop until the limit is reached.
+ * This is given as {@link Repeater#limitTimeTo(groovy.time.Duration)} and the execution time
+ * is then checked to ensure it is between 100% and 400% of the specified value. Due to scheduling
+ * delays and other factors in a non RTOS system it is expected that the repeater will take much
+ * longer to exit occasionally.
+ *
+ * @see #runRespectsMaximumIterationLimitAndReturnsFalseIfReached()
+ */
+ @Test(groups="Integration")
+ public void runRespectsTimeLimitAndReturnsFalseIfReached() {
+ final long LIMIT = 2000l;
+ Repeater repeater = new Repeater("runRespectsTimeLimitAndReturnsFalseIfReached")
+ .repeat()
+ .every(100 * MILLISECONDS)
+ .until { false }
+ .limitTimeTo(LIMIT, TimeUnit.MILLISECONDS);
+
+ Stopwatch stopwatch = new Stopwatch().start();
+ boolean result = repeater.run();
+ stopwatch.stop();
+
+ assertFalse result;
+
+ long difference = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+ assertTrue(difference >= LIMIT, "Difference was: " + difference);
+ assertTrue(difference < 4 * LIMIT, "Difference was: " + difference);
+ }
+
+ @Test(expectedExceptions = [ IllegalStateException.class ])
+ public void runFailsIfUntilWasNotSet() {
+ new Repeater("runFailsIfUntilWasNotSet")
+ .repeat()
+ .every(10 * MILLISECONDS)
+ .run();
+ fail "Expected exception was not thrown"
+ }
+
+ @Test(expectedExceptions = [ IllegalStateException.class ])
+ public void runFailsIfEveryWasNotSet() {
+ new Repeater("runFailsIfEveryWasNotSet")
+ .repeat()
+ .until { true }
+ .run();
+ fail "Expected exception was not thrown"
+ }
+
+ @Test(expectedExceptions = [ UnsupportedOperationException.class ])
+ public void testRethrowsException() {
+ boolean result = new Repeater("throwRuntimeException")
+ .repeat()
+ .every(10 * MILLISECONDS)
+ .until { throw new UnsupportedOperationException("fail") }
+ .rethrowException()
+ .limitIterationsTo(2)
+ .run();
+ fail "Expected exception was not thrown"
+ }
+
+ @Test
+ public void testNoRethrowsException() {
+ try {
+ boolean result = new Repeater("throwRuntimeException")
+ .repeat()
+ .every(10 * MILLISECONDS)
+ .until { throw new UnsupportedOperationException("fail") }
+ .limitIterationsTo(2)
+ .run();
+ assertFalse result
+ } catch (RuntimeException re) {
+ fail "Exception should not have been thrown: " + re.getMessage()
+ }
+ }
+
+ public void testFlags() {
+ int count=0;
+ new Repeater(period: 5*MILLISECONDS, timeout: 100*MILLISECONDS).repeat({ count++ }).until({ count>100}).run();
+ assertTrue count>10
+ assertTrue count<30
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/test/java/org/apache/brooklyn/core/util/internal/TypeCoercionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/TypeCoercionsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/TypeCoercionsTest.java
new file mode 100644
index 0000000..f1bb3f9
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/TypeCoercionsTest.java
@@ -0,0 +1,360 @@
+/*
+ * 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.core.util.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.core.util.flags.ClassCoercionException;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.codehaus.groovy.runtime.GStringImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.Lifecycle;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.text.StringPredicates;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+
+public class TypeCoercionsTest {
+
+ private static final Logger log = LoggerFactory.getLogger(TypeCoercionsTest.class);
+
+ @Test
+ public void testCoerceCharSequenceToString() {
+ assertEquals(TypeCoercions.coerce(new StringBuilder("abc"), String.class), "abc");
+ assertEquals(TypeCoercions.coerce(new GStringImpl(new Object[0], new String[0]), String.class), "");
+ }
+
+ @Test
+ public void testCoerceStringToPrimitive() {
+ assertEquals(TypeCoercions.coerce("1", Character.class), (Character)'1');
+ assertEquals(TypeCoercions.coerce(" ", Character.class), (Character)' ');
+ assertEquals(TypeCoercions.coerce("1", Short.class), (Short)((short)1));
+ assertEquals(TypeCoercions.coerce("1", Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce("1", Long.class), (Long)1l);
+ assertEquals(TypeCoercions.coerce("1", Float.class), (Float)1f);
+ assertEquals(TypeCoercions.coerce("1", Double.class), (Double)1d);
+ assertEquals(TypeCoercions.coerce("true", Boolean.class), (Boolean)true);
+ assertEquals(TypeCoercions.coerce("False", Boolean.class), (Boolean)false);
+ assertEquals(TypeCoercions.coerce("true ", Boolean.class), (Boolean)true);
+
+ assertEquals(TypeCoercions.coerce("1", char.class), (Character)'1');
+ assertEquals(TypeCoercions.coerce("1", short.class), (Short)((short)1));
+ assertEquals(TypeCoercions.coerce("1", int.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce("1", long.class), (Long)1l);
+ assertEquals(TypeCoercions.coerce("1", float.class), (Float)1f);
+ assertEquals(TypeCoercions.coerce("1", double.class), (Double)1d);
+ assertEquals(TypeCoercions.coerce("TRUE", boolean.class), (Boolean)true);
+ assertEquals(TypeCoercions.coerce("false", boolean.class), (Boolean)false);
+ }
+
+ @Test
+ public void testCoercePrimitivesToSameType() {
+ assertEquals(TypeCoercions.coerce('1', Character.class), (Character)'1');
+ assertEquals(TypeCoercions.coerce((short)1, Short.class), (Short)((short)1));
+ assertEquals(TypeCoercions.coerce(1, Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce(1l, Long.class), (Long)1l);
+ assertEquals(TypeCoercions.coerce(1f, Float.class), (Float)1f);
+ assertEquals(TypeCoercions.coerce(1d, Double.class), (Double)1d);
+ assertEquals(TypeCoercions.coerce(true, Boolean.class), (Boolean)true);
+ }
+
+ @Test
+ public void testCastPrimitives() {
+ assertEquals(TypeCoercions.coerce(1L, Character.class), (Character)(char)1);
+ assertEquals(TypeCoercions.coerce(1L, Byte.class), (Byte)(byte)1);
+ assertEquals(TypeCoercions.coerce(1L, Short.class), (Short)(short)1);
+ assertEquals(TypeCoercions.coerce(1L, Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce(1L, Long.class), (Long)(long)1);
+ assertEquals(TypeCoercions.coerce(1L, Float.class), (Float)(float)1);
+ assertEquals(TypeCoercions.coerce(1L, Double.class), (Double)(double)1);
+
+ assertEquals(TypeCoercions.coerce(1L, char.class), (Character)(char)1);
+ assertEquals(TypeCoercions.coerce(1L, byte.class), (Byte)(byte)1);
+ assertEquals(TypeCoercions.coerce(1L, short.class), (Short)(short)1);
+ assertEquals(TypeCoercions.coerce(1L, int.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce(1L, long.class), (Long)(long)1);
+ assertEquals(TypeCoercions.coerce(1L, float.class), (Float)(float)1);
+ assertEquals(TypeCoercions.coerce(1L, double.class), (Double)(double)1);
+
+ assertEquals(TypeCoercions.coerce((char)1, Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce((byte)1, Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce((short)1, Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce((int)1, Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce((long)1, Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce((float)1, Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce((double)1, Integer.class), (Integer)1);
+ }
+
+ @Test
+ public void testCoercePrimitiveFailures() {
+ // error messages don't have to be this exactly, but they should include sufficient information...
+ assertCoercionFailsWithErrorMatching("maybe", boolean.class, StringPredicates.containsAllLiterals("String", "boolean", "maybe"));
+ assertCoercionFailsWithErrorMatching("NaN", int.class, StringPredicates.containsAllLiterals("int", "NaN"));
+ assertCoercionFailsWithErrorMatching('c', boolean.class, StringPredicates.containsAllLiterals("boolean", "(c)")); // will say 'string' rather than 'char'
+ assertCoercionFailsWithErrorMatching(0, boolean.class, StringPredicates.containsAllLiterals("Integer", "boolean", "0"));
+ }
+
+ protected void assertCoercionFailsWithErrorMatching(Object input, Class<?> type, Predicate<? super String> errorMessageRequirement) {
+ try {
+ Object result = TypeCoercions.coerce(input, type);
+ Assert.fail("Should have failed type coercion of "+input+" to "+type+", instead got: "+result);
+ } catch (Exception e) {
+ if (errorMessageRequirement==null || errorMessageRequirement.apply(e.toString()))
+ log.info("Primitive coercion failed as expected, with: "+e);
+ else
+ Assert.fail("Error from type coercion of "+input+" to "+type+" failed with wrong exception; expected match of "+errorMessageRequirement+" but got: "+e);
+ }
+
+ }
+
+ @Test
+ public void testCastToNumericPrimitives() {
+ assertEquals(TypeCoercions.coerce(BigInteger.ONE, Integer.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce(BigInteger.ONE, int.class), (Integer)1);
+ assertEquals(TypeCoercions.coerce(BigInteger.valueOf(Long.MAX_VALUE), Long.class), (Long)Long.MAX_VALUE);
+ assertEquals(TypeCoercions.coerce(BigInteger.valueOf(Long.MAX_VALUE), long.class), (Long)Long.MAX_VALUE);
+
+ assertEquals(TypeCoercions.coerce(BigDecimal.valueOf(0.5), Double.class), 0.5d, 0.00001d);
+ assertEquals(TypeCoercions.coerce(BigDecimal.valueOf(0.5), double.class), 0.5d, 0.00001d);
+ }
+
+ @Test
+ public void testCoerceStringToBigNumber() {
+ assertEquals(TypeCoercions.coerce("0.5", BigDecimal.class), BigDecimal.valueOf(0.5));
+ assertEquals(TypeCoercions.coerce("1", BigInteger.class), BigInteger.valueOf(1));
+ }
+
+ @Test
+ public void testCoerceStringToEnum() {
+ assertEquals(TypeCoercions.coerce("STARTING", Lifecycle.class), Lifecycle.STARTING);
+ assertEquals(TypeCoercions.coerce("Starting", Lifecycle.class), Lifecycle.STARTING);
+ assertEquals(TypeCoercions.coerce("starting", Lifecycle.class), Lifecycle.STARTING);
+
+ assertEquals(TypeCoercions.coerce("LOWERCASE", PerverseEnum.class), PerverseEnum.lowercase);
+ assertEquals(TypeCoercions.coerce("CAMELCASE", PerverseEnum.class), PerverseEnum.camelCase);
+ assertEquals(TypeCoercions.coerce("upper", PerverseEnum.class), PerverseEnum.UPPER);
+ assertEquals(TypeCoercions.coerce("upper_with_underscore", PerverseEnum.class), PerverseEnum.UPPER_WITH_UNDERSCORE);
+ assertEquals(TypeCoercions.coerce("LOWER_WITH_UNDERSCORE", PerverseEnum.class), PerverseEnum.lower_with_underscore);
+ }
+ public static enum PerverseEnum {
+ lowercase,
+ camelCase,
+ UPPER,
+ UPPER_WITH_UNDERSCORE,
+ lower_with_underscore;
+ }
+
+ @Test(expectedExceptions = ClassCoercionException.class)
+ public void testCoerceStringToEnumFailure() {
+ TypeCoercions.coerce("scrambled-eggs", Lifecycle.class);
+ }
+
+ @Test
+ public void testListToSetCoercion() {
+ Set<?> s = TypeCoercions.coerce(ImmutableList.of(1), Set.class);
+ Assert.assertEquals(s, ImmutableSet.of(1));
+ }
+
+ @Test
+ public void testSetToListCoercion() {
+ List<?> s = TypeCoercions.coerce(ImmutableSet.of(1), List.class);
+ Assert.assertEquals(s, ImmutableList.of(1));
+ }
+
+ @Test
+ public void testIterableToArrayCoercion() {
+ String[] s = TypeCoercions.coerce(ImmutableList.of("a", "b"), String[].class);
+ Assert.assertTrue(Arrays.equals(s, new String[] {"a", "b"}), "result="+Arrays.toString(s));
+
+ Integer[] i = TypeCoercions.coerce(ImmutableList.of(1, 2), Integer[].class);
+ Assert.assertTrue(Arrays.equals(i, new Integer[] {1, 2}), "result="+Arrays.toString(i));
+
+ int[] i2 = TypeCoercions.coerce(ImmutableList.of(1, 2), int[].class);
+ Assert.assertTrue(Arrays.equals(i2, new int[] {1, 2}), "result="+Arrays.toString(i2));
+
+ int[] i3 = TypeCoercions.coerce(MutableSet.of("1", 2), int[].class);
+ Assert.assertTrue(Arrays.equals(i3, new int[] {1, 2}), "result="+Arrays.toString(i3));
+ }
+
+ @Test
+ public void testListEntryCoercion() {
+ List<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), new TypeToken<List<Class<?>>>() { });
+ Assert.assertEquals(s, ImmutableList.of(Integer.class, Double.class));
+ }
+
+ @Test
+ public void testListEntryToSetCoercion() {
+ Set<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), new TypeToken<Set<Class<?>>>() { });
+ Assert.assertEquals(s, ImmutableSet.of(Integer.class, Double.class));
+ }
+
+ @Test
+ public void testListEntryToCollectionCoercion() {
+ Collection<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), new TypeToken<Collection<Class<?>>>() { });
+ Assert.assertEquals(s, ImmutableList.of(Integer.class, Double.class));
+ }
+
+ @Test
+ public void testMapValueCoercion() {
+ Map<?,?> s = TypeCoercions.coerce(ImmutableMap.of("int", "java.lang.Integer", "double", "java.lang.Double"), new TypeToken<Map<String, Class<?>>>() { });
+ Assert.assertEquals(s, ImmutableMap.of("int", Integer.class, "double", Double.class));
+ }
+
+ @Test
+ public void testMapKeyCoercion() {
+ Map<?,?> s = TypeCoercions.coerce(ImmutableMap.of("java.lang.Integer", "int", "java.lang.Double", "double"), new TypeToken<Map<Class<?>, String>>() { });
+ Assert.assertEquals(s, ImmutableMap.of(Integer.class, "int", Double.class, "double"));
+ }
+
+ @Test
+ public void testStringToListCoercion() {
+ List<?> s = TypeCoercions.coerce("a,b,c", List.class);
+ Assert.assertEquals(s, ImmutableList.of("a", "b", "c"));
+ }
+
+ @Test
+ @SuppressWarnings("serial")
+ public void testCoerceRecursivelyStringToGenericsCollection() {
+ assertEquals(TypeCoercions.coerce("1,2", new TypeToken<List<Integer>>() {}), ImmutableList.of(1, 2));
+ }
+
+ @Test
+ public void testJsonStringToMapCoercion() {
+ Map<?,?> s = TypeCoercions.coerce("{ \"a\" : \"1\", b : 2 }", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+ }
+
+ @Test
+ public void testJsonStringWithoutQuotesToMapCoercion() {
+ Map<?,?> s = TypeCoercions.coerce("{ a : 1 }", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", 1));
+ }
+
+ @Test
+ public void testJsonComplexTypesToMapCoercion() {
+ Map<?,?> s = TypeCoercions.coerce("{ a : [1, \"2\", '\"3\"'], b: { c: d, 'e': \"f\" } }", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", ImmutableList.<Object>of(1, "2", "\"3\""),
+ "b", ImmutableMap.of("c", "d", "e", "f")));
+ }
+
+ @Test
+ public void testJsonStringWithoutBracesToMapCoercion() {
+ Map<?,?> s = TypeCoercions.coerce("a : 1", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", 1));
+ }
+
+ @Test
+ public void testJsonStringWithoutBracesWithMultipleToMapCoercion() {
+ Map<?,?> s = TypeCoercions.coerce("a : 1, b : 2", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", 2));
+ }
+
+ @Test
+ public void testKeyEqualsValueStringToMapCoercion() {
+ Map<?,?> s = TypeCoercions.coerce("a=1,b=2", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", "2"));
+ }
+
+ @Test(expectedExceptions=IllegalArgumentException.class)
+ public void testJsonStringWithoutBracesOrSpaceDisallowedAsMapCoercion() {
+ // yaml requires spaces after the colon
+ Map<?,?> s = TypeCoercions.coerce("a:1,b:2", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", 2));
+ }
+
+ @Test
+ public void testEqualsInBracesMapCoercion() {
+ Map<?,?> s = TypeCoercions.coerce("{ a = 1, b = '2' }", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", "2"));
+ }
+
+ @Test
+ public void testKeyEqualsOrColonValueWithBracesStringToMapCoercion() {
+ Map<?,?> s = TypeCoercions.coerce("{ a=1, b: 2 }", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+ }
+
+ @Test
+ public void testKeyEqualsOrColonValueWithoutBracesStringToMapCoercion() {
+ Map<?,?> s = TypeCoercions.coerce("a=1, b: 2", Map.class);
+ Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+ }
+
+ @Test
+ public void testAs() {
+ Integer x = TypeCoercions.coerce(new WithAs("3"), Integer.class);
+ Assert.assertEquals(x, (Integer)3);
+ }
+
+ @Test
+ public void testFrom() {
+ WithFrom x = TypeCoercions.coerce("3", WithFrom.class);
+ Assert.assertEquals(x.value, 3);
+ }
+
+ @Test
+ public void testCoerceStringToNumber() {
+ assertEquals(TypeCoercions.coerce("1", Number.class), (Number) Double.valueOf(1));
+ assertEquals(TypeCoercions.coerce("1.0", Number.class), (Number) Double.valueOf(1.0));
+ }
+
+ @Test(expectedExceptions = ClassCoercionException.class)
+ public void testInvalidCoercionThrowsClassCoercionException() {
+ TypeCoercions.coerce(new Object(), TypeToken.of(Integer.class));
+ }
+
+ @Test
+ public void testCoercionFunction() {
+ assertEquals(TypeCoercions.function(Double.class).apply("1"), Double.valueOf(1));
+ }
+
+ public static class WithAs {
+ String value;
+ public WithAs(Object x) { value = ""+x; }
+ public Integer asInteger() {
+ return Integer.parseInt(value);
+ }
+ }
+
+ public static class WithFrom {
+ int value;
+ public static WithFrom fromString(String s) {
+ WithFrom result = new WithFrom();
+ result.value = Integer.parseInt(s);
+ return result;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/RecordingSshTool.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/RecordingSshTool.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/RecordingSshTool.java
new file mode 100644
index 0000000..fdf3e73
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/RecordingSshTool.java
@@ -0,0 +1,97 @@
+/*
+ * 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.core.util.internal.ssh;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+/** Mock tool */
+public class RecordingSshTool implements SshTool {
+
+ public static class ExecCmd {
+ public final Map<String,?> props;
+ public final String summaryForLogging;
+ public final List<String> commands;
+ public final Map<?,?> env;
+
+ ExecCmd(Map<String,?> props, String summaryForLogging, List<String> commands, Map env) {
+ this.props = props;
+ this.summaryForLogging = summaryForLogging;
+ this.commands = commands;
+ this.env = env;
+ }
+
+ @Override
+ public String toString() {
+ return "ExecCmd["+summaryForLogging+": "+commands+"; "+props+"; "+env+"]";
+ }
+ }
+
+ public static List<ExecCmd> execScriptCmds = Lists.newCopyOnWriteArrayList();
+
+ private boolean connected;
+
+ public RecordingSshTool(Map<?,?> props) {
+ }
+ @Override public void connect() {
+ connected = true;
+ }
+ @Override public void connect(int maxAttempts) {
+ connected = true;
+ }
+ @Override public void disconnect() {
+ connected = false;
+ }
+ @Override public boolean isConnected() {
+ return connected;
+ }
+ @Override public int execScript(Map<String, ?> props, List<String> commands, Map<String, ?> env) {
+ execScriptCmds.add(new ExecCmd(props, "", commands, env));
+ return 0;
+ }
+ @Override public int execScript(Map<String, ?> props, List<String> commands) {
+ return execScript(props, commands, ImmutableMap.<String,Object>of());
+ }
+ @Override public int execCommands(Map<String, ?> props, List<String> commands, Map<String, ?> env) {
+ execScriptCmds.add(new ExecCmd(props, "", commands, env));
+ return 0;
+ }
+ @Override public int execCommands(Map<String, ?> props, List<String> commands) {
+ return execCommands(props, commands, ImmutableMap.<String,Object>of());
+ }
+ @Override public int copyToServer(Map<String, ?> props, File localFile, String pathAndFileOnRemoteServer) {
+ return 0;
+ }
+ @Override public int copyToServer(Map<String, ?> props, InputStream contents, String pathAndFileOnRemoteServer) {
+ return 0;
+ }
+ @Override public int copyToServer(Map<String, ?> props, byte[] contents, String pathAndFileOnRemoteServer) {
+ return 0;
+ }
+ @Override public int copyFromServer(Map<String, ?> props, String pathAndFileOnRemoteServer, File local) {
+ return 0;
+ }
+}
\ No newline at end of file