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/18 17:03:11 UTC

[02/64] [abbrv] incubator-brooklyn git commit: BROOKLYN-162 - apply org.apache package prefix to utils-common

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/pool/BasicPoolTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/pool/BasicPoolTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/pool/BasicPoolTest.java
new file mode 100644
index 0000000..16d3877
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/pool/BasicPoolTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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.util.pool;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.util.pool.BasicPool;
+import org.apache.brooklyn.util.pool.Lease;
+import org.apache.brooklyn.util.pool.Pool;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.testng.internal.annotations.Sets;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+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;
+
+public class BasicPoolTest {
+
+    private List<Integer> closedVals;
+    private Supplier<Integer> supplier;
+    Function<Integer,Void> closer;
+    private ListeningExecutorService executor;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        // Note we use final theCounter variable, rather than just a field, to guarantee 
+        // that each sequential test run won't be accessing the same field value if a test
+        // doesn't tear down and keeps executing in another thread for some reason.
+        
+        final AtomicInteger theCounter = new AtomicInteger(0);
+        closedVals = new CopyOnWriteArrayList<Integer>();
+        
+        supplier = new Supplier<Integer>() {
+            @Override public Integer get() {
+                return theCounter.getAndIncrement();
+            }
+        };
+        closer = new Function<Integer,Void>() {
+            @Override public Void apply(@Nullable Integer input) {
+                closedVals.add(input);
+                return null;
+            }
+        };
+        executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (executor != null) executor.shutdownNow();
+    }
+    
+    @Test
+    public void testGeneratesNewValuesWhenRequired() throws Exception {
+        Pool<Integer> pool = BasicPool.<Integer>builder().supplier(supplier).build();
+        
+        Lease<Integer> lease1 = pool.leaseObject();
+        assertEquals(lease1.leasedObject(), (Integer)0);
+        
+        Lease<Integer> lease2 = pool.leaseObject();
+        assertEquals(lease2.leasedObject(), (Integer)1);
+    }
+    
+    @Test
+    public void testReusesReturnedVals() throws Exception {
+        Pool<Integer> pool = BasicPool.<Integer>builder().supplier(supplier).build();
+        
+        Lease<Integer> lease1 = pool.leaseObject();
+        assertEquals(lease1.leasedObject(), (Integer)0);
+        lease1.close();
+        
+        Lease<Integer> lease2 = pool.leaseObject();
+        assertEquals(lease2.leasedObject(), (Integer)0);
+    }
+    
+    @Test
+    public void testGeneratesNewIfOnlyUnviableValsInPool() throws Exception {
+        Pool<Integer> pool = BasicPool.<Integer>builder().supplier(supplier).viabilityChecker(Predicates.alwaysFalse()).closer(closer).build();
+        
+        Lease<Integer> lease1 = pool.leaseObject();
+        assertEquals(lease1.leasedObject(), (Integer)0);
+        lease1.close();
+        
+        Lease<Integer> lease2 = pool.leaseObject();
+        assertEquals(lease2.leasedObject(), (Integer)1);
+        
+        // Expect the "unviable" resource to have been closed
+        assertEquals(closedVals, ImmutableList.of(0));
+    }
+    
+    @Test
+    public void testReusesOnlyViableVals() throws Exception {
+        Pool<Integer> pool = BasicPool.<Integer>builder().supplier(supplier).viabilityChecker(Predicates.equalTo(1)).build();
+        
+        Lease<Integer> lease1 = pool.leaseObject();
+        Lease<Integer> lease2 = pool.leaseObject();
+        Lease<Integer> lease3 = pool.leaseObject();
+        
+        lease1.close();
+        lease2.close();
+        lease3.close();
+        
+        Lease<Integer> lease4 = pool.leaseObject();
+        assertEquals(lease4.leasedObject(), (Integer)1);
+    }
+    
+    @Test
+    public void testClosesResourcesInPool() throws Exception {
+        Pool<Integer> pool = BasicPool.<Integer>builder().supplier(supplier).closer(closer).build();
+        
+        Lease<Integer> lease1 = pool.leaseObject();
+        Lease<Integer> lease2 = pool.leaseObject();
+        lease1.close();
+        lease2.close();
+
+        pool.close();
+        assertEquals(closedVals, ImmutableList.of(0, 1));
+    }
+    
+    @Test
+    public void testClosesResourceReturnedAfterPoolIsClosed() throws Exception {
+        Pool<Integer> pool = BasicPool.<Integer>builder().supplier(supplier).closer(closer).build();
+        
+        Lease<Integer> lease1 = pool.leaseObject();
+        pool.close();
+        assertEquals(closedVals, ImmutableList.of());
+        
+        lease1.close();
+        assertEquals(closedVals, ImmutableList.of(lease1.leasedObject()));
+    }
+    
+    @Test
+    public void testDoesNotReuseUnviableVals() throws Exception {
+        Pool<Integer> pool = BasicPool.<Integer>builder().supplier(supplier).viabilityChecker(Predicates.alwaysFalse()).build();
+        
+        Lease<Integer> lease1 = pool.leaseObject();
+        assertEquals(lease1.leasedObject(), (Integer)0);
+        lease1.close();
+        
+        Lease<Integer> lease2 = pool.leaseObject();
+        assertEquals(lease2.leasedObject(), (Integer)1);
+    }
+    
+    @Test
+    public void testConcurrentCallsNeverHaveSameVal() throws Exception {
+        final Pool<Integer> pool = BasicPool.<Integer>builder().supplier(supplier).build();
+        final Set<Lease<Integer>> leases = Collections.newSetFromMap(new ConcurrentHashMap<Lease<Integer>, Boolean>());
+        List<ListenableFuture<?>> futures = Lists.newArrayList();
+        
+        for (int i = 0; i < 1000; i++) {
+            futures.add(executor.submit(new Runnable() {
+                public void run() {
+                    leases.add(pool.leaseObject());
+                }
+            }));
+        }
+        Futures.allAsList(futures).get();
+        
+        Set<Integer> currentlyLeased = Sets.newLinkedHashSet();
+        for (Lease<Integer> lease : leases) {
+            boolean val = currentlyLeased.add(lease.leasedObject());
+            if (!val) fail("duplicate="+lease.leasedObject()+"; vals="+leases);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/repeat/RepeaterTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/repeat/RepeaterTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/repeat/RepeaterTest.java
new file mode 100644
index 0000000..728120e
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/repeat/RepeaterTest.java
@@ -0,0 +1,240 @@
+/*
+ * 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.util.repeat;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.util.repeat.Repeater;
+import org.apache.brooklyn.util.time.Duration;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.Callables;
+
+public class RepeaterTest {
+
+    @Test
+    public void sanityTest() {
+        new Repeater("Sanity test")
+            .until(Callables.returning(true))
+            .every(Duration.millis(10));
+    }
+
+    @Test
+    public void sanityTestDescription() {
+        new Repeater()
+            .until(Callables.returning(true))
+            .every(Duration.millis(10));
+    }
+
+    @Test
+    public void sanityTestBuilder() {
+        Repeater.create("Sanity test")
+            .until(Callables.returning(true))
+            .every(Duration.millis(10));
+    }
+
+    @Test
+    public void sanityTestBuilderDescription() {
+        Repeater.create()
+            .until(Callables.returning(true))
+            .every(Duration.millis(10));
+    }
+
+    @Test
+    public void repeatSucceedsIfClosureIsNonNull() {
+        new Repeater("repeatSucceedsIfClosureIsNonNull").repeat(Callables.returning(true));
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class, IllegalArgumentException.class })
+    public void untilFailsIfClosureIsNull() {
+        new Repeater("untilFailsIfClosureIsNull").until(null);
+        fail("Expected exception was not thrown");
+    }
+
+    @Test
+    public void untilSucceedsIfClosureIsNonNull() {
+        new Repeater("untilSucceedsIfClosureIsNonNull")
+            .until(Callables.returning(true));
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class, IllegalArgumentException.class })
+    public void everyFailsIfPeriodIsZero() {
+        new Repeater("everyFailsIfPeriodIsZero").every(Duration.ZERO);
+        fail("Expected exception was not thrown");
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class, IllegalArgumentException.class })
+    public void everyFailsIfPeriodIsNegative() {
+        new Repeater("everyFailsIfPeriodIsNegative").every(Duration.millis(-1));
+        fail("Expected exception was not thrown");
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class, IllegalArgumentException.class })
+    public void everyFailsIfUnitsIsNull() {
+        new Repeater("everyFailsIfUnitsIsNull").every(10, null);
+        fail("Expected exception was not thrown");
+    }
+
+    @Test
+    public void everySucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
+        new Repeater("repeatSucceedsIfClosureIsNonNull").every(Duration.millis(10));
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class, IllegalArgumentException.class })
+    public void limitTimeToFailsIfPeriodIsZero() {
+        new Repeater("limitTimeToFailsIfPeriodIsZero").limitTimeTo(0, TimeUnit.MILLISECONDS);
+        fail("Expected exception was not thrown");
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class, IllegalArgumentException.class })
+    public void limitTimeToFailsIfPeriodIsNegative() {
+        new Repeater("limitTimeToFailsIfPeriodIsNegative").limitTimeTo(-1, TimeUnit.MILLISECONDS);
+        fail("Expected exception was not thrown");
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class, IllegalArgumentException.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 everyAcceptsTimeUnit() {
+        new Repeater("everyAcceptsTimeUnit").every(1000000L, TimeUnit.MICROSECONDS);
+    }
+
+    @Test
+    public void runReturnsTrueIfExitConditionIsTrue() {
+        assertTrue(new Repeater("runReturnsTrueIfExitConditionIsTrue")
+            .every(Duration.millis(1))
+            .until(Callables.returning(true))
+            .run());
+    }
+
+    @Test
+    public void runRespectsMaximumIterationLimitAndReturnsFalseIfReached() {
+        final AtomicInteger iterations = new AtomicInteger();
+        assertFalse(new Repeater("runRespectsMaximumIterationLimitAndReturnsFalseIfReached")
+            .repeat(new Runnable() { public void run() { iterations.incrementAndGet(); } })
+            .every(Duration.millis(1))
+            .until(Callables.returning(false))
+            .limitIterationsTo(5)
+            .run());
+        assertEquals(iterations.get(), 5);
+    }
+
+    /**
+     * 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")
+            .every(Duration.millis(100))
+            .until(Callables.returning(false))
+            .limitTimeTo(LIMIT, TimeUnit.MILLISECONDS);
+
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        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")
+            .every(Duration.millis(10))
+            .run();
+        fail("Expected exception was not thrown");
+    }
+
+    @Test(expectedExceptions = { IllegalStateException.class })
+    public void runFailsIfEveryWasNotSet() {
+        new Repeater("runFailsIfEveryWasNotSet")
+            .until(Callables.returning(true))
+            .run();
+        fail("Expected exception was not thrown");
+    }
+
+    @Test(expectedExceptions = { UnsupportedOperationException.class })
+    public void testRethrowsException() {
+        new Repeater("throwRuntimeException")
+            .every(Duration.millis(10))
+            .until(callableThrowingUnsupportedFail())
+            .rethrowException()
+            .limitIterationsTo(2)
+            .run();
+        fail("Expected exception was not thrown");
+    }
+
+    @Test
+    public void testNoRethrowsException() {
+        try {
+            boolean result = new Repeater("throwRuntimeException")
+                .every(Duration.millis(10))
+                .until(callableThrowingUnsupportedFail())
+                .limitIterationsTo(2)
+                .run();
+            assertFalse(result);
+        } catch (RuntimeException re) {
+            fail("Exception should not have been thrown: " + re.getMessage());
+        }
+    }
+    
+    private static Callable<Boolean> callableThrowingUnsupportedFail() {
+        return new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                throw new UnsupportedOperationException("fail");
+            }
+        };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/ssh/IptablesCommandsFirewalldTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/ssh/IptablesCommandsFirewalldTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/ssh/IptablesCommandsFirewalldTest.java
new file mode 100644
index 0000000..78d202b
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/ssh/IptablesCommandsFirewalldTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.util.ssh;
+
+import org.apache.brooklyn.util.net.Protocol;
+import org.apache.brooklyn.util.ssh.IptablesCommands;
+import org.apache.brooklyn.util.ssh.IptablesCommands.Chain;
+import org.apache.brooklyn.util.ssh.IptablesCommands.Policy;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class IptablesCommandsFirewalldTest {
+    private static final String addFirewalldRule = "( if test \"$UID\" -eq 0; then "
+            + "( ( /usr/bin/firewall-cmd --direct --add-rule ipv4 filter INPUT 0  -p tcp --dport 3306 -j ACCEPT "
+            + "&& /usr/bin/firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0  -p tcp --dport 3306 -j ACCEPT ) ); "
+            + "else echo \"( /usr/bin/firewall-cmd --direct --add-rule ipv4 filter INPUT 0  -p tcp --dport 3306 -j ACCEPT "
+            + "&& /usr/bin/firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0  -p tcp --dport 3306 -j ACCEPT )\" "
+            + "| sudo -E -n -S -s -- bash ; fi )";
+
+    private static final String firewalldService = "( if test \"$UID\" -eq 0; then ( ( { "
+            + "which systemctl && systemctl status firewalld ; } || /usr/bin/systemctl status firewalld ) ); "
+            + "else echo \"( { which systemctl && systemctl status firewalld ; } || "
+            + "/usr/bin/systemctl status firewalld )\" | sudo -E -n -S -s -- bash ; fi )";
+
+    private static final String firewalldServiceRestart = "( if test \"$UID\" -eq 0; then ( ( { "
+            + "which systemctl && systemctl restart firewalld ; } || "
+            + "/usr/bin/systemctl restart firewalld ) ); else echo \"( { "
+            + "which systemctl && systemctl restart firewalld ; } || /usr/bin/systemctl restart firewalld )\" | "
+            + "sudo -E -n -S -s -- bash ; fi )";
+
+    private static final String firewalldServiceStart = "( if test \"$UID\" -eq 0; then ( ( { "
+            + "which systemctl && systemctl start firewalld ; } "
+            + "|| /usr/bin/systemctl start firewalld ) ); "
+            + "else echo \"( { which systemctl && systemctl start firewalld ; } || "
+            + "/usr/bin/systemctl start firewalld )\" | sudo -E -n -S -s -- bash ; fi )";
+
+    private static final String firewalldServiceStatus = "( if test \"$UID\" -eq 0; then ( ( { "
+            + "which systemctl && systemctl status firewalld ; "
+            + "} || /usr/bin/systemctl status firewalld ) ); else echo \"( { "
+            + "which systemctl && systemctl status firewalld ; } || "
+            + "/usr/bin/systemctl status firewalld )\" | sudo -E -n -S -s -- bash ; fi )";
+
+    private static final String firewalldServiceStop = "( if test \"$UID\" -eq 0; then ( ( { "
+            + "which systemctl && systemctl stop firewalld ; } || /usr/bin/systemctl stop firewalld ) ); "
+            + "else echo \"( { which systemctl && systemctl stop firewalld ; } || "
+            + "/usr/bin/systemctl stop firewalld )\" | sudo -E -n -S -s -- bash ; fi )";
+
+    private static final String firewalldServiceIsActive = "( if test \"$UID\" -eq 0; then ( ( { "
+            + "which systemctl && systemctl is-active firewalld ; } || /usr/bin/systemctl is-active firewalld ) ); "
+            + "else echo \"( { which systemctl && systemctl is-active firewalld ; } || /usr/bin/systemctl is-active firewalld )\" | "
+            + "sudo -E -n -S -s -- bash ; fi )";
+
+    @Test
+    public void testAddFirewalldRule() {
+        Assert.assertEquals(IptablesCommands.addFirewalldRule(Chain.INPUT,
+                Protocol.TCP, 3306, Policy.ACCEPT), addFirewalldRule);
+    }
+
+    @Test
+    public void testFirewalldService() {
+        Assert.assertEquals(IptablesCommands.firewalldService("status"), firewalldService);
+    }
+
+    @Test
+    public void testFirewalldServiceRestart() {
+        Assert.assertEquals(IptablesCommands.firewalldServiceRestart(), firewalldServiceRestart);
+    }
+
+    @Test
+    public void testFirewalldServiceStart() {
+        Assert.assertEquals(IptablesCommands.firewalldServiceStart(), firewalldServiceStart);
+    }
+
+    @Test
+    public void testFirewalldServiceStatus() {
+        Assert.assertEquals(IptablesCommands.firewalldServiceStatus(), firewalldServiceStatus);
+    }
+
+    @Test
+    public void testFirewalldServiceStop() {
+        Assert.assertEquals(IptablesCommands.firewalldServiceStop(), firewalldServiceStop);
+    }
+
+    @Test
+    public void testFirewalldServiceIsActive() {
+        Assert.assertEquals(IptablesCommands.firewalldServiceIsActive(), firewalldServiceIsActive);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/ssh/IptablesCommandsTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/ssh/IptablesCommandsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/ssh/IptablesCommandsTest.java
new file mode 100644
index 0000000..d30a1b4
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/ssh/IptablesCommandsTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.util.ssh;
+
+import org.apache.brooklyn.util.ssh.IptablesCommands;
+import org.apache.brooklyn.util.ssh.IptablesCommands.Chain;
+import org.apache.brooklyn.util.ssh.IptablesCommands.Policy;
+import org.apache.brooklyn.util.ssh.IptablesCommands.Protocol;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class IptablesCommandsTest {
+
+    private static final String cleanUptptablesRules = "( if test \"$UID\" -eq 0; then ( /sbin/iptables -F ); else sudo -E -n -S -- /sbin/iptables -F; fi )";
+
+    public static final String insertIptablesRule = "( if test \"$UID\" -eq 0; then ( /sbin/iptables -I INPUT -i eth0 -p tcp --dport 3306 -j ACCEPT ); "
+            + "else sudo -E -n -S -- /sbin/iptables -I INPUT -i eth0 -p tcp --dport 3306 -j ACCEPT; fi )";
+    private static final String appendIptablesRule = "( if test \"$UID\" -eq 0; then ( /sbin/iptables -A INPUT -i eth0 -p tcp --dport 3306 -j ACCEPT ); "
+            + "else sudo -E -n -S -- /sbin/iptables -A INPUT -i eth0 -p tcp --dport 3306 -j ACCEPT; fi )";
+    private static final String insertIptablesRuleAll = "( if test \"$UID\" -eq 0; then ( /sbin/iptables -I INPUT -p tcp --dport 3306 -j ACCEPT ); "
+            + "else sudo -E -n -S -- /sbin/iptables -I INPUT -p tcp --dport 3306 -j ACCEPT; fi )";
+    private static final String appendIptablesRuleAll = "( if test \"$UID\" -eq 0; then ( /sbin/iptables -A INPUT -p tcp --dport 3306 -j ACCEPT ); "
+            + "else sudo -E -n -S -- /sbin/iptables -A INPUT -p tcp --dport 3306 -j ACCEPT; fi )";
+    private static final String saveIptablesRules = "( ( if test \"$UID\" -eq 0; then ( service iptables save ); else sudo -E -n -S -- service iptables save; fi ) || " +
+            "( ( { which zypper && { echo zypper exists, doing refresh && (( if test \"$UID\" -eq 0; then ( zypper --non-interactive --no-gpg-checks refresh ); else sudo -E -n -S -- zypper --non-interactive --no-gpg-checks refresh; fi ) || true) && ( if test \"$UID\" -eq 0; then ( zypper --non-interactive --no-gpg-checks install iptables-persistent ); else sudo -E -n -S -- zypper --non-interactive --no-gpg-checks install iptables-persistent; fi ) ; } ; } || " +
+            "{ which apt-get && { echo apt-get exists, doing update && export DEBIAN_FRONTEND=noninteractive && (( if test \"$UID\" -eq 0; then ( apt-get update ); else sudo -E -n -S -- apt-get update; fi ) || true) && ( if test \"$UID\" -eq 0; then ( apt-get install -y --allow-unauthenticated iptables-persistent ); else sudo -E -n -S -- apt-get install -y --allow-unauthenticated iptables-persistent; fi ) ; } ; } || " +
+            "{ which yum && { echo yum exists, doing update && (( if test \"$UID\" -eq 0; then ( yum check-update ); else sudo -E -n -S -- yum check-update; fi ) || true) && (( if test \"$UID\" -eq 0; then ( yum -y install epel-release ); else sudo -E -n -S -- yum -y install epel-release; fi ) || true) && ( if test \"$UID\" -eq 0; then ( yum -y --nogpgcheck install iptables-persistent ); else sudo -E -n -S -- yum -y --nogpgcheck install iptables-persistent; fi ) ; } ; } || " +
+            "{ which brew && brew install iptables-persistent ; } || " +
+            "{ which port && ( if test \"$UID\" -eq 0; then ( port install iptables-persistent ); else sudo -E -n -S -- port install iptables-persistent; fi ) ; } || " +
+            "(( echo \"WARNING: no known/successful package manager to install iptables-persistent, may fail subsequently\" | tee /dev/stderr ) || true) ) && ( if test \"$UID\" -eq 0; then ( /etc/init.d/iptables-persistent save ); else sudo -E -n -S -- /etc/init.d/iptables-persistent save; fi ) ) )";
+
+    @Test
+    public void testCleanUpIptablesRules() {
+        Assert.assertEquals(IptablesCommands.cleanUpIptablesRules(), cleanUptptablesRules);
+    }
+
+    @Test
+    public void testInsertIptablesRules() {
+        Assert.assertEquals(IptablesCommands.insertIptablesRule(Chain.INPUT, "eth0", Protocol.TCP, 3306, Policy.ACCEPT),
+                insertIptablesRule);
+    }
+
+    @Test
+    public void testAppendIptablesRules() {
+        Assert.assertEquals(IptablesCommands.appendIptablesRule(Chain.INPUT, "eth0", Protocol.TCP, 3306, Policy.ACCEPT),
+                appendIptablesRule);
+    }
+
+    @Test
+    public void testInsertIptablesRulesForAllInterfaces() {
+        Assert.assertEquals(IptablesCommands.insertIptablesRule(Chain.INPUT, Protocol.TCP, 3306, Policy.ACCEPT),
+                insertIptablesRuleAll);
+    }
+
+    @Test
+    public void testAppendIptablesRulesForAllInterfaces() {
+        Assert.assertEquals(IptablesCommands.appendIptablesRule(Chain.INPUT, Protocol.TCP, 3306, Policy.ACCEPT),
+                appendIptablesRuleAll);
+    }
+
+    @Test
+    public void testSaveIptablesRules() {
+        Assert.assertEquals(IptablesCommands.saveIptablesRules(), saveIptablesRules);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/stream/StreamGobblerTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/stream/StreamGobblerTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/stream/StreamGobblerTest.java
new file mode 100644
index 0000000..0bb2b94
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/stream/StreamGobblerTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.util.stream;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.stream.StreamGobbler;
+import org.testng.annotations.Test;
+
+public class StreamGobblerTest {
+    private String NL = Os.LINE_SEPARATOR;
+
+    @Test
+    public void testGobbleStream() throws Exception {
+        byte[] bytes = new byte[] {'a','b','c'};
+        InputStream stream = new ByteArrayInputStream(bytes);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        StreamGobbler gobbler = new StreamGobbler(stream, out, null);
+        gobbler.start();
+        try {
+            gobbler.join(10*1000);
+            assertFalse(gobbler.isAlive());
+            assertEquals(new String(out.toByteArray()), "abc" + NL);
+        } finally {
+            gobbler.close();
+            gobbler.interrupt();
+        }
+    }
+    
+    @Test
+    public void testGobbleMultiLineBlockingStream() throws Exception {
+        PipedOutputStream pipedOutputStream = new PipedOutputStream();
+        PipedInputStream stream = new PipedInputStream(pipedOutputStream);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        StreamGobbler gobbler = new StreamGobbler(stream, out, null);
+        gobbler.start();
+        try {
+            pipedOutputStream.write("line1\n".getBytes());
+            assertEqualsEventually(out, "line1" + NL);
+
+            pipedOutputStream.write("line2\n".getBytes());
+            assertEqualsEventually(out, "line1" + NL + "line2" + NL);
+
+            pipedOutputStream.write("line".getBytes());
+            pipedOutputStream.write("3\n".getBytes());
+            assertEqualsEventually(out, "line1" + NL + "line2" + NL + "line3" + NL);
+
+            pipedOutputStream.close();
+            
+            gobbler.join(10*1000);
+            assertFalse(gobbler.isAlive());
+            assertEquals(new String(out.toByteArray()), "line1" + NL + "line2" + NL + "line3" + NL);
+        } finally {
+            gobbler.close();
+            gobbler.interrupt();
+        }
+    }
+    
+    private void assertEqualsEventually(final ByteArrayOutputStream out, final String expected) {
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertEquals(new String(out.toByteArray()), expected);
+            }});
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/stream/ThreadLocalStdoutStderrTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/stream/ThreadLocalStdoutStderrTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/stream/ThreadLocalStdoutStderrTest.java
new file mode 100644
index 0000000..e77db01
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/stream/ThreadLocalStdoutStderrTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.util.stream;
+
+import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.stream.ThreadLocalPrintStream;
+import org.apache.brooklyn.util.stream.ThreadLocalPrintStream.OutputCapturingContext;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class ThreadLocalStdoutStderrTest {
+
+    /** simple example showing how a capture to stdout can be set up */
+    @Test
+    public void testStdoutCapture() {
+        OutputCapturingContext capture = ThreadLocalPrintStream.stdout().captureTee();
+        System.out.println("hello");
+        String out = capture.end();
+        Assert.assertEquals("hello", out.trim());
+        
+        System.out.println("goodbye - not captured, restored normal output");
+        Assert.assertEquals("hello", out.trim());
+    }
+
+    @Test
+    public void testStdoutCaptureDetail() {
+        ThreadLocalPrintStream.stdout();
+        System.out.println("1 - not captured, but next goes to capture only");
+        OutputCapturingContext capture = ThreadLocalPrintStream.stdout().capture();
+        final String TWO = "2 - captured";
+        System.out.println(TWO);
+        Assert.assertEquals(TWO, capture.getOutputSoFar().trim());
+        String out = capture.end();
+        Assert.assertEquals(TWO, out.trim());
+        System.out.println("3 - not captured, restored normal output");
+        Assert.assertEquals(TWO, capture.getOutputSoFar().trim());
+    }
+    
+    @Test
+    public void testStderrCaptureDetail() {
+        ThreadLocalPrintStream.stderr();
+        System.err.println("1 - not captured, but next goes to capture only");
+        OutputCapturingContext capture = ThreadLocalPrintStream.stderr().capture();
+        final String TWO = "2 - captured";
+        System.err.println(TWO);
+        Assert.assertEquals(TWO, capture.getOutputSoFar().trim());
+        String out = capture.end();
+        Assert.assertEquals(TWO, out.trim());
+        System.err.println("3 - not captured, restored normal output");
+        Assert.assertEquals(TWO, capture.getOutputSoFar().trim());
+    }
+    
+    @Test
+    public void testStdoutCaptureTeeDetail() {
+        ThreadLocalPrintStream.stdout();
+        System.out.println("1 - not captured, but next go to capture and stdout");
+        OutputCapturingContext capture1 = ThreadLocalPrintStream.stdout().captureTee();
+        OutputCapturingContext capture2 = ThreadLocalPrintStream.stdout().captureTee();
+        final String TWO = "2 - captured";
+        System.out.println(TWO);
+        Assert.assertEquals(TWO, capture1.getOutputSoFar().trim());
+        Assert.assertEquals(TWO, capture2.getOutputSoFar().trim());
+        String out2 = capture2.end();
+        
+        final String THREE = "3 - captured by 1";
+        System.out.println(THREE);
+        String out1 = capture1.end();
+        
+        System.out.println("4 - not captured, restored normal output");
+        Assert.assertEquals(TWO, out2.trim());
+        Assert.assertEquals(TWO+Os.LINE_SEPARATOR+THREE, out1.trim());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/ByteSizeStringsTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/ByteSizeStringsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/ByteSizeStringsTest.java
new file mode 100644
index 0000000..64cd57b
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/ByteSizeStringsTest.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.text;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Arrays;
+
+import org.apache.brooklyn.test.FixedLocaleTest;
+import org.apache.brooklyn.util.text.ByteSizeStrings;
+import org.apache.brooklyn.util.text.Strings;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * Test the different {@link ByteSizeStrings} formatting options using a list of byte sizes.
+ */
+@Test
+public class ByteSizeStringsTest extends FixedLocaleTest {
+    
+    public void testSizeString() {
+        assertEquals(Strings.makeSizeString(-1), "-1 B");
+        assertEquals(Strings.makeSizeString(0), "0 B");
+        assertEquals(Strings.makeSizeString(999), "999 B");
+        assertEquals(Strings.makeSizeString(1024), "1024 B");
+        assertEquals(Strings.makeSizeString(1234), "1234 B");
+        assertEquals(Strings.makeSizeString(2345), "2.34 kB");
+        assertEquals(Strings.makeSizeString(4096), "4.10 kB");
+        assertEquals(Strings.makeSizeString(4567), "4.57 kB");
+        assertEquals(Strings.makeSizeString(65535), "65.5 kB");
+        assertEquals(Strings.makeSizeString(23456789L), "23.5 MB");
+        assertEquals(Strings.makeSizeString(23456789012L), "23.5 GB");
+        assertEquals(Strings.makeSizeString(23456789012345L), "23.5 TB");
+        assertEquals(Strings.makeSizeString(Long.MAX_VALUE), "9223372 TB");
+    }
+
+    public void testJavaSizeString() {
+        assertEquals(ByteSizeStrings.java().makeSizeString(-1), "-1");
+        assertEquals(ByteSizeStrings.java().makeSizeString(0), "0");
+        assertEquals(ByteSizeStrings.java().makeSizeString(999), "999");
+        assertEquals(ByteSizeStrings.java().makeSizeString(1024), "1024");
+        assertEquals(ByteSizeStrings.java().makeSizeString(1234), "1234");
+        assertEquals(ByteSizeStrings.java().makeSizeString(2345), "2345");
+        assertEquals(ByteSizeStrings.java().makeSizeString(4096), "4096");
+        assertEquals(ByteSizeStrings.java().makeSizeString(4567), "4567");
+        assertEquals(ByteSizeStrings.java().makeSizeString(6789), "6789");
+        assertEquals(ByteSizeStrings.java().makeSizeString(65535), "64k");
+        assertEquals(ByteSizeStrings.java().makeSizeString(23456789L), "22m");
+        assertEquals(ByteSizeStrings.java().makeSizeString(23456789012L), "22g");
+        assertEquals(ByteSizeStrings.java().makeSizeString(23456789012345L), "21000g");
+        assertEquals(ByteSizeStrings.java().makeSizeString(Long.MAX_VALUE), "8388608000g");
+    }
+
+    public void testISOSizeString() {
+        assertEquals(ByteSizeStrings.iso().makeSizeString(-1), "-1 B");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(0), "0 B");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(999), "999 B");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(1024), "1024 B");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(1234), "1234 B");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(2345), "2.29 KiB");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(4096), "4 KiB");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(4567), "4.46 KiB");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(6789), "6.63 KiB");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(65535), "64.0 KiB");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(23456789L), "22.4 MiB");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(23456789012L), "21.8 GiB");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(23456789012345L), "21.3 TiB");
+        assertEquals(ByteSizeStrings.iso().makeSizeString(Long.MAX_VALUE), "8388608 TiB");
+    }
+
+    public void testBuilder() {
+        ByteSizeStrings strings = ByteSizeStrings.builder()
+                .bytesPerMetricUnit(1024)
+                .precision(4)
+                .lowerLimit(5)
+                .maxLen(4)
+                .suffixBytes("b")
+                .suffixKilo("kb")
+                .suffixMega("Mb")
+                .suffixGiga("Gb")
+                .suffixTera("Tb")
+                .addSpace()
+                .build();
+
+        assertEquals(strings.makeSizeString(-1), "-1 b");
+        assertEquals(strings.makeSizeString(0), "0 b");
+        assertEquals(strings.makeSizeString(999), "999 b");
+        assertEquals(strings.makeSizeString(1024), "1024 b");
+        assertEquals(strings.makeSizeString(1234), "1234 b");
+        assertEquals(strings.makeSizeString(2345), "2345 b");
+        assertEquals(strings.makeSizeString(4096), "4096 b");
+        assertEquals(strings.makeSizeString(4567), "4567 b");
+        assertEquals(strings.makeSizeString(6789), "6.630 kb");
+        assertEquals(strings.makeSizeString(65535), "64.00 kb");
+        assertEquals(strings.makeSizeString(23456789L), "22.37 Mb");
+        assertEquals(strings.makeSizeString(23456789012L), "21.85 Gb");
+        assertEquals(strings.makeSizeString(23456789012345L), "21.33 Tb");
+        assertEquals(strings.makeSizeString(Long.MAX_VALUE), "8388608 Tb");
+    }
+
+    public void testFormatter() {
+        ByteSizeStrings iso = ByteSizeStrings.iso();
+        assertEquals(String.format("%s", iso.formatted(23456789L)), "22.4 MiB");
+        assertEquals(String.format("%.6s", iso.formatted(23456789L)), "22.3701 MiB");
+        assertEquals(String.format("%#s", iso.formatted(23456789L)), "23.5 MB");
+    }
+
+    public void testFunction() {
+        ByteSizeStrings iso = ByteSizeStrings.iso();
+        Iterable<String> bytes = Iterables.transform(Arrays.asList(23456789L, 23456789012L, 23456789012345L), iso);
+        assertEquals(Iterables.get(bytes, 0), "22.4 MiB");
+        assertEquals(Iterables.get(bytes, 1), "21.8 GiB");
+        assertEquals(Iterables.get(bytes, 2), "21.3 TiB");
+    }
+    
+    public void testParse() {
+        assertEquals(ByteSizeStrings.parse("1", "k"), 1024);
+        
+        // basics
+        assertEquals(ByteSizeStrings.parse("1b"), 1);
+        assertEquals(ByteSizeStrings.parse("1k"), 1024);
+        assertEquals(ByteSizeStrings.parse("1m"), 1024*1024);
+        assertEquals(ByteSizeStrings.parse("1g"), 1024*1024*1024);
+        assertEquals(ByteSizeStrings.parse("1t"), 1024L*1024*1024*1024);
+
+        // iso
+        assertEquals(ByteSizeStrings.parse("64.0 KiB"), 65536);
+        // metric
+        assertEquals(ByteSizeStrings.parse("64.0 KB"), 64000);
+        // java
+        assertEquals(ByteSizeStrings.parse("64.0k"), 65536);
+        
+        // spaces and things
+        assertEquals(ByteSizeStrings.parse("64k"), 65536);
+        assertEquals(ByteSizeStrings.parse("64 k"), 65536);
+        
+        // smaller than zero
+        assertEquals(ByteSizeStrings.parse("0.5t"), 512L*1024*1024*1024);
+
+        // applying default unit
+        assertEquals(ByteSizeStrings.parse("1", "k"), 1024);
+        // not applying default unit
+        assertEquals(ByteSizeStrings.parse("1k", "m"), 1024);
+        // forcing use of metric
+        assertEquals(ByteSizeStrings.parse("1k", "m", ByteSizeStrings.metric()), 1000);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/ComparableVersionTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/ComparableVersionTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/ComparableVersionTest.java
new file mode 100644
index 0000000..16b07b8
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/ComparableVersionTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util.text;
+
+import org.apache.brooklyn.util.text.NaturalOrderComparator;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class ComparableVersionTest {
+
+    public static final NaturalOrderComparator noc = new NaturalOrderComparator();
+    
+    @Test
+    public void testBasicOnes() {
+        Assert.assertEquals(0, noc.compare("a", "a"));
+        Assert.assertTrue(noc.compare("a", "b") < 0);
+        Assert.assertTrue(noc.compare("b", "a") > 0);
+        
+        Assert.assertTrue(noc.compare("9", "10") < 0);
+        Assert.assertTrue(noc.compare("10", "9") > 0);
+        
+        Assert.assertTrue(noc.compare("b10", "a9") > 0);
+        Assert.assertTrue(noc.compare("b9", "a10") > 0);
+        
+        Assert.assertTrue(noc.compare(" 9", "10") < 0);
+        Assert.assertTrue(noc.compare("10", " 9") > 0);
+    }
+
+    @Test
+    public void testVersionNumbers() {
+        Assert.assertEquals(0, noc.compare("10.5.8", "10.5.8"));
+        Assert.assertTrue(noc.compare("10.5", "9.9") > 0);
+        Assert.assertTrue(noc.compare("10.5.1", "10.5") > 0);
+        Assert.assertTrue(noc.compare("10.5.1", "10.6") < 0);
+        Assert.assertTrue(noc.compare("10.5.1-1", "10.5.1-0") > 0);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/IdentifiersTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/IdentifiersTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/IdentifiersTest.java
new file mode 100644
index 0000000..1b2068f
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/IdentifiersTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.util.text;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.brooklyn.util.text.Identifiers;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class IdentifiersTest {
+
+    private static final Logger log = LoggerFactory.getLogger(IdentifiersTest.class);
+    
+    @Test
+    public void testRandomId() {
+        String id1 = Identifiers.makeRandomId(4);
+        Assert.assertEquals(id1.length(), 4);
+        String id2 = Identifiers.makeRandomId(4);
+        Assert.assertNotEquals(id1, id2);
+    }
+
+    //The test is disabled since it takes a while to finish
+    //and there is still the possibility that it could fail.
+    @Test(enabled = false)
+    public void testRandomIdRandomness() {
+        int collisionTestCnt = 100000;
+        int sampleSize = 2000;
+        
+        int duplicateTests = 0;
+        for(int testIdx = 0; testIdx < collisionTestCnt; testIdx++) {
+            Set<String> randomIds = new HashSet<String>();
+            for (int sampleCnt = 0; sampleCnt < sampleSize; sampleCnt++) {
+                if(!randomIds.add(Identifiers.makeRandomId(4))) {
+                    duplicateTests++;
+                    break;
+                }
+            }
+        }
+        double probability = ((double)duplicateTests)*100/collisionTestCnt;
+        log.info("testRandomIdRandomness probability = " + probability);
+        Assert.assertEquals(probability, 15, 0.5d, "Expected probability of collision with id of length 4 and 2000 samples is 15%.");
+    }
+
+    @Test
+    public void testFromHash() {
+        String id1 = Identifiers.makeIdFromHash("Hello".hashCode());
+        Assert.assertTrue(!Strings.isBlank(id1));
+        
+        String id2 = Identifiers.makeIdFromHash("hello".hashCode());
+        String id3 = Identifiers.makeIdFromHash("hello".hashCode());
+        Assert.assertEquals(id2, id3);
+        Assert.assertNotEquals(id1, id2);
+
+        Assert.assertEquals(Identifiers.makeIdFromHash(0), "A");
+        
+        String idLong = Identifiers.makeIdFromHash(Long.MAX_VALUE);
+        log.info("ID's made from hash, of 'hello' is "+id1+" and of Long.MAX_VALUE is "+idLong);
+        Assert.assertTrue(idLong.length() > id1.length());
+    }
+
+    @Test
+    public void testFromNegativeHash() {
+        String id1 = Identifiers.makeIdFromHash(-1);
+        Assert.assertTrue(!Strings.isBlank(id1));
+        log.info("ID's made from hash, of -1 is "+id1+" and of Long.MIN_VALUE is "+Identifiers.makeIdFromHash(Long.MIN_VALUE));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/KeyValueParserTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/KeyValueParserTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/KeyValueParserTest.java
new file mode 100644
index 0000000..8ca1528
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/KeyValueParserTest.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.util.text;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.util.text.KeyValueParser;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+/**
+ * The ConfigParserTest
+ *
+ * @author aled
+ **/
+public class KeyValueParserTest {
+
+    // Gives an example of how to do this with guava. But note that does not
+    // give the same behaviour for quoted values.
+    @Test
+    public void testGuavaEquivalent() {
+        assertOrderedMapsEqual(Splitter.on(",").withKeyValueSeparator("=").split("a=x,b=y"), ImmutableMap.of("a", "x", "b", "y"));
+    }
+    
+    @Test
+    public void testTrimsWhiteSpaceOutsideOfQuotes() throws Exception {
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a=x"), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a=x "), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap(" a=x"), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a =x"), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a= x"), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a = x"), ImmutableMap.of("a", "x"));
+
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a=\"x\""), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a=\"x\" "), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap(" a=\"x\""), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a =\"x\""), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a= \"x\""), ImmutableMap.of("a", "x"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a = \"x\""), ImmutableMap.of("a", "x"));
+        
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a=x,b=y"), ImmutableMap.of("a", "x", "b", "y"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a=x, b=y"), ImmutableMap.of("a", "x", "b", "y"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a=x,\tb=y"), ImmutableMap.of("a", "x", "b", "y"));
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a=x ,b=y"), ImmutableMap.of("a", "x", "b", "y"));
+    }
+
+    @Test
+    public void testPreservesWhiteSpaceInsideQuotes() throws Exception {
+        assertOrderedMapsEqual(KeyValueParser.parseMap("a=\" x \""), ImmutableMap.of("a", " x "));
+    }
+
+    @Test
+    public void testConfigParseMap() throws Exception {
+        Map<String, String> result = KeyValueParser.parseMap("a=x, b=\"x x\", c, \"d d\"");
+        Map<String, String> expected = Maps.newLinkedHashMap();
+        expected.put("a", "x");
+        expected.put("b", "x x");
+        expected.put("c", null);
+        expected.put("d d", null);
+        
+        assertOrderedMapsEqual(result, expected);
+        assertOrderedMapsEqual(KeyValueParser.parseMap(KeyValueParser.toLine(expected)), expected);
+    }
+    
+    @Test
+    public void testConfigParseMapWithBigWhiteSpace() throws Exception {
+        Map<String, String> result = KeyValueParser.parseMap(" a=x,  b=y ");
+        Map<String, String> expected = Maps.newLinkedHashMap();
+        expected.put("a", "x");
+        expected.put("b", "y");
+        
+        assertOrderedMapsEqual(result, expected);
+        assertOrderedMapsEqual(KeyValueParser.parseMap(KeyValueParser.toLine(expected)), expected);
+    }
+    
+    @Test
+    public void testConfigParseMapWithEmptyValue() throws Exception {
+        Map<String, String> result = KeyValueParser.parseMap("a=\"\"");
+        Map<String, String> expected = Maps.newLinkedHashMap();
+        expected.put("a", "");
+        
+        assertOrderedMapsEqual(result, expected);
+        assertOrderedMapsEqual(KeyValueParser.parseMap(KeyValueParser.toLine(expected)), expected);
+    }
+    
+    @Test
+    public void testConfigParseMapWithNoValue() throws Exception {
+        Map<String, String> result = KeyValueParser.parseMap("a=, b");
+        Map<String, String> expected = Maps.newLinkedHashMap();
+        expected.put("a", "");
+        expected.put("b", null);
+        
+        assertOrderedMapsEqual(result, expected);
+        assertOrderedMapsEqual(KeyValueParser.parseMap(KeyValueParser.toLine(expected)), expected);
+    }
+    
+    @Test
+    public void testConfigParseList() throws Exception {
+        assertParsedList(Arrays.asList("a", "b b"));
+        assertParsedList(Arrays.asList("\"a\" \"a\""));
+        assertParsedList(Arrays.<String>asList());
+        
+        StringBuilder ascii = new StringBuilder();
+        for (int i = 0; i <= 127; i++) {
+            ascii.append((char)i);
+        }
+        assertParsedList(Arrays.asList(ascii.toString()));
+    }
+    
+    @Test
+    public void testConfigParseListWithEmptyValue() throws Exception {
+        assertParsedList(Arrays.asList(""));
+        assertEquals(KeyValueParser.parseList("\"\""), Arrays.asList(""));
+    }
+    
+    private void assertParsedList(List<String> expected) {
+        assertEquals(KeyValueParser.parseList(KeyValueParser.toLine(expected)), expected);
+    }
+    
+    private void assertOrderedMapsEqual(Map<?,?> map1, Map<?,?> map2) {
+        Assert.assertEquals(map1, map2);
+        Assert.assertEquals(ImmutableList.copyOf(map1.keySet()), ImmutableList.copyOf(map2.keySet()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/NaturalOrderComparatorTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/NaturalOrderComparatorTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/NaturalOrderComparatorTest.java
new file mode 100644
index 0000000..3e99e58
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/NaturalOrderComparatorTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.util.text;
+
+import org.apache.brooklyn.util.text.ComparableVersion;
+import org.apache.brooklyn.util.text.NaturalOrderComparator;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class NaturalOrderComparatorTest {
+
+    public static final NaturalOrderComparator noc = new NaturalOrderComparator();
+    
+    ComparableVersion v = new ComparableVersion("10.5.8");
+    ComparableVersion v_rc2 = new ComparableVersion("10.5.8-rc2");
+    
+    @Test
+    public void testBasicOnes() {
+        Assert.assertTrue(v.isGreaterThanAndNotEqualTo("10.5"));
+        Assert.assertTrue(v.isGreaterThanOrEqualTo("10.5.8"));
+        Assert.assertFalse(v.isGreaterThanAndNotEqualTo("10.5.8"));
+
+        Assert.assertTrue(v.isLessThanAndNotEqualTo("10.6"));
+        Assert.assertTrue(v.isLessThanOrEqualTo("10.5.8"));
+        Assert.assertFalse(v.isLessThanAndNotEqualTo("10.5.8"));
+        
+        Assert.assertTrue(v.isLessThanAndNotEqualTo("10.5.8.1"));
+        
+        Assert.assertTrue(v_rc2.isLessThanAndNotEqualTo("10.5.8-rc3")) ;
+        Assert.assertTrue(v_rc2.isGreaterThanAndNotEqualTo("10.5.8-rc1"));
+        
+        Assert.assertTrue(v_rc2.isGreaterThanAndNotEqualTo("10.5.8-beta1")==v_rc2.isGreaterThanAndNotEqualTo("10.5.8-beta3"));
+        
+        Assert.assertTrue(v.isInRange("[10.5,10.6)"));
+        Assert.assertFalse(v.isInRange("[10.5,10.5.8)"));
+        Assert.assertTrue(v.isInRange("[10.5,)"));
+        Assert.assertTrue(v.isInRange("[9,)"));
+        Assert.assertFalse(v.isInRange("(10.5.8,)"));
+        Assert.assertFalse(v.isInRange("[10.6,)"));
+        Assert.assertTrue(v.isInRange("[,11)"));
+        Assert.assertTrue(v.isInRange("[,]"));
+    }
+
+    @Test(expectedExceptions={IllegalArgumentException.class})
+    public void testError1() { v.isInRange("10.5"); }
+    @Test(expectedExceptions={IllegalArgumentException.class})
+    public void testError2() { v.isInRange("[10.5"); }
+    @Test(expectedExceptions={IllegalArgumentException.class})
+    public void testError3() { v.isInRange("[10.5]"); }
+
+    @Test(groups="WIP", enabled=false)
+    public void testUnderscoreDoesNotChangeMeaningOfNumberInNoc() {
+        // why??
+        Assert.assertTrue(noc.compare("0.0.0_SNAPSHOT", "0.0.1-SNAPSHOT-20141111114709760") < 0);
+
+        Assert.assertTrue(v.isGreaterThanAndNotEqualTo(v_rc2.version));
+        Assert.assertTrue(v_rc2.isLessThanAndNotEqualTo(v.version));
+    }
+    
+    @Test(groups="WIP", enabled=false)
+    public void testUnderscoreDoesNotChangeMeaningOfNumberInOurWorld() {
+        Assert.assertTrue(new ComparableVersion("0.0.0_SNAPSHOT").isLessThanAndNotEqualTo("0.0.1-SNAPSHOT-20141111114709760"));
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/QuotedStringTokenizerTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/QuotedStringTokenizerTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/QuotedStringTokenizerTest.java
new file mode 100644
index 0000000..968dd5e
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/QuotedStringTokenizerTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.util.text;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.brooklyn.util.text.QuotedStringTokenizer;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class QuotedStringTokenizerTest {
+
+    // have to initialise to use the methods (instance as it can take custom tokens)
+    private QuotedStringTokenizer defaultTokenizer= new QuotedStringTokenizer("", true); 
+
+    @Test
+    public void testQuoting() throws Exception {
+        assertQuoteUnquoteFor("a=b");
+        assertQuoteUnquoteFor("a=\"things\",b=c");
+        assertQuoteUnquoteFor("thing=\"\"");
+        assertQuoteUnquoteFor("\"thing\"=\"\"");
+        assertQuoteUnquoteFor("");
+        assertQuoteUnquoteFor("\"");
+        assertQuoteUnquoteFor("\"\"");
+
+        assertUnquoteFor("", "''");
+        assertUnquoteFor("thing=", "\"thing\"=\"\"");
+        assertUnquoteFor("a=", "a=\"\"");
+    }
+
+    @Test
+    public void testTokenizing() throws Exception {
+        testResultingTokens("foo,bar,baz", "\"", false, ",", false, "foo", "bar", "baz");
+        testResultingTokens("\"foo,bar\",baz", "\"", false, ",", false, "foo,bar", "baz");
+        testResultingTokens("\"foo,,bar\",baz", "\"", false, ",", false, "foo,,bar", "baz");
+
+        // Have seen "the operator ""foo"" is not recognised" entries in BAML CSV files.
+        testResultingTokens("foo \"\"bar\"\" baz", "\"", false, ",", false, "foo bar baz");
+        testResultingTokens("\"foo \"\"bar\"\" baz\"", "\"", false, ",", false, "foo bar baz");
+
+        // FIXME: would like to return empty tokens when we encounter adjacent delimiters, but need
+        // to work around brain-dead java.util.StringTokenizer to do this.
+        // testResultingTokens("foo,,baz", "\"", false, ",", false, "foo", "", "baz");
+    }
+
+    @Test
+    public void testTokenizingBuilder() throws Exception {
+        Assert.assertEquals(Arrays.asList("foo", "bar"), QuotedStringTokenizer.builder().buildList("foo bar"));
+        Assert.assertEquals(Arrays.asList("foo,bar"), QuotedStringTokenizer.builder().buildList("foo,bar"));
+        Assert.assertEquals(Arrays.asList("foo", "bar"), QuotedStringTokenizer.builder().delimiterChars(",").buildList("foo,bar"));
+        Assert.assertEquals(Arrays.asList("foo", " bar"), QuotedStringTokenizer.builder().delimiterChars(",").buildList("foo, bar"));
+        Assert.assertEquals(Arrays.asList("foo", "bar"), QuotedStringTokenizer.builder().addDelimiterChars(",").buildList("foo, bar"));
+    }
+
+    @Test
+    public void testCommaInQuotes() throws Exception {
+        List<String> l = QuotedStringTokenizer.builder().addDelimiterChars(",").buildList("location1,byon:(hosts=\"loc2,loc3\"),location4");
+        Assert.assertEquals(Arrays.asList("location1", "byon:(hosts=\"loc2,loc3\")", "location4"), l);
+    }
+
+    /** not implemented yet */
+    @Test(enabled=false)
+    public void testCommaInParentheses() throws Exception {
+        List<String> l = QuotedStringTokenizer.builder().addDelimiterChars(",").buildList("location1, byon:(hosts=\"loc2,loc3\",user=foo),location4");
+        Assert.assertEquals(Arrays.asList("location1", "byon:(hosts=\"loc2,loc3\",user=foo)", "location4"), l);
+    }
+
+    private void testResultingTokens(String input, String quoteChars, boolean includeQuotes, String delimiterChars, boolean includeDelimiters, String... expectedTokens) {
+        QuotedStringTokenizer tok = new QuotedStringTokenizer(input, quoteChars, includeQuotes, delimiterChars, includeDelimiters);
+        testResultingTokens(input, tok, expectedTokens);
+    }
+
+    private void testResultingTokens(String input, QuotedStringTokenizer tok, String... expectedTokens) {
+        List<String> actual = new LinkedList<String>();
+        while (tok.hasMoreTokens()) actual.add(tok.nextToken());
+        assertEquals(actual, Arrays.asList(expectedTokens), "Wrong tokens returned.");
+    }
+
+    private void assertQuoteUnquoteFor(String unquoted) {
+        String quoted = defaultTokenizer.quoteToken(unquoted);
+        String reunquoted = defaultTokenizer.unquoteToken(quoted);
+        //System.out.println("orig="+unquoted+"  quoted="+quoted+"   reunquoted="+reunquoted);
+        assertEquals(reunquoted, unquoted);
+    }
+
+    private void assertUnquoteFor(String expected, String quoted) {
+        String unquoted = defaultTokenizer.unquoteToken(quoted);
+        //System.out.println("expected="+expected+"  quoted="+quoted+"   unquoted="+unquoted);
+        assertEquals(unquoted, expected);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/StringEscapesTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/StringEscapesTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringEscapesTest.java
new file mode 100644
index 0000000..b864240
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringEscapesTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.util.text;
+
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.text.StringEscapes;
+import org.apache.brooklyn.util.text.StringEscapes.BashStringEscapes;
+import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class StringEscapesTest {
+
+    @Test
+    public void testEscapeSql() {
+        Assert.assertEquals(StringEscapes.escapeSql("I've never been to Brooklyn"), "I''ve never been to Brooklyn");
+    }
+
+    
+    @Test
+    public void testBashEscaping() {
+        Assert.assertEquals(
+            BashStringEscapes.doubleQuoteLiteralsForBash("-Dname=Bob Johnson", "-Dnet.worth=$100"),
+            "\"-Dname=Bob Johnson\" \"-Dnet.worth=\\$100\"");
+    }
+
+    @Test
+    public void testBashEscapable() {
+        Assert.assertTrue(BashStringEscapes.isValidForDoubleQuotingInBash("Bob Johnson"));
+        Assert.assertFalse(BashStringEscapes.isValidForDoubleQuotingInBash("\""));
+        Assert.assertTrue(BashStringEscapes.isValidForDoubleQuotingInBash("\\\""));
+    }    
+    
+    /** Bash handles ampersand in double quoted strings without escaping. */
+    @Test
+    public void testBashEscapableAmpersand() {
+        Assert.assertTrue(BashStringEscapes.isValidForDoubleQuotingInBash("&"));
+        Assert.assertTrue(BashStringEscapes.isValidForDoubleQuotingInBash("Marks & Spencer"));
+    }
+
+    @Test
+    public void testJavaUnwrap() {
+        Assert.assertEquals(JavaStringEscapes.unwrapJavaString("\"Hello World\""), "Hello World");
+        Assert.assertEquals(JavaStringEscapes.unwrapJavaString("\"Hello \\\"Bob\\\"\""), "Hello \"Bob\"");
+        try {
+            JavaStringEscapes.unwrapJavaString("Hello World");
+            Assert.fail("Should have thrown");
+        } catch (Exception e) { /* expected */ }
+        try {
+            // missing final quote
+            JavaStringEscapes.unwrapJavaString("\"Hello \\\"Bob\\\"");
+            Assert.fail("Should have thrown");
+        } catch (Exception e) { /* expected */ }
+        
+        Assert.assertEquals(JavaStringEscapes.unwrapJavaStringIfWrapped("\"Hello World\""), "Hello World");
+        Assert.assertEquals(JavaStringEscapes.unwrapJavaStringIfWrapped("\"Hello \\\"Bob\\\"\""), "Hello \"Bob\"");
+        Assert.assertEquals(JavaStringEscapes.unwrapJavaStringIfWrapped("Hello World"), "Hello World");
+        try {
+            // missing final quote
+            JavaStringEscapes.unwrapJavaStringIfWrapped("\"Hello \\\"Bob\\\"");
+            Assert.fail("Should have thrown");
+        } catch (Exception e) { /* expected */ }
+    }
+    
+    @Test
+    public void testJavaEscape() {
+        Assert.assertEquals(JavaStringEscapes.wrapJavaString("Hello \"World\""), "\"Hello \\\"World\\\"\"");
+    }
+    
+    @Test
+    public void testJavaLists() {
+        Assert.assertEquals(MutableList.of("hello", "world"),
+            JavaStringEscapes.unwrapQuotedJavaStringList("\"hello\", \"world\"", ","));
+        try {
+            JavaStringEscapes.unwrapQuotedJavaStringList("\"hello\", world", ",");
+            Assert.fail("Should have thrown");
+        } catch (Exception e) { /* expected */ }
+        
+        Assert.assertEquals(MutableList.of("hello", "world"),
+            JavaStringEscapes.unwrapJsonishListIfPossible("\"hello\", \"world\""));
+        Assert.assertEquals(MutableList.of("hello"),
+            JavaStringEscapes.unwrapJsonishListIfPossible("hello"));
+        Assert.assertEquals(MutableList.of("hello", "world"),
+            JavaStringEscapes.unwrapJsonishListIfPossible("hello, world"));
+        Assert.assertEquals(MutableList.of("hello", "world"),
+            JavaStringEscapes.unwrapJsonishListIfPossible("\"hello\", world"));
+        Assert.assertEquals(MutableList.of("hello", "world"),
+            JavaStringEscapes.unwrapJsonishListIfPossible("[ \"hello\", world ]"));
+        // if can't parse e.g. because contains double quote, then returns original string as single element list
+        Assert.assertEquals(MutableList.of("hello\", \"world\""),
+            JavaStringEscapes.unwrapJsonishListIfPossible("hello\", \"world\""));
+        Assert.assertEquals(MutableList.of(),
+            JavaStringEscapes.unwrapJsonishListIfPossible(" "));
+        Assert.assertEquals(MutableList.of(""),
+            JavaStringEscapes.unwrapJsonishListIfPossible("\"\""));
+        Assert.assertEquals(MutableList.of("x"),
+            JavaStringEscapes.unwrapJsonishListIfPossible(",,x,"));
+        Assert.assertEquals(MutableList.of("","x",""),
+            JavaStringEscapes.unwrapJsonishListIfPossible("\"\",,x,\"\""));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/StringFunctionsTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/StringFunctionsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringFunctionsTest.java
new file mode 100644
index 0000000..d00b6a2
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringFunctionsTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.util.text;
+
+import org.apache.brooklyn.util.text.StringFunctions;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class StringFunctionsTest {
+
+    @Test
+    public static void testPrepend() {
+        Assert.assertEquals(StringFunctions.prepend("Hello ").apply("World"), "Hello World");
+    }
+    
+    @Test
+    public static void testFormatter() {
+        Assert.assertEquals(StringFunctions.formatter("Hello %s").apply("World"), "Hello World");
+    }
+    
+    @Test
+    public static void testFormatterForArray() {
+        Assert.assertEquals(StringFunctions.formatterForArray("Hello %s").apply(new Object[] { "World" }), "Hello World");
+    }
+    
+    @Test
+    public static void testSurround() {
+        Assert.assertEquals(StringFunctions.surround("goodbye ", " world").apply("cruel"), "goodbye cruel world");
+    }
+    
+    @Test
+    public static void testLowerCase() {
+        Assert.assertEquals(StringFunctions.toLowerCase().apply("Hello World"), "hello world");
+    }
+    
+    @Test
+    public static void testUpperCase() {
+        Assert.assertEquals(StringFunctions.toUpperCase().apply("Hello World"), "HELLO WORLD");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/StringPredicatesTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/StringPredicatesTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringPredicatesTest.java
new file mode 100644
index 0000000..219e948
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringPredicatesTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.text;
+
+import org.apache.brooklyn.util.text.StringPredicates;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public class StringPredicatesTest {
+
+    @Test
+    public static void testIsBlank() {
+        Assert.assertTrue(StringPredicates.isBlank().apply(""));
+        Assert.assertTrue(StringPredicates.isBlank().apply(" \n\t"));
+        Assert.assertTrue(StringPredicates.isBlank().apply(null));
+        Assert.assertFalse(StringPredicates.isBlank().apply(" hi "));
+    }
+    
+    @Test
+    public static void testContainsLiteral() {
+        Assert.assertTrue(StringPredicates.containsLiteral("xx").apply("texxxt tessst"));
+        Assert.assertFalse(StringPredicates.containsLiteral("xx").apply("text test"));
+        Assert.assertFalse(StringPredicates.containsLiteral("xx").apply("texXxt tessst"));
+        
+        Assert.assertTrue(StringPredicates.containsLiteralIgnoreCase("xx").apply("texxxt tessst"));
+        Assert.assertFalse(StringPredicates.containsLiteralIgnoreCase("xx").apply("text test"));
+        Assert.assertTrue(StringPredicates.containsLiteralIgnoreCase("xx").apply("texXxt tessst"));
+        
+        Assert.assertTrue(StringPredicates.containsAllLiterals("xx", "ss").apply("texxxt tessst"));
+        Assert.assertFalse(StringPredicates.containsAllLiterals("xx", "tt").apply("texxxt tessst"));
+    }
+    
+    @Test
+    public static void testEqualToAny() {
+        Assert.assertTrue(StringPredicates.equalToAny(ImmutableSet.of("1", "2")).apply("2"));
+        Assert.assertFalse(StringPredicates.equalToAny(ImmutableSet.of("1", "2")).apply("3"));
+    }
+    
+    @Test
+    public static void testStartsWith() {
+        Assert.assertTrue(StringPredicates.startsWith("t").apply("test"));
+        Assert.assertFalse(StringPredicates.startsWith("v").apply("test"));
+        
+        Assert.assertTrue(StringPredicates.isStringStartingWith("t").apply("test"));
+        Assert.assertFalse(StringPredicates.isStringStartingWith("t").apply(true));
+    }
+    
+    @Test
+    public static void testMatches() {
+        Assert.assertTrue(StringPredicates.matchesRegex("t.*").apply("test"));
+        Assert.assertFalse(StringPredicates.matchesRegex("v.*").apply("test"));
+        
+        Assert.assertTrue(StringPredicates.matchesGlob("t*").apply("test"));
+        Assert.assertFalse(StringPredicates.matchesGlob("v*").apply("test"));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/test/java/org/apache/brooklyn/util/text/StringShortenerTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/StringShortenerTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringShortenerTest.java
new file mode 100644
index 0000000..90b0cad
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringShortenerTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util.text;
+
+import org.apache.brooklyn.util.text.StringShortener;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class StringShortenerTest {
+
+    @Test
+    public void testSimpleShortener() {
+        StringShortener ss = new StringShortener()
+            .separator("-")
+            .append("1", "hello")
+            .append("2", "new")
+            .append("3", "world")
+            .canRemove("2")
+            .canTruncate("1", 2)
+            .canTruncate("3", 2);
+        
+        Assert.assertEquals(ss.getStringOfMaxLength(12), "hello-world");
+        Assert.assertEquals(ss.getStringOfMaxLength(10), "hell-world");
+        Assert.assertEquals(ss.getStringOfMaxLength(6), "he-wor");
+        Assert.assertEquals(ss.getStringOfMaxLength(5), "he-wo");
+        Assert.assertEquals(ss.getStringOfMaxLength(4), "he-w");
+        Assert.assertEquals(ss.getStringOfMaxLength(0), "");
+    }
+
+    @Test
+    public void testEdgeCases() {
+        StringShortener ss = new StringShortener();
+        ss.separator(null);
+        Assert.assertEquals(ss.getStringOfMaxLength(4), "");
+        ss.append("1", "hello");
+        Assert.assertEquals(ss.getStringOfMaxLength(8), "hello");
+        Assert.assertEquals(ss.getStringOfMaxLength(4), "hell");
+        ss.append("2", "world");
+        ss.append("3", null);
+        Assert.assertEquals(ss.getStringOfMaxLength(15), "helloworld");
+        Assert.assertEquals(ss.getStringOfMaxLength(8), "hellowor");
+        ss.canTruncate("1", 2);
+        Assert.assertEquals(ss.getStringOfMaxLength(8), "helworld");
+        Assert.assertEquals(ss.getStringOfMaxLength(5), "hewor");
+        Assert.assertEquals(ss.getStringOfMaxLength(2), "he");
+        Assert.assertEquals(ss.getStringOfMaxLength(0), "");
+    }
+
+}