package brooklyn.entity.basic;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;

import java.util.List;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import brooklyn.entity.proxying.BasicEntitySpec;
import brooklyn.event.SensorEvent;
import brooklyn.event.SensorEventListener;
import brooklyn.policy.Policy;
import brooklyn.policy.basic.AbstractPolicy;
import brooklyn.test.TestUtils;
import brooklyn.test.entity.TestApplication;
import brooklyn.test.entity.TestEntity;
import brooklyn.util.MutableMap;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;

public class PolicyRegistrationTest {

    private static final int TIMEOUT_MS = 10*1000;
    
    private TestApplication app;
    private TestEntity entity;
    private Policy policy1;
    private Policy policy2;

    private List<PolicyDescriptor> added;
    private List<PolicyDescriptor> removed;

    @BeforeMethod(alwaysRun=true)
    public void setUp() {
        app = ApplicationBuilder.builder(TestApplication.class).manage();
        entity = app.createAndManageChild(BasicEntitySpec.newInstance(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());
                }});
    }
    
    @AfterMethod(alwaysRun=true)
    public void tearDown() {
        if (app != null) Entities.destroyAll(app);
    }
    
    @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 testRemoveAllPolicies() {
        entity.addPolicy(policy1);
        entity.addPolicy(policy2);
        entity.removeAllPolicies();
        
        assertEquals(entity.getPolicies(), ImmutableList.of());
        assertEqualsEventually(ImmutableSet.copyOf(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);
                }});
    }
}

@@ -110,16 +110,45 @@
 .fail;%0A%0A
+import java.util.Collection;%0A
 import j
@@ -3668,32 +3668,42 @@
 ;%0A        assert
+Collection
 EqualsEventually
@@ -3707,36 +3707,15 @@
 lly(
-ImmutableSet.copyOf(
 removed
-)
 , Im
@@ -4015,24 +4015,24 @@
 oid run() %7B%0A
-
             
@@ -4116,10 +4116,598 @@
 ;%0A    %7D%0A
+    %0A    // Ignores order of vals in collection, but asserts each same size and same elements %0A    private %3CT%3E void assertCollectionEqualsEventually(final Collection%3C? extends T%3E actual, final Collection%3C? extends T%3E expected) %7B%0A        TestUtils.assertEventually(MutableMap.of(%22timeout%22, TIMEOUT_MS), new Runnable() %7B%0A                @Override public void run() %7B%0A                    assertEquals(ImmutableSet.copyOf(actual), ImmutableSet.copyOf(expected), %22actual=%22+actual);%0A                    assertEquals(actual.size(), expected.size(), %22actual=%22+actual);%0A                %7D%7D);%0A    %7D%0A
 %7D%0A

Fix PolicyRegistrationTest.testRemoveAllPolicies