brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aleds...@apache.org
Subject [16/62] [abbrv] incubator-brooklyn git commit: rename core’s o.a.b.entity to o.a.b.core.entity
Date Wed, 19 Aug 2015 21:20:50 GMT
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/OwnedChildrenTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/OwnedChildrenTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/OwnedChildrenTest.java
new file mode 100644
index 0000000..dede9aa
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/OwnedChildrenTest.java
@@ -0,0 +1,213 @@
+/*
+ * 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.entity;
+
+import static org.apache.brooklyn.test.Asserts.assertEqualsIgnoringOrder;
+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 org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.entity.AbstractApplication;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.Entities;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class OwnedChildrenTest {
+
+    private Application app;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() {
+        app = new AbstractApplication() {};
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown(){
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    // Tests that the deprecated "owner" still works
+    @Test
+    public void testSetOwnerInConstructorMap() {
+        Entity e = new AbstractEntity(app) {};
+        
+        assertEquals(e.getParent(), app);
+        assertEqualsIgnoringOrder(app.getChildren(), ImmutableList.of(e));
+        assertEquals(e.getApplication(), app);
+    }
+    
+    @Test
+    public void testSetParentInConstructorMap() {
+        Entity e = new AbstractEntity(app) {};
+        
+        assertEquals(e.getParent(), app);
+        assertEqualsIgnoringOrder(app.getChildren(), ImmutableList.of(e));
+        assertEquals(e.getApplication(), app);
+    }
+    
+    @Test
+    public void testSetParentInConstructorArgument() {
+        Entity e = new AbstractEntity(app) {};
+        
+        assertEquals(e.getParent(), app);
+        assertEqualsIgnoringOrder(app.getChildren(), ImmutableList.of(e));
+        assertEquals(e.getApplication(), app);
+    }
+    
+    @Test
+    public void testSetParentInSetterMethod() {
+        Entity e = new AbstractEntity() {};
+        e.setParent(app);
+        
+        assertEquals(e.getParent(), app);
+        assertEqualsIgnoringOrder(app.getChildren(), ImmutableList.of(e));
+        assertEquals(e.getApplication(), app);
+    }
+
+    @Test
+    public void testAddChild() {
+        Entity e = new AbstractEntity() {};
+        app.addChild(e);
+        
+        assertEquals(e.getParent(), app);
+        assertEqualsIgnoringOrder(app.getChildren(), ImmutableList.of(e));
+        assertEquals(e.getApplication(), app);
+    }
+    
+    @Test
+    public void testSetParentWhenMatchesParentSetInConstructor() {
+        Entity e = new AbstractEntity(app) {};
+        e.setParent(app);
+        
+        assertEquals(e.getParent(), app);
+        assertEqualsIgnoringOrder(app.getChildren(), ImmutableList.of(e));
+    }
+    
+    @Test(expectedExceptions = UnsupportedOperationException.class)
+    public void testSetParentWhenDiffersFromParentSetInConstructor() {
+        Entity e = new AbstractEntity(app) {};
+        Entity e2 = new AbstractEntity() {};
+        e.setParent(e2);
+        fail();
+    }
+    
+    @Test
+    public void testParentCanHaveMultipleChildren() {
+        Entity e = new AbstractEntity(app) {};
+        Entity e2 = new AbstractEntity(app) {};
+        
+        assertEquals(e.getParent(), app);
+        assertEquals(e2.getParent(), app);
+        assertEqualsIgnoringOrder(app.getChildren(), ImmutableList.of(e,e2));
+    }
+    
+    @Test
+    public void testHierarchyOfOwners() {
+        Entity e = new AbstractEntity(app) {};
+        Entity e2 = new AbstractEntity(e) {};
+        Entity e3 = new AbstractEntity(e2) {};
+        
+        assertEquals(app.getParent(), null);
+        assertEquals(e.getParent(), app);
+        assertEquals(e2.getParent(), e);
+        assertEquals(e3.getParent(), e2);
+        
+        assertEqualsIgnoringOrder(app.getChildren(), ImmutableList.of(e));
+        assertEqualsIgnoringOrder(e.getChildren(), ImmutableList.of(e2));
+        assertEqualsIgnoringOrder(e2.getChildren(), ImmutableList.of(e3));
+        assertEqualsIgnoringOrder(e3.getChildren(), ImmutableList.of());
+    }
+    
+    @Test(enabled = false) // FIXME fails currently
+    public void testRemoveChild() {
+        Entity e = new AbstractEntity(app) {};
+        app.removeChild(e);
+        
+        assertEqualsIgnoringOrder(app.getChildren(), ImmutableList.of());
+        assertEquals(e.getParent(), null);
+    }
+    
+    @Test
+    public void testParentalLoopForbiddenViaAddChild() {
+        Entity e = new AbstractEntity() {};
+        Entity e2 = new AbstractEntity(e) {};
+        try {
+            e2.addChild(e);
+            fail();
+        } catch (IllegalStateException ex) {
+            // success
+        }
+        
+        assertEqualsIgnoringOrder(e.getChildren(), ImmutableList.of(e2));
+        assertEqualsIgnoringOrder(e2.getChildren(), ImmutableList.of());
+        assertEquals(e.getParent(), null);
+        assertEquals(e2.getParent(), e);
+    }
+    
+    @Test
+    public void testParentalLoopForbiddenViaSetParent() {
+        Entity e = new AbstractEntity() {};
+        Entity e2 = new AbstractEntity(e) {};
+        try {
+            e.setParent(e2);
+            fail();
+        } catch (IllegalStateException ex) {
+			ex.printStackTrace();
+            // success
+        }
+        assertEqualsIgnoringOrder(e.getChildren(), ImmutableList.of(e2));
+        assertEqualsIgnoringOrder(e2.getChildren(), ImmutableList.of());
+        assertEquals(e.getParent(), null);
+        assertEquals(e2.getParent(), e);
+    }
+    
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testParentingOneselfForbidden() {
+        AbstractEntity e = new AbstractEntity() {};
+        e.addChild(e);
+        fail();
+    }
+    
+    @Test
+    public void testIsAncestor() {
+        AbstractEntity e = new AbstractEntity(app) {};
+        AbstractEntity e2 = new AbstractEntity(e) {};
+        
+		assertTrue(Entities.isAncestor(e2, app));
+		assertTrue(Entities.isAncestor(e2, e));
+		assertFalse(Entities.isAncestor(e2, e2));
+    }
+    
+    @Test
+    public void testIsDescendant() {
+        AbstractEntity e = new AbstractEntity(app) {};
+        AbstractEntity e2 = new AbstractEntity(e) {};
+
+		assertTrue(Entities.isDescendant(app, e));
+		assertTrue(Entities.isDescendant(app, e2));
+		assertFalse(Entities.isDescendant(e2, e));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/PolicyRegistrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/PolicyRegistrationTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/PolicyRegistrationTest.java
new file mode 100644
index 0000000..325168a
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/PolicyRegistrationTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.entity;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.lifecycle.PolicyDescriptor;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.core.test.entity.TestEntityNoEnrichersImpl;
+import org.apache.brooklyn.policy.core.AbstractPolicy;
+import org.apache.brooklyn.test.TestUtils;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+public class PolicyRegistrationTest extends BrooklynAppUnitTestSupport {
+
+    private static final int TIMEOUT_MS = 10*1000;
+    
+    private TestEntity entity;
+    private Policy policy1;
+    private Policy policy2;
+
+    private List<PolicyDescriptor> added;
+    private List<PolicyDescriptor> removed;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        policy1 = new AbstractPolicy() {};
+        policy2 = new AbstractPolicy() {};
+        
+        added = Lists.newCopyOnWriteArrayList();
+        removed = Lists.newCopyOnWriteArrayList();
+        
+        app.subscribe(entity, AbstractEntity.POLICY_ADDED, new SensorEventListener<PolicyDescriptor>() {
+            @Override public void onEvent(SensorEvent<PolicyDescriptor> event) {
+                added.add(event.getValue());
+            }});
+        app.subscribe(entity, AbstractEntity.POLICY_REMOVED, new SensorEventListener<PolicyDescriptor>() {
+                @Override public void onEvent(SensorEvent<PolicyDescriptor> event) {
+                    removed.add(event.getValue());
+                }});
+    }
+    
+    @Test
+    public void testGetPoliciesIsInitiallyEmpty() {
+        assertEquals(entity.getPolicies(), ImmutableList.of());
+    }
+
+    @Test(expectedExceptions = { UnsupportedOperationException.class })
+    public void testGetPoliciesReturnsImmutableCollection() {
+        entity.getPolicies().add(policy1);
+        fail();
+    }
+
+    @Test
+    public void testAddAndRemovePolicies() {
+        entity.addPolicy(policy1);
+        assertEquals(entity.getPolicies(), ImmutableList.of(policy1));
+        assertEqualsEventually(added, ImmutableList.of(new PolicyDescriptor(policy1)));
+        
+        entity.addPolicy(policy2);
+        assertEquals(entity.getPolicies(), ImmutableList.of(policy1, policy2));
+        assertEqualsEventually(added, ImmutableList.of(new PolicyDescriptor(policy1), new PolicyDescriptor(policy2)));
+        
+        entity.removePolicy(policy1);
+        assertEquals(entity.getPolicies(), ImmutableList.of(policy2));
+        assertEqualsEventually(removed, ImmutableList.of(new PolicyDescriptor(policy1)));
+        
+        entity.removePolicy(policy2);
+        assertEquals(entity.getPolicies(), ImmutableList.of());
+        assertEqualsEventually(removed, ImmutableList.of(new PolicyDescriptor(policy1), new PolicyDescriptor(policy2)));
+    }
+
+    @Test
+    public void testAddPolicySpec() {
+        EntitySpecTest.MyPolicy policy = entity.addPolicy(PolicySpec.create(EntitySpecTest.MyPolicy.class));
+        assertNotNull(policy);
+        assertEquals(entity.getPolicies(), ImmutableList.of(policy));
+        assertEqualsEventually(added, ImmutableList.of(new PolicyDescriptor(policy)));
+    }
+    
+    @Test
+    public void testAddEnricherSpec() {
+        TestEntity entity2 = app.createAndManageChild(EntitySpec.create(TestEntity.class, TestEntityNoEnrichersImpl.class));
+        EntitySpecTest.MyEnricher enricher = entity2.addEnricher(EnricherSpec.create(EntitySpecTest.MyEnricher.class));
+        assertNotNull(enricher);
+        assertEquals(entity2.getEnrichers(), ImmutableList.of(enricher));
+    }
+
+    @Test
+    public void testRemoveAllPolicies() {
+        entity.addPolicy(policy1);
+        entity.addPolicy(policy2);
+        entity.removeAllPolicies();
+        
+        assertEquals(entity.getPolicies(), ImmutableList.of());
+        assertCollectionEqualsEventually(removed, ImmutableSet.of(new PolicyDescriptor(policy1), new PolicyDescriptor(policy2)));
+    }
+    
+    private <T> void assertEqualsEventually(final T actual, final T expected) {
+        TestUtils.assertEventually(MutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+                @Override public void run() {
+                    assertEquals(actual, expected, "actual="+actual);
+                }});
+    }
+    
+    // Ignores order of vals in collection, but asserts each same size and same elements 
+    private <T> void assertCollectionEqualsEventually(final Collection<? extends T> actual, final Collection<? extends T> expected) {
+        TestUtils.assertEventually(MutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+                @Override public void run() {
+                    assertEquals(ImmutableSet.copyOf(actual), ImmutableSet.copyOf(expected), "actual="+actual);
+                    assertEquals(actual.size(), expected.size(), "actual="+actual);
+                }});
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java b/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java
new file mode 100644
index 0000000..44920ed
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java
@@ -0,0 +1,115 @@
+/*
+ * 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.entity;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.primitives.Longs;
+
+/**
+ * An event listener that records each event and allows callers to access all values and
+ * all values sorted by event timestamp.
+ */
+public class RecordingSensorEventListener<T> implements SensorEventListener<T>, Iterable<SensorEvent<T>> {
+
+    private final List<SensorEvent<T>> events = Lists.newCopyOnWriteArrayList();
+    private final boolean suppressDuplicates;
+    private T lastValue;
+
+    public RecordingSensorEventListener() {
+        this(false);
+    }
+
+    public RecordingSensorEventListener(boolean suppressDuplicates) {
+        this.suppressDuplicates = suppressDuplicates;
+    }
+
+    @Override
+    public void onEvent(SensorEvent<T> event) {
+        if (!suppressDuplicates || events.isEmpty() || !Objects.equals(lastValue, event.getValue())) {
+            events.add(event);
+            lastValue = event.getValue();
+        }
+    }
+
+    /**
+     * @return An immutable iterable of the recorded events.
+     */
+    public List<SensorEvent<T>> getEvents() {
+        return ImmutableList.copyOf(events);
+    }
+
+    /**
+     * @return A live read-only view of recorded events.
+     */
+    public Iterable<T> getEventValues() {
+        return FluentIterable.from(events)
+                .transform(new GetValueFunction<T>());
+    }
+
+    /**
+     * @return A static read-only view of event values sorted by the time at which they occurred.
+     */
+    public Iterable<T> getEventValuesSortedByTimestamp() {
+        List<SensorEvent<T>> copy = Lists.newArrayList(events);
+        Collections.sort(copy, new EventTimestampComparator());
+        return FluentIterable.from(copy)
+                .transform(new GetValueFunction<T>());
+    }
+
+    /**
+     * Clears all events recorded by the listener.
+     */
+    public void clearEvents() {
+        this.events.clear();
+        lastValue = null;
+    }
+
+    @Override
+    public Iterator<SensorEvent<T>> iterator() {
+        return getEvents().iterator();
+    }
+
+    private static class GetValueFunction<T> implements Function<SensorEvent<T>, T> {
+        @Override
+        public T apply(SensorEvent<T> input) {
+            return input.getValue();
+        }
+    }
+
+    private static class EventTimestampComparator implements Comparator<SensorEvent<?>> {
+        @Override
+        public int compare(SensorEvent<?> o1, SensorEvent<?> o2) {
+            return Longs.compare(o1.getTimestamp(), o2.getTimestamp());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/SanitizerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/SanitizerTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/SanitizerTest.java
new file mode 100644
index 0000000..79161d4
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/SanitizerTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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.entity;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.apache.brooklyn.core.config.Sanitizer;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class SanitizerTest {
+
+    @Test
+    public void testSanitize() throws Exception {
+        Map<String, Object> sanitized = Sanitizer.sanitize(ConfigBag.newInstance(ImmutableMap.of("password", "pa55w0rd", "mykey", "myval")));
+        assertEquals(sanitized, ImmutableMap.of("password", "xxxxxxxx", "mykey", "myval"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/BasicEntityDriverManagerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/BasicEntityDriverManagerTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/BasicEntityDriverManagerTest.java
new file mode 100644
index 0000000..fd0d421
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/BasicEntityDriverManagerTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.entity.drivers;
+
+import static org.testng.Assert.assertTrue;
+
+import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
+import org.apache.brooklyn.core.entity.drivers.BasicEntityDriverManager;
+import org.apache.brooklyn.core.entity.drivers.ReflectiveEntityDriverFactoryTest.MyDriver;
+import org.apache.brooklyn.core.entity.drivers.ReflectiveEntityDriverFactoryTest.MyDriverDependentEntity;
+import org.apache.brooklyn.core.entity.drivers.ReflectiveEntityDriverFactoryTest.MySshDriver;
+import org.apache.brooklyn.core.entity.drivers.RegistryEntityDriverFactoryTest.MyOtherSshDriver;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.core.SimulatedLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
+
+public class BasicEntityDriverManagerTest {
+
+    private BasicEntityDriverManager manager;
+    private SshMachineLocation sshLocation;
+    private SimulatedLocation simulatedLocation;
+
+    @BeforeMethod
+    public void setUp() throws Exception {
+        manager = new BasicEntityDriverManager();
+        sshLocation = new SshMachineLocation(MutableMap.of("address", "localhost"));
+        simulatedLocation = new SimulatedLocation();
+    }
+
+    @AfterMethod
+    public void tearDown(){
+        // nothing to tear down; no management context created
+    }
+    
+    @Test
+    public void testPrefersRegisteredDriver() throws Exception {
+        DriverDependentEntity<MyDriver> entity = new MyDriverDependentEntity<MyDriver>(MyDriver.class);
+        manager.registerDriver(MyDriver.class, SshMachineLocation.class, MyOtherSshDriver.class);
+        assertTrue(manager.build(entity, sshLocation) instanceof MyOtherSshDriver);
+    }
+    
+    @Test
+    public void testFallsBackToReflectiveDriver() throws Exception {
+        DriverDependentEntity<MyDriver> entity = new MyDriverDependentEntity<MyDriver>(MyDriver.class);
+        assertTrue(manager.build(entity, sshLocation) instanceof MySshDriver);
+    }
+    
+    @Test
+    public void testRespectsLocationWhenDecidingOnDriver() throws Exception {
+        DriverDependentEntity<MyDriver> entity = new MyDriverDependentEntity<MyDriver>(MyDriver.class);
+        manager.registerDriver(MyDriver.class, SimulatedLocation.class, MyOtherSshDriver.class);
+        assertTrue(manager.build(entity, simulatedLocation) instanceof MyOtherSshDriver);
+        assertTrue(manager.build(entity, sshLocation) instanceof MySshDriver);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/EntityDriverRegistryTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/EntityDriverRegistryTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/EntityDriverRegistryTest.java
new file mode 100644
index 0000000..977d380
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/EntityDriverRegistryTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.entity.drivers;
+
+import static org.testng.Assert.assertTrue;
+
+import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.drivers.ReflectiveEntityDriverFactoryTest.MyDriver;
+import org.apache.brooklyn.core.entity.drivers.ReflectiveEntityDriverFactoryTest.MyDriverDependentEntity;
+import org.apache.brooklyn.core.entity.drivers.RegistryEntityDriverFactoryTest.MyOtherSshDriver;
+import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+
+public class EntityDriverRegistryTest {
+
+    private ManagementContext managementContext;
+    private SshMachineLocation sshLocation;
+
+    @BeforeMethod
+    public void setUp() throws Exception {
+        managementContext = new LocalManagementContextForTests();
+        sshLocation = new SshMachineLocation(MutableMap.of("address", "localhost"));
+    }
+
+    @AfterMethod
+    public void tearDown(){
+        if (managementContext != null) Entities.destroyAll(managementContext);
+    }
+
+    @Test
+    public void testInstantiatesRegisteredDriver() throws Exception {
+        managementContext.getEntityDriverManager().registerDriver(MyDriver.class, SshMachineLocation.class, MyOtherSshDriver.class);
+        DriverDependentEntity<MyDriver> entity = new MyDriverDependentEntity<MyDriver>(MyDriver.class);
+        MyDriver driver = managementContext.getEntityDriverManager().build(entity, sshLocation);
+        assertTrue(driver instanceof MyOtherSshDriver);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactoryTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactoryTest.java
new file mode 100644
index 0000000..86a2d99
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactoryTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.entity.drivers;
+
+import org.apache.brooklyn.location.paas.PaasLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
+import org.apache.brooklyn.api.entity.drivers.EntityDriver;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.drivers.ReflectiveEntityDriverFactory;
+import org.apache.brooklyn.core.test.location.TestPaasLocation;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+
+public class ReflectiveEntityDriverFactoryTest {
+
+    private ReflectiveEntityDriverFactory factory;
+    private SshMachineLocation sshLocation;
+    private PaasLocation paasLocation;
+    private DriverDependentEntity<MyDriver> entity;
+    
+    @BeforeMethod
+    public void setUp() throws Exception {
+        factory = new ReflectiveEntityDriverFactory();
+        sshLocation = new SshMachineLocation(MutableMap.of("address", "localhost"));
+        entity = new MyDriverDependentEntity<MyDriver>(MyDriver.class);
+
+        paasLocation = new TestPaasLocation();
+    }
+
+    @AfterMethod
+    public void tearDown() {
+        // nothing to tear down; no management context created
+    }
+    
+    protected void assertDriverIs(Class<?> clazz, Location location) {
+        MyDriver driver = factory.build(entity, location);
+        assertTrue(driver.getClass().equals(clazz), "driver="+driver+"; should be "+clazz);
+    }
+    
+    @Test
+    public void testInstantiatesSshDriver() throws Exception {
+        assertDriverIs(MySshDriver.class, sshLocation);
+    }
+
+    @Test
+    public void testInstantiatesPaasDriver() throws Exception {
+        assertDriverIs(MyTestPaasDriver.class, paasLocation);
+    }
+    
+    @Test
+    public void testFullNameMapping() throws Exception {
+        factory.addClassFullNameMapping(MyDriver.class.getName(), MyCustomDriver.class.getName());
+        assertDriverIs(MyCustomDriver.class, sshLocation);
+    }
+
+    @Test
+    public void testFullNameMappingMulti() throws Exception {
+        factory.addClassFullNameMapping(MyDriver.class.getName(), "X");
+        factory.addClassFullNameMapping(MyDriver.class.getName(), MyCustomDriver.class.getName());
+        assertDriverIs(MyCustomDriver.class, sshLocation);
+    }
+
+
+    @Test
+    public void testFullNameMappingFailure1() throws Exception {
+        factory.addClassFullNameMapping(MyDriver.class.getName()+"X", MyCustomDriver.class.getName());
+        assertDriverIs(MySshDriver.class, sshLocation);
+    }
+
+    @Test
+    public void testFullNameMappingFailure2() throws Exception {
+        factory.addClassFullNameMapping(MyDriver.class.getName(), MyCustomDriver.class.getName());
+        factory.addClassFullNameMapping(MyDriver.class.getName(), "X");
+        assertDriverIs(MySshDriver.class, sshLocation);
+    }
+
+    @Test
+    public void testSimpleNameMapping() throws Exception {
+        factory.addClassSimpleNameMapping(MyDriver.class.getSimpleName(), MyCustomDriver.class.getSimpleName());
+        assertDriverIs(MyCustomDriver.class, sshLocation);
+    }
+
+    @Test
+    public void testSimpleNameMappingFailure() throws Exception {
+        factory.addClassSimpleNameMapping(MyDriver.class.getSimpleName()+"X", MyCustomDriver.class.getSimpleName());
+        assertDriverIs(MySshDriver.class, sshLocation);
+    }
+    
+    public static class MyDriverDependentEntity<D extends EntityDriver> extends AbstractEntity implements DriverDependentEntity<D> {
+        private final Class<D> clazz;
+
+        public MyDriverDependentEntity(Class<D> clazz) {
+            this.clazz = clazz;
+        }
+        
+        @Override
+        public Class<D> getDriverInterface() {
+            return clazz;
+        }
+        
+        @Override
+        public D getDriver() {
+            throw new UnsupportedOperationException();
+        }
+    }
+    
+    public static interface MyDriver extends EntityDriver {
+    }
+    
+    public static class MySshDriver implements MyDriver {
+        public MySshDriver(Entity entity, SshMachineLocation machine) {
+        }
+
+        @Override
+        public Location getLocation() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public EntityLocal getEntity() {
+            throw new UnsupportedOperationException();
+        }
+    }
+    
+    public static class MyCustomDriver extends MySshDriver {
+        public MyCustomDriver(Entity entity, SshMachineLocation machine) {
+            super(entity, machine);
+        }
+    }
+    
+    public static class MyTestPaasDriver implements MyDriver {
+        public MyTestPaasDriver(Entity entity, PaasLocation location) {
+        }
+
+        @Override
+        public Location getLocation() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public EntityLocal getEntity() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/RegistryEntityDriverFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/RegistryEntityDriverFactoryTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/RegistryEntityDriverFactoryTest.java
new file mode 100644
index 0000000..97aa2d2
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/RegistryEntityDriverFactoryTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.entity.drivers;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.drivers.RegistryEntityDriverFactory;
+import org.apache.brooklyn.core.entity.drivers.ReflectiveEntityDriverFactoryTest.MyDriver;
+import org.apache.brooklyn.core.entity.drivers.ReflectiveEntityDriverFactoryTest.MyDriverDependentEntity;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.core.SimulatedLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
+
+public class RegistryEntityDriverFactoryTest {
+
+    private RegistryEntityDriverFactory factory;
+    private SshMachineLocation sshLocation;
+    private SimulatedLocation simulatedLocation;
+
+    @BeforeMethod
+    public void setUp() throws Exception {
+        factory = new RegistryEntityDriverFactory();
+        sshLocation = new SshMachineLocation(MutableMap.of("address", "localhost"));
+        simulatedLocation = new SimulatedLocation();
+    }
+
+    @AfterMethod
+    public void tearDown(){
+        // nothing to tear down; no management context created
+    }
+
+    @Test
+    public void testHasDriver() throws Exception {
+        DriverDependentEntity<MyDriver> entity = new MyDriverDependentEntity<MyDriver>(MyDriver.class);
+        factory.registerDriver(MyDriver.class, SshMachineLocation.class, MyOtherSshDriver.class);
+        assertTrue(factory.hasDriver(entity, sshLocation));
+        assertFalse(factory.hasDriver(entity, simulatedLocation));
+    }
+
+    @Test
+    public void testInstantiatesRegisteredDriver() throws Exception {
+        DriverDependentEntity<MyDriver> entity = new MyDriverDependentEntity<MyDriver>(MyDriver.class);
+        factory.registerDriver(MyDriver.class, SshMachineLocation.class, MyOtherSshDriver.class);
+        MyDriver driver = factory.build(entity, sshLocation);
+        assertTrue(driver instanceof MyOtherSshDriver);
+    }
+
+    public static class MyOtherSshDriver implements MyDriver {
+        public MyOtherSshDriver(Entity entity, Location machine) {
+        }
+
+        @Override
+        public EntityLocal getEntity() {
+            throw new UnsupportedOperationException();
+        }
+        
+        @Override
+        public Location getLocation() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadsRegistryTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadsRegistryTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadsRegistryTest.java
new file mode 100644
index 0000000..56c711d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/BasicDownloadsRegistryTest.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.entity.drivers.downloads;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.core.SimulatedLocation;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class BasicDownloadsRegistryTest {
+
+    private BrooklynProperties brooklynProperties;
+    private LocalManagementContext managementContext;
+    private Location loc;
+    private TestApplication app;
+    private TestEntity entity;
+    private MyEntityDriver driver;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        brooklynProperties = BrooklynProperties.Factory.newEmpty();
+        managementContext = new LocalManagementContext(brooklynProperties);
+        loc = new SimulatedLocation();
+        app = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        driver = new MyEntityDriver(entity, loc);
+        
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testUsesDownloadUrlAttribute() throws Exception {
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        entity.setAttribute(Attributes.DOWNLOAD_URL, "acme.com/version=${version},type=${type},simpletype=${simpletype}");
+        String expectedFilename = String.format("version=%s,type=%s,simpletype=%s", "myversion", TestEntity.class.getName(), "TestEntity");
+        
+        String expectedLocalRepo = String.format("file://$HOME/.brooklyn/repository/%s/%s/%s", "TestEntity", "myversion", expectedFilename);
+        String expectedDownloadUrl = String.format("acme.com/%s", expectedFilename);
+        String expectedCloudsoftRepo = String.format("http://downloads.cloudsoftcorp.com/brooklyn/repository/%s/%s/%s", "TestEntity", "myversion", expectedFilename);
+        assertResolves(expectedLocalRepo, expectedDownloadUrl, expectedCloudsoftRepo);
+    }
+    
+    @Test
+    public void testUsesDownloadAddonUrlsAttribute() throws Exception {
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myentityversion");
+        entity.setAttribute(Attributes.DOWNLOAD_ADDON_URLS, ImmutableMap.of("myaddon", "acme.com/addon=${addon},version=${addonversion},type=${type},simpletype=${simpletype}"));
+        String expectedFilename = String.format("addon=%s,version=%s,type=%s,simpletype=%s", "myaddon", "myaddonversion", TestEntity.class.getName(), "TestEntity");
+        
+        String expectedLocalRepo = String.format("file://$HOME/.brooklyn/repository/%s/%s/%s", "TestEntity", "myentityversion", expectedFilename);
+        String expectedDownloadUrl = String.format("acme.com/%s", expectedFilename);
+        String expectedCloudsoftRepo = String.format("http://downloads.cloudsoftcorp.com/brooklyn/repository/%s/%s/%s", "TestEntity", "myentityversion", expectedFilename);
+        DownloadResolver actual = managementContext.getEntityDownloadsManager().newDownloader(driver, "myaddon", ImmutableMap.of("addonversion", "myaddonversion"));
+        assertEquals(actual.getTargets(), ImmutableList.of(expectedLocalRepo, expectedDownloadUrl, expectedCloudsoftRepo), "actual="+actual);
+    }
+    
+    @Test
+    public void testDefaultResolverSubstitutesDownloadUrlFailsIfVersionMissing() throws Exception {
+        entity.setAttribute(Attributes.DOWNLOAD_URL, "version=${version}");
+        try {
+            DownloadResolver result = managementContext.getEntityDownloadsManager().newDownloader(driver);
+            fail("Should have failed, but got "+result);
+        } catch (IllegalArgumentException e) {
+            if (!e.toString().contains("${version}")) throw e;
+        }
+    }
+    
+    @Test
+    public void testReturnsLocalRepoThenOverrideThenAttributeValThenCloudsoftUrlThenFallback() throws Exception {
+        BrooklynProperties managementProperties = managementContext.getBrooklynProperties();
+        managementProperties.put("brooklyn.downloads.all.url", "http://fromprops/${version}.allprimary");
+        managementProperties.put("brooklyn.downloads.all.fallbackurl", "http://fromfallback/${version}.allfallback");
+        entity.setAttribute(Attributes.DOWNLOAD_URL, "http://fromattrib/${version}.default");
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        String expectedFilename = "myversion.allprimary";
+
+        String expectedLocalRepo = String.format("file://$HOME/.brooklyn/repository/%s/%s/%s", "TestEntity", "myversion", expectedFilename);
+        String expectedDownloadUrl = String.format("http://fromattrib/%s", "myversion.default");
+        String expectedCloudsoftRepo = String.format("http://downloads.cloudsoftcorp.com/brooklyn/repository/%s/%s/%s", "TestEntity", "myversion", expectedFilename);
+        assertResolves(
+                expectedLocalRepo,
+                "http://fromprops/myversion.allprimary", 
+                expectedDownloadUrl, 
+                expectedCloudsoftRepo, 
+                "http://fromfallback/myversion.allfallback");
+    }
+
+    @Test
+    public void testInfersFilenameFromDownloadUrl() throws Exception {
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        entity.setAttribute(Attributes.DOWNLOAD_URL, "http://myhost.com/myfile-${version}.tar.gz");
+
+        DownloadResolver actual = managementContext.getEntityDownloadsManager().newDownloader(driver);
+        assertEquals(actual.getFilename(), "myfile-myversion.tar.gz");
+    }
+    
+    @Test
+    public void testInfersAddonFilenameFromDownloadUrl() throws Exception {
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        entity.setAttribute(Attributes.DOWNLOAD_ADDON_URLS, ImmutableMap.of("myaddon", "http://myhost.com/myfile-${addonversion}.tar.gz"));
+
+        DownloadResolver actual = managementContext.getEntityDownloadsManager().newDownloader(driver, "myaddon", ImmutableMap.of("addonversion", "myaddonversion"));
+        assertEquals(actual.getFilename(), "myfile-myaddonversion.tar.gz");
+    }
+    
+    @Test
+    public void testCanOverrideFilenameFromDownloadUrl() throws Exception {
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        entity.setAttribute(Attributes.DOWNLOAD_URL, "http://myhost.com/download/");
+
+        DownloadResolver actual = managementContext.getEntityDownloadsManager().newDownloader(driver, ImmutableMap.of("filename", "overridden.filename.tar.gz"));
+        assertEquals(actual.getFilename(), "overridden.filename.tar.gz");
+    }
+    
+    private void assertResolves(String... expected) {
+        DownloadResolver actual = managementContext.getEntityDownloadsManager().newDownloader(driver);
+        assertEquals(actual.getTargets(), ImmutableList.copyOf(expected), "actual="+actual);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadProducerFromLocalRepoTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadProducerFromLocalRepoTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadProducerFromLocalRepoTest.java
new file mode 100644
index 0000000..393e539
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadProducerFromLocalRepoTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.entity.drivers.downloads;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager.DownloadRequirement;
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager.DownloadTargets;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.drivers.downloads.BasicDownloadRequirement;
+import org.apache.brooklyn.core.entity.drivers.downloads.DownloadProducerFromLocalRepo;
+import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.core.SimulatedLocation;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class DownloadProducerFromLocalRepoTest {
+
+    private BrooklynProperties brooklynProperties;
+    private LocalManagementContext managementContext;
+    private Location loc;
+    private TestApplication app;
+    private TestEntity entity;
+    private MyEntityDriver driver;
+    private String entitySimpleType;
+    private DownloadProducerFromLocalRepo resolver;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        brooklynProperties = BrooklynProperties.Factory.newEmpty();
+        managementContext = new LocalManagementContext(brooklynProperties);
+        
+        loc = new SimulatedLocation();
+        app = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        driver = new MyEntityDriver(entity, loc);
+        entitySimpleType = TestEntity.class.getSimpleName();
+        
+        resolver = new DownloadProducerFromLocalRepo(brooklynProperties);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testReturnsEmptyWhenDisabled() throws Exception {
+        brooklynProperties.put(DownloadProducerFromLocalRepo.LOCAL_REPO_ENABLED, false);
+        assertResolves(ImmutableList.<String>of(), ImmutableList.<String>of());
+    }
+    
+    @Test
+    public void testReturnsDefault() throws Exception {
+        // uses default of ${simpletype}-${version}.tar.gz";
+        String entityVersion = "myversion";
+        String downloadFilename = (entitySimpleType+"-"+entityVersion+".tar.gz").toLowerCase();
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, entityVersion);
+        assertResolves(String.format("file://$HOME/.brooklyn/repository/%s/%s/%s", entitySimpleType, entityVersion, downloadFilename));
+    }
+    
+    @Test
+    public void testReturnsFilenameFromDriver() throws Exception {
+        String entityVersion = "myversion";
+        String filename = "my.file.name";
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, entityVersion);
+        
+        BasicDownloadRequirement req = new BasicDownloadRequirement(driver, ImmutableMap.of("filename", filename));
+        assertResolves(req, String.format("file://$HOME/.brooklyn/repository/%s/%s/%s", entitySimpleType, entityVersion, filename));
+    }
+    
+    @Test
+    public void testReturnsFileSuffixFromRequirements() throws Exception {
+        // uses ${driver.downloadFileSuffix}
+        String entityVersion = "myversion";
+        String fileSuffix = "mysuffix";
+        String expectedFilename = (entitySimpleType+"-"+entityVersion+"."+fileSuffix).toLowerCase();
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, entityVersion);
+        
+        BasicDownloadRequirement req = new BasicDownloadRequirement(driver, ImmutableMap.of("fileSuffix", fileSuffix));
+        assertResolves(req, String.format("file://$HOME/.brooklyn/repository/%s/%s/%s", entitySimpleType, entityVersion, expectedFilename));
+    }
+    
+    private void assertResolves(String... expected) {
+        assertResolves(ImmutableList.copyOf(expected), ImmutableList.<String>of());
+    }
+    
+    private void assertResolves(List<String> expectedPrimaries, List<String> expectedFallbacks) {
+        assertResolves(new BasicDownloadRequirement(driver), expectedPrimaries, expectedFallbacks);
+    }
+    
+    private void assertResolves(DownloadRequirement req, String... expected) {
+        assertResolves(req, ImmutableList.copyOf(expected), ImmutableList.<String>of());
+    }
+
+    private void assertResolves(DownloadRequirement req, List<String> expectedPrimaries, List<String> expectedFallbacks) {
+        DownloadTargets actual = resolver.apply(req);
+        assertEquals(actual.getPrimaryLocations(), expectedPrimaries);
+        assertEquals(actual.getFallbackLocations(), expectedFallbacks);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadProducerFromPropertiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadProducerFromPropertiesTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadProducerFromPropertiesTest.java
new file mode 100644
index 0000000..e3b8f1c
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadProducerFromPropertiesTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.entity.drivers.downloads;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager.DownloadRequirement;
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager.DownloadTargets;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.drivers.downloads.BasicDownloadRequirement;
+import org.apache.brooklyn.core.entity.drivers.downloads.DownloadProducerFromLocalRepo;
+import org.apache.brooklyn.core.entity.drivers.downloads.DownloadProducerFromProperties;
+import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.core.SimulatedLocation;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class DownloadProducerFromPropertiesTest {
+
+    private BrooklynProperties brooklynProperties;
+    private LocalManagementContext managementContext;
+    private Location loc;
+    private TestApplication app;
+    private TestEntity entity;
+    private MyEntityDriver driver;
+    private DownloadProducerFromProperties resolver;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        brooklynProperties = BrooklynProperties.Factory.newEmpty();
+        brooklynProperties.put(DownloadProducerFromLocalRepo.LOCAL_REPO_ENABLED, false);
+        managementContext = new LocalManagementContext(brooklynProperties);
+        
+        loc = new SimulatedLocation();
+        app = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        driver = new MyEntityDriver(entity, loc);
+        
+        resolver = new DownloadProducerFromProperties(brooklynProperties);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testReturnsEmptyWhenEmpty() throws Exception {
+        assertResolves(ImmutableList.<String>of(), ImmutableList.<String>of());
+    }
+    
+    @Test
+    public void testReturnsGlobalUrl() throws Exception {
+        brooklynProperties.put("brooklyn.downloads.all.url", "myurl");
+        assertResolves("myurl");
+    }
+    
+    @Test
+    public void testReturnsGlobalUrlsSplitOnSemicolon() throws Exception {
+        brooklynProperties.put("brooklyn.downloads.all.url", "myurl; myurl2");
+        assertResolves("myurl", "myurl2");
+    }
+    
+    @Test
+    public void testReturnsGlobalFallbackUrl() throws Exception {
+        brooklynProperties.put("brooklyn.downloads.all.fallbackurl", "myurl");
+        assertResolves(ImmutableList.<String>of(), ImmutableList.of("myurl"));
+    }
+
+    @Test
+    public void testSubstitutionsAppliedToFallbackUrl() throws Exception {
+        brooklynProperties.put("brooklyn.downloads.all.fallbackurl", "version=${version}");
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        assertResolves(ImmutableList.<String>of(), ImmutableList.of("version=myversion"));
+    }
+
+    @Test
+    public void testReturnsGlobalFallbackUrlAsLast() throws Exception {
+        brooklynProperties.put("brooklyn.downloads.all.url", "myurl");
+        brooklynProperties.put("brooklyn.downloads.all.fallbackurl", "myurl2");
+        assertResolves(ImmutableList.of("myurl"), ImmutableList.of("myurl2"));
+    }
+    
+    @Test
+    public void testReturnsGlobalUrlWithEntitySubstituions() throws Exception {
+        brooklynProperties.put("brooklyn.downloads.all.url", "version=${version}");
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        assertResolves("version=myversion");
+    }
+    
+    @Test
+    public void testEntitySpecificUrlOverridesGlobalUrl() throws Exception {
+        brooklynProperties.put("brooklyn.downloads.all.url", "version=${version}");
+        brooklynProperties.put("brooklyn.downloads.entity.TestEntity.url", "overridden,version=${version}");
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        assertResolves("overridden,version=myversion", "version=myversion");
+    }
+    
+    @Test
+    public void testEntitySpecificAddonUsesGlobalUrl() throws Exception {
+        brooklynProperties.put("brooklyn.downloads.all.url", "version=${version}");
+
+        DownloadRequirement req = new BasicDownloadRequirement(driver, "myaddon", ImmutableMap.of("version", "myversion"));
+        assertResolves(req, ImmutableList.of("version=myversion"), ImmutableList.<String>of());
+    }
+    
+    @Test
+    public void testEntitySpecificAddonOverridesGlobalUrl() throws Exception {
+        brooklynProperties.put("brooklyn.downloads.all.url", "${addon}-${version}");
+        brooklynProperties.put("brooklyn.downloads.entity.TestEntity.addon.myaddon.url", "overridden,${addon}-${version}");
+
+        DownloadRequirement req = new BasicDownloadRequirement(driver, "myaddon", ImmutableMap.of("version", "myversion"));
+        assertResolves(req, ImmutableList.of("overridden,myaddon-myversion", "myaddon-myversion"), ImmutableList.<String>of());
+    }
+    
+    private void assertResolves(String... expected) {
+        assertResolves(ImmutableList.copyOf(expected), ImmutableList.<String>of());
+    }
+    
+    private void assertResolves(List<String> expectedPrimaries, List<String> expectedFallbacks) {
+        assertResolves(new BasicDownloadRequirement(driver), expectedPrimaries, expectedFallbacks);
+    }
+    
+    private void assertResolves(DownloadRequirement req, String... expected) {
+        assertResolves(req, ImmutableList.copyOf(expected), ImmutableList.<String>of());
+    }
+
+    private void assertResolves(DownloadRequirement req, List<String> expectedPrimaries, List<String> expectedFallbacks) {
+        DownloadTargets actual = resolver.apply(req);
+        assertEquals(actual.getPrimaryLocations(), expectedPrimaries, "actual="+actual);
+        assertEquals(actual.getFallbackLocations(), expectedFallbacks, "actual="+actual);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadSubstitutersTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadSubstitutersTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadSubstitutersTest.java
new file mode 100644
index 0000000..0d2ea21
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/DownloadSubstitutersTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.entity.drivers.downloads;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolverManager.DownloadTargets;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.drivers.downloads.BasicDownloadRequirement;
+import org.apache.brooklyn.core.entity.drivers.downloads.DownloadSubstituters;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.location.core.SimulatedLocation;
+
+import com.google.common.base.Functions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class DownloadSubstitutersTest extends BrooklynAppUnitTestSupport {
+
+    private Location loc;
+    private TestEntity entity;
+    private MyEntityDriver driver;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = new SimulatedLocation();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        driver = new MyEntityDriver(entity, loc);
+    }
+    
+    @Test
+    public void testSimpleSubstitution() throws Exception {
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        String pattern = "mykey1=${mykey1},mykey2=${mykey2}";
+        String result = DownloadSubstituters.substitute(pattern, ImmutableMap.of("mykey1", "myval1", "mykey2", "myval2"));
+        assertEquals(result, "mykey1=myval1,mykey2=myval2");
+    }
+
+    @Test
+    public void testSubstitutionIncludesDefaultSubs() throws Exception {
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        String pattern = "version=${version},type=${type},simpletype=${simpletype}";
+        BasicDownloadRequirement req = new BasicDownloadRequirement(driver);
+        String result = DownloadSubstituters.substitute(req, pattern);
+        assertEquals(result, String.format("version=%s,type=%s,simpletype=%s", "myversion", TestEntity.class.getName(), TestEntity.class.getSimpleName()));
+    }
+
+    @Test
+    public void testSubstitutionDoesMultipleMatches() throws Exception {
+        String simpleType = TestEntity.class.getSimpleName();
+        String pattern = "simpletype=${simpletype},simpletype=${simpletype}";
+        BasicDownloadRequirement req = new BasicDownloadRequirement(driver);
+        String result = DownloadSubstituters.substitute(req, pattern);
+        assertEquals(result, String.format("simpletype=%s,simpletype=%s", simpleType, simpleType));
+    }
+
+    @Test
+    public void testSubstitutionUsesEntityBean() throws Exception {
+        String entityid = entity.getId();
+        String pattern = "id=${entity.id}";
+        BasicDownloadRequirement req = new BasicDownloadRequirement(driver);
+        String result = DownloadSubstituters.substitute(req, pattern);
+        assertEquals(result, String.format("id=%s", entityid));
+    }
+
+    @Test
+    public void testSubstitutionUsesDriverBean() throws Exception {
+        String entityid = entity.getId();
+        String pattern = "id=${driver.entity.id}";
+        BasicDownloadRequirement req = new BasicDownloadRequirement(driver);
+        String result = DownloadSubstituters.substitute(req, pattern);
+        assertEquals(result, String.format("id=%s", entityid));
+    }
+
+    @Test
+    public void testSubstitutionUsesOverrides() throws Exception {
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        String pattern = "version=${version},mykey1=${mykey1}";
+        BasicDownloadRequirement req = new BasicDownloadRequirement(driver, ImmutableMap.of("version", "overriddenversion", "mykey1", "myval1"));
+        String result = DownloadSubstituters.substitute(req, pattern);
+        assertEquals(result, "version=overriddenversion,mykey1=myval1");
+    }
+
+    @Test
+    public void testThrowsIfUnmatchedSubstitutions() throws Exception {
+        String pattern = "nothere=${nothere}";
+        BasicDownloadRequirement req = new BasicDownloadRequirement(driver);
+        try {
+            String result = DownloadSubstituters.substitute(req, pattern);
+            fail("Should have failed, but got "+result);
+        } catch (IllegalArgumentException e) {
+            if (!e.toString().contains("${nothere}")) throw e;
+        }
+    }
+
+    @Test
+    public void testSubstituter() throws Exception {
+        entity.setConfig(BrooklynConfigKeys.SUGGESTED_VERSION, "myversion");
+        String baseurl = "version=${version},type=${type},simpletype=${simpletype}";
+        Map<String,Object> subs = DownloadSubstituters.getBasicEntitySubstitutions(driver);
+        DownloadTargets result = DownloadSubstituters.substituter(Functions.constant(baseurl), Functions.constant(subs)).apply(new BasicDownloadRequirement(driver));
+        String expected = String.format("version=%s,type=%s,simpletype=%s", "myversion", TestEntity.class.getName(), TestEntity.class.getSimpleName());
+        assertEquals(result.getPrimaryLocations(), ImmutableList.of(expected));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/FilenameProducersTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/FilenameProducersTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/FilenameProducersTest.java
new file mode 100644
index 0000000..0fd155d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/FilenameProducersTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.entity.drivers.downloads;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.core.entity.drivers.downloads.FilenameProducers;
+import org.testng.annotations.Test;
+
+public class FilenameProducersTest {
+
+    @Test
+    public void testInferFilename() throws Exception {
+        assertEquals(FilenameProducers.inferFilename("myname.tgz"), "myname.tgz");
+        assertEquals(FilenameProducers.inferFilename("a/myname.tgz"), "myname.tgz");
+        assertEquals(FilenameProducers.inferFilename("acme.com/download/"), null);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/MyEntityDriver.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/MyEntityDriver.java b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/MyEntityDriver.java
new file mode 100644
index 0000000..504d07c
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/drivers/downloads/MyEntityDriver.java
@@ -0,0 +1,44 @@
+/*
+ * 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.entity.drivers.downloads;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.drivers.EntityDriver;
+import org.apache.brooklyn.api.location.Location;
+
+public class MyEntityDriver implements EntityDriver {
+    private final Entity entity;
+    private final Location location;
+
+    MyEntityDriver(Entity entity, Location location) {
+        this.entity = entity;
+        this.location = location;
+    }
+    
+    @Override
+    public EntityLocal getEntity() {
+        return (EntityLocal) entity;
+    }
+
+    @Override
+    public Location getLocation() {
+        return location;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java b/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
new file mode 100644
index 0000000..9d14868
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntity.java
@@ -0,0 +1,53 @@
+/*
+ * 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.entity.hello;
+
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.annotation.Effector;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.effector.core.MethodEffector;
+import org.apache.brooklyn.entity.group.AbstractGroup;
+import org.apache.brooklyn.sensor.core.BasicSensor;
+import org.apache.brooklyn.sensor.core.Sensors;
+
+@ImplementedBy(HelloEntityImpl.class)
+public interface HelloEntity extends AbstractGroup {
+
+    /** records name of the person represented by this entity */
+    public static ConfigKey<String> MY_NAME = ConfigKeys.newStringConfigKey("my.name");
+    
+    /** this "person"'s favourite name */
+    public static AttributeSensor<String> FAVOURITE_NAME = Sensors.newStringSensor("my.favourite.name");
+    
+    /** records age (in years) of the person represented by this entity */
+    public static AttributeSensor<Integer> AGE = Sensors.newIntegerSensor("my.age");
+    
+    /** emits a "birthday" event whenever age is changed (tests non-attribute events) */    
+    public static Sensor<Void> ITS_MY_BIRTHDAY = new BasicSensor<Void>(Void.TYPE, "my.birthday");
+    
+    /**  */
+    public static MethodEffector<Void> SET_AGE = new MethodEffector<Void>(HelloEntity.class, "setAge");
+    
+    @Effector(description="allows setting the age")
+    public void setAge(@EffectorParam(name="age") Integer age);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c27cf1d0/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntityImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntityImpl.java b/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntityImpl.java
new file mode 100644
index 0000000..67ae8a6
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/entity/hello/HelloEntityImpl.java
@@ -0,0 +1,31 @@
+/*
+ * 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.entity.hello;
+
+import org.apache.brooklyn.entity.group.AbstractGroupImpl;
+
+
+public class HelloEntityImpl extends AbstractGroupImpl implements HelloEntity {
+
+    @Override
+    public void setAge(Integer age) {
+        setAttribute(AGE, age);
+        emit(ITS_MY_BIRTHDAY, null);
+    }
+}


Mime
View raw message