Add some test cases to Intent Manager tests

- test that getIntents() returns the proper items
- test that subclass compilers work
- test the behavior of intents with no compiler
- test the behavior of intents with no installer
- test the behavior of installs that never finish

Change-Id: If0bff389e7fce2f71eb7a97051547dbd05ab588c
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
index cc9073b..16cb357 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
@@ -1,13 +1,14 @@
 package org.onosproject.net.intent.impl;
 
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
 
 import org.hamcrest.Description;
-import org.hamcrest.Matchers;
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.After;
 import org.junit.Before;
@@ -36,20 +37,21 @@
 import org.onosproject.store.trivial.impl.SimpleIntentBatchQueue;
 import org.onosproject.store.trivial.impl.SimpleIntentStore;
 
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
 
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.onosproject.net.intent.IntentState.*;
 import static org.onlab.util.Tools.delay;
+import static org.onosproject.net.intent.IntentState.FAILED;
+import static org.onosproject.net.intent.IntentState.INSTALLED;
+import static org.onosproject.net.intent.IntentState.WITHDRAWN;
 
 /**
  * Test intent manager and transitions.
@@ -76,6 +78,185 @@
     protected TestIntentCompiler compiler = new TestIntentCompiler();
     protected TestIntentInstaller installer = new TestIntentInstaller();
 
+    private static class TestListener implements IntentListener {
+        final Multimap<IntentEvent.Type, IntentEvent> events = HashMultimap.create();
+        Map<IntentEvent.Type, CountDownLatch> latchMap = Maps.newHashMap();
+
+        @Override
+        public void event(IntentEvent event) {
+            events.put(event.type(), event);
+            if (latchMap.containsKey(event.type())) {
+                latchMap.get(event.type()).countDown();
+            }
+        }
+
+        public int getCounts(IntentEvent.Type type) {
+            return events.get(type).size();
+        }
+
+        public void setLatch(int count, IntentEvent.Type type) {
+            latchMap.put(type, new CountDownLatch(count));
+        }
+
+        public void await(IntentEvent.Type type) {
+            try {
+                assertTrue("Timed out waiting for: " + type,
+                        latchMap.get(type).await(5, TimeUnit.SECONDS));
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static class TestIntentTracker implements ObjectiveTrackerService {
+        private TopologyChangeDelegate delegate;
+        @Override
+        public void setDelegate(TopologyChangeDelegate delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public void unsetDelegate(TopologyChangeDelegate delegate) {
+            if (delegate.equals(this.delegate)) {
+                this.delegate = null;
+            }
+        }
+
+        @Override
+        public void addTrackedResources(IntentId intentId, Collection<NetworkResource> resources) {
+            //TODO
+        }
+
+        @Override
+        public void removeTrackedResources(IntentId intentId, Collection<NetworkResource> resources) {
+            //TODO
+        }
+    }
+
+    private static class MockIntent extends Intent {
+        private static AtomicLong counter = new AtomicLong(0);
+
+        private final Long number;
+        // Nothing new here
+        public MockIntent(Long number) {
+            super(APPID, null);
+            this.number = number;
+        }
+
+        public Long number() {
+            return number;
+        }
+
+        public static Long nextId() {
+            return counter.getAndIncrement();
+        }
+    }
+
+    private static class MockInstallableIntent extends MockIntent {
+        public MockInstallableIntent(Long number) {
+            super(number);
+        }
+
+        @Override
+        public boolean isInstallable() {
+            return true;
+        }
+    }
+
+    private static class TestIntentCompiler implements IntentCompiler<MockIntent> {
+        @Override
+        public List<Intent> compile(MockIntent intent, List<Intent> installable,
+                                    Set<LinkResourceAllocations> resources) {
+            return Lists.newArrayList(new MockInstallableIntent(intent.number()));
+        }
+    }
+
+    private static class TestIntentCompilerError implements IntentCompiler<MockIntent> {
+        @Override
+        public List<Intent> compile(MockIntent intent, List<Intent> installable,
+                                    Set<LinkResourceAllocations> resources) {
+            throw new IntentCompilationException("Compilation always fails");
+        }
+    }
+
+    private static class TestIntentInstaller implements IntentInstaller<MockInstallableIntent> {
+        @Override
+        public List<FlowRuleBatchOperation> install(MockInstallableIntent intent) {
+            FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue());
+            List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
+            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr));
+            return Lists.newArrayList(new FlowRuleBatchOperation(rules));
+        }
+
+        @Override
+        public List<FlowRuleBatchOperation> uninstall(MockInstallableIntent intent) {
+            FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue());
+            List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
+            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr));
+            return Lists.newArrayList(new FlowRuleBatchOperation(rules));
+        }
+
+        @Override
+        public List<FlowRuleBatchOperation> replace(MockInstallableIntent oldIntent, MockInstallableIntent newIntent) {
+            FlowRule fr = new IntentTestsMocks.MockFlowRule(oldIntent.number().intValue());
+            FlowRule fr2 = new IntentTestsMocks.MockFlowRule(newIntent.number().intValue());
+            List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
+            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr));
+            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr2));
+            return Lists.newArrayList(new FlowRuleBatchOperation(rules));
+        }
+    }
+
+    private static class TestIntentErrorInstaller implements IntentInstaller<MockInstallableIntent> {
+        @Override
+        public List<FlowRuleBatchOperation> install(MockInstallableIntent intent) {
+            throw new IntentInstallationException("install() always fails");
+        }
+
+        @Override
+        public List<FlowRuleBatchOperation> uninstall(MockInstallableIntent intent) {
+            throw new IntentRemovalException("uninstall() always fails");
+        }
+
+        @Override
+        public List<FlowRuleBatchOperation> replace(MockInstallableIntent oldIntent, MockInstallableIntent newIntent) {
+            throw new IntentInstallationException("replace() always fails");
+        }
+    }
+
+    /**
+     * Hamcrest matcher to check that a conllection of Intents contains an
+     * Intent with the specified Intent Id.
+     */
+    public static class EntryForIntentMatcher extends TypeSafeMatcher<Collection<Intent>> {
+        private final IntentId id;
+
+        public EntryForIntentMatcher(IntentId idValue) {
+            id = idValue;
+        }
+
+        @Override
+        public boolean matchesSafely(Collection<Intent> intents) {
+            for (Intent intent : intents) {
+                if (intent.id().equals(id)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("an intent with id \" ").
+                    appendText(id.toString()).
+                    appendText("\"");
+        }
+    }
+
+    private static EntryForIntentMatcher hasIntentWithId(IntentId id) {
+        return new EntryForIntentMatcher(id);
+    }
+
     @Before
     public void setUp() {
         manager = new IntentManager();
@@ -253,176 +434,120 @@
         service.submit(intent);
         listener.await(Type.INSTALL_REQ);
         listener.await(Type.FAILED);
-
-    }
-
-    private static class TestListener implements IntentListener {
-        final Multimap<IntentEvent.Type, IntentEvent> events = HashMultimap.create();
-        Map<IntentEvent.Type, CountDownLatch> latchMap = Maps.newHashMap();
-
-        @Override
-        public void event(IntentEvent event) {
-            events.put(event.type(), event);
-            if (latchMap.containsKey(event.type())) {
-                latchMap.get(event.type()).countDown();
-            }
-        }
-
-        public int getCounts(IntentEvent.Type type) {
-            return events.get(type).size();
-        }
-
-        public void setLatch(int count, IntentEvent.Type type) {
-            latchMap.put(type, new CountDownLatch(count));
-        }
-
-        public void await(IntentEvent.Type type) {
-            try {
-                assertTrue("Timed out waiting for: " + type,
-                        latchMap.get(type).await(5, TimeUnit.SECONDS));
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    private static class TestIntentTracker implements ObjectiveTrackerService {
-        private TopologyChangeDelegate delegate;
-        @Override
-        public void setDelegate(TopologyChangeDelegate delegate) {
-            this.delegate = delegate;
-        }
-
-        @Override
-        public void unsetDelegate(TopologyChangeDelegate delegate) {
-            if (delegate.equals(this.delegate)) {
-                this.delegate = null;
-            }
-        }
-
-        @Override
-        public void addTrackedResources(IntentId intentId, Collection<NetworkResource> resources) {
-            //TODO
-        }
-
-        @Override
-        public void removeTrackedResources(IntentId intentId, Collection<NetworkResource> resources) {
-            //TODO
-        }
-    }
-
-    private static class MockIntent extends Intent {
-        private static AtomicLong counter = new AtomicLong(0);
-
-        private final Long number;
-        // Nothing new here
-        public MockIntent(Long number) {
-            super(APPID, null);
-            this.number = number;
-        }
-
-        public Long number() {
-            return number;
-        }
-
-        public static Long nextId() {
-            return counter.getAndIncrement();
-        }
-    }
-
-    private static class MockInstallableIntent extends MockIntent {
-        public MockInstallableIntent(Long number) {
-            super(number);
-        }
-
-        @Override
-        public boolean isInstallable() {
-            return true;
-        }
-    }
-
-    private static class TestIntentCompiler implements IntentCompiler<MockIntent> {
-        @Override
-        public List<Intent> compile(MockIntent intent, List<Intent> installable,
-                                    Set<LinkResourceAllocations> resources) {
-            return Lists.newArrayList(new MockInstallableIntent(intent.number()));
-        }
-    }
-
-    private static class TestIntentCompilerError implements IntentCompiler<MockIntent> {
-        @Override
-        public List<Intent> compile(MockIntent intent, List<Intent> installable,
-                                    Set<LinkResourceAllocations> resources) {
-            throw new IntentCompilationException("Compilation always fails");
-        }
-    }
-
-    private static class TestIntentInstaller implements IntentInstaller<MockInstallableIntent> {
-        @Override
-        public List<FlowRuleBatchOperation> install(MockInstallableIntent intent) {
-            FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue());
-            List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
-            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr));
-            return Lists.newArrayList(new FlowRuleBatchOperation(rules));
-        }
-
-        @Override
-        public List<FlowRuleBatchOperation> uninstall(MockInstallableIntent intent) {
-            FlowRule fr = new IntentTestsMocks.MockFlowRule(intent.number().intValue());
-            List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
-            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr));
-            return Lists.newArrayList(new FlowRuleBatchOperation(rules));
-        }
-
-        @Override
-        public List<FlowRuleBatchOperation> replace(MockInstallableIntent oldIntent, MockInstallableIntent newIntent) {
-            FlowRule fr = new IntentTestsMocks.MockFlowRule(oldIntent.number().intValue());
-            FlowRule fr2 = new IntentTestsMocks.MockFlowRule(newIntent.number().intValue());
-            List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
-            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, fr));
-            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, fr2));
-            return Lists.newArrayList(new FlowRuleBatchOperation(rules));
-        }
-    }
-
-    private static class TestIntentErrorInstaller implements IntentInstaller<MockInstallableIntent> {
-        @Override
-        public List<FlowRuleBatchOperation> install(MockInstallableIntent intent) {
-            throw new IntentInstallationException("install() always fails");
-        }
-
-        @Override
-        public List<FlowRuleBatchOperation> uninstall(MockInstallableIntent intent) {
-            throw new IntentRemovalException("uninstall() always fails");
-        }
-
-        @Override
-        public List<FlowRuleBatchOperation> replace(MockInstallableIntent oldIntent, MockInstallableIntent newIntent) {
-            throw new IntentInstallationException("replace() always fails");
-        }
     }
 
     /**
-     * Hamcrest matcher to check that a conllection of Intents contains an
-     * Intent with the specified Intent Id.
+     * Tests handling a future that contains an unresolvable error as a result of
+     * installing an intent.
      */
-    public static class EntryForIntentMatcher extends TypeSafeMatcher<Collection<Intent>> {
-        private final String id;
+    @Test
+    public void errorIntentInstallNeverTrue() {
+        final Long id = MockIntent.nextId();
+        flowRuleService.setFuture(false, 1);
+        MockIntent intent = new MockIntent(id);
+        listener.setLatch(1, Type.WITHDRAWN);
+        listener.setLatch(1, Type.INSTALL_REQ);
+        service.submit(intent);
+        listener.await(Type.INSTALL_REQ);
+        // The delay here forces the retry loop in the intent manager to time out
+        delay(100);
+        flowRuleService.setFuture(false, 1);
+        service.withdraw(intent);
+        listener.await(Type.WITHDRAWN);
+    }
 
-        public EntryForIntentMatcher(String idValue) {
-            id = idValue;
+    /**
+     * Tests that a compiler for a subclass of an intent that already has a
+     * compiler is automatically added.
+     */
+    @Test
+    public void intentSubclassCompile() {
+        class MockIntentSubclass extends MockIntent {
+            public MockIntentSubclass(Long number) {
+                super(number);
+            }
+        }
+        flowRuleService.setFuture(true);
+
+        listener.setLatch(1, Type.INSTALL_REQ);
+        listener.setLatch(1, Type.INSTALLED);
+        Intent intent = new MockIntentSubclass(MockIntent.nextId());
+        service.submit(intent);
+        listener.await(Type.INSTALL_REQ);
+        listener.await(Type.INSTALLED);
+        assertEquals(1L, service.getIntentCount());
+        assertEquals(1L, flowRuleService.getFlowRuleCount());
+
+        final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers =
+                extensionService.getCompilers();
+        assertEquals(2, compilers.size());
+        assertNotNull(compilers.get(MockIntentSubclass.class));
+        assertNotNull(compilers.get(MockIntent.class));
+    }
+
+    /**
+     * Tests an intent with no compiler.
+     */
+    @Test
+    public void intentWithoutCompiler() {
+        class IntentNoCompiler extends Intent {
+            IntentNoCompiler() {
+                super(APPID, null);
+            }
         }
 
-        @Override
-        public boolean matchesSafely(Collection<Intent> intents) {
-            return hasItem(Matchers.<Intent>hasProperty("id", equalTo(id))).matches(intents);
-        }
+        Intent intent = new IntentNoCompiler();
+        listener.setLatch(1, Type.INSTALL_REQ);
+        listener.setLatch(1, Type.FAILED);
+        service.submit(intent);
+        listener.await(Type.INSTALL_REQ);
+        listener.await(Type.FAILED);
+    }
 
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("an intent with id \" ").
-                    appendText(id).
-                    appendText("\"");
-        }
+    /**
+     * Tests an intent with no installer.
+     */
+    @Test
+    public void intentWithoutInstaller() {
+
+        extensionService.unregisterInstaller(MockInstallableIntent.class);
+
+        MockIntent intent = new MockIntent(MockIntent.nextId());
+        listener.setLatch(1, Type.INSTALL_REQ);
+        listener.setLatch(1, Type.FAILED);
+        service.submit(intent);
+        listener.await(Type.INSTALL_REQ);
+        listener.await(Type.FAILED);
+    }
+
+    /**
+     * Tests that the intent fetching methods are correct.
+     */
+    @Test
+    public void testIntentFetching() {
+        List<Intent> intents;
+
+        flowRuleService.setFuture(true);
+
+        intents = Lists.newArrayList(service.getIntents());
+        assertThat(intents, hasSize(0));
+
+        final MockIntent intent1 = new MockIntent(MockIntent.nextId());
+        final MockIntent intent2 = new MockIntent(MockIntent.nextId());
+
+        listener.setLatch(2, Type.INSTALL_REQ);
+        listener.setLatch(2, Type.INSTALLED);
+        service.submit(intent1);
+        service.submit(intent2);
+        listener.await(Type.INSTALL_REQ);
+        listener.await(Type.INSTALL_REQ);
+        listener.await(Type.INSTALLED);
+        listener.await(Type.INSTALLED);
+
+        intents = Lists.newArrayList(service.getIntents());
+        assertThat(intents, hasSize(2));
+
+        assertThat(intents, hasIntentWithId(intent1.id()));
+        assertThat(intents, hasIntentWithId(intent2.id()));
     }
 }