aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/core/net/src/test
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
commit13d05bc8458758ee39cb829098241e89616717ee (patch)
tree22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/core/net/src/test
parent6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff)
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/core/net/src/test')
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java198
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/FeaturesServiceAdapter.java168
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ConfigPropertyDefinitionsTest.java49
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/cluster/impl/MastershipManagerTest.java180
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/DummyIdBlockAllocator.java48
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/IdBlockAllocatorBasedIdGeneratorTest.java58
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/TestCoreManager.java29
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/event/impl/CoreEventDispatcherTest.java132
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/config/impl/NetworkConfigManagerTest.java242
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/BasicDeviceOperatorTest.java89
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java331
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/OpticalPortOperatorTest.java80
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java514
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java640
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveCompositionTreeTest.java603
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java536
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/BasicHostOperatorTest.java76
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java529
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java320
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/LinksHaveEntryWithSourceDestinationPairMatcher.java97
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentAccumulatorTest.java160
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTest.java261
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTestMock.java285
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java672
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/MockFlowRuleService.java116
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/ObjectiveTrackerTest.java326
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompilerTest.java167
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java163
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsIntentCompilerTest.java188
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java142
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java276
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java147
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java172
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompilerTest.java320
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/phase/CompilingTest.java149
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/BasicLinkOperatorTest.java77
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java311
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java667
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java194
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java164
-rw-r--r--framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java215
41 files changed, 10091 insertions, 0 deletions
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java
new file mode 100644
index 00000000..1ce31ac3
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.app.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.app.ApplicationEvent;
+import org.onosproject.app.ApplicationListener;
+import org.onosproject.app.ApplicationState;
+import org.onosproject.app.ApplicationStoreAdapter;
+import org.onosproject.common.app.ApplicationArchive;
+import org.onosproject.core.Application;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.DefaultApplication;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.onosproject.app.ApplicationEvent.Type.*;
+import static org.onosproject.app.ApplicationState.ACTIVE;
+import static org.onosproject.app.ApplicationState.INSTALLED;
+import static org.onosproject.app.DefaultApplicationDescriptionTest.*;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+
+/**
+ * Test of the application manager implementation.
+ */
+public class ApplicationManagerTest {
+
+ public static final DefaultApplicationId APP_ID = new DefaultApplicationId(1, APP_NAME);
+
+ private ApplicationManager mgr = new ApplicationManager();
+ private ApplicationListener listener = new TestListener();
+
+ @Before
+ public void setUp() {
+ injectEventDispatcher(mgr, new TestEventDispatcher());
+ mgr.featuresService = new TestFeaturesService();
+ mgr.store = new TestStore();
+ mgr.activate();
+ mgr.addListener(listener);
+ }
+
+ @After
+ public void tearDown() {
+ mgr.removeListener(listener);
+ mgr.deactivate();
+ }
+
+ private void validate(Application app) {
+ assertEquals("incorrect name", APP_NAME, app.id().name());
+ assertEquals("incorrect version", VER, app.version());
+ assertEquals("incorrect origin", ORIGIN, app.origin());
+
+ assertEquals("incorrect description", DESC, app.description());
+ assertEquals("incorrect features URI", FURL, app.featuresRepo().get());
+ assertEquals("incorrect features", FEATURES, app.features());
+ }
+
+ @Test
+ public void install() {
+ InputStream stream = ApplicationArchive.class.getResourceAsStream("app.zip");
+ Application app = mgr.install(stream);
+ validate(app);
+ assertEquals("incorrect features URI used", app.featuresRepo().get(),
+ ((TestFeaturesService) mgr.featuresService).uri);
+ assertEquals("incorrect app count", 1, mgr.getApplications().size());
+ assertEquals("incorrect app", app, mgr.getApplication(APP_ID));
+ assertEquals("incorrect app state", INSTALLED, mgr.getState(APP_ID));
+ }
+
+ @Test
+ public void uninstall() {
+ install();
+ mgr.uninstall(APP_ID);
+ assertEquals("incorrect app count", 0, mgr.getApplications().size());
+ }
+
+ @Test
+ public void activate() {
+ install();
+ mgr.activate(APP_ID);
+ assertEquals("incorrect app state", ACTIVE, mgr.getState(APP_ID));
+ }
+
+ @Test
+ public void deactivate() {
+ activate();
+ mgr.deactivate(APP_ID);
+ assertEquals("incorrect app state", INSTALLED, mgr.getState(APP_ID));
+ }
+
+
+ private class TestListener implements ApplicationListener {
+ private ApplicationEvent event;
+
+ @Override
+ public void event(ApplicationEvent event) {
+ this.event = event;
+ }
+ }
+
+ private class TestStore extends ApplicationStoreAdapter {
+
+ private Application app;
+ private ApplicationState state;
+
+ @Override
+ public Application create(InputStream appDescStream) {
+ app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, PERMS,
+ Optional.of(FURL), FEATURES);
+ state = INSTALLED;
+ delegate.notify(new ApplicationEvent(APP_INSTALLED, app));
+ return app;
+ }
+
+ @Override
+ public Set<Application> getApplications() {
+ return app != null ? ImmutableSet.of(app) : ImmutableSet.of();
+ }
+
+ @Override
+ public Application getApplication(ApplicationId appId) {
+ return app;
+ }
+
+ @Override
+ public void remove(ApplicationId appId) {
+ delegate.notify(new ApplicationEvent(APP_UNINSTALLED, app));
+ app = null;
+ state = null;
+ }
+
+ @Override
+ public ApplicationState getState(ApplicationId appId) {
+ return state;
+ }
+
+ @Override
+ public void activate(ApplicationId appId) {
+ state = ApplicationState.ACTIVE;
+ delegate.notify(new ApplicationEvent(APP_ACTIVATED, app));
+ }
+
+ @Override
+ public void deactivate(ApplicationId appId) {
+ state = INSTALLED;
+ delegate.notify(new ApplicationEvent(APP_DEACTIVATED, app));
+ }
+ }
+
+ private class TestFeaturesService extends FeaturesServiceAdapter {
+ private URI uri;
+ private Set<String> features = new HashSet<>();
+
+ @Override
+ public void addRepository(URI uri) throws Exception {
+ this.uri = uri;
+ }
+
+ @Override
+ public void removeRepository(URI uri) throws Exception {
+ this.uri = null;
+ }
+
+ @Override
+ public void installFeature(String name) throws Exception {
+ features.add(name);
+ }
+
+ @Override
+ public void uninstallFeature(String name) throws Exception {
+ features.remove(name);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/FeaturesServiceAdapter.java b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/FeaturesServiceAdapter.java
new file mode 100644
index 00000000..fc19b0a1
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/FeaturesServiceAdapter.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.app.impl;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.Repository;
+
+import java.net.URI;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * Adapter for testing against Apache Karaf feature service.
+ */
+public class FeaturesServiceAdapter implements org.apache.karaf.features.FeaturesService {
+ @Override
+ public void validateRepository(URI uri) throws Exception {
+
+ }
+
+ @Override
+ public void addRepository(URI uri) throws Exception {
+
+ }
+
+ @Override
+ public void addRepository(URI uri, boolean install) throws Exception {
+
+ }
+
+ @Override
+ public void removeRepository(URI uri) throws Exception {
+
+ }
+
+ @Override
+ public void removeRepository(URI uri, boolean uninstall) throws Exception {
+
+ }
+
+ @Override
+ public void restoreRepository(URI uri) throws Exception {
+
+ }
+
+ @Override
+ public Repository[] listRepositories() {
+ return new Repository[0];
+ }
+
+ @Override
+ public Repository getRepository(String repoName) {
+ return null;
+ }
+
+ @Override
+ public Repository getRepository(URI uri) {
+ return null;
+ }
+
+ @Override
+ public String getRepositoryName(URI uri) {
+ return null;
+ }
+
+ @Override
+ public void installFeature(String name) throws Exception {
+
+ }
+
+ @Override
+ public void installFeature(String name, EnumSet<Option> options) throws Exception {
+
+ }
+
+ @Override
+ public void installFeature(String name, String version) throws Exception {
+
+ }
+
+ @Override
+ public void installFeature(String name, String version, EnumSet<Option> options) throws Exception {
+
+ }
+
+ @Override
+ public void installFeature(Feature f, EnumSet<Option> options) throws Exception {
+
+ }
+
+ @Override
+ public void installFeatures(Set<Feature> features, EnumSet<Option> options) throws Exception {
+
+ }
+
+ @Override
+ public void uninstallFeature(String name, EnumSet<Option> options) throws Exception {
+
+ }
+
+ @Override
+ public void uninstallFeature(String name) throws Exception {
+
+ }
+
+ @Override
+ public void uninstallFeature(String name, String version, EnumSet<Option> options) throws Exception {
+
+ }
+
+ @Override
+ public void uninstallFeature(String name, String version) throws Exception {
+
+ }
+
+ @Override
+ public Feature[] listFeatures() throws Exception {
+ return new Feature[0];
+ }
+
+ @Override
+ public Feature[] listInstalledFeatures() {
+ return new Feature[0];
+ }
+
+ @Override
+ public boolean isInstalled(Feature f) {
+ return false;
+ }
+
+ @Override
+ public Feature[] getFeatures(String name, String version) throws Exception {
+ return new Feature[0];
+ }
+
+ @Override
+ public Feature[] getFeatures(String name) throws Exception {
+ return new Feature[0];
+ }
+
+ @Override
+ public Feature getFeature(String name, String version) throws Exception {
+ return null;
+ }
+
+ @Override
+ public Feature getFeature(String name) throws Exception {
+ return null;
+ }
+
+ @Override
+ public void refreshRepository(URI uri) throws Exception {
+
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ConfigPropertyDefinitionsTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ConfigPropertyDefinitionsTest.java
new file mode 100644
index 00000000..66e9c7b4
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ConfigPropertyDefinitionsTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.cfg.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.Test;
+import org.onosproject.cfg.ConfigProperty;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+import static org.onosproject.cfg.ConfigProperty.Type.STRING;
+import static org.onosproject.cfg.ConfigProperty.defineProperty;
+import static org.onosproject.cfg.impl.ConfigPropertyDefinitions.read;
+import static org.onosproject.cfg.impl.ConfigPropertyDefinitions.write;
+
+/**
+ * Tests of the config property definitions utility.
+ */
+public class ConfigPropertyDefinitionsTest {
+
+ @Test
+ public void basics() throws IOException {
+ Set<ConfigProperty> original = ImmutableSet
+ .of(defineProperty("foo", STRING, "dingo", "FOO"),
+ defineProperty("bar", STRING, "bat", "BAR"));
+ ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+ write(out, original);
+ Set<ConfigProperty> read = read(new ByteArrayInputStream(out.toByteArray()));
+ assertEquals("incorrect defs", original, read);
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/cluster/impl/MastershipManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/cluster/impl/MastershipManagerTest.java
new file mode 100644
index 00000000..bf1a1ff3
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/cluster/impl/MastershipManagerTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.cluster.impl;
+
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.ClusterServiceAdapter;
+import org.onosproject.cluster.ControllerNode;
+import org.onosproject.cluster.DefaultControllerNode;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.mastership.MastershipStore;
+import org.onosproject.mastership.MastershipTermService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.store.trivial.SimpleMastershipStore;
+
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.onosproject.net.MastershipRole.MASTER;
+import static org.onosproject.net.MastershipRole.NONE;
+import static org.onosproject.net.MastershipRole.STANDBY;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+
+/**
+ * Test codifying the mastership service contracts.
+ */
+public class MastershipManagerTest {
+
+ private static final NodeId NID_LOCAL = new NodeId("local");
+ private static final NodeId NID_OTHER = new NodeId("foo");
+ private static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
+ private static final DeviceId DEV_MASTER = DeviceId.deviceId("of:1");
+ private static final DeviceId DEV_OTHER = DeviceId.deviceId("of:2");
+
+ private MastershipManager mgr;
+ protected MastershipService service;
+
+ @Before
+ public void setUp() {
+ mgr = new MastershipManager();
+ service = mgr;
+ injectEventDispatcher(mgr, new TestEventDispatcher());
+ mgr.clusterService = new TestClusterService();
+ mgr.store = new TestSimpleMastershipStore(mgr.clusterService);
+ mgr.activate();
+ }
+
+ @After
+ public void tearDown() {
+ mgr.deactivate();
+ mgr.clusterService = null;
+ injectEventDispatcher(mgr, null);
+ mgr.store = null;
+ }
+
+ @Test
+ public void setRole() {
+ mgr.setRole(NID_OTHER, DEV_MASTER, MASTER);
+ assertEquals("wrong local role:", NONE, mgr.getLocalRole(DEV_MASTER));
+ assertEquals("wrong obtained role:", STANDBY, Futures.getUnchecked(mgr.requestRoleFor(DEV_MASTER)));
+
+ //set to master
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ assertEquals("wrong local role:", MASTER, mgr.getLocalRole(DEV_MASTER));
+ }
+
+ @Test
+ public void relinquishMastership() {
+ //no backups - should just turn to NONE for device.
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ assertEquals("wrong role:", MASTER, mgr.getLocalRole(DEV_MASTER));
+ mgr.relinquishMastership(DEV_MASTER);
+ assertNull("wrong master:", mgr.getMasterFor(DEV_OTHER));
+ assertEquals("wrong role:", NONE, mgr.getLocalRole(DEV_MASTER));
+
+ //not master, nothing should happen
+ mgr.setRole(NID_LOCAL, DEV_OTHER, NONE);
+ mgr.relinquishMastership(DEV_OTHER);
+ assertNull("wrong role:", mgr.getMasterFor(DEV_OTHER));
+
+ //provide NID_OTHER as backup and relinquish
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_MASTER));
+ mgr.setRole(NID_OTHER, DEV_MASTER, STANDBY);
+ mgr.relinquishMastership(DEV_MASTER);
+ assertEquals("wrong master:", NID_OTHER, mgr.getMasterFor(DEV_MASTER));
+ }
+
+ @Test
+ public void requestRoleFor() {
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ mgr.setRole(NID_OTHER, DEV_OTHER, MASTER);
+
+ //local should be master for one but standby for other
+ assertEquals("wrong role:", MASTER, Futures.getUnchecked(mgr.requestRoleFor(DEV_MASTER)));
+ assertEquals("wrong role:", STANDBY, Futures.getUnchecked(mgr.requestRoleFor(DEV_OTHER)));
+ }
+
+ @Test
+ public void getMasterFor() {
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ mgr.setRole(NID_OTHER, DEV_OTHER, MASTER);
+ assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_MASTER));
+ assertEquals("wrong master:", NID_OTHER, mgr.getMasterFor(DEV_OTHER));
+
+ //have NID_OTHER hand over DEV_OTHER to NID_LOCAL
+ mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER);
+ assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_OTHER));
+ }
+
+ @Test
+ public void getDevicesOf() {
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY);
+ assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size());
+ //hand both devices to NID_LOCAL
+ mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER);
+ assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size());
+ }
+
+ @Test
+ public void termService() {
+ MastershipTermService ts = mgr;
+
+ //term = 1 for both
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ assertEquals("inconsistent term: ", 1, ts.getMastershipTerm(DEV_MASTER).termNumber());
+
+ //hand devices to NID_LOCAL and back: term = 1 + 2
+ mgr.setRole(NID_OTHER, DEV_MASTER, MASTER);
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ assertEquals("inconsistent terms: ", 3, ts.getMastershipTerm(DEV_MASTER).termNumber());
+ }
+
+ private final class TestClusterService extends ClusterServiceAdapter {
+
+ ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
+
+ @Override
+ public ControllerNode getLocalNode() {
+ return local;
+ }
+
+ @Override
+ public Set<ControllerNode> getNodes() {
+ return Sets.newHashSet();
+ }
+
+ }
+
+ private final class TestSimpleMastershipStore extends SimpleMastershipStore
+ implements MastershipStore {
+
+ public TestSimpleMastershipStore(ClusterService clusterService) {
+ super.clusterService = clusterService;
+ }
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/DummyIdBlockAllocator.java b/framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/DummyIdBlockAllocator.java
new file mode 100644
index 00000000..383e981a
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/DummyIdBlockAllocator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.core.impl;
+
+import org.onosproject.core.IdBlock;
+
+public class DummyIdBlockAllocator implements IdBlockAllocator {
+ private long blockTop;
+ private static final long BLOCK_SIZE = 0x1000000L;
+
+ /**
+ * Returns a block of IDs which are unique and unused.
+ * Range of IDs is fixed size and is assigned incrementally as this method
+ * called.
+ *
+ * @return an IdBlock containing a set of unique IDs
+ */
+ @Override
+ public IdBlock allocateUniqueIdBlock() {
+ synchronized (this) {
+ long blockHead = blockTop;
+ long blockTail = blockTop + BLOCK_SIZE;
+
+ IdBlock block = new IdBlock(blockHead, BLOCK_SIZE);
+ blockTop = blockTail;
+
+ return block;
+ }
+ }
+
+ @Override
+ public IdBlock allocateUniqueIdBlock(long range) {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/IdBlockAllocatorBasedIdGeneratorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/IdBlockAllocatorBasedIdGeneratorTest.java
new file mode 100644
index 00000000..8a4e6185
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/IdBlockAllocatorBasedIdGeneratorTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.core.impl;
+
+import org.easymock.EasyMock;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.core.IdBlock;
+
+/**
+ * Suites of test of {@link org.onosproject.core.impl.BlockAllocatorBasedIdGenerator}.
+ */
+public class IdBlockAllocatorBasedIdGeneratorTest {
+ private IdBlockAllocator allocator;
+ private BlockAllocatorBasedIdGenerator sut;
+
+ @Before
+ public void setUp() {
+ allocator = EasyMock.createMock(IdBlockAllocator.class);
+
+ }
+
+ /**
+ * Tests generated IntentId sequences using two {@link org.onosproject.core.IdBlock blocks}.
+ */
+ @Test
+ public void testIds() {
+ EasyMock.expect(allocator.allocateUniqueIdBlock())
+ .andReturn(new IdBlock(0, 3))
+ .andReturn(new IdBlock(4, 3));
+
+ EasyMock.replay(allocator);
+ sut = new BlockAllocatorBasedIdGenerator(allocator);
+
+ Assert.assertThat(sut.getNewId(), Matchers.is(0L));
+ Assert.assertThat(sut.getNewId(), Matchers.is(1L));
+ Assert.assertThat(sut.getNewId(), Matchers.is(2L));
+
+ Assert.assertThat(sut.getNewId(), Matchers.is(4L));
+ Assert.assertThat(sut.getNewId(), Matchers.is(5L));
+ Assert.assertThat(sut.getNewId(), Matchers.is(6L));
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/TestCoreManager.java b/framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/TestCoreManager.java
new file mode 100644
index 00000000..474d1705
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/TestCoreManager.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.core.impl;
+
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.core.IdGenerator;
+
+public class TestCoreManager extends CoreServiceAdapter {
+
+ @Override
+ public IdGenerator getIdGenerator(String topic) {
+ IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
+ return new BlockAllocatorBasedIdGenerator(idBlockAllocator);
+ }
+
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/event/impl/CoreEventDispatcherTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/event/impl/CoreEventDispatcherTest.java
new file mode 100644
index 00000000..9ba3db59
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/event/impl/CoreEventDispatcherTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.event.impl;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.event.AbstractEvent;
+import org.onosproject.event.EventSink;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test of the even dispatcher mechanism.
+ */
+public class CoreEventDispatcherTest {
+
+ private final CoreEventDispatcher dispatcher = new CoreEventDispatcher();
+ private final PrickleSink prickleSink = new PrickleSink();
+ private final GooSink gooSink = new GooSink();
+
+ @Before
+ public void setUp() {
+ dispatcher.activate();
+ dispatcher.addSink(Prickle.class, prickleSink);
+ dispatcher.addSink(Goo.class, gooSink);
+ }
+
+ @After
+ public void tearDown() {
+ dispatcher.removeSink(Goo.class);
+ dispatcher.removeSink(Prickle.class);
+ dispatcher.deactivate();
+ }
+
+ @Test
+ public void post() throws Exception {
+ prickleSink.latch = new CountDownLatch(1);
+ dispatcher.post(new Prickle("yo"));
+ prickleSink.latch.await(100, TimeUnit.MILLISECONDS);
+ validate(prickleSink, "yo");
+ validate(gooSink);
+ }
+
+ @Test
+ public void postEventWithBadSink() throws Exception {
+ gooSink.latch = new CountDownLatch(1);
+ dispatcher.post(new Goo("boom"));
+ gooSink.latch.await(100, TimeUnit.MILLISECONDS);
+ validate(gooSink, "boom");
+ validate(prickleSink);
+ }
+
+ @Test
+ public void postEventWithNoSink() throws Exception {
+ dispatcher.post(new Thing("boom"));
+ validate(gooSink);
+ validate(prickleSink);
+ }
+
+ private void validate(Sink sink, String... strings) {
+ int i = 0;
+ assertEquals("incorrect event count", strings.length, sink.subjects.size());
+ for (String string : strings) {
+ assertEquals("incorrect event", string, sink.subjects.get(i++));
+ }
+ }
+
+ private enum Type { FOO }
+
+ private static class Thing extends AbstractEvent<Type, String> {
+ protected Thing(String subject) {
+ super(Type.FOO, subject);
+ }
+ }
+
+ private static class Prickle extends Thing {
+ protected Prickle(String subject) {
+ super(subject);
+ }
+ }
+
+ private static class Goo extends Thing {
+ protected Goo(String subject) {
+ super(subject);
+ }
+ }
+
+ private static class Sink {
+ final List<String> subjects = new ArrayList<>();
+ CountDownLatch latch;
+
+ protected void process(String subject) {
+ subjects.add(subject);
+ latch.countDown();
+ }
+ }
+
+ private static class PrickleSink extends Sink implements EventSink<Prickle> {
+ @Override
+ public void process(Prickle event) {
+ process(event.subject());
+ }
+ }
+
+ private static class GooSink extends Sink implements EventSink<Goo> {
+ @Override
+ public void process(Goo event) {
+ process(event.subject());
+ throw new IllegalStateException("BOOM!");
+ }
+ }
+
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/config/impl/NetworkConfigManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/config/impl/NetworkConfigManagerTest.java
new file mode 100644
index 00000000..2d03bfc8
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/config/impl/NetworkConfigManagerTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.config.impl;
+
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onosproject.event.EventDeliveryServiceAdapter;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.NetworkConfigService;
+import org.onosproject.net.config.SubjectFactory;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.store.config.impl.DistributedNetworkConfigStore;
+import org.onosproject.store.service.TestStorageService;
+
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Unit tests for network config registry.
+ */
+public class NetworkConfigManagerTest {
+ private NetworkConfigManager manager;
+ private NetworkConfigRegistry registry;
+ private NetworkConfigService configService;
+ private DistributedNetworkConfigStore configStore;
+
+ /**
+ * Config classes for testing.
+ */
+ public class BasicConfig1 extends Config<String> { }
+ public class BasicConfig2 extends Config<String> { }
+
+ public class MockSubjectFactory extends SubjectFactory<String> {
+ protected MockSubjectFactory(Class<String> subjectClass, String subjectKey) {
+ super(subjectClass, subjectKey);
+ }
+
+ @Override
+ public String createSubject(String subjectKey) {
+ return subjectKey + "-subject";
+ }
+ }
+
+ /**
+ * Config factory classes for testing.
+ */
+ public class MockConfigFactory1 extends ConfigFactory<String, BasicConfig1> {
+ protected MockConfigFactory1(SubjectFactory<String> subjectFactory,
+ Class<BasicConfig1> configClass, String configKey) {
+ super(subjectFactory, configClass, configKey);
+ }
+ @Override
+ public BasicConfig1 createConfig() {
+ return new BasicConfig1();
+ }
+ }
+
+ public class MockConfigFactory2 extends ConfigFactory<String, BasicConfig2> {
+ protected MockConfigFactory2(SubjectFactory<String> subjectFactory,
+ Class<BasicConfig2> configClass, String configKey) {
+ super(subjectFactory, configClass, configKey);
+ }
+ @Override
+ public BasicConfig2 createConfig() {
+ return new BasicConfig2();
+ }
+ }
+
+ MockSubjectFactory factory1 = new MockSubjectFactory(String.class,
+ "key1");
+ MockSubjectFactory factory2 = new MockSubjectFactory(String.class,
+ "key2");
+
+ MockConfigFactory1 config1Factory = new MockConfigFactory1(factory1,
+ BasicConfig1.class, "config1");
+ MockConfigFactory2 config2Factory = new MockConfigFactory2(factory2,
+ BasicConfig2.class, "config2");
+
+
+ @Before
+ public void setUp() throws Exception {
+ configStore = new DistributedNetworkConfigStore();
+ TestUtils.setField(configStore, "storageService", new TestStorageService());
+ configStore.activate();
+ manager = new NetworkConfigManager();
+ manager.store = configStore;
+ NetTestTools.injectEventDispatcher(manager, new EventDeliveryServiceAdapter());
+ manager.activate();
+ registry = manager;
+ configService = manager;
+ }
+
+ @After
+ public void tearDown() {
+ configStore.deactivate();
+ manager.deactivate();
+ }
+
+ @Test
+ public void testRegistry() {
+ assertThat(registry.getConfigFactories(), hasSize(0));
+ assertThat(registry.getConfigFactories(String.class), hasSize(0));
+ assertThat(registry.getConfigFactory(BasicConfig1.class), nullValue());
+
+ registry.registerConfigFactory(config1Factory);
+ registry.registerConfigFactory(config2Factory);
+
+ assertThat(registry.getConfigFactories(), hasSize(2));
+ assertThat(registry.getConfigFactories(String.class), hasSize(2));
+
+ ConfigFactory queried = registry.getConfigFactory(BasicConfig1.class);
+ assertThat(queried, is(config1Factory));
+
+ registry.unregisterConfigFactory(queried);
+ // Factory associations are not removed according to code documentation
+ assertThat(registry.getConfigFactories(), hasSize(1));
+ assertThat(registry.getConfigFactories(String.class), hasSize(1));
+ assertThat(registry.getConfigFactory(BasicConfig1.class), nullValue());
+ }
+
+ @Test
+ public void configIdEquals() {
+ NetworkConfigManager.ConfigIdentifier id1 =
+ new NetworkConfigManager.ConfigIdentifier("s1", "c1");
+ NetworkConfigManager.ConfigIdentifier likeId1 =
+ new NetworkConfigManager.ConfigIdentifier("s1", "c1");
+ NetworkConfigManager.ConfigIdentifier id2 =
+ new NetworkConfigManager.ConfigIdentifier("s1", "c2");
+ NetworkConfigManager.ConfigIdentifier id3 =
+ new NetworkConfigManager.ConfigIdentifier("s2", "c1");
+
+ new EqualsTester().addEqualityGroup(id1, likeId1)
+ .addEqualityGroup(id2)
+ .addEqualityGroup(id3)
+ .testEquals();
+ }
+
+ @Test
+ public void configKeyEquals() {
+ NetworkConfigManager.ConfigKey key1 =
+ new NetworkConfigManager.ConfigKey(String.class, String.class);
+ NetworkConfigManager.ConfigKey likeKey1 =
+ new NetworkConfigManager.ConfigKey(String.class, String.class);
+ NetworkConfigManager.ConfigKey key2 =
+ new NetworkConfigManager.ConfigKey(String.class, Integer.class);
+ NetworkConfigManager.ConfigKey key3 =
+ new NetworkConfigManager.ConfigKey(Integer.class, String.class);
+
+ new EqualsTester().addEqualityGroup(key1, likeKey1)
+ .addEqualityGroup(key2)
+ .addEqualityGroup(key3)
+ .testEquals();
+ }
+
+ /**
+ * Tests creation, query and removal of a factory.
+ */
+ @Test
+ public void testAddConfig() {
+
+ assertThat(configService.getSubjectFactory(String.class), nullValue());
+ assertThat(configService.getSubjectFactory("key"), nullValue());
+
+ registry.registerConfigFactory(config1Factory);
+ registry.registerConfigFactory(config2Factory);
+ configService.addConfig("configKey", BasicConfig1.class);
+
+ Config newConfig = configService.getConfig("configKey", BasicConfig1.class);
+ assertThat(newConfig, notNullValue());
+
+ assertThat(configService.getSubjectFactory(String.class), notNullValue());
+ assertThat(configService.getSubjectFactory("key1"), notNullValue());
+
+ Set<Class> classes = configService.getSubjectClasses();
+ assertThat(classes, hasSize(1));
+
+ Set<String> subjectsForClass =
+ configService.getSubjects(String.class);
+ assertThat(subjectsForClass, hasSize(1));
+
+ Set<String> subjectsForConfig =
+ configService.getSubjects(String.class, BasicConfig1.class);
+ assertThat(subjectsForConfig, hasSize(1));
+
+ Class queriedConfigClass = configService.getConfigClass("key1", "config1");
+ assertThat(queriedConfigClass == BasicConfig1.class, is(true));
+
+ Set<? extends Config> configs = configService.getConfigs("configKey");
+ assertThat(configs.size(), is(1));
+ configs.forEach(c -> assertThat(c, instanceOf(BasicConfig1.class)));
+
+ configService.removeConfig("configKey", BasicConfig1.class);
+ Config newConfigAfterRemove = configService.getConfig("configKey", BasicConfig1.class);
+ assertThat(newConfigAfterRemove, nullValue());
+ }
+
+ /**
+ * Tests creation, query and removal of a factory.
+ */
+ @Test
+ public void testApplyConfig() {
+
+ assertThat(configService.getSubjectFactory(String.class), nullValue());
+ assertThat(configService.getSubjectFactory("key"), nullValue());
+
+ registry.registerConfigFactory(config1Factory);
+ registry.registerConfigFactory(config2Factory);
+ configService.applyConfig("configKey", BasicConfig1.class, new ObjectMapper().createObjectNode());
+
+ Config newConfig = configService.getConfig("configKey", BasicConfig1.class);
+ assertThat(newConfig, notNullValue());
+
+ assertThat(configService.getSubjectFactory(String.class), notNullValue());
+ assertThat(configService.getSubjectFactory("key1"), notNullValue());
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/BasicDeviceOperatorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/BasicDeviceOperatorTest.java
new file mode 100644
index 00000000..8827c558
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/BasicDeviceOperatorTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.device.impl;
+
+import static org.onosproject.net.Device.Type.SWITCH;
+import static org.onosproject.net.Device.Type.ROADM;
+import static org.junit.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.ChassisId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.net.config.basics.BasicDeviceConfig;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DeviceDescription;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+
+public class BasicDeviceOperatorTest {
+
+ private static final String NAME1 = "of:foo";
+ private static final String NAME2 = "of:bar";
+ private static final String OWNER = "somebody";
+ private static final URI DURI = URI.create(NAME1);
+ private static final String MFR = "whitebox";
+ private static final String HW = "1.1.x";
+ private static final String SW = "3.9.1";
+ private static final String SN = "43311-12345";
+ private static final ChassisId CID = new ChassisId();
+
+ private static final SparseAnnotations SA = DefaultAnnotations.builder()
+ .set(AnnotationKeys.DRIVER, NAME2).build();
+
+ private static final DeviceDescription DEV1 = new DefaultDeviceDescription(
+ DURI, SWITCH, MFR, HW, SW, SN, CID, SA);
+
+ private final ConfigApplyDelegate delegate = new ConfigApplyDelegate() {
+ @Override
+ public void onApply(Config config) {
+ }
+ };
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ private static final BasicDeviceConfig SW_BDC = new BasicDeviceConfig();
+ private static final BasicDeviceConfig RD_BDC = new BasicDeviceConfig();
+
+ @Before
+ public void setUp() {
+ SW_BDC.init(DeviceId.deviceId(NAME1), NAME1, JsonNodeFactory.instance.objectNode(), mapper, delegate);
+ SW_BDC.type(SWITCH).driver(NAME1).owner(OWNER);
+ RD_BDC.init(DeviceId.deviceId(NAME2), NAME2, JsonNodeFactory.instance.objectNode(), mapper, delegate);
+ RD_BDC.type(ROADM);
+ }
+
+ @Test
+ public void testDescOps() {
+ DeviceDescription desc = BasicDeviceOperator.combine(null, DEV1);
+ assertEquals(desc, DEV1);
+
+ // override driver name
+ desc = BasicDeviceOperator.combine(SW_BDC, DEV1);
+ assertEquals(NAME1, desc.annotations().value(AnnotationKeys.DRIVER));
+
+ // override Device Type
+ desc = BasicDeviceOperator.combine(RD_BDC, DEV1);
+ assertEquals(ROADM, desc.type());
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
new file mode 100644
index 00000000..04f266f0
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.device.impl;
+
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.ChassisId;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cluster.ClusterServiceAdapter;
+import org.onosproject.cluster.ControllerNode;
+import org.onosproject.cluster.DefaultControllerNode;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.event.Event;
+import org.onosproject.net.config.NetworkConfigServiceAdapter;
+import org.onosproject.mastership.MastershipServiceAdapter;
+import org.onosproject.mastership.MastershipTerm;
+import org.onosproject.mastership.MastershipTermService;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DefaultDeviceDescription;
+import org.onosproject.net.device.DefaultPortDescription;
+import org.onosproject.net.device.DeviceAdminService;
+import org.onosproject.net.device.DeviceDescription;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceProvider;
+import org.onosproject.net.device.DeviceProviderRegistry;
+import org.onosproject.net.device.DeviceProviderService;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.PortDescription;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.trivial.SimpleDeviceStore;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+import static org.junit.Assert.*;
+import static org.onosproject.net.Device.Type.SWITCH;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+import static org.onosproject.net.device.DeviceEvent.Type.*;
+
+/**
+ * Test codifying the device service & device provider service contracts.
+ */
+public class DeviceManagerTest {
+
+ private static final ProviderId PID = new ProviderId("of", "foo");
+ private static final DeviceId DID1 = deviceId("of:foo");
+ private static final DeviceId DID2 = deviceId("of:bar");
+ private static final String MFR = "whitebox";
+ private static final String HW = "1.1.x";
+ private static final String SW1 = "3.8.1";
+ private static final String SW2 = "3.9.5";
+ private static final String SN = "43311-12345";
+ private static final ChassisId CID = new ChassisId();
+
+ private static final PortNumber P1 = PortNumber.portNumber(1);
+ private static final PortNumber P2 = PortNumber.portNumber(2);
+ private static final PortNumber P3 = PortNumber.portNumber(3);
+ private static final NodeId NID_LOCAL = new NodeId("local");
+ private static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
+
+ private DeviceManager mgr;
+
+ protected DeviceService service;
+ protected DeviceAdminService admin;
+ protected DeviceProviderRegistry registry;
+ protected DeviceProviderService providerService;
+ protected TestProvider provider;
+ protected TestListener listener = new TestListener();
+
+ @Before
+ public void setUp() {
+ mgr = new DeviceManager();
+ service = mgr;
+ admin = mgr;
+ registry = mgr;
+ mgr.store = new SimpleDeviceStore();
+ injectEventDispatcher(mgr, new TestEventDispatcher());
+ TestMastershipManager mastershipManager = new TestMastershipManager();
+ mgr.mastershipService = mastershipManager;
+ mgr.termService = mastershipManager;
+ mgr.clusterService = new TestClusterService();
+ mgr.networkConfigService = new TestNetworkConfigService();
+ mgr.activate();
+
+
+ service.addListener(listener);
+
+ provider = new TestProvider();
+ providerService = registry.register(provider);
+ assertTrue("provider should be registered",
+ registry.getProviders().contains(provider.id()));
+ }
+
+ @After
+ public void tearDown() {
+ registry.unregister(provider);
+ assertFalse("provider should not be registered",
+ registry.getProviders().contains(provider.id()));
+ service.removeListener(listener);
+ mgr.deactivate();
+ }
+
+ private void connectDevice(DeviceId deviceId, String swVersion) {
+ DeviceDescription description =
+ new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
+ HW, swVersion, SN, CID);
+ providerService.deviceConnected(deviceId, description);
+ assertNotNull("device should be found", service.getDevice(DID1));
+ }
+
+ @Test
+ public void deviceConnected() {
+ assertNull("device should not be found", service.getDevice(DID1));
+ connectDevice(DID1, SW1);
+ validateEvents(DEVICE_ADDED);
+
+ Iterator<Device> it = service.getDevices().iterator();
+ assertNotNull("one device expected", it.next());
+ assertFalse("only one device expected", it.hasNext());
+ assertEquals("incorrect device count", 1, service.getDeviceCount());
+ assertTrue("device should be available", service.isAvailable(DID1));
+ }
+
+ @Test
+ public void deviceDisconnected() {
+ connectDevice(DID1, SW1);
+ connectDevice(DID2, SW1);
+ validateEvents(DEVICE_ADDED, DEVICE_ADDED);
+ assertTrue("device should be available", service.isAvailable(DID1));
+
+ // Disconnect
+ providerService.deviceDisconnected(DID1);
+ assertNotNull("device should not be found", service.getDevice(DID1));
+ assertFalse("device should not be available", service.isAvailable(DID1));
+ validateEvents(DEVICE_AVAILABILITY_CHANGED);
+
+ // Reconnect
+ connectDevice(DID1, SW1);
+ validateEvents(DEVICE_AVAILABILITY_CHANGED);
+
+ assertEquals("incorrect device count", 2, service.getDeviceCount());
+ }
+
+ @Test
+ public void deviceUpdated() {
+ connectDevice(DID1, SW1);
+ validateEvents(DEVICE_ADDED);
+
+ connectDevice(DID1, SW2);
+ validateEvents(DEVICE_UPDATED);
+ }
+
+ @Test
+ public void getRole() {
+ connectDevice(DID1, SW1);
+ assertEquals("incorrect role", MastershipRole.MASTER, service.getRole(DID1));
+ }
+
+ @Test
+ public void updatePorts() {
+ connectDevice(DID1, SW1);
+ List<PortDescription> pds = new ArrayList<>();
+ pds.add(new DefaultPortDescription(P1, true));
+ pds.add(new DefaultPortDescription(P2, true));
+ pds.add(new DefaultPortDescription(P3, true));
+ providerService.updatePorts(DID1, pds);
+ validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED, PORT_ADDED);
+ pds.clear();
+
+ pds.add(new DefaultPortDescription(P1, false));
+ pds.add(new DefaultPortDescription(P3, true));
+ providerService.updatePorts(DID1, pds);
+ validateEvents(PORT_UPDATED, PORT_REMOVED);
+ }
+
+ @Test
+ public void updatePortStatus() {
+ connectDevice(DID1, SW1);
+ List<PortDescription> pds = new ArrayList<>();
+ pds.add(new DefaultPortDescription(P1, true));
+ pds.add(new DefaultPortDescription(P2, true));
+ providerService.updatePorts(DID1, pds);
+ validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
+
+ providerService.portStatusChanged(DID1, new DefaultPortDescription(P1, false));
+ validateEvents(PORT_UPDATED);
+ providerService.portStatusChanged(DID1, new DefaultPortDescription(P1, false));
+ assertTrue("no events expected", listener.events.isEmpty());
+ }
+
+ @Test
+ public void getPorts() {
+ connectDevice(DID1, SW1);
+ List<PortDescription> pds = new ArrayList<>();
+ pds.add(new DefaultPortDescription(P1, true));
+ pds.add(new DefaultPortDescription(P2, true));
+ providerService.updatePorts(DID1, pds);
+ validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
+ assertEquals("wrong port count", 2, service.getPorts(DID1).size());
+
+ Port port = service.getPort(DID1, P1);
+ assertEquals("incorrect port", P1, service.getPort(DID1, P1).number());
+ assertEquals("incorrect state", true, service.getPort(DID1, P1).isEnabled());
+ }
+
+ @Test
+ public void removeDevice() {
+ connectDevice(DID1, SW1);
+ connectDevice(DID2, SW2);
+ assertEquals("incorrect device count", 2, service.getDeviceCount());
+ admin.removeDevice(DID1);
+ assertNull("device should not be found", service.getDevice(DID1));
+ assertNotNull("device should be found", service.getDevice(DID2));
+ assertEquals("incorrect device count", 1, service.getDeviceCount());
+
+ }
+
+ protected void validateEvents(Enum... types) {
+ int i = 0;
+ assertEquals("wrong events received", types.length, listener.events.size());
+ for (Event event : listener.events) {
+ assertEquals("incorrect event type", types[i], event.type());
+ i++;
+ }
+ listener.events.clear();
+ }
+
+
+ private class TestProvider extends AbstractProvider implements DeviceProvider {
+ private DeviceId deviceReceived;
+ private MastershipRole roleReceived;
+
+ public TestProvider() {
+ super(PID);
+ }
+
+ @Override
+ public void triggerProbe(DeviceId deviceId) {
+ }
+
+ @Override
+ public void roleChanged(DeviceId device, MastershipRole newRole) {
+ deviceReceived = device;
+ roleReceived = newRole;
+ }
+
+ @Override
+ public boolean isReachable(DeviceId device) {
+ return false;
+ }
+ }
+
+ private static class TestListener implements DeviceListener {
+ final List<DeviceEvent> events = new ArrayList<>();
+
+ @Override
+ public void event(DeviceEvent event) {
+ events.add(event);
+ }
+ }
+
+ private static class TestMastershipManager
+ extends MastershipServiceAdapter implements MastershipTermService {
+ @Override
+ public MastershipRole getLocalRole(DeviceId deviceId) {
+ return MastershipRole.MASTER;
+ }
+
+ @Override
+ public Set<DeviceId> getDevicesOf(NodeId nodeId) {
+ return Sets.newHashSet(DID1, DID2);
+ }
+
+ @Override
+ public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) {
+ return CompletableFuture.completedFuture(MastershipRole.MASTER);
+ }
+
+ @Override
+ public CompletableFuture<Void> relinquishMastership(DeviceId deviceId) {
+ return CompletableFuture.completedFuture(null);
+ }
+
+ @Override
+ public MastershipTerm getMastershipTerm(DeviceId deviceId) {
+ // FIXME: just returning something not null
+ return MastershipTerm.of(NID_LOCAL, 1);
+ }
+ }
+
+ // code clone
+ private final class TestClusterService extends ClusterServiceAdapter {
+
+ ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
+
+ @Override
+ public ControllerNode getLocalNode() {
+ return local;
+ }
+
+ }
+
+ private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/OpticalPortOperatorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/OpticalPortOperatorTest.java
new file mode 100644
index 00000000..78bc08e0
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/OpticalPortOperatorTest.java
@@ -0,0 +1,80 @@
+package org.onosproject.net.device.impl;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.net.config.basics.OpticalPortConfig;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.OduCltPort;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.device.OduCltPortDescription;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+
+import static org.junit.Assert.assertEquals;
+
+public class OpticalPortOperatorTest {
+ private static final DeviceId DID = DeviceId.deviceId("op-test");
+ private static final String TPNAME = "test-port-100";
+ private static final String SPNAME = "out-port-200";
+ private static final String CFGNAME = "cfg-name";
+
+ private static final PortNumber NAMED = PortNumber.portNumber(100, TPNAME);
+ private static final PortNumber UNNAMED = PortNumber.portNumber(101);
+ private static final ConnectPoint NCP = new ConnectPoint(DID, UNNAMED);
+
+ private static final SparseAnnotations SA = DefaultAnnotations.builder()
+ .set(AnnotationKeys.STATIC_PORT, SPNAME)
+ .build();
+
+ private static final OduCltPortDescription N_DESC = new OduCltPortDescription(
+ NAMED, true, OduCltPort.SignalType.CLT_100GBE, SA);
+ private static final OduCltPortDescription FAULTY = new OduCltPortDescription(
+ null, true, OduCltPort.SignalType.CLT_100GBE);
+
+ private final ConfigApplyDelegate delegate = new MockCfgDelegate();
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ private static final OpticalPortConfig N_OPC = new OpticalPortConfig();
+ private static final OpticalPortConfig UNN_OPC = new OpticalPortConfig();
+
+ @Before
+ public void setUp() {
+ N_OPC.init(NCP, TPNAME, JsonNodeFactory.instance.objectNode(), mapper, delegate);
+ UNN_OPC.init(NCP, TPNAME, JsonNodeFactory.instance.objectNode(), mapper, delegate);
+
+ N_OPC.portName(CFGNAME).portNumberName(101L).portType(Port.Type.ODUCLT).staticLambda(300L);
+ UNN_OPC.portType(Port.Type.ODUCLT);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testDescOps() {
+ // port-null desc + opc with port number name
+ OduCltPortDescription res = (OduCltPortDescription) OpticalPortOperator.combine(N_OPC, FAULTY);
+ assertEquals(CFGNAME, res.portNumber().name());
+ // full desc + opc with name
+ assertEquals(TPNAME, N_DESC.portNumber().name());
+ res = (OduCltPortDescription) OpticalPortOperator.combine(N_OPC, N_DESC);
+ long sl = Long.valueOf(res.annotations().value(AnnotationKeys.STATIC_LAMBDA));
+ assertEquals(CFGNAME, res.portNumber().name());
+ assertEquals(300L, sl);
+ // port-null desc + opc without port number name - throws RE
+ res = (OduCltPortDescription) OpticalPortOperator.combine(UNN_OPC, FAULTY);
+ }
+
+ private class MockCfgDelegate implements ConfigApplyDelegate {
+
+ @Override
+ public void onApply(@SuppressWarnings("rawtypes") Config config) {
+ config.apply();
+ }
+
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java
new file mode 100644
index 00000000..319412fe
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.edgeservice.impl;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.event.Event;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultPort;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.edge.EdgePortEvent;
+import org.onosproject.net.edge.EdgePortListener;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.link.LinkEvent;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketServiceAdapter;
+import org.onosproject.net.topology.Topology;
+import org.onosproject.net.topology.TopologyEvent;
+import org.onosproject.net.topology.TopologyListener;
+import org.onosproject.net.topology.TopologyServiceAdapter;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+import static org.onosproject.net.device.DeviceEvent.Type.*;
+import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_ADDED;
+import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_REMOVED;
+import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
+import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
+import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED;
+
+/**
+ * Test of the edge port manager. Each device has ports '0' through 'numPorts - 1'
+ * as specified by the variable 'numPorts'.
+ */
+public class EdgeManagerTest {
+
+ private EdgeManager mgr;
+ private int totalPorts = 10;
+ private boolean alwaysReturnPorts = false;
+ private final Set<ConnectPoint> infrastructurePorts = Sets.newConcurrentHashSet();
+ private List<EdgePortEvent> events = Lists.newArrayList();
+ private final Map<DeviceId, Device> devices = Maps.newConcurrentMap();
+ private Set<OutboundPacket> packets = Sets.newConcurrentHashSet();
+ private final EdgePortListener testListener = new TestListener(events);
+ private TestTopologyManager testTopologyManager;
+
+ @Before
+ public void setUp() {
+ mgr = new EdgeManager();
+ injectEventDispatcher(mgr, new TestEventDispatcher());
+ testTopologyManager = new TestTopologyManager(infrastructurePorts);
+ mgr.topologyService = testTopologyManager;
+ mgr.deviceService = new TestDeviceManager(devices);
+ mgr.packetService = new TestPacketManager();
+ mgr.activate();
+ mgr.addListener(testListener);
+
+ }
+
+
+ @After
+ public void tearDown() {
+ mgr.removeListener(testListener);
+ mgr.deactivate();
+ }
+
+ @Test
+ public void testBasics() {
+ //Setup
+ int numDevices = 20;
+ int numPorts = 4;
+ defaultPopulator(numDevices, numPorts);
+
+ assertEquals("Unexpected number of ports", numDevices * numPorts, infrastructurePorts.size());
+
+ assertFalse("no ports expected", mgr.getEdgePoints().iterator().hasNext());
+
+ assertFalse("Expected isEdge to return false",
+ mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1)));
+
+ removeInfraPort(NetTestTools.connectPoint(Integer.toString(1), 1));
+ assertTrue("Expected isEdge to return false",
+ mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1)));
+ }
+
+ @Test
+ public void testLinkUpdates() {
+ //Setup
+ ConnectPoint testPoint, referencePoint;
+
+ //Testing link removal
+ List<Event> eventsToAdd = Lists.newArrayList();
+ eventsToAdd.add(new LinkEvent(LINK_REMOVED, NetTestTools.link("a", 1, "b", 2)));
+ TopologyEvent event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
+ testTopologyManager.listener.event(event);
+
+ assertTrue("The list contained an unexpected number of events", events.size() == 2);
+ assertTrue("The first element is of the wrong type.",
+ events.get(0).type() == EDGE_PORT_ADDED);
+ assertTrue("The second element is of the wrong type.",
+ events.get(1).type() == EDGE_PORT_ADDED);
+
+ testPoint = events.get(0).subject();
+ referencePoint = NetTestTools.connectPoint("a", 1);
+ assertTrue("The port numbers of the first element are incorrect",
+ testPoint.port().toLong() == referencePoint.port().toLong());
+ assertTrue("The device id of the first element is incorrect.",
+ testPoint.deviceId().equals(referencePoint.deviceId()));
+
+ testPoint = events.get(1).subject();
+ referencePoint = NetTestTools.connectPoint("b", 2);
+ assertTrue("The port numbers of the second element are incorrect",
+ testPoint.port().toLong() == referencePoint.port().toLong());
+ assertTrue("The device id of the second element is incorrect.",
+ testPoint.deviceId().equals(referencePoint.deviceId()));
+
+ //Rebroadcast event to ensure it results in no additional events
+ testTopologyManager.listener.event(event);
+ assertTrue("The list contained an unexpected number of events", events.size() == 2);
+
+ //Testing link adding when links to remove exist
+ eventsToAdd.clear();
+ events.clear();
+ eventsToAdd.add(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2)));
+ event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
+ testTopologyManager.listener.event(event);
+
+ assertTrue("The list contained an unexpected number of events", events.size() == 2);
+ assertTrue("The first element is of the wrong type.",
+ events.get(0).type() == EDGE_PORT_REMOVED);
+ assertTrue("The second element is of the wrong type.",
+ events.get(1).type() == EDGE_PORT_REMOVED);
+
+ testPoint = events.get(0).subject();
+ referencePoint = NetTestTools.connectPoint("a", 1);
+ assertTrue("The port numbers of the first element are incorrect",
+ testPoint.port().toLong() == referencePoint.port().toLong());
+ assertTrue("The device id of the first element is incorrect.",
+ testPoint.deviceId().equals(referencePoint.deviceId()));
+
+ testPoint = events.get(1).subject();
+ referencePoint = NetTestTools.connectPoint("b", 2);
+ assertTrue("The port numbers of the second element are incorrect",
+ testPoint.port().toLong() == referencePoint.port().toLong());
+ assertTrue("The device id of the second element is incorrect.",
+ testPoint.deviceId().equals(referencePoint.deviceId()));
+
+ //Apparent duplicate of previous method tests removal when the elements have already been removed
+ eventsToAdd.clear();
+ events.clear();
+ eventsToAdd.add(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2)));
+ event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
+ testTopologyManager.listener.event(event);
+
+ assertTrue("The list should contain no events, the removed elements don't exist.", events.size() == 0);
+ }
+
+ @Test
+ public void testDeviceUpdates() {
+ //Setup
+
+ Device referenceDevice;
+ TopologyEvent event;
+ List<Event> eventsToAdd = Lists.newArrayList();
+ int numDevices = 10;
+ int numInfraPorts = 5;
+ totalPorts = 10;
+ defaultPopulator(numDevices, numInfraPorts);
+
+ //Test response to device added events
+ referenceDevice = NetTestTools.device("1");
+ eventsToAdd.add(new DeviceEvent(DEVICE_ADDED, referenceDevice,
+ new DefaultPort(referenceDevice, PortNumber.portNumber(1), true)));
+ event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
+ testTopologyManager.listener.event(event);
+
+ //Check that ports were populated correctly
+ assertTrue("Unexpected number of new ports added",
+ mgr.deviceService.getPorts(NetTestTools.did("1")).size() == 10);
+
+ //Check that of the ten ports the half that are infrastructure ports aren't added
+ assertEquals("Unexpected number of new edge ports added", (totalPorts - numInfraPorts), events.size());
+
+ for (int index = 0; index < numInfraPorts; index++) {
+ assertTrue("Unexpected type of event", events.get(index).type() == EDGE_PORT_ADDED);
+ }
+ //Names here are irrelevant, the first 5 ports are populated as infrastructure, 6-10 are edge
+ for (int index = 0; index < events.size(); index++) {
+ assertEquals("Port added had unexpected port number.",
+ events.get(index).subject().port(),
+ NetTestTools.connectPoint("a", index + numInfraPorts + 1).port());
+ }
+ events.clear();
+
+ //Repost the event to test repeated posts
+ testTopologyManager.listener.event(event);
+ assertEquals("The redundant notification should not have created additional notifications.",
+ 0, events.size());
+ //Calculate the size of the returned iterable of edge points.
+ Iterable<ConnectPoint> pts = mgr.getEdgePoints();
+ Iterator pointIterator = pts.iterator();
+ int count = 0;
+ for (; pointIterator.hasNext(); count++) {
+ pointIterator.next();
+ }
+ assertEquals("Unexpected number of edge points", totalPorts - numInfraPorts, count);
+ //Testing device removal
+ events.clear();
+ eventsToAdd.clear();
+ eventsToAdd.add(new DeviceEvent(DEVICE_REMOVED, referenceDevice,
+ new DefaultPort(referenceDevice, PortNumber.portNumber(1), true)));
+ event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
+ testTopologyManager.listener.event(event);
+
+ assertEquals("There should be five new events from removal of edge points",
+ totalPorts - numInfraPorts, events.size());
+ for (int index = 0; index < events.size(); index++) {
+ //Assert that the correct port numbers were removed in the correct order
+ assertEquals("Port removed had unexpected port number.",
+ events.get(index).subject().port(),
+ (NetTestTools.connectPoint("a", index + numInfraPorts + 1).port()));
+ //Assert that the events are of the correct type
+ assertEquals("Unexpected type of event", events.get(index).type(), EDGE_PORT_REMOVED);
+ }
+ events.clear();
+ //Rebroadcast event to check that it triggers no new behavior
+ testTopologyManager.listener.event(event);
+ assertEquals("Rebroadcast of removal event should not produce additional events",
+ 0, events.size());
+
+ //Testing device status change, changed from unavailable to available
+ events.clear();
+ eventsToAdd.clear();
+ //Make sure that the devicemanager shows the device as available.
+ addDevice(referenceDevice, "1", 5);
+ devices.put(referenceDevice.id(), referenceDevice);
+
+ eventsToAdd.add(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, referenceDevice));
+ event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
+ testTopologyManager.listener.event(event);
+ //An earlier setup set half of the reference device ports to infrastructure
+ assertEquals("An unexpected number of events were generated.", totalPorts - numInfraPorts, events.size());
+ for (int i = 0; i < 5; i++) {
+ assertEquals("The event was not of the right type", events.get(i).type(), EDGE_PORT_ADDED);
+ }
+ events.clear();
+ testTopologyManager.listener.event(event);
+ assertEquals("No events should have been generated for a set of existing ports.", 0, events.size());
+
+ //Test removal when state changes when the device becomes unavailable
+
+ //Ensure that the deviceManager shows the device as unavailable
+ removeDevice(referenceDevice);
+ /*This variable copies the behavior of the topology by returning ports attached to an unavailable device
+ //this behavior is necessary for the following event to execute properly, if these statements are removed
+ no events will be generated since no ports will be provided in getPorts() to EdgeManager.
+ */
+ alwaysReturnPorts = true;
+ testTopologyManager.listener.event(event);
+ alwaysReturnPorts = false;
+ assertEquals("An unexpected number of events were created.", totalPorts - numInfraPorts, events.size());
+ for (int i = 0; i < 5; i++) {
+ EdgePortEvent edgeEvent = events.get(i);
+ assertEquals("The event is of an unexpected type.",
+ EdgePortEvent.Type.EDGE_PORT_REMOVED, edgeEvent.type());
+ assertEquals("The event pertains to an unexpected port", PortNumber.portNumber(i + numInfraPorts + 1),
+ edgeEvent.subject().port());
+ }
+ }
+
+ @Test
+ public void testInternalCache() {
+ List<Event> eventsToAdd = Lists.newArrayList();
+ int numDevices = 10;
+ //Number of infrastructure ports per device
+ int numPorts = 5;
+ //Total ports per device when requesting all devices
+ totalPorts = 10;
+ defaultPopulator(numDevices, numPorts);
+ for (int i = 0; i < numDevices; i++) {
+ Device newDevice = NetTestTools.device(Integer.toString(i));
+ devices.put(newDevice.id(), newDevice);
+ eventsToAdd.add(new DeviceEvent(DEVICE_ADDED, newDevice));
+ }
+ TopologyEvent event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
+ testTopologyManager.listener.event(event);
+
+ //Check all ports have correct designations
+ ConnectPoint testPoint;
+ for (int deviceNum = 0; deviceNum < numDevices; deviceNum++) {
+ for (int portNum = 1; portNum <= totalPorts; portNum++) {
+ testPoint = NetTestTools.connectPoint(Integer.toString(deviceNum), portNum);
+ if (portNum <= numPorts) {
+ assertFalse("This should not be an edge point", mgr.isEdgePoint(testPoint));
+ } else {
+ assertTrue("This should be an edge point", mgr.isEdgePoint(testPoint));
+ }
+ }
+ }
+ int count = 0;
+ for (ConnectPoint ignored : mgr.getEdgePoints()) {
+ count++;
+ }
+ assertEquals("There are an unexpeceted number of edge points returned.",
+ (totalPorts - numPorts) * numDevices, count);
+ for (int deviceNumber = 0; deviceNumber < numDevices; deviceNumber++) {
+ count = 0;
+ for (ConnectPoint ignored : mgr.getEdgePoints(NetTestTools.did("1"))) {
+ count++;
+ }
+ assertEquals("This element has an unexpected number of edge points.", (totalPorts - numPorts), count);
+ }
+ }
+
+
+ @Test
+ public void testEmit() {
+ byte[] arr = new byte[10];
+ Device referenceDevice;
+ TopologyEvent event;
+ List<Event> eventsToAdd = Lists.newArrayList();
+ int numDevices = 10;
+ int numInfraPorts = 5;
+ totalPorts = 10;
+ defaultPopulator(numDevices, numInfraPorts);
+ for (byte byteIndex = 0; byteIndex < arr.length; byteIndex++) {
+ arr[byteIndex] = byteIndex;
+ }
+ for (int i = 0; i < numDevices; i++) {
+ referenceDevice = NetTestTools.device(Integer.toString(i));
+ eventsToAdd.add(new DeviceEvent(DEVICE_ADDED, referenceDevice,
+ new DefaultPort(referenceDevice, PortNumber.portNumber(1), true)));
+ }
+ event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
+ testTopologyManager.listener.event(event);
+
+ mgr.emitPacket(ByteBuffer.wrap(arr), Optional.<TrafficTreatment>empty());
+
+ assertEquals("There were an unexpected number of emitted packets",
+ (totalPorts - numInfraPorts) * numDevices, packets.size());
+ Iterator<OutboundPacket> packetIter = packets.iterator();
+ OutboundPacket packet;
+ while (packetIter.hasNext()) {
+ packet = packetIter.next();
+ assertEquals("The packet had an incorrect payload.", arr, packet.data().array());
+ }
+ //Start testing emission to a specific device
+ packets.clear();
+ mgr.emitPacket(NetTestTools.did(Integer.toString(1)), ByteBuffer.wrap(arr), Optional.<TrafficTreatment>empty());
+
+ assertEquals("Unexpected number of outbound packets were emitted.",
+ totalPorts - numInfraPorts, packets.size());
+ packetIter = packets.iterator();
+ while (packetIter.hasNext()) {
+ packet = packetIter.next();
+ assertEquals("The packet had an incorrect payload", arr, packet.data().array());
+ }
+ }
+
+
+ /**
+ * @param numDevices the number of devices to populate.
+ * @param numInfraPorts the number of ports to be set as infrastructure on each device, numbered base 0, ports 0
+ * through numInfraPorts - 1
+ */
+ private void defaultPopulator(int numDevices, int numInfraPorts) {
+ for (int device = 0; device < numDevices; device++) {
+ String str = Integer.toString(device);
+ Device deviceToAdd = NetTestTools.device(str);
+ devices.put(deviceToAdd.id(), deviceToAdd);
+ for (int port = 1; port <= numInfraPorts; port++) {
+ infrastructurePorts.add(NetTestTools.connectPoint(str, port));
+ }
+ }
+ }
+
+ /**
+ * Adds the specified device with the specified number of edge ports so long as it is less than the total ports.
+ *
+ * @param device The device to be added
+ * @param deviceName The name given to generate the devices DID
+ * @param numInfraPorts The number of ports to be added numbered 1 ... numInfraPorts
+ */
+ private void addDevice(Device device, String deviceName, int numInfraPorts) {
+ if (!devices.keySet().contains(device.id())) {
+ devices.put(device.id(), device);
+ for (int i = 1; i <= numInfraPorts && i <= totalPorts; i++) {
+ infrastructurePorts.add(NetTestTools.connectPoint(deviceName, i));
+ }
+ }
+ }
+
+ private void removeDevice(Device device) {
+ devices.remove(device.id());
+ }
+
+ private void removeInfraPort(ConnectPoint port) {
+ infrastructurePorts.remove(port);
+ }
+
+ private class TestTopologyManager extends TopologyServiceAdapter {
+ private TopologyListener listener;
+ private Set<ConnectPoint> infrastructurePorts;
+
+ public TestTopologyManager(Set<ConnectPoint> infrastructurePorts) {
+ this.infrastructurePorts = infrastructurePorts;
+ }
+
+ @Override
+ public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
+ return infrastructurePorts.contains(connectPoint);
+ }
+
+ @Override
+ public void addListener(TopologyListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void removeListener(TopologyListener listener) {
+ this.listener = null;
+ }
+ }
+
+ private class TestDeviceManager extends DeviceServiceAdapter {
+
+ private Map<DeviceId, Device> devices;
+
+ public TestDeviceManager(Map<DeviceId, Device> devices) {
+ this.devices = devices;
+ }
+
+ @Override
+ public boolean isAvailable(DeviceId deviceId) {
+ for (DeviceId id : devices.keySet()) {
+ if (id.equals(deviceId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public List<Port> getPorts(DeviceId deviceId) {
+ List<Port> ports = new ArrayList<>();
+ Device device = devices.get(deviceId);
+ if (device == null && !alwaysReturnPorts) {
+ return ports;
+ }
+ for (int portNum = 1; portNum <= totalPorts; portNum++) {
+ //String is generated using 'of:' + the passed name, this creates a
+ ports.add(new DefaultPort(device, PortNumber.portNumber(portNum), true));
+ }
+ return ports;
+ }
+
+ @Override
+ public Iterable<Device> getAvailableDevices() {
+ return devices.values();
+ }
+ }
+
+ private class TestPacketManager extends PacketServiceAdapter {
+ @Override
+ public void emit(OutboundPacket packet) {
+ packets.add(packet);
+ }
+ }
+
+ private class TestListener implements EdgePortListener {
+ private List<EdgePortEvent> events;
+
+ public TestListener(List<EdgePortEvent> events) {
+ this.events = events;
+ }
+
+ @Override
+ public void event(EdgePortEvent event) {
+ events.add(event);
+ }
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
new file mode 100644
index 00000000..7ef8762c
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
@@ -0,0 +1,640 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.flow.impl;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.Device;
+import org.onosproject.net.Device.Type;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.flow.CompletedBatchOperation;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowEntry.FlowEntryState;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleBatchOperation;
+import org.onosproject.net.flow.FlowRuleEvent;
+import org.onosproject.net.flow.FlowRuleListener;
+import org.onosproject.net.flow.FlowRuleProvider;
+import org.onosproject.net.flow.FlowRuleProviderRegistry;
+import org.onosproject.net.flow.FlowRuleProviderService;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.StoredFlowEntry;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.trivial.SimpleFlowRuleStore;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADDED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVE_REQUESTED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
+
+/**
+ * Test codifying the flow rule service & flow rule provider service contracts.
+ */
+public class FlowRuleManagerTest {
+
+
+ private static final ProviderId PID = new ProviderId("of", "foo");
+ private static final DeviceId DID = DeviceId.deviceId("of:001");
+ private static final int TIMEOUT = 10;
+ private static final Device DEV = new DefaultDevice(
+ PID, DID, Type.SWITCH, "", "", "", "", null);
+
+ private FlowRuleManager mgr;
+
+ protected FlowRuleService service;
+ protected FlowRuleProviderRegistry registry;
+ protected FlowRuleProviderService providerService;
+ protected TestProvider provider;
+ protected TestListener listener = new TestListener();
+ private ApplicationId appId;
+
+
+ @Before
+ public void setUp() {
+ mgr = new FlowRuleManager();
+ mgr.store = new SimpleFlowRuleStore();
+ injectEventDispatcher(mgr, new TestEventDispatcher());
+ mgr.deviceService = new TestDeviceService();
+ mgr.coreService = new TestCoreService();
+ mgr.operationsService = MoreExecutors.newDirectExecutorService();
+ mgr.deviceInstallers = MoreExecutors.newDirectExecutorService();
+ mgr.cfgService = new ComponentConfigAdapter();
+ service = mgr;
+ registry = mgr;
+
+ mgr.activate(null);
+ mgr.addListener(listener);
+ provider = new TestProvider(PID);
+ providerService = registry.register(provider);
+ appId = new TestApplicationId(0, "FlowRuleManagerTest");
+ assertTrue("provider should be registered",
+ registry.getProviders().contains(provider.id()));
+ }
+
+ @After
+ public void tearDown() {
+ registry.unregister(provider);
+ assertFalse("provider should not be registered",
+ registry.getProviders().contains(provider.id()));
+ service.removeListener(listener);
+ mgr.deactivate();
+ injectEventDispatcher(mgr, null);
+ mgr.deviceService = null;
+ }
+
+ private FlowRule flowRule(int tsval, int trval) {
+ TestSelector ts = new TestSelector(tsval);
+ TestTreatment tr = new TestTreatment(trval);
+ return DefaultFlowRule.builder()
+ .forDevice(DID)
+ .withSelector(ts)
+ .withTreatment(tr)
+ .withPriority(10)
+ .fromApp(appId)
+ .makeTemporary(TIMEOUT)
+ .build();
+ }
+
+
+ private FlowRule addFlowRule(int hval) {
+ FlowRule rule = flowRule(hval, hval);
+ service.applyFlowRules(rule);
+
+ assertNotNull("rule should be found", service.getFlowEntries(DID));
+ return rule;
+ }
+
+ private void validateEvents(FlowRuleEvent.Type... events) {
+ if (events == null) {
+ assertTrue("events generated", listener.events.isEmpty());
+ }
+
+ int i = 0;
+ System.err.println("events :" + listener.events);
+ for (FlowRuleEvent e : listener.events) {
+ assertEquals("unexpected event", events[i], e.type());
+ i++;
+ }
+
+ assertEquals("mispredicted number of events",
+ events.length, listener.events.size());
+
+ listener.events.clear();
+ }
+
+ private int flowCount() {
+ return Sets.newHashSet(service.getFlowEntries(DID)).size();
+ }
+
+ @Test
+ public void getFlowEntries() {
+ assertTrue("store should be empty",
+ Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
+ FlowRule f1 = addFlowRule(1);
+ FlowRule f2 = addFlowRule(2);
+
+ FlowEntry fe1 = new DefaultFlowEntry(f1);
+ FlowEntry fe2 = new DefaultFlowEntry(f2);
+ assertEquals("2 rules should exist", 2, flowCount());
+
+ providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2));
+ validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
+ RULE_ADDED, RULE_ADDED);
+
+ addFlowRule(1);
+ System.err.println("events :" + listener.events);
+ assertEquals("should still be 2 rules", 2, flowCount());
+
+ providerService.pushFlowMetrics(DID, ImmutableList.of(fe1));
+ validateEvents(RULE_UPDATED);
+ }
+
+ private boolean validateState(Map<FlowRule, FlowEntryState> expected) {
+ Map<FlowRule, FlowEntryState> expectedToCheck = new HashMap<>(expected);
+ Iterable<FlowEntry> rules = service.getFlowEntries(DID);
+ for (FlowEntry f : rules) {
+ assertTrue("Unexpected FlowRule " + f, expectedToCheck.containsKey(f));
+ assertEquals("FlowEntry" + f, expectedToCheck.get(f), f.state());
+ expectedToCheck.remove(f);
+ }
+ assertEquals(Collections.emptySet(), expectedToCheck.entrySet());
+ return true;
+ }
+
+ @Test
+ public void applyFlowRules() {
+
+ FlowRule r1 = flowRule(1, 1);
+ FlowRule r2 = flowRule(2, 2);
+ FlowRule r3 = flowRule(3, 3);
+
+ assertTrue("store should be empty",
+ Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
+ mgr.applyFlowRules(r1, r2, r3);
+ assertEquals("3 rules should exist", 3, flowCount());
+ assertTrue("Entries should be pending add.",
+ validateState(ImmutableMap.of(
+ r1, FlowEntryState.PENDING_ADD,
+ r2, FlowEntryState.PENDING_ADD,
+ r3, FlowEntryState.PENDING_ADD)));
+ }
+
+ @Test
+ public void removeFlowRules() {
+ FlowRule f1 = addFlowRule(1);
+ FlowRule f2 = addFlowRule(2);
+ FlowRule f3 = addFlowRule(3);
+ assertEquals("3 rules should exist", 3, flowCount());
+
+ FlowEntry fe1 = new DefaultFlowEntry(f1);
+ FlowEntry fe2 = new DefaultFlowEntry(f2);
+ FlowEntry fe3 = new DefaultFlowEntry(f3);
+ providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2, fe3));
+ validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
+ RULE_ADDED, RULE_ADDED, RULE_ADDED);
+
+ mgr.removeFlowRules(f1, f2);
+ //removing from north, so no events generated
+ validateEvents(RULE_REMOVE_REQUESTED, RULE_REMOVE_REQUESTED);
+ assertEquals("3 rule should exist", 3, flowCount());
+ assertTrue("Entries should be pending remove.",
+ validateState(ImmutableMap.of(
+ f1, FlowEntryState.PENDING_REMOVE,
+ f2, FlowEntryState.PENDING_REMOVE,
+ f3, FlowEntryState.ADDED)));
+
+ mgr.removeFlowRules(f1);
+ assertEquals("3 rule should still exist", 3, flowCount());
+ }
+
+ @Test
+ public void flowRemoved() {
+
+ FlowRule f1 = addFlowRule(1);
+ FlowRule f2 = addFlowRule(2);
+ StoredFlowEntry fe1 = new DefaultFlowEntry(f1);
+ FlowEntry fe2 = new DefaultFlowEntry(f2);
+
+
+ providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2));
+ service.removeFlowRules(f1);
+
+ fe1.setState(FlowEntryState.REMOVED);
+
+
+
+ providerService.flowRemoved(fe1);
+
+
+ validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED,
+ RULE_ADDED, RULE_REMOVE_REQUESTED, RULE_REMOVED);
+
+ providerService.flowRemoved(fe1);
+ validateEvents();
+
+ FlowRule f3 = flowRule(3, 3);
+ FlowEntry fe3 = new DefaultFlowEntry(f3);
+ service.applyFlowRules(f3);
+
+ providerService.pushFlowMetrics(DID, Collections.singletonList(fe3));
+ validateEvents(RULE_ADD_REQUESTED, RULE_ADDED);
+
+ providerService.flowRemoved(fe3);
+ validateEvents();
+
+ }
+
+ @Test
+ public void flowMetrics() {
+ FlowRule f1 = flowRule(1, 1);
+ FlowRule f2 = flowRule(2, 2);
+ FlowRule f3 = flowRule(3, 3);
+
+ mgr.applyFlowRules(f1, f2, f3);
+
+ FlowEntry fe1 = new DefaultFlowEntry(f1);
+ FlowEntry fe2 = new DefaultFlowEntry(f2);
+
+ //FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
+ //FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
+
+ providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2));
+
+ assertTrue("Entries should be added.",
+ validateState(ImmutableMap.of(
+ f1, FlowEntryState.ADDED,
+ f2, FlowEntryState.ADDED,
+ f3, FlowEntryState.PENDING_ADD)));
+
+ validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
+ RULE_ADDED, RULE_ADDED);
+ }
+
+ @Test
+ public void extraneousFlow() {
+ FlowRule f1 = flowRule(1, 1);
+ FlowRule f2 = flowRule(2, 2);
+ FlowRule f3 = flowRule(3, 3);
+ mgr.applyFlowRules(f1, f2);
+
+// FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
+// FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
+// FlowRule updatedF3 = flowRule(f3, FlowRuleState.ADDED);
+ FlowEntry fe1 = new DefaultFlowEntry(f1);
+ FlowEntry fe2 = new DefaultFlowEntry(f2);
+ FlowEntry fe3 = new DefaultFlowEntry(f3);
+
+
+ providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2, fe3));
+
+ validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED, RULE_ADDED);
+
+ }
+
+ /*
+ * Tests whether a rule that was marked for removal but no flowRemoved was received
+ * is indeed removed at the next stats update.
+ */
+ @Test
+ public void flowMissingRemove() {
+ FlowRule f1 = flowRule(1, 1);
+ FlowRule f2 = flowRule(2, 2);
+ FlowRule f3 = flowRule(3, 3);
+
+// FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
+// FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
+
+ FlowEntry fe1 = new DefaultFlowEntry(f1);
+ FlowEntry fe2 = new DefaultFlowEntry(f2);
+ mgr.applyFlowRules(f1, f2, f3);
+
+ mgr.removeFlowRules(f3);
+
+ providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2));
+
+ validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
+ RULE_REMOVE_REQUESTED, RULE_ADDED, RULE_ADDED, RULE_REMOVED);
+
+ }
+
+ @Test
+ public void getByAppId() {
+ FlowRule f1 = flowRule(1, 1);
+ FlowRule f2 = flowRule(2, 2);
+ mgr.applyFlowRules(f1, f2);
+
+ assertTrue("should have two rules",
+ Lists.newLinkedList(mgr.getFlowRulesById(appId)).size() == 2);
+ }
+
+ @Test
+ public void removeByAppId() {
+ FlowRule f1 = flowRule(1, 1);
+ FlowRule f2 = flowRule(2, 2);
+ mgr.applyFlowRules(f1, f2);
+
+
+ mgr.removeFlowRulesById(appId);
+
+ //only check that we are in pending remove. Events and actual remove state will
+ // be set by flowRemoved call.
+ validateState(ImmutableMap.of(
+ f1, FlowEntryState.PENDING_REMOVE,
+ f2, FlowEntryState.PENDING_REMOVE));
+ }
+
+ private static class TestListener implements FlowRuleListener {
+ final List<FlowRuleEvent> events = new ArrayList<>();
+
+ @Override
+ public void event(FlowRuleEvent event) {
+ events.add(event);
+ }
+ }
+
+ private static class TestDeviceService extends DeviceServiceAdapter {
+
+ @Override
+ public int getDeviceCount() {
+ return 1;
+ }
+
+ @Override
+ public Iterable<Device> getDevices() {
+ return Collections.singletonList(DEV);
+ }
+
+ @Override
+ public Device getDevice(DeviceId deviceId) {
+ return DEV;
+ }
+
+ @Override
+ public MastershipRole getRole(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public List<Port> getPorts(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public Port getPort(DeviceId deviceId, PortNumber portNumber) {
+ return null;
+ }
+
+ @Override
+ public boolean isAvailable(DeviceId deviceId) {
+ return false;
+ }
+
+ @Override
+ public void addListener(DeviceListener listener) {
+ }
+
+ @Override
+ public void removeListener(DeviceListener listener) {
+ }
+
+ }
+
+ private class TestProvider extends AbstractProvider implements FlowRuleProvider {
+
+ protected TestProvider(ProviderId id) {
+ super(PID);
+ }
+
+ @Override
+ public void applyFlowRule(FlowRule... flowRules) {
+ }
+
+ @Override
+ public void removeFlowRule(FlowRule... flowRules) {
+ }
+
+ @Override
+ public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
+ }
+
+ @Override
+ public void executeBatch(FlowRuleBatchOperation batch) {
+ // TODO: need to call batchOperationComplete
+ }
+
+ private class TestInstallationFuture
+ implements ListenableFuture<CompletedBatchOperation> {
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return true;
+ }
+
+ @Override
+ public CompletedBatchOperation get()
+ throws InterruptedException, ExecutionException {
+ return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet(), null);
+ }
+
+ @Override
+ public CompletedBatchOperation get(long timeout, TimeUnit unit)
+ throws InterruptedException,
+ ExecutionException, TimeoutException {
+ return new CompletedBatchOperation(true, Collections.<FlowRule>emptySet(), null);
+ }
+
+ @Override
+ public void addListener(Runnable task, Executor executor) {
+ if (isDone()) {
+ executor.execute(task);
+ }
+ }
+ }
+
+ }
+
+ private class TestSelector implements TrafficSelector {
+
+ //for controlling hashcode uniqueness;
+ private final int testval;
+
+ public TestSelector(int val) {
+ testval = val;
+ }
+
+ @Override
+ public Set<Criterion> criteria() {
+ return null;
+ }
+
+ @Override
+ public Criterion getCriterion(
+ org.onosproject.net.flow.criteria.Criterion.Type type) {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return testval;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof TestSelector) {
+ return this.testval == ((TestSelector) o).testval;
+ }
+ return false;
+ }
+
+ }
+
+ private class TestTreatment implements TrafficTreatment {
+
+ //for controlling hashcode uniqueness;
+ private final int testval;
+
+ public TestTreatment(int val) {
+ testval = val;
+ }
+
+ @Override
+ public List<Instruction> deferred() {
+ return null;
+ }
+
+ @Override
+ public List<Instruction> immediate() {
+ return null;
+ }
+
+ @Override
+ public List<Instruction> allInstructions() {
+ return null;
+ }
+
+ @Override
+ public Instructions.TableTypeTransition tableTransition() {
+ return null;
+ }
+
+ @Override
+ public boolean clearedDeferred() {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return testval;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof TestTreatment) {
+ return this.testval == ((TestTreatment) o).testval;
+ }
+ return false;
+ }
+
+ @Override
+ public MetadataInstruction writeMetadata() {
+ return null;
+ }
+
+ @Override
+ public Instructions.MeterInstruction metered() {
+ return null;
+ }
+
+ }
+
+ public class TestApplicationId extends DefaultApplicationId {
+ public TestApplicationId(int id, String name) {
+ super(id, name);
+ }
+ }
+
+ private class TestCoreService extends CoreServiceAdapter {
+
+ @Override
+ public IdGenerator getIdGenerator(String topic) {
+ return new IdGenerator() {
+ private AtomicLong counter = new AtomicLong(0);
+ @Override
+ public long getNewId() {
+ return counter.getAndIncrement();
+ }
+ };
+ }
+ }
+
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveCompositionTreeTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveCompositionTreeTest.java
new file mode 100644
index 00000000..1e898d37
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveCompositionTreeTest.java
@@ -0,0 +1,603 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.flowobjective.impl;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test FlowObjectiveCompositionTree.
+ */
+@Ignore
+public class FlowObjectiveCompositionTreeTest {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Before
+ public void setUp() {}
+
+ @After
+ public void tearDown() {}
+
+ /*@Test
+ public void testParallelComposition() {
+ FlowObjectiveCompositionTree policyTree = FlowObjectiveCompositionUtil.parsePolicyString("31+32");
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPSrc(IpPrefix.valueOf("1.0.0.0/24"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder().build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(0)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.1/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(1))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.2/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(2))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder().build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(0)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ System.out.println("---------- Parallel ----------");
+ for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
+ System.out.println(forwardingObjectiveToString(fo));
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(3))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+ helper(policyTree, forwardingObjective);
+ }
+
+ System.out.println("---------- Parallel ----------");
+ for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
+ System.out.println(forwardingObjectiveToString(fo));
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(3))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .remove();
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPSrc(IpPrefix.valueOf("1.0.0.0/24"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .remove();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder().build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(0)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .remove();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ System.out.println("---------- Parallel ----------");
+ for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
+ System.out.println(forwardingObjectiveToString(fo));
+ }
+ }
+
+ @Test
+ public void testSequentialComposition() {
+ FlowObjectiveCompositionTree policyTree = FlowObjectiveCompositionUtil.parsePolicyString("31>32");
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPSrc(IpPrefix.valueOf("0.0.0.0/2"))
+ .matchIPDst(IpPrefix.valueOf("3.0.0.0/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setIpDst(IpAddress.valueOf("2.0.0.1"))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(3)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("3.0.0.0/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setIpDst(IpAddress.valueOf("2.0.0.2"))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder().build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(0)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.1/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(1))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.2/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(2))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder().build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(0)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ System.out.println("---------- Sequential ----------");
+ for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
+ System.out.println(forwardingObjectiveToString(fo));
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(3))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPSrc(IpPrefix.valueOf("0.0.0.0/1"))
+ .matchIPDst(IpPrefix.valueOf("3.0.0.0/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setIpDst(IpAddress.valueOf("2.0.0.3"))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(3)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ System.out.println("---------- Sequential ----------");
+ for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
+ System.out.println(forwardingObjectiveToString(fo));
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(3))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .remove();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPSrc(IpPrefix.valueOf("0.0.0.0/1"))
+ .matchIPDst(IpPrefix.valueOf("3.0.0.0/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setIpDst(IpAddress.valueOf("2.0.0.3"))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(3)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .remove();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ System.out.println("---------- Sequential ----------");
+ for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
+ System.out.println(forwardingObjectiveToString(fo));
+ }
+ }
+
+ @Test
+ public void testOverrideComposition() {
+ FlowObjectiveCompositionTree policyTree = FlowObjectiveCompositionUtil.parsePolicyString("31/32");
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPSrc(IpPrefix.valueOf("1.0.0.0/32"))
+ .matchIPDst(IpPrefix.valueOf("2.0.0.1/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(3))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(31, "a"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.1/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(1))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.2/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(2))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+ helper(policyTree, forwardingObjective);
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder().build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(0)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+
+ helper(policyTree, forwardingObjective);
+ }
+
+ System.out.println("---------- Override ----------");
+ for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
+ System.out.println(forwardingObjectiveToString(fo));
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(3))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .add();
+ helper(policyTree, forwardingObjective);
+ }
+
+ System.out.println("---------- Override ----------");
+ for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
+ System.out.println(forwardingObjectiveToString(fo));
+ }
+
+ {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf("2.0.0.3/32"))
+ .build();
+
+ TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.portNumber(3))
+ .build();
+
+ ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+ .fromApp(new DefaultApplicationId(32, "b"))
+ .makePermanent()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(1)
+ .withSelector(selector)
+ .withTreatment(treatment)
+ .remove();
+ helper(policyTree, forwardingObjective);
+ }
+
+ System.out.println("---------- Override ----------");
+ for (ForwardingObjective fo : policyTree.forwardTable.getForwardingObjectives()) {
+ System.out.println(forwardingObjectiveToString(fo));
+ }
+ }
+
+ private void helper(FlowObjectiveCompositionTree policyTree, ForwardingObjective forwardingObjective) {
+ log.info("before composition");
+ log.info("\t{}", forwardingObjectiveToString(forwardingObjective));
+ List<ForwardingObjective> forwardingObjectives
+ = policyTree.updateForward(forwardingObjective);
+ log.info("after composition");
+ for (ForwardingObjective fo : forwardingObjectives) {
+ log.info("\t{}", forwardingObjectiveToString(fo));
+ }
+ }*/
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
new file mode 100644
index 00000000..ae7cc874
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
@@ -0,0 +1,536 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.group.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.core.GroupId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.impl.DeviceManager;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.group.DefaultGroup;
+import org.onosproject.net.group.DefaultGroupBucket;
+import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.DefaultGroupKey;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupEvent;
+import org.onosproject.net.group.GroupKey;
+import org.onosproject.net.group.GroupListener;
+import org.onosproject.net.group.GroupOperation;
+import org.onosproject.net.group.GroupOperations;
+import org.onosproject.net.group.GroupProvider;
+import org.onosproject.net.group.GroupProviderRegistry;
+import org.onosproject.net.group.GroupProviderService;
+import org.onosproject.net.group.GroupService;
+import org.onosproject.net.group.StoredGroupEntry;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.trivial.SimpleGroupStore;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * Test codifying the group service & group provider service contracts.
+ */
+public class GroupManagerTest {
+
+ private static final ProviderId PID = new ProviderId("of", "groupfoo");
+ private static final DeviceId DID = DeviceId.deviceId("of:001");
+
+ private GroupManager mgr;
+ private GroupService groupService;
+ private GroupProviderRegistry providerRegistry;
+ private TestGroupListener internalListener = new TestGroupListener();
+ private GroupListener listener = internalListener;
+ private TestGroupProvider internalProvider;
+ private GroupProvider provider;
+ private GroupProviderService providerService;
+ private ApplicationId appId;
+
+ @Before
+ public void setUp() {
+ mgr = new GroupManager();
+ groupService = mgr;
+ mgr.deviceService = new DeviceManager();
+ mgr.store = new SimpleGroupStore();
+ injectEventDispatcher(mgr, new TestEventDispatcher());
+ providerRegistry = mgr;
+
+ mgr.activate();
+ mgr.addListener(listener);
+
+ internalProvider = new TestGroupProvider(PID);
+ provider = internalProvider;
+ providerService = providerRegistry.register(provider);
+ appId = new DefaultApplicationId(2, "org.groupmanager.test");
+ assertTrue("provider should be registered",
+ providerRegistry.getProviders().contains(provider.id()));
+ }
+
+ @After
+ public void tearDown() {
+ providerRegistry.unregister(provider);
+ assertFalse("provider should not be registered",
+ providerRegistry.getProviders().contains(provider.id()));
+ mgr.removeListener(listener);
+ mgr.deactivate();
+ injectEventDispatcher(mgr, null);
+ }
+
+ /**
+ * Tests group service north bound and south bound interfaces.
+ * The following operations are tested:
+ * a)Tests group creation before the device group AUDIT completes
+ * b)Tests initial device group AUDIT process
+ * c)Tests deletion process of any extraneous groups
+ * d)Tests execution of any pending group creation requests
+ * after the device group AUDIT completes
+ * e)Tests re-apply process of any missing groups
+ * f)Tests event notifications after receiving confirmation for
+ * any operations from data plane
+ * g)Tests group bucket modifications (additions and deletions)
+ * h)Tests group deletion
+ */
+ @Test
+ public void testGroupService() {
+ // Test Group creation before AUDIT process
+ testGroupCreationBeforeAudit();
+
+ // Test initial group audit process
+ testInitialAuditWithPendingGroupRequests();
+
+ // Test audit with extraneous and missing groups
+ testAuditWithExtraneousMissingGroups();
+
+ // Test audit with confirmed groups
+ testAuditWithConfirmedGroups();
+
+ // Test group add bucket operations
+ testAddBuckets();
+
+ // Test group remove bucket operations
+ testRemoveBuckets();
+
+ // Test group remove operations
+ testRemoveGroup();
+ }
+
+ // Test Group creation before AUDIT process
+ private void testGroupCreationBeforeAudit() {
+ PortNumber[] ports1 = {PortNumber.portNumber(31),
+ PortNumber.portNumber(32)};
+ PortNumber[] ports2 = {PortNumber.portNumber(41),
+ PortNumber.portNumber(42)};
+ GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
+ List<GroupBucket> buckets = new ArrayList<>();
+ List<PortNumber> outPorts = new ArrayList<>();
+ outPorts.addAll(Arrays.asList(ports1));
+ outPorts.addAll(Arrays.asList(ports2));
+ for (PortNumber portNumber: outPorts) {
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.setOutput(portNumber)
+ .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
+ .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(106));
+ buckets.add(DefaultGroupBucket.createSelectGroupBucket(
+ tBuilder.build()));
+ }
+ GroupBuckets groupBuckets = new GroupBuckets(buckets);
+ GroupDescription newGroupDesc = new DefaultGroupDescription(DID,
+ Group.Type.SELECT,
+ groupBuckets,
+ key,
+ null,
+ appId);
+ groupService.addGroup(newGroupDesc);
+ internalProvider.validate(DID, null);
+ assertEquals(null, groupService.getGroup(DID, key));
+ assertEquals(0, Iterables.size(groupService.getGroups(DID, appId)));
+ }
+
+ // Test initial AUDIT process with pending group requests
+ private void testInitialAuditWithPendingGroupRequests() {
+ PortNumber[] ports1 = {PortNumber.portNumber(31),
+ PortNumber.portNumber(32)};
+ PortNumber[] ports2 = {PortNumber.portNumber(41),
+ PortNumber.portNumber(42)};
+ GroupId gId1 = new DefaultGroupId(1);
+ Group group1 = createSouthboundGroupEntry(gId1,
+ Arrays.asList(ports1),
+ 0);
+ GroupId gId2 = new DefaultGroupId(2);
+ // Non zero reference count will make the group manager to queue
+ // the extraneous groups until reference count is zero.
+ Group group2 = createSouthboundGroupEntry(gId2,
+ Arrays.asList(ports2),
+ 2);
+ List<Group> groupEntries = Arrays.asList(group1, group2);
+ providerService.pushGroupMetrics(DID, groupEntries);
+ // First group metrics would trigger the device audit completion
+ // post which all pending group requests are also executed.
+ GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
+ Group createdGroup = groupService.getGroup(DID, key);
+ int createdGroupId = createdGroup.id().id();
+ assertNotEquals(gId1.id(), createdGroupId);
+ assertNotEquals(gId2.id(), createdGroupId);
+
+ List<GroupOperation> expectedGroupOps = Arrays.asList(
+ GroupOperation.createDeleteGroupOperation(gId1,
+ Group.Type.SELECT),
+ GroupOperation.createAddGroupOperation(
+ createdGroup.id(),
+ Group.Type.SELECT,
+ createdGroup.buckets()));
+ internalProvider.validate(DID, expectedGroupOps);
+ }
+
+ // Test AUDIT process with extraneous groups and missing groups
+ private void testAuditWithExtraneousMissingGroups() {
+ PortNumber[] ports1 = {PortNumber.portNumber(31),
+ PortNumber.portNumber(32)};
+ PortNumber[] ports2 = {PortNumber.portNumber(41),
+ PortNumber.portNumber(42)};
+ GroupId gId1 = new DefaultGroupId(1);
+ Group group1 = createSouthboundGroupEntry(gId1,
+ Arrays.asList(ports1),
+ 0);
+ GroupId gId2 = new DefaultGroupId(2);
+ Group group2 = createSouthboundGroupEntry(gId2,
+ Arrays.asList(ports2),
+ 0);
+ List<Group> groupEntries = Arrays.asList(group1, group2);
+ providerService.pushGroupMetrics(DID, groupEntries);
+ GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
+ Group createdGroup = groupService.getGroup(DID, key);
+ List<GroupOperation> expectedGroupOps = Arrays.asList(
+ GroupOperation.createDeleteGroupOperation(gId1,
+ Group.Type.SELECT),
+ GroupOperation.createDeleteGroupOperation(gId2,
+ Group.Type.SELECT),
+ GroupOperation.createAddGroupOperation(createdGroup.id(),
+ Group.Type.SELECT,
+ createdGroup.buckets()));
+ internalProvider.validate(DID, expectedGroupOps);
+ }
+
+ // Test AUDIT with confirmed groups
+ private void testAuditWithConfirmedGroups() {
+ GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
+ Group createdGroup = groupService.getGroup(DID, key);
+ createdGroup = new DefaultGroup(createdGroup.id(),
+ DID,
+ Group.Type.SELECT,
+ createdGroup.buckets());
+ List<Group> groupEntries = Collections.singletonList(createdGroup);
+ providerService.pushGroupMetrics(DID, groupEntries);
+ internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_ADDED));
+ }
+
+ // Test group add bucket operations
+ private void testAddBuckets() {
+ GroupKey addKey = new DefaultGroupKey("group1AddBuckets".getBytes());
+
+ GroupKey prevKey = new DefaultGroupKey("group1BeforeAudit".getBytes());
+ Group createdGroup = groupService.getGroup(DID, prevKey);
+ List<GroupBucket> buckets = new ArrayList<>();
+ buckets.addAll(createdGroup.buckets().buckets());
+
+ PortNumber[] addPorts = {PortNumber.portNumber(51),
+ PortNumber.portNumber(52)};
+ List<PortNumber> outPorts;
+ outPorts = new ArrayList<PortNumber>();
+ outPorts.addAll(Arrays.asList(addPorts));
+ List<GroupBucket> addBuckets;
+ addBuckets = new ArrayList<GroupBucket>();
+ for (PortNumber portNumber: outPorts) {
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.setOutput(portNumber)
+ .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
+ .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(106));
+ addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
+ tBuilder.build()));
+ buckets.add(DefaultGroupBucket.createSelectGroupBucket(
+ tBuilder.build()));
+ }
+ GroupBuckets groupAddBuckets = new GroupBuckets(addBuckets);
+ groupService.addBucketsToGroup(DID,
+ prevKey,
+ groupAddBuckets,
+ addKey,
+ appId);
+ GroupBuckets updatedBuckets = new GroupBuckets(buckets);
+ List<GroupOperation> expectedGroupOps = Collections.singletonList(
+ GroupOperation.createModifyGroupOperation(createdGroup.id(),
+ Group.Type.SELECT,
+ updatedBuckets));
+ internalProvider.validate(DID, expectedGroupOps);
+ Group existingGroup = groupService.getGroup(DID, addKey);
+ List<Group> groupEntries = Collections.singletonList(existingGroup);
+ providerService.pushGroupMetrics(DID, groupEntries);
+ internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED));
+ }
+
+ // Test group remove bucket operations
+ private void testRemoveBuckets() {
+ GroupKey removeKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
+
+ GroupKey prevKey = new DefaultGroupKey("group1AddBuckets".getBytes());
+ Group createdGroup = groupService.getGroup(DID, prevKey);
+ List<GroupBucket> buckets = new ArrayList<>();
+ buckets.addAll(createdGroup.buckets().buckets());
+
+ PortNumber[] removePorts = {PortNumber.portNumber(31),
+ PortNumber.portNumber(32)};
+ List<PortNumber> outPorts = new ArrayList<>();
+ outPorts.addAll(Arrays.asList(removePorts));
+ List<GroupBucket> removeBuckets = new ArrayList<>();
+ for (PortNumber portNumber: outPorts) {
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.setOutput(portNumber)
+ .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
+ .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(106));
+ removeBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
+ tBuilder.build()));
+ buckets.remove(DefaultGroupBucket.createSelectGroupBucket(
+ tBuilder.build()));
+ }
+ GroupBuckets groupRemoveBuckets = new GroupBuckets(removeBuckets);
+ groupService.removeBucketsFromGroup(DID,
+ prevKey,
+ groupRemoveBuckets,
+ removeKey,
+ appId);
+ GroupBuckets updatedBuckets = new GroupBuckets(buckets);
+ List<GroupOperation> expectedGroupOps = Collections.singletonList(
+ GroupOperation.createModifyGroupOperation(createdGroup.id(),
+ Group.Type.SELECT,
+ updatedBuckets));
+ internalProvider.validate(DID, expectedGroupOps);
+ Group existingGroup = groupService.getGroup(DID, removeKey);
+ List<Group> groupEntries = Collections.singletonList(existingGroup);
+ providerService.pushGroupMetrics(DID, groupEntries);
+ internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED));
+ }
+
+ // Test group remove operations
+ private void testRemoveGroup() {
+ GroupKey currKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
+ Group existingGroup = groupService.getGroup(DID, currKey);
+ groupService.removeGroup(DID, currKey, appId);
+ List<GroupOperation> expectedGroupOps = Collections.singletonList(
+ GroupOperation.createDeleteGroupOperation(existingGroup.id(),
+ Group.Type.SELECT));
+ internalProvider.validate(DID, expectedGroupOps);
+ List<Group> groupEntries = Collections.emptyList();
+ providerService.pushGroupMetrics(DID, groupEntries);
+ internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVED));
+ }
+
+ /**
+ * Test GroupOperationFailure function in Group Manager.
+ * a)GroupAddFailure
+ * b)GroupUpdateFailure
+ * c)GroupRemoteFailure
+ */
+ @Test
+ public void testGroupOperationFailure() {
+ PortNumber[] ports1 = {PortNumber.portNumber(31),
+ PortNumber.portNumber(32)};
+ PortNumber[] ports2 = {PortNumber.portNumber(41),
+ PortNumber.portNumber(42)};
+ // Test Group creation before AUDIT process
+ GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
+ List<GroupBucket> buckets = new ArrayList<>();
+ List<PortNumber> outPorts = new ArrayList<>();
+ outPorts.addAll(Arrays.asList(ports1));
+ outPorts.addAll(Arrays.asList(ports2));
+ for (PortNumber portNumber: outPorts) {
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.setOutput(portNumber)
+ .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
+ .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(106));
+ buckets.add(DefaultGroupBucket.createSelectGroupBucket(
+ tBuilder.build()));
+ }
+ GroupBuckets groupBuckets = new GroupBuckets(buckets);
+ GroupDescription newGroupDesc = new DefaultGroupDescription(DID,
+ Group.Type.SELECT,
+ groupBuckets,
+ key,
+ null,
+ appId);
+ groupService.addGroup(newGroupDesc);
+
+ // Test initial group audit process
+ GroupId gId1 = new DefaultGroupId(1);
+ Group group1 = createSouthboundGroupEntry(gId1,
+ Arrays.asList(ports1),
+ 0);
+ GroupId gId2 = new DefaultGroupId(2);
+ // Non zero reference count will make the group manager to queue
+ // the extraneous groups until reference count is zero.
+ Group group2 = createSouthboundGroupEntry(gId2,
+ Arrays.asList(ports2),
+ 2);
+ List<Group> groupEntries = Arrays.asList(group1, group2);
+ providerService.pushGroupMetrics(DID, groupEntries);
+ Group createdGroup = groupService.getGroup(DID, key);
+
+ // Group Add failure test
+ GroupOperation groupAddOp = GroupOperation.
+ createAddGroupOperation(createdGroup.id(),
+ createdGroup.type(),
+ createdGroup.buckets());
+ providerService.groupOperationFailed(DID, groupAddOp);
+ internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_ADD_FAILED));
+
+ // Group Mod failure test
+ groupService.addGroup(newGroupDesc);
+ createdGroup = groupService.getGroup(DID, key);
+ assertNotNull(createdGroup);
+
+ GroupOperation groupModOp = GroupOperation.
+ createModifyGroupOperation(createdGroup.id(),
+ createdGroup.type(),
+ createdGroup.buckets());
+ providerService.groupOperationFailed(DID, groupModOp);
+ internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATE_FAILED));
+
+ // Group Delete failure test
+ groupService.addGroup(newGroupDesc);
+ createdGroup = groupService.getGroup(DID, key);
+ assertNotNull(createdGroup);
+
+ GroupOperation groupDelOp = GroupOperation.
+ createDeleteGroupOperation(createdGroup.id(),
+ createdGroup.type());
+ providerService.groupOperationFailed(DID, groupDelOp);
+ internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVE_FAILED));
+
+ }
+
+ private Group createSouthboundGroupEntry(GroupId gId,
+ List<PortNumber> ports,
+ long referenceCount) {
+ List<PortNumber> outPorts = new ArrayList<>();
+ outPorts.addAll(ports);
+
+ List<GroupBucket> buckets = new ArrayList<>();
+ for (PortNumber portNumber: outPorts) {
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.setOutput(portNumber)
+ .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
+ .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(106));
+ buckets.add(DefaultGroupBucket.createSelectGroupBucket(
+ tBuilder.build()));
+ }
+ GroupBuckets groupBuckets = new GroupBuckets(buckets);
+ StoredGroupEntry group = new DefaultGroup(
+ gId, DID, Group.Type.SELECT, groupBuckets);
+ group.setReferenceCount(referenceCount);
+ return group;
+ }
+
+ private static class TestGroupListener implements GroupListener {
+ final List<GroupEvent> events = new ArrayList<>();
+
+ @Override
+ public void event(GroupEvent event) {
+ events.add(event);
+ }
+
+ public void validateEvent(List<GroupEvent.Type> expectedEvents) {
+ int i = 0;
+ System.err.println("events :" + events);
+ for (GroupEvent e : events) {
+ assertEquals("unexpected event", expectedEvents.get(i), e.type());
+ i++;
+ }
+ assertEquals("mispredicted number of events",
+ expectedEvents.size(), events.size());
+ events.clear();
+ }
+ }
+
+ private class TestGroupProvider
+ extends AbstractProvider implements GroupProvider {
+ DeviceId lastDeviceId;
+ List<GroupOperation> groupOperations = new ArrayList<>();
+
+ protected TestGroupProvider(ProviderId id) {
+ super(id);
+ }
+
+ @Override
+ public void performGroupOperation(DeviceId deviceId,
+ GroupOperations groupOps) {
+ lastDeviceId = deviceId;
+ groupOperations.addAll(groupOps.operations());
+ }
+
+ public void validate(DeviceId expectedDeviceId,
+ List<GroupOperation> expectedGroupOps) {
+ if (expectedGroupOps == null) {
+ assertTrue("events generated", groupOperations.isEmpty());
+ return;
+ }
+
+ assertEquals(lastDeviceId, expectedDeviceId);
+ assertTrue((this.groupOperations.containsAll(expectedGroupOps) &&
+ expectedGroupOps.containsAll(groupOperations)));
+
+ groupOperations.clear();
+ lastDeviceId = null;
+ }
+
+ }
+
+}
+
+
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/BasicHostOperatorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/BasicHostOperatorTest.java
new file mode 100644
index 00000000..e7f14b5d
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/BasicHostOperatorTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.host.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.net.config.basics.BasicHostConfig;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.host.DefaultHostDescription;
+import org.onosproject.net.host.HostDescription;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+
+public class BasicHostOperatorTest {
+ private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01");
+ private static final VlanId VLAN = VlanId.vlanId((short) 10);
+ private static final IpAddress IP = IpAddress.valueOf("10.0.0.1");
+
+ private static final HostId ID = HostId.hostId(MAC);
+ private static final HostLocation LOC = new HostLocation(
+ DeviceId.deviceId("of:foo"),
+ PortNumber.portNumber(100),
+ 123L
+ );
+ private static final HostDescription HOST = new DefaultHostDescription(MAC, VLAN, LOC, IP);
+
+ private final ConfigApplyDelegate delegate = new ConfigApplyDelegate() {
+ @Override
+ public void onApply(Config config) {
+ }
+ };
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ private static final BasicHostConfig BHC = new BasicHostConfig();
+ private static final String NAME = "testhost";
+ private static final double LAT = 40.96;
+
+ @Before
+ public void setUp() {
+ BHC.init(ID, "test", JsonNodeFactory.instance.objectNode(), mapper, delegate);
+ BHC.name(NAME).latitude(40.96);
+ }
+
+ @Test
+ public void testDescOps() {
+ HostDescription desc = BasicHostOperator.combine(BHC, HOST);
+ assertEquals(NAME, desc.annotations().value(AnnotationKeys.NAME));
+ assertEquals(null, desc.annotations().value(AnnotationKeys.LONGITUDE));
+ assertEquals(String.valueOf(LAT), desc.annotations().value(AnnotationKeys.LATITUDE));
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
new file mode 100644
index 00000000..dbb807f8
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.host.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
+import static org.onosproject.net.host.HostEvent.Type.HOST_MOVED;
+import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED;
+import static org.onosproject.net.host.HostEvent.Type.HOST_UPDATED;
+
+import java.util.List;
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.event.Event;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.net.config.NetworkConfigServiceAdapter;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.host.DefaultHostDescription;
+import org.onosproject.net.host.HostDescription;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
+import org.onosproject.net.host.InterfaceIpAddress;
+import org.onosproject.net.host.PortAddresses;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.trivial.SimpleHostStore;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * Test codifying the host service & host provider service contracts.
+ */
+public class HostManagerTest {
+
+ private static final ProviderId PID = new ProviderId("of", "foo");
+
+ private static final VlanId VLAN1 = VlanId.vlanId((short) 1);
+ private static final VlanId VLAN2 = VlanId.vlanId((short) 2);
+ private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01");
+ private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
+ private static final MacAddress MAC3 = MacAddress.valueOf("00:00:33:00:00:03");
+ private static final MacAddress MAC4 = MacAddress.valueOf("00:00:44:00:00:04");
+ private static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
+ private static final HostId HID2 = HostId.hostId(MAC2, VLAN1);
+ private static final HostId HID3 = HostId.hostId(MAC3, VLAN1);
+ private static final HostId HID4 = HostId.hostId(MAC4, VLAN1);
+
+ private static final IpAddress IP1 = IpAddress.valueOf("10.0.0.1");
+ private static final IpAddress IP2 = IpAddress.valueOf("10.0.0.2");
+ private static final IpAddress IP3 = IpAddress.valueOf("2001::1");
+ private static final IpAddress IP4 = IpAddress.valueOf("2001::2");
+
+ private static final DeviceId DID1 = DeviceId.deviceId("of:001");
+ private static final DeviceId DID2 = DeviceId.deviceId("of:002");
+ private static final PortNumber P1 = PortNumber.portNumber(100);
+ private static final PortNumber P2 = PortNumber.portNumber(200);
+ private static final HostLocation LOC1 = new HostLocation(DID1, P1, 123L);
+ private static final HostLocation LOC2 = new HostLocation(DID1, P2, 123L);
+ private static final ConnectPoint CP1 = new ConnectPoint(DID1, P1);
+ private static final ConnectPoint CP2 = new ConnectPoint(DID2, P2);
+
+ private static final InterfaceIpAddress IA1 =
+ new InterfaceIpAddress(IpAddress.valueOf("10.1.1.1"),
+ IpPrefix.valueOf("10.1.1.0/24"));
+ private static final InterfaceIpAddress IA2 =
+ new InterfaceIpAddress(IpAddress.valueOf("10.2.2.2"),
+ IpPrefix.valueOf("10.2.0.0/16"));
+ private static final InterfaceIpAddress IA3 =
+ new InterfaceIpAddress(IpAddress.valueOf("10.3.3.3"),
+ IpPrefix.valueOf("10.3.3.0/24"));
+ private static final InterfaceIpAddress IA4 =
+ new InterfaceIpAddress(IpAddress.valueOf("2001:100::1"),
+ IpPrefix.valueOf("2001:100::/56"));
+ private static final InterfaceIpAddress IA5 =
+ new InterfaceIpAddress(IpAddress.valueOf("2001:200::1"),
+ IpPrefix.valueOf("2001:200::/48"));
+ private static final InterfaceIpAddress IA6 =
+ new InterfaceIpAddress(IpAddress.valueOf("2001:300::1"),
+ IpPrefix.valueOf("2001:300::/56"));
+
+ private HostManager mgr;
+
+ protected TestListener listener = new TestListener();
+ protected HostProviderRegistry registry;
+ protected TestHostProvider provider;
+ protected HostProviderService providerService;
+
+ @Before
+ public void setUp() {
+ mgr = new HostManager();
+ mgr.store = new SimpleHostStore();
+ injectEventDispatcher(mgr, new TestEventDispatcher());
+ registry = mgr;
+ mgr.networkConfigService = new TestNetworkConfigService();
+ mgr.activate();
+
+ mgr.addListener(listener);
+
+ provider = new TestHostProvider();
+ providerService = registry.register(provider);
+ assertTrue("provider should be registered",
+ registry.getProviders().contains(provider.id()));
+ }
+
+ @After
+ public void tearDown() {
+ registry.unregister(provider);
+ assertFalse("provider should not be registered",
+ registry.getProviders().contains(provider.id()));
+
+ mgr.removeListener(listener);
+ mgr.deactivate();
+ injectEventDispatcher(mgr, null);
+ }
+
+ private void detect(HostId hid, MacAddress mac, VlanId vlan,
+ HostLocation loc, IpAddress ip) {
+ HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ip);
+ providerService.hostDetected(hid, descr);
+ assertNotNull("host should be found", mgr.getHost(hid));
+ }
+
+ private void validateEvents(Enum... types) {
+ int i = 0;
+ assertEquals("wrong events received", types.length, listener.events.size());
+ for (Event event : listener.events) {
+ assertEquals("incorrect event type", types[i], event.type());
+ i++;
+ }
+ listener.events.clear();
+ }
+
+ @Test
+ public void hostDetected() {
+ assertNull("host shouldn't be found", mgr.getHost(HID1));
+
+ // host addition
+ detect(HID1, MAC1, VLAN1, LOC1, IP1);
+ assertEquals("exactly one should be found", 1, mgr.getHostCount());
+ detect(HID2, MAC2, VLAN2, LOC2, IP1);
+ assertEquals("two hosts should be found", 2, mgr.getHostCount());
+ validateEvents(HOST_ADDED, HOST_ADDED);
+
+ // host motion
+ detect(HID1, MAC1, VLAN1, LOC2, IP1);
+ validateEvents(HOST_MOVED);
+ assertEquals("only two hosts should be found", 2, mgr.getHostCount());
+
+ // host update
+ detect(HID1, MAC1, VLAN1, LOC2, IP2);
+ validateEvents(HOST_UPDATED);
+ assertEquals("only two hosts should be found", 2, mgr.getHostCount());
+ }
+
+ @Test
+ public void hostDetectedIPv6() {
+ assertNull("host shouldn't be found", mgr.getHost(HID3));
+
+ // host addition
+ detect(HID3, MAC3, VLAN1, LOC1, IP3);
+ assertEquals("exactly one should be found", 1, mgr.getHostCount());
+ detect(HID4, MAC4, VLAN2, LOC2, IP3);
+ assertEquals("two hosts should be found", 2, mgr.getHostCount());
+ validateEvents(HOST_ADDED, HOST_ADDED);
+
+ // host motion
+ detect(HID3, MAC3, VLAN1, LOC2, IP3);
+ validateEvents(HOST_MOVED);
+ assertEquals("only two hosts should be found", 2, mgr.getHostCount());
+
+ // host update
+ detect(HID3, MAC3, VLAN1, LOC2, IP4);
+ validateEvents(HOST_UPDATED);
+ assertEquals("only two hosts should be found", 2, mgr.getHostCount());
+ }
+
+ @Test
+ public void hostVanished() {
+ detect(HID1, MAC1, VLAN1, LOC1, IP1);
+ providerService.hostVanished(HID1);
+ validateEvents(HOST_ADDED, HOST_REMOVED);
+
+ assertNull("host should have been removed", mgr.getHost(HID1));
+ }
+
+ @Test
+ public void hostVanishedIPv6() {
+ detect(HID3, MAC3, VLAN1, LOC1, IP3);
+ providerService.hostVanished(HID3);
+ validateEvents(HOST_ADDED, HOST_REMOVED);
+
+ assertNull("host should have been removed", mgr.getHost(HID3));
+ }
+
+ private void validateHosts(
+ String msg, Iterable<Host> hosts, HostId... ids) {
+ Set<HostId> hids = Sets.newHashSet(ids);
+ for (Host h : hosts) {
+ assertTrue(msg, hids.remove(h.id()));
+ }
+ assertTrue("expected hosts not fetched from store", hids.isEmpty());
+ }
+
+ @Test
+ public void getHosts() {
+ detect(HID1, MAC1, VLAN1, LOC1, IP1);
+ detect(HID2, MAC2, VLAN1, LOC2, IP2);
+
+ validateHosts("host not properly stored", mgr.getHosts(), HID1, HID2);
+ validateHosts("can't get hosts by VLAN", mgr.getHostsByVlan(VLAN1), HID1, HID2);
+ validateHosts("can't get hosts by MAC", mgr.getHostsByMac(MAC1), HID1);
+ validateHosts("can't get hosts by IP", mgr.getHostsByIp(IP1), HID1);
+ validateHosts("can't get hosts by location", mgr.getConnectedHosts(LOC1), HID1);
+ assertTrue("incorrect host location", mgr.getConnectedHosts(DID2).isEmpty());
+ }
+
+ @Test
+ public void getHostsIPv6() {
+ detect(HID3, MAC3, VLAN1, LOC1, IP3);
+ detect(HID4, MAC4, VLAN1, LOC2, IP4);
+
+ validateHosts("host not properly stored", mgr.getHosts(), HID3, HID4);
+ validateHosts("can't get hosts by VLAN", mgr.getHostsByVlan(VLAN1), HID3, HID4);
+ validateHosts("can't get hosts by MAC", mgr.getHostsByMac(MAC3), HID3);
+ validateHosts("can't get hosts by IP", mgr.getHostsByIp(IP3), HID3);
+ validateHosts("can't get hosts by location", mgr.getConnectedHosts(LOC1), HID3);
+ assertTrue("incorrect host location", mgr.getConnectedHosts(DID2).isEmpty());
+ }
+
+ private static class TestHostProvider extends AbstractProvider
+ implements HostProvider {
+
+ protected TestHostProvider() {
+ super(PID);
+ }
+
+ @Override
+ public ProviderId id() {
+ return PID;
+ }
+
+ @Override
+ public void triggerProbe(Host host) {
+ }
+
+ }
+
+ private static class TestListener implements HostListener {
+
+ protected List<HostEvent> events = Lists.newArrayList();
+
+ @Override
+ public void event(HostEvent event) {
+ events.add(event);
+ }
+
+ }
+
+ @Test
+ public void bindAddressesToPort() {
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+
+ // Add some more addresses and check that they're added correctly
+ PortAddresses add2 =
+ new PortAddresses(CP1, Sets.newHashSet(IA3), null,
+ VlanId.vlanId((short) 2));
+
+ mgr.bindAddressesToPort(add2);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(2, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+ assertTrue(storedAddresses.contains(add2));
+
+ PortAddresses add3 = new PortAddresses(CP1, null, MAC2, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add3);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(3, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+ assertTrue(storedAddresses.contains(add2));
+ assertTrue(storedAddresses.contains(add3));
+ }
+
+ @Test
+ public void bindAddressesToPortIPv6() {
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA4, IA5), MAC3, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+
+ // Add some more addresses and check that they're added correctly
+ PortAddresses add2 =
+ new PortAddresses(CP1, Sets.newHashSet(IA6), null,
+ VlanId.vlanId((short) 2));
+
+ mgr.bindAddressesToPort(add2);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(2, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+ assertTrue(storedAddresses.contains(add2));
+
+ PortAddresses add3 = new PortAddresses(CP1, null, MAC4, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add3);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(3, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+ assertTrue(storedAddresses.contains(add2));
+ assertTrue(storedAddresses.contains(add3));
+ }
+
+ @Test
+ public void unbindAddressesFromPort() {
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+
+ PortAddresses rem1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA1), null, VlanId.NONE);
+
+ mgr.unbindAddressesFromPort(rem1);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ // It shouldn't have been removed because it didn't match the originally
+ // submitted address object
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+
+ mgr.unbindAddressesFromPort(add1);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertTrue(storedAddresses.isEmpty());
+ }
+
+ @Test
+ public void unbindAddressesFromPortIPv6() {
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA4, IA5), MAC3, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+
+ PortAddresses rem1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA4), null, VlanId.NONE);
+
+ mgr.unbindAddressesFromPort(rem1);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ // It shouldn't have been removed because it didn't match the originally
+ // submitted address object
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+
+ mgr.unbindAddressesFromPort(add1);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertTrue(storedAddresses.isEmpty());
+ }
+
+ @Test
+ public void clearAddresses() {
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+
+ mgr.clearAddresses(CP1);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertTrue(storedAddresses.isEmpty());
+ }
+
+ @Test
+ public void clearAddressesIPv6() {
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA4, IA5), MAC3, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+
+ mgr.clearAddresses(CP1);
+ storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertTrue(storedAddresses.isEmpty());
+ }
+
+ @Test
+ public void getAddressBindingsForPort() {
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+ }
+
+ @Test
+ public void getAddressBindingsForPortIPv6() {
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA4, IA5), MAC3, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
+
+ assertEquals(1, storedAddresses.size());
+ assertTrue(storedAddresses.contains(add1));
+ }
+
+ @Test
+ public void getAddressBindings() {
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindings();
+
+ assertTrue(storedAddresses.isEmpty());
+
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+
+ storedAddresses = mgr.getAddressBindings();
+
+ assertTrue(storedAddresses.size() == 1);
+
+ PortAddresses add2 =
+ new PortAddresses(CP2, Sets.newHashSet(IA3), MAC2, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add2);
+
+ storedAddresses = mgr.getAddressBindings();
+
+ assertTrue(storedAddresses.size() == 2);
+ assertTrue(storedAddresses.equals(Sets.newHashSet(add1, add2)));
+ }
+
+ @Test
+ public void getAddressBindingsIPv6() {
+ Set<PortAddresses> storedAddresses = mgr.getAddressBindings();
+
+ assertTrue(storedAddresses.isEmpty());
+
+ PortAddresses add1 =
+ new PortAddresses(CP1, Sets.newHashSet(IA4, IA5), MAC3, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add1);
+
+ storedAddresses = mgr.getAddressBindings();
+
+ assertTrue(storedAddresses.size() == 1);
+
+ PortAddresses add2 =
+ new PortAddresses(CP2, Sets.newHashSet(IA5), MAC4, VlanId.NONE);
+
+ mgr.bindAddressesToPort(add2);
+
+ storedAddresses = mgr.getAddressBindings();
+
+ assertTrue(storedAddresses.size() == 2);
+ assertTrue(storedAddresses.equals(Sets.newHashSet(add1, add2)));
+ }
+
+ private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
new file mode 100644
index 00000000..d6ff473a
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.host.impl;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import org.junit.After;
+import org.junit.Test;
+import org.onlab.packet.ARP;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.host.HostProvider;
+import org.onosproject.net.host.InterfaceIpAddress;
+import org.onosproject.net.host.PortAddresses;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketServiceAdapter;
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class HostMonitorTest {
+
+ private static final IpAddress TARGET_IP_ADDR =
+ IpAddress.valueOf("10.0.0.1");
+ private static final IpAddress SOURCE_ADDR =
+ IpAddress.valueOf("10.0.0.99");
+ private static final InterfaceIpAddress IA1 =
+ new InterfaceIpAddress(SOURCE_ADDR, IpPrefix.valueOf("10.0.0.0/24"));
+ private MacAddress sourceMac = MacAddress.valueOf(1L);
+
+ private HostMonitor hostMonitor;
+
+ @After
+ public void shutdown() {
+ hostMonitor.shutdown();
+ }
+
+ @Test
+ public void testMonitorHostExists() throws Exception {
+ ProviderId id = new ProviderId("fake://", "id");
+
+ Host host = createMock(Host.class);
+ expect(host.providerId()).andReturn(id);
+ replay(host);
+
+ HostManager hostManager = createMock(HostManager.class);
+ expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
+ .andReturn(Collections.singleton(host));
+ replay(hostManager);
+
+ HostProvider hostProvider = createMock(HostProvider.class);
+ expect(hostProvider.id()).andReturn(id).anyTimes();
+ hostProvider.triggerProbe(host);
+ expectLastCall().once();
+ replay(hostProvider);
+
+ hostMonitor = new HostMonitor(null, hostManager, null);
+
+ hostMonitor.registerHostProvider(hostProvider);
+ hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
+
+ hostMonitor.run(null);
+
+ verify(hostProvider);
+ }
+
+ @Test
+ public void testMonitorHostDoesNotExist() throws Exception {
+
+ HostManager hostManager = createMock(HostManager.class);
+
+ DeviceId devId = DeviceId.deviceId("fake");
+
+ Device device = createMock(Device.class);
+ expect(device.id()).andReturn(devId).anyTimes();
+ replay(device);
+
+ PortNumber portNum = PortNumber.portNumber(1L);
+
+ Port port = createMock(Port.class);
+ expect(port.number()).andReturn(portNum).anyTimes();
+ replay(port);
+
+ TestDeviceService deviceService = new TestDeviceService();
+ deviceService.addDevice(device, Collections.singleton(port));
+
+ ConnectPoint cp = new ConnectPoint(devId, portNum);
+ PortAddresses pa =
+ new PortAddresses(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE);
+
+ expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
+ .andReturn(Collections.emptySet()).anyTimes();
+ replay(hostManager);
+
+ InterfaceService interfaceService = createMock(InterfaceService.class);
+ expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR))
+ .andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE))
+ .anyTimes();
+ replay(interfaceService);
+
+ TestPacketService packetService = new TestPacketService();
+
+
+ // Run the test
+ hostMonitor = new HostMonitor(packetService, hostManager, interfaceService);
+
+ hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
+ hostMonitor.run(null);
+
+
+ // Check that a packet was sent to our PacketService and that it has
+ // the properties we expect
+ assertEquals(1, packetService.packets.size());
+ OutboundPacket packet = packetService.packets.get(0);
+
+ // Check the output port is correct
+ assertEquals(1, packet.treatment().immediate().size());
+ Instruction instruction = packet.treatment().immediate().get(0);
+ assertTrue(instruction instanceof OutputInstruction);
+ OutputInstruction oi = (OutputInstruction) instruction;
+ assertEquals(portNum, oi.port());
+
+ // Check the output packet is correct (well the important bits anyway)
+ final byte[] pktData = new byte[packet.data().remaining()];
+ packet.data().get(pktData);
+ Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
+ assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
+ ARP arp = (ARP) eth.getPayload();
+ assertArrayEquals(SOURCE_ADDR.toOctets(),
+ arp.getSenderProtocolAddress());
+ assertArrayEquals(sourceMac.toBytes(),
+ arp.getSenderHardwareAddress());
+ assertArrayEquals(TARGET_IP_ADDR.toOctets(),
+ arp.getTargetProtocolAddress());
+ }
+
+ @Test
+ public void testMonitorHostDoesNotExistWithVlan() throws Exception {
+
+ HostManager hostManager = createMock(HostManager.class);
+
+ DeviceId devId = DeviceId.deviceId("fake");
+ short vlan = 5;
+
+ Device device = createMock(Device.class);
+ expect(device.id()).andReturn(devId).anyTimes();
+ replay(device);
+
+ PortNumber portNum = PortNumber.portNumber(1L);
+
+ Port port = createMock(Port.class);
+ expect(port.number()).andReturn(portNum).anyTimes();
+ replay(port);
+
+ TestDeviceService deviceService = new TestDeviceService();
+ deviceService.addDevice(device, Collections.singleton(port));
+
+ ConnectPoint cp = new ConnectPoint(devId, portNum);
+ PortAddresses pa =
+ new PortAddresses(cp, Collections.singleton(IA1), sourceMac,
+ VlanId.vlanId(vlan));
+
+ expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
+ .andReturn(Collections.emptySet()).anyTimes();
+ replay(hostManager);
+
+ InterfaceService interfaceService = createMock(InterfaceService.class);
+ expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR))
+ .andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.vlanId(vlan)))
+ .anyTimes();
+ replay(interfaceService);
+
+ TestPacketService packetService = new TestPacketService();
+
+
+ // Run the test
+ hostMonitor = new HostMonitor(packetService, hostManager, interfaceService);
+
+ hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
+ hostMonitor.run(null);
+
+
+ // Check that a packet was sent to our PacketService and that it has
+ // the properties we expect
+ assertEquals(1, packetService.packets.size());
+ OutboundPacket packet = packetService.packets.get(0);
+
+ // Check the output port is correct
+ assertEquals(1, packet.treatment().immediate().size());
+ Instruction instruction = packet.treatment().immediate().get(0);
+ assertTrue(instruction instanceof OutputInstruction);
+ OutputInstruction oi = (OutputInstruction) instruction;
+ assertEquals(portNum, oi.port());
+
+ // Check the output packet is correct (well the important bits anyway)
+ final byte[] pktData = new byte[packet.data().remaining()];
+ packet.data().get(pktData);
+ Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
+ assertEquals(vlan, eth.getVlanID());
+ ARP arp = (ARP) eth.getPayload();
+ assertArrayEquals(SOURCE_ADDR.toOctets(),
+ arp.getSenderProtocolAddress());
+ assertArrayEquals(sourceMac.toBytes(),
+ arp.getSenderHardwareAddress());
+ assertArrayEquals(TARGET_IP_ADDR.toOctets(),
+ arp.getTargetProtocolAddress());
+ }
+
+ class TestPacketService extends PacketServiceAdapter {
+
+ List<OutboundPacket> packets = new ArrayList<>();
+
+ @Override
+ public void emit(OutboundPacket packet) {
+ packets.add(packet);
+ }
+ }
+
+ class TestDeviceService extends DeviceServiceAdapter {
+
+ List<Device> devices = Lists.newArrayList();
+ Multimap<DeviceId, Port> devicePorts = HashMultimap.create();
+
+ void addDevice(Device device, Set<Port> ports) {
+ devices.add(device);
+ for (Port p : ports) {
+ devicePorts.put(device.id(), p);
+ }
+ }
+
+ @Override
+ public int getDeviceCount() {
+ return 0;
+ }
+
+ @Override
+ public Iterable<Device> getDevices() {
+ return devices;
+ }
+
+ @Override
+ public Device getDevice(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public MastershipRole getRole(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public List<Port> getPorts(DeviceId deviceId) {
+ List<Port> ports = Lists.newArrayList();
+ for (Port p : devicePorts.get(deviceId)) {
+ ports.add(p);
+ }
+ return ports;
+ }
+
+ @Override
+ public Port getPort(DeviceId deviceId, PortNumber portNumber) {
+ return null;
+ }
+
+ @Override
+ public boolean isAvailable(DeviceId deviceId) {
+ return false;
+ }
+
+ @Override
+ public void addListener(DeviceListener listener) {
+ }
+
+ @Override
+ public void removeListener(DeviceListener listener) {
+ }
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/LinksHaveEntryWithSourceDestinationPairMatcher.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/LinksHaveEntryWithSourceDestinationPairMatcher.java
new file mode 100644
index 00000000..d34143c9
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/LinksHaveEntryWithSourceDestinationPairMatcher.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent;
+
+import java.util.Collection;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.onosproject.net.EdgeLink;
+import org.onosproject.net.Link;
+
+/**
+ * Matcher to determine if a Collection of Links contains a path between a source
+ * and a destination.
+ */
+public class LinksHaveEntryWithSourceDestinationPairMatcher extends
+ TypeSafeMatcher<Collection<Link>> {
+ private final String source;
+ private final String destination;
+
+ /**
+ * Creates a matcher for a given path represented by a source and
+ * a destination.
+ *
+ * @param source string identifier for the source of the path
+ * @param destination string identifier for the destination of the path
+ */
+ LinksHaveEntryWithSourceDestinationPairMatcher(String source,
+ String destination) {
+ this.source = source;
+ this.destination = destination;
+ }
+
+ @Override
+ public boolean matchesSafely(Collection<Link> links) {
+ for (Link link : links) {
+ if (source.equals(destination) && link instanceof EdgeLink) {
+ EdgeLink edgeLink = (EdgeLink) link;
+ if (edgeLink.hostLocation().elementId()
+ .toString().endsWith(source)) {
+ return true;
+ }
+ }
+
+ if (link.src().elementId().toString().endsWith(source) &&
+ link.dst().elementId().toString().endsWith(destination)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("link lookup for source \"");
+ description.appendText(source);
+ description.appendText(" and destination ");
+ description.appendText(destination);
+ description.appendText("\"");
+ }
+
+ @Override
+ public void describeMismatchSafely(Collection<Link> links,
+ Description mismatchDescription) {
+ mismatchDescription.appendText("was ").
+ appendText(links.toString());
+ }
+
+ /**
+ * Creates a link has path matcher.
+ *
+ * @param source string identifier for the source of the path
+ * @param destination string identifier for the destination of the path
+ * @return matcher to match the path
+ */
+ public static LinksHaveEntryWithSourceDestinationPairMatcher linksHasPath(
+ String source,
+ String destination) {
+ return new LinksHaveEntryWithSourceDestinationPairMatcher(source,
+ destination);
+ }
+}
+
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentAccumulatorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentAccumulatorTest.java
new file mode 100644
index 00000000..219d2fd5
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentAccumulatorTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentBatchDelegate;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.IntentTestsMocks.MockIntent;
+import org.onosproject.net.intent.IntentTestsMocks.MockTimestamp;
+import org.onosproject.net.intent.MockIdGenerator;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+
+/**
+ * Unit tests for the intent accumulator.
+ */
+public class IntentAccumulatorTest {
+
+ Intent intent1;
+ Intent intent2;
+ Intent intent3;
+ IdGenerator mockGenerator;
+
+ private static IntentDataMatcher containsIntent(Intent intent) {
+ return new IntentDataMatcher(intent);
+ }
+
+ /**
+ * Creates mock intents used by the test.
+ */
+ @Before
+ public void localSetup() {
+ mockGenerator = new MockIdGenerator();
+ Intent.bindIdGenerator(mockGenerator);
+
+ intent1 = new MockIntent(1L);
+ intent2 = new MockIntent(2L);
+ intent3 = new MockIntent(3L);
+ }
+
+ /**
+ * Removes id generator from the Intent class.
+ */
+ @After
+ public void localTearDown() {
+ Intent.unbindIdGenerator(mockGenerator);
+ }
+
+ /**
+ * Hamcrest matcher to check that a collection of intent data objects
+ * contains an entry for a given intent.
+ */
+ private static final class IntentDataMatcher
+ extends TypeSafeDiagnosingMatcher<Collection<IntentData>> {
+
+ final Intent intent;
+
+ public IntentDataMatcher(Intent intent) {
+ this.intent = intent;
+ }
+
+ /**
+ * Check that the given collection of intent data contains a specific
+ * intent.
+ *
+ * @param operations collection of intent data
+ * @param description description
+ * @return true if the collection contains the intent, false otherwise.
+ */
+ public boolean matchesSafely(Collection<IntentData> operations,
+ Description description) {
+ for (IntentData operation : operations) {
+ if (operation.key().equals(intent.key())) {
+ if (operation.state() != IntentState.INSTALLED) {
+ description.appendText("state was " + operation.state());
+ return false;
+ }
+ return true;
+ }
+ }
+ description.appendText("key was not found " + intent.key());
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("INSTALLED state intent with key " + intent.key());
+ }
+ }
+
+ /**
+ * Mock batch delegate class. Gets calls from the accumulator and checks
+ * that the operations have been properly compressed.
+ */
+ private class MockIntentBatchDelegate
+ implements IntentBatchDelegate {
+ public void execute(Collection<IntentData> operations) {
+ assertThat(operations, hasSize(3));
+ assertThat(operations, containsIntent(intent1));
+ assertThat(operations, containsIntent(intent2));
+ assertThat(operations, containsIntent(intent3));
+ }
+ }
+
+ /**
+ * Tests that the accumulator properly compresses operations on the same
+ * intents.
+ */
+ @Test
+ public void checkAccumulator() {
+
+ MockIntentBatchDelegate delegate = new MockIntentBatchDelegate();
+ IntentAccumulator accumulator = new IntentAccumulator(delegate);
+
+ List<IntentData> intentDataItems = ImmutableList.of(
+ new IntentData(intent1, IntentState.INSTALLING,
+ new MockTimestamp(1)),
+ new IntentData(intent2, IntentState.INSTALLING,
+ new MockTimestamp(1)),
+ new IntentData(intent3, IntentState.INSTALLED,
+ new MockTimestamp(1)),
+ new IntentData(intent2, IntentState.INSTALLED,
+ new MockTimestamp(1)),
+ new IntentData(intent2, IntentState.INSTALLED,
+ new MockTimestamp(1)),
+ new IntentData(intent1, IntentState.INSTALLED,
+ new MockTimestamp(1)));
+
+
+ accumulator.processItems(intentDataItems);
+ }
+
+
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTest.java
new file mode 100644
index 00000000..0f6ce67c
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl;
+
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentServiceAdapter;
+import org.onosproject.net.intent.IntentStore;
+import org.onosproject.net.intent.IntentStoreDelegate;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.store.Timestamp;
+import org.onosproject.store.trivial.SimpleIntentStore;
+import org.onosproject.store.trivial.SystemClockTimestamp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.intent.IntentState.*;
+import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
+
+/**
+ * Test intent cleanup.
+ */
+public class IntentCleanupTest {
+
+ private IntentCleanup cleanup;
+ private MockIntentService service;
+ private IntentStore store;
+ protected IdGenerator idGenerator; // global or one per test? per test for now.
+
+ private static class MockIntentService extends IntentServiceAdapter {
+
+ private int submitCounter = 0;
+
+ @Override
+ public void submit(Intent intent) {
+ submitCounter++;
+ }
+
+ public int submitCounter() {
+ return submitCounter;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ service = new MockIntentService();
+ store = new SimpleIntentStore();
+ cleanup = new IntentCleanup();
+ idGenerator = new MockIdGenerator();
+
+ cleanup.cfgService = new ComponentConfigAdapter();
+ cleanup.service = service;
+ cleanup.store = store;
+ cleanup.period = 10;
+ cleanup.retryThreshold = 3;
+ cleanup.activate();
+
+ assertTrue("store should be empty",
+ Sets.newHashSet(cleanup.store.getIntents()).isEmpty());
+
+ Intent.bindIdGenerator(idGenerator);
+ }
+
+ @After
+ public void tearDown() {
+ cleanup.deactivate();
+
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ /**
+ * Trigger resubmit of intent in CORRUPT during periodic poll.
+ */
+ @Test
+ public void corruptPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {}
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ cleanup.run(); //FIXME broken?
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+ }
+
+ /**
+ * Trigger resubmit of intent in INSTALL_REQ for too long.
+ */
+ @Test
+ public void pendingPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {}
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ cleanup.run();
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+
+ }
+
+ /**
+ * Trigger resubmit of intent in INSTALLING for too long.
+ */
+ @Test
+ public void installingPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(INSTALLING);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ cleanup.run();
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+
+ }
+
+ /**
+ * Only submit one of two intents because one is too new.
+ */
+ @Test
+ public void skipPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {}
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+ store.addPending(data);
+
+ Intent intent2 = new MockIntent(2L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ data = new IntentData(intent2, INSTALL_REQ, version);
+ store.addPending(data);
+
+ cleanup.run();
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+ }
+
+ /**
+ * Verify resubmit in response to CORRUPT event.
+ */
+ @Test
+ public void corruptEvent() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+
+ store.addPending(data);
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+ }
+
+ /**
+ * Intent should not be retried because threshold is reached.
+ */
+ @Test
+ public void corruptEventThreshold() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ intentData.setErrorCount(cleanup.retryThreshold);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+
+ store.addPending(data);
+ assertEquals("Expect number of submits incorrect",
+ 0, service.submitCounter());
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTestMock.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTestMock.java
new file mode 100644
index 00000000..15ee24e6
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTestMock.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl;
+
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentStore;
+import org.onosproject.net.intent.IntentStoreDelegate;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.store.Timestamp;
+import org.onosproject.store.trivial.SimpleIntentStore;
+import org.onosproject.store.trivial.SystemClockTimestamp;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.intent.IntentState.*;
+import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
+
+/**
+ * Test intent cleanup using Mocks.
+ * FIXME remove this or IntentCleanupTest
+ */
+public class IntentCleanupTestMock {
+
+ private IntentCleanup cleanup;
+ private IntentService service;
+ private IntentStore store;
+ protected IdGenerator idGenerator; // global or one per test? per test for now.
+
+ @Before
+ public void setUp() {
+ service = createMock(IntentService.class);
+ store = new SimpleIntentStore();
+ cleanup = new IntentCleanup();
+ idGenerator = new MockIdGenerator();
+
+ service.addListener(cleanup);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.cfgService = new ComponentConfigAdapter();
+ cleanup.service = service;
+ cleanup.store = store;
+ cleanup.period = 1000;
+ cleanup.retryThreshold = 3;
+ cleanup.activate();
+
+ verify(service);
+ reset(service);
+
+ assertTrue("store should be empty",
+ Sets.newHashSet(cleanup.store.getIntents()).isEmpty());
+
+ Intent.bindIdGenerator(idGenerator);
+ }
+
+ @After
+ public void tearDown() {
+ service.removeListener(cleanup);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.deactivate();
+
+ verify(service);
+ reset(service);
+
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ /**
+ * Trigger resubmit of intent in CORRUPT during periodic poll.
+ */
+ @Test
+ public void corruptPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {}
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ service.submit(intent);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.run(); //FIXME broken?
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Trigger resubmit of intent in INSTALL_REQ for too long.
+ */
+ @Test
+ public void pendingPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {}
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ service.submit(intent);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.run();
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Trigger resubmit of intent in INSTALLING for too long.
+ */
+ @Test
+ public void installingPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(INSTALLING);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ service.submit(intent);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.run();
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Only submit one of two intents because one is too new.
+ */
+ @Test
+ public void skipPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {}
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+ store.addPending(data);
+
+ Intent intent2 = new MockIntent(2L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ data = new IntentData(intent2, INSTALL_REQ, version);
+ store.addPending(data);
+
+ service.submit(intent2);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.run();
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Verify resubmit in response to CORRUPT event.
+ */
+ @Test
+ public void corruptEvent() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+
+ service.submit(intent);
+ expectLastCall().once();
+ replay(service);
+
+ store.addPending(data);
+
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Intent should not be retried because threshold is reached.
+ */
+ @Test
+ public void corruptEventThreshold() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ intentData.setErrorCount(cleanup.retryThreshold);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+
+ replay(service);
+
+ store.addPending(data);
+
+ verify(service);
+ reset(service);
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
new file mode 100644
index 00000000..4bf32f43
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.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 org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.onosproject.TestApplicationId;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.impl.TestCoreManager;
+import org.onosproject.net.NetworkResource;
+import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentCompiler;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentEvent.Type;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.resource.link.LinkResourceAllocations;
+import org.onosproject.store.trivial.SimpleIntentStore;
+
+import java.util.Collection;
+import java.util.Collections;
+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.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.*;
+import static org.onlab.junit.TestTools.assertAfter;
+import static org.onlab.util.Tools.delay;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+import static org.onosproject.net.intent.IntentState.*;
+import static org.onosproject.net.intent.IntentTestsMocks.MockFlowRule;
+import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
+
+/**
+ * Test intent manager and transitions.
+ *
+ * TODO implement the following tests:
+ * - {submit, withdraw, update, replace} intent
+ * - {submit, update, recompiling} intent with failed compilation
+ * - failed reservation
+ * - push timeout recovery
+ * - failed items recovery
+ *
+ * in general, verify intents store, flow store, and work queue
+ */
+
+public class IntentManagerTest {
+
+ private static final int SUBMIT_TIMEOUT_MS = 1000;
+ private static final ApplicationId APPID = new TestApplicationId("manager-test");
+
+ private IntentManager manager;
+ private MockFlowRuleService flowRuleService;
+
+ protected IntentService service;
+ protected IntentExtensionService extensionService;
+ protected TestListener listener = new TestListener();
+ protected TestIntentCompiler compiler = new TestIntentCompiler();
+
+ 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(Key key, Collection<NetworkResource> resources) {
+ //TODO
+ }
+
+ @Override
+ public void removeTrackedResources(Key key, Collection<NetworkResource> resources) {
+ //TODO
+ }
+
+ @Override
+ public void trackIntent(IntentData intentData) {
+ //TODO
+ }
+ }
+
+ private static class MockInstallableIntent extends FlowRuleIntent {
+
+ public MockInstallableIntent() {
+ super(APPID, Collections.singletonList(new MockFlowRule(100)));
+ }
+ }
+
+ 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());
+ }
+ }
+
+ private static class TestIntentCompilerMultipleFlows implements IntentCompiler<MockIntent> {
+ @Override
+ public List<Intent> compile(MockIntent intent, List<Intent> installable,
+ Set<LinkResourceAllocations> resources) {
+
+ return IntStream.rangeClosed(1, 5)
+ .mapToObj(mock -> (new MockInstallableIntent()))
+ .collect(Collectors.toList());
+ }
+ }
+
+
+ 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");
+ }
+ }
+
+ /**
+ * Hamcrest matcher to check that a collection 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();
+ flowRuleService = new MockFlowRuleService();
+ manager.store = new SimpleIntentStore();
+ injectEventDispatcher(manager, new TestEventDispatcher());
+ manager.trackerService = new TestIntentTracker();
+ manager.flowRuleService = flowRuleService;
+ manager.coreService = new TestCoreManager();
+ service = manager;
+ extensionService = manager;
+
+ manager.activate();
+ service.addListener(listener);
+ extensionService.registerCompiler(MockIntent.class, compiler);
+
+ assertTrue("store should be empty",
+ Sets.newHashSet(service.getIntents()).isEmpty());
+ assertEquals(0L, flowRuleService.getFlowRuleCount());
+ }
+
+ public void verifyState() {
+ // verify that all intents are parked and the batch operation is unblocked
+ Set<IntentState> parked = Sets.newHashSet(INSTALLED, WITHDRAWN, FAILED, CORRUPT);
+ for (Intent i : service.getIntents()) {
+ IntentState state = service.getIntentState(i.key());
+ assertTrue("Intent " + i.id() + " is in invalid state " + state,
+ parked.contains(state));
+ }
+ //the batch has not yet been removed when we receive the last event
+ // FIXME: this doesn't guarantee to avoid the race
+
+ //FIXME
+// for (int tries = 0; tries < 10; tries++) {
+// if (manager.batchService.getPendingOperations().isEmpty()) {
+// break;
+// }
+// delay(10);
+// }
+// assertTrue("There are still pending batch operations.",
+// manager.batchService.getPendingOperations().isEmpty());
+
+ }
+
+ @After
+ public void tearDown() {
+ extensionService.unregisterCompiler(MockIntent.class);
+ service.removeListener(listener);
+ manager.deactivate();
+ // TODO null the other refs?
+ }
+
+ @Test
+ public void submitIntent() {
+ flowRuleService.setFuture(true);
+
+ listener.setLatch(1, Type.INSTALL_REQ);
+ listener.setLatch(1, Type.INSTALLED);
+ Intent intent = new MockIntent(MockIntent.nextId());
+ service.submit(intent);
+ listener.await(Type.INSTALL_REQ);
+ listener.await(Type.INSTALLED);
+ assertEquals(1L, service.getIntentCount());
+ assertEquals(1L, flowRuleService.getFlowRuleCount());
+ verifyState();
+ }
+
+ @Test
+ public void withdrawIntent() {
+ flowRuleService.setFuture(true);
+
+ listener.setLatch(1, Type.INSTALLED);
+ Intent intent = new MockIntent(MockIntent.nextId());
+ service.submit(intent);
+ listener.await(Type.INSTALLED);
+ assertEquals(1L, service.getIntentCount());
+ assertEquals(1L, flowRuleService.getFlowRuleCount());
+
+ listener.setLatch(1, Type.WITHDRAWN);
+ service.withdraw(intent);
+ listener.await(Type.WITHDRAWN);
+ assertEquals(0L, flowRuleService.getFlowRuleCount());
+ verifyState();
+ }
+
+ @Test
+ @Ignore("This is disabled because we are seeing intermittent failures on Jenkins")
+ public void stressSubmitWithdrawUnique() {
+ flowRuleService.setFuture(true);
+
+ int count = 500;
+ Intent[] intents = new Intent[count];
+
+ listener.setLatch(count, Type.WITHDRAWN);
+
+ for (int i = 0; i < count; i++) {
+ intents[i] = new MockIntent(MockIntent.nextId());
+ service.submit(intents[i]);
+ }
+
+ for (int i = 0; i < count; i++) {
+ service.withdraw(intents[i]);
+ }
+
+ listener.await(Type.WITHDRAWN);
+ assertEquals(0L, flowRuleService.getFlowRuleCount());
+ verifyState();
+ }
+
+ @Test
+ public void stressSubmitWithdrawSame() {
+ flowRuleService.setFuture(true);
+
+ int count = 50;
+
+ Intent intent = new MockIntent(MockIntent.nextId());
+ for (int i = 0; i < count; i++) {
+ service.submit(intent);
+ service.withdraw(intent);
+ }
+
+ assertAfter(SUBMIT_TIMEOUT_MS, () -> {
+ assertEquals(1L, service.getIntentCount());
+ assertEquals(0L, flowRuleService.getFlowRuleCount());
+ });
+ verifyState();
+ }
+
+
+ /**
+ * Tests for proper behavior of installation of an intent that triggers
+ * a compilation error.
+ */
+ @Test
+ public void errorIntentCompile() {
+ final TestIntentCompilerError errorCompiler = new TestIntentCompilerError();
+ extensionService.registerCompiler(MockIntent.class, errorCompiler);
+ 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);
+ verifyState();
+ }
+
+ /**
+ * Tests handling a future that contains an error as a result of
+ * installing an intent.
+ */
+ @Ignore("skipping until we fix update ordering problem")
+ @Test
+ public void errorIntentInstallFromFlows() {
+ final Long id = MockIntent.nextId();
+ flowRuleService.setFuture(false);
+ MockIntent intent = new MockIntent(id);
+ listener.setLatch(1, Type.FAILED);
+ listener.setLatch(1, Type.INSTALL_REQ);
+ service.submit(intent);
+ listener.await(Type.INSTALL_REQ);
+ listener.await(Type.FAILED);
+ // FIXME the intent will be moved into INSTALLED immediately which overrides FAILED
+ // ... the updates come out of order
+ verifyState();
+ }
+
+ /**
+ * Tests handling a future that contains an unresolvable error as a result of
+ * installing an intent.
+ */
+ @Test
+ public void errorIntentInstallNeverTrue() {
+ final Long id = MockIntent.nextId();
+ flowRuleService.setFuture(false);
+ MockIntent intent = new MockIntent(id);
+ listener.setLatch(1, Type.CORRUPT);
+ 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);
+ service.withdraw(intent);
+ listener.await(Type.CORRUPT);
+ verifyState();
+ }
+
+ /**
+ * 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));
+ verifyState();
+ }
+
+ /**
+ * Tests an intent with no compiler.
+ */
+ @Test
+ public void intentWithoutCompiler() {
+ class IntentNoCompiler extends Intent {
+ IntentNoCompiler() {
+ super(APPID, null, Collections.emptyList(),
+ Intent.DEFAULT_INTENT_PRIORITY);
+ }
+ }
+
+ 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);
+ verifyState();
+ }
+
+ /**
+ * Tests an intent with no installer.
+ */
+ @Test
+ public void intentWithoutInstaller() {
+ MockIntent intent = new MockIntent(MockIntent.nextId());
+ listener.setLatch(1, Type.INSTALL_REQ);
+ listener.setLatch(1, Type.CORRUPT);
+ service.submit(intent);
+ listener.await(Type.INSTALL_REQ);
+ listener.await(Type.CORRUPT);
+ verifyState();
+ }
+
+ /**
+ * 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()));
+ verifyState();
+ }
+
+ /**
+ * Tests that removing all intents results in no flows remaining.
+ */
+ @Test
+ public void testFlowRemoval() {
+ 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(1, Type.INSTALL_REQ);
+ listener.setLatch(1, Type.INSTALLED);
+
+ service.submit(intent1);
+ listener.await(Type.INSTALL_REQ);
+ listener.await(Type.INSTALLED);
+
+
+ listener.setLatch(1, Type.INSTALL_REQ);
+ listener.setLatch(1, Type.INSTALLED);
+
+ service.submit(intent2);
+ listener.await(Type.INSTALL_REQ);
+ listener.await(Type.INSTALLED);
+
+ assertThat(listener.getCounts(Type.INSTALLED), is(2));
+ assertThat(flowRuleService.getFlowRuleCount(), is(2));
+
+ listener.setLatch(1, Type.WITHDRAWN);
+ service.withdraw(intent1);
+ listener.await(Type.WITHDRAWN);
+
+ listener.setLatch(1, Type.WITHDRAWN);
+ service.withdraw(intent2);
+ listener.await(Type.WITHDRAWN);
+
+ assertThat(listener.getCounts(Type.WITHDRAWN), is(2));
+ assertThat(flowRuleService.getFlowRuleCount(), is(0));
+ }
+
+ /**
+ * Test failure to install an intent, then succeed on retry via IntentCleanup.
+ */
+ @Test
+ public void testCorruptCleanup() {
+ IntentCleanup cleanup = new IntentCleanup();
+ cleanup.service = manager;
+ cleanup.store = manager.store;
+ cleanup.cfgService = new ComponentConfigAdapter();
+
+ try {
+ cleanup.activate();
+
+ final TestIntentCompilerMultipleFlows errorCompiler = new TestIntentCompilerMultipleFlows();
+ extensionService.registerCompiler(MockIntent.class, errorCompiler);
+ List<Intent> intents;
+
+ flowRuleService.setFuture(false);
+
+ intents = Lists.newArrayList(service.getIntents());
+ assertThat(intents, hasSize(0));
+
+ final MockIntent intent1 = new MockIntent(MockIntent.nextId());
+
+ listener.setLatch(1, Type.INSTALL_REQ);
+ listener.setLatch(1, Type.CORRUPT);
+ listener.setLatch(1, Type.INSTALLED);
+
+ service.submit(intent1);
+
+ listener.await(Type.INSTALL_REQ);
+ listener.await(Type.CORRUPT);
+
+ flowRuleService.setFuture(true);
+
+ listener.await(Type.INSTALLED);
+
+ assertThat(listener.getCounts(Type.CORRUPT), is(1));
+ assertThat(listener.getCounts(Type.INSTALLED), is(1));
+ assertEquals(INSTALLED, manager.getIntentState(intent1.key()));
+ assertThat(flowRuleService.getFlowRuleCount(), is(5));
+ } finally {
+ cleanup.deactivate();
+ }
+ }
+
+ /**
+ * Test failure to install an intent, and verify retries.
+ */
+ @Test
+ public void testCorruptRetry() {
+ IntentCleanup cleanup = new IntentCleanup();
+ cleanup.service = manager;
+ cleanup.store = manager.store;
+ cleanup.cfgService = new ComponentConfigAdapter();
+ cleanup.period = 1_000_000;
+ cleanup.retryThreshold = 3;
+
+ try {
+ cleanup.activate();
+
+ final TestIntentCompilerMultipleFlows errorCompiler = new TestIntentCompilerMultipleFlows();
+ extensionService.registerCompiler(MockIntent.class, errorCompiler);
+ List<Intent> intents;
+
+ flowRuleService.setFuture(false);
+
+ intents = Lists.newArrayList(service.getIntents());
+ assertThat(intents, hasSize(0));
+
+ final MockIntent intent1 = new MockIntent(MockIntent.nextId());
+
+ listener.setLatch(1, Type.INSTALL_REQ);
+ listener.setLatch(cleanup.retryThreshold, Type.CORRUPT);
+ listener.setLatch(1, Type.INSTALLED);
+
+ service.submit(intent1);
+
+ listener.await(Type.INSTALL_REQ);
+ listener.await(Type.CORRUPT);
+ assertEquals(CORRUPT, manager.getIntentState(intent1.key()));
+ assertThat(listener.getCounts(Type.CORRUPT), is(cleanup.retryThreshold));
+
+ } finally {
+ cleanup.deactivate();
+ }
+ }
+
+ /**
+ * Tests that an intent that fails installation results in no flows remaining.
+ */
+ @Test
+ @Ignore("MockFlowRule numbering issue") //test works if run independently
+ public void testFlowRemovalInstallError() {
+ final TestIntentCompilerMultipleFlows errorCompiler = new TestIntentCompilerMultipleFlows();
+ extensionService.registerCompiler(MockIntent.class, errorCompiler);
+ List<Intent> intents;
+
+ flowRuleService.setFuture(true);
+ //FIXME relying on "3" is brittle
+ flowRuleService.setErrorFlow(3);
+
+ intents = Lists.newArrayList(service.getIntents());
+ assertThat(intents, hasSize(0));
+
+ final MockIntent intent1 = new MockIntent(MockIntent.nextId());
+
+ listener.setLatch(1, Type.INSTALL_REQ);
+ listener.setLatch(1, Type.CORRUPT);
+
+ service.submit(intent1);
+ listener.await(Type.INSTALL_REQ);
+ listener.await(Type.CORRUPT);
+
+ assertThat(listener.getCounts(Type.CORRUPT), is(1));
+ // in this test, there will still be flows abandoned on the data plane
+ //assertThat(flowRuleService.getFlowRuleCount(), is(0));
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/MockFlowRuleService.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/MockFlowRuleService.java
new file mode 100644
index 00000000..8bd29bf8
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/MockFlowRuleService.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl;
+
+import com.google.common.collect.Sets;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleServiceAdapter;
+
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+import static org.onosproject.net.flow.FlowRuleOperation.Type.REMOVE;
+
+
+public class MockFlowRuleService extends FlowRuleServiceAdapter {
+
+ final Set<FlowRule> flows = Sets.newHashSet();
+ boolean success;
+
+ int errorFlow = -1;
+ public void setErrorFlow(int errorFlow) {
+ this.errorFlow = errorFlow;
+ }
+
+ public void setFuture(boolean success) {
+ this.success = success;
+ }
+
+ @Override
+ public void apply(FlowRuleOperations ops) {
+ AtomicBoolean thisSuccess = new AtomicBoolean(success);
+ ops.stages().forEach(stage -> stage.forEach(flow -> {
+ if (errorFlow == flow.rule().id().value()) {
+ thisSuccess.set(false);
+ } else {
+ switch (flow.type()) {
+ case ADD:
+ case MODIFY: //TODO is this the right behavior for modify?
+ flows.add(flow.rule());
+ break;
+ case REMOVE:
+ flows.remove(flow.rule());
+ break;
+ default:
+ break;
+ }
+ }
+ }));
+ if (thisSuccess.get()) {
+ ops.callback().onSuccess(ops);
+ } else {
+ ops.callback().onError(ops);
+ }
+ }
+
+ @Override
+ public int getFlowRuleCount() {
+ return flows.size();
+ }
+
+ @Override
+ public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
+ return flows.stream()
+ .filter(flow -> flow.deviceId().equals(deviceId))
+ .map(DefaultFlowEntry::new)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void applyFlowRules(FlowRule... flowRules) {
+ for (FlowRule flow : flowRules) {
+ flows.add(flow);
+ }
+ }
+
+ @Override
+ public void removeFlowRules(FlowRule... flowRules) {
+ for (FlowRule flow : flowRules) {
+ flows.remove(flow);
+ }
+ }
+
+ @Override
+ public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
+ return flows.stream()
+ .filter(flow -> flow.appId() == id.id())
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Iterable<FlowRule> getFlowRulesByGroupId(ApplicationId appId, short groupId) {
+ return flows.stream()
+ .filter(flow -> flow.appId() == appId.id() && flow.groupId().id() == groupId)
+ .collect(Collectors.toList());
+ }
+}
+
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/ObjectiveTrackerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/ObjectiveTrackerTest.java
new file mode 100644
index 00000000..58fa1292
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/ObjectiveTrackerTest.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.junit.TestUtils.TestUtilsException;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.event.Event;
+import org.onosproject.net.Device;
+import org.onosproject.net.Link;
+import org.onosproject.net.NetworkResource;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.link.LinkEvent;
+import org.onosproject.net.resource.link.LinkResourceEvent;
+import org.onosproject.net.resource.link.LinkResourceListener;
+import org.onosproject.net.topology.Topology;
+import org.onosproject.net.topology.TopologyEvent;
+import org.onosproject.net.topology.TopologyListener;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+import static org.easymock.EasyMock.createMock;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.onosproject.net.NetTestTools.APP_ID;
+import static org.onosproject.net.NetTestTools.device;
+import static org.onosproject.net.NetTestTools.link;
+
+/**
+ * Tests for the objective tracker.
+ */
+public class ObjectiveTrackerTest {
+ private static final int WAIT_TIMEOUT_SECONDS = 2;
+ private Topology topology;
+ private ObjectiveTracker tracker;
+ private TestTopologyChangeDelegate delegate;
+ private List<Event> reasons;
+ private TopologyListener listener;
+ private DeviceListener deviceListener;
+ private LinkResourceListener linkResourceListener;
+ private IdGenerator mockGenerator;
+
+ /**
+ * Initialization shared by all test cases.
+ *
+ * @throws TestUtilsException if any filed look ups fail
+ */
+ @Before
+ public void setUp() throws TestUtilsException {
+ topology = createMock(Topology.class);
+ tracker = new ObjectiveTracker();
+ delegate = new TestTopologyChangeDelegate();
+ tracker.setDelegate(delegate);
+ reasons = new LinkedList<>();
+ listener = TestUtils.getField(tracker, "listener");
+ deviceListener = TestUtils.getField(tracker, "deviceListener");
+ linkResourceListener = TestUtils.getField(tracker, "linkResourceListener");
+ mockGenerator = new MockIdGenerator();
+ Intent.bindIdGenerator(mockGenerator);
+ }
+
+ /**
+ * Code to clean up shared by all test case.
+ */
+ @After
+ public void tearDown() {
+ tracker.unsetDelegate(delegate);
+ Intent.unbindIdGenerator(mockGenerator);
+ }
+
+ /**
+ * Topology change delegate mock that tracks the events coming into it
+ * and saves them. It provides a latch so that tests can wait for events
+ * to be generated.
+ */
+ static class TestTopologyChangeDelegate implements TopologyChangeDelegate {
+
+ CountDownLatch latch = new CountDownLatch(1);
+ List<Key> intentIdsFromEvent;
+ boolean compileAllFailedFromEvent;
+
+ @Override
+ public void triggerCompile(Iterable<Key> intentKeys,
+ boolean compileAllFailed) {
+ intentIdsFromEvent = Lists.newArrayList(intentKeys);
+ compileAllFailedFromEvent = compileAllFailed;
+ latch.countDown();
+ }
+ }
+
+ /**
+ * Tests an event with no associated reasons.
+ *
+ * @throws InterruptedException if the latch wait fails.
+ */
+ @Test
+ public void testEventNoReasons() throws InterruptedException {
+ final TopologyEvent event = new TopologyEvent(
+ TopologyEvent.Type.TOPOLOGY_CHANGED,
+ topology,
+ null);
+
+ listener.event(event);
+ assertThat(
+ delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS),
+ is(true));
+
+ assertThat(delegate.intentIdsFromEvent, hasSize(0));
+ assertThat(delegate.compileAllFailedFromEvent, is(true));
+ }
+
+ /**
+ * Tests an event for a link down where none of the reasons match
+ * currently installed intents.
+ *
+ * @throws InterruptedException if the latch wait fails.
+ */
+ @Test
+ public void testEventLinkDownNoMatches() throws InterruptedException {
+ final Link link = link("src", 1, "dst", 2);
+ final LinkEvent linkEvent = new LinkEvent(LinkEvent.Type.LINK_REMOVED, link);
+ reasons.add(linkEvent);
+
+ final TopologyEvent event = new TopologyEvent(
+ TopologyEvent.Type.TOPOLOGY_CHANGED,
+ topology,
+ reasons);
+
+ listener.event(event);
+ assertThat(
+ delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS),
+ is(true));
+
+ assertThat(delegate.intentIdsFromEvent, hasSize(0));
+ assertThat(delegate.compileAllFailedFromEvent, is(false));
+ }
+
+ /**
+ * Tests an event for a link being added.
+ *
+ * @throws InterruptedException if the latch wait fails.
+ */
+ @Test
+ public void testEventLinkAdded() throws InterruptedException {
+ final Link link = link("src", 1, "dst", 2);
+ final LinkEvent linkEvent = new LinkEvent(LinkEvent.Type.LINK_ADDED, link);
+ reasons.add(linkEvent);
+
+ final TopologyEvent event = new TopologyEvent(
+ TopologyEvent.Type.TOPOLOGY_CHANGED,
+ topology,
+ reasons);
+
+ listener.event(event);
+ assertThat(
+ delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS),
+ is(true));
+
+ assertThat(delegate.intentIdsFromEvent, hasSize(0));
+ assertThat(delegate.compileAllFailedFromEvent, is(true));
+ }
+
+ /**
+ * Tests an event for a link down where the link matches existing intents.
+ *
+ * @throws InterruptedException if the latch wait fails.
+ */
+ @Test
+ public void testEventLinkDownMatch() throws Exception {
+ final Link link = link("src", 1, "dst", 2);
+ final LinkEvent linkEvent = new LinkEvent(LinkEvent.Type.LINK_REMOVED, link);
+ reasons.add(linkEvent);
+
+ final TopologyEvent event = new TopologyEvent(
+ TopologyEvent.Type.TOPOLOGY_CHANGED,
+ topology,
+ reasons);
+
+ final Key key = Key.of(0x333L, APP_ID);
+ Collection<NetworkResource> resources = ImmutableSet.of(link);
+ tracker.addTrackedResources(key, resources);
+
+ listener.event(event);
+ assertThat(
+ delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS),
+ is(true));
+
+ assertThat(delegate.intentIdsFromEvent, hasSize(1));
+ assertThat(delegate.compileAllFailedFromEvent, is(false));
+ assertThat(delegate.intentIdsFromEvent.get(0).toString(),
+ equalTo("0x333"));
+ }
+
+ /**
+ * Tests a resource available event.
+ *
+ * @throws InterruptedException if the latch wait fails.
+ */
+ @Test
+ public void testResourceEvent() throws Exception {
+ LinkResourceEvent event = new LinkResourceEvent(
+ LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
+ new HashSet<>());
+ linkResourceListener.event(event);
+
+ assertThat(
+ delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS),
+ is(true));
+
+ assertThat(delegate.intentIdsFromEvent, hasSize(0));
+ assertThat(delegate.compileAllFailedFromEvent, is(true));
+ }
+
+ /**
+ * Tests an event for a host becoming available that matches an intent.
+ *
+ * @throws InterruptedException if the latch wait fails.
+ */
+
+ @Test
+ public void testEventHostAvailableMatch() throws Exception {
+ final Device host = device("host1");
+
+ final DeviceEvent deviceEvent =
+ new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, host);
+ reasons.add(deviceEvent);
+
+ final Key key = Key.of(0x333L, APP_ID);
+ Collection<NetworkResource> resources = ImmutableSet.of(host.id());
+ tracker.addTrackedResources(key, resources);
+
+ deviceListener.event(deviceEvent);
+ assertThat(
+ delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS),
+ is(true));
+
+ assertThat(delegate.intentIdsFromEvent, hasSize(1));
+ assertThat(delegate.compileAllFailedFromEvent, is(true));
+ assertThat(delegate.intentIdsFromEvent.get(0).toString(),
+ equalTo("0x333"));
+ }
+
+ /**
+ * Tests an event for a host becoming unavailable that matches an intent.
+ *
+ * @throws InterruptedException if the latch wait fails.
+ */
+
+ @Test
+ public void testEventHostUnavailableMatch() throws Exception {
+ final Device host = device("host1");
+
+ final DeviceEvent deviceEvent =
+ new DeviceEvent(DeviceEvent.Type.DEVICE_REMOVED, host);
+ reasons.add(deviceEvent);
+
+ final Key key = Key.of(0x333L, APP_ID);
+ Collection<NetworkResource> resources = ImmutableSet.of(host.id());
+ tracker.addTrackedResources(key, resources);
+
+ deviceListener.event(deviceEvent);
+ assertThat(
+ delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS),
+ is(true));
+
+ assertThat(delegate.intentIdsFromEvent, hasSize(1));
+ assertThat(delegate.compileAllFailedFromEvent, is(false));
+ assertThat(delegate.intentIdsFromEvent.get(0).toString(),
+ equalTo("0x333"));
+ }
+
+ /**
+ * Tests an event for a host becoming available that matches an intent.
+ *
+ * @throws InterruptedException if the latch wait fails.
+ */
+
+ @Test
+ public void testEventHostAvailableNoMatch() throws Exception {
+ final Device host = device("host1");
+
+ final DeviceEvent deviceEvent =
+ new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, host);
+ reasons.add(deviceEvent);
+
+ deviceListener.event(deviceEvent);
+ assertThat(
+ delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS),
+ is(true));
+
+ assertThat(delegate.intentIdsFromEvent, hasSize(0));
+ assertThat(delegate.compileAllFailedFromEvent, is(true));
+ }
+
+
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompilerTest.java
new file mode 100644
index 00000000..5588904d
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompilerTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl.compiler;
+
+import org.hamcrest.Matchers;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.TestApplicationId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.intent.AbstractIntentTest;
+import org.onosproject.net.intent.HostToHostIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentTestsMocks;
+import org.onosproject.net.intent.PathIntent;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.onosproject.net.NetTestTools.hid;
+import static org.onosproject.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath;
+
+/**
+ * Unit tests for the HostToHost intent compiler.
+ */
+public class HostToHostIntentCompilerTest extends AbstractIntentTest {
+ private static final String HOST_ONE_MAC = "00:00:00:00:00:01";
+ private static final String HOST_TWO_MAC = "00:00:00:00:00:02";
+ private static final String HOST_ONE_VLAN = "-1";
+ private static final String HOST_TWO_VLAN = "-1";
+ private static final String HOST_ONE = HOST_ONE_MAC + "/" + HOST_ONE_VLAN;
+ private static final String HOST_TWO = HOST_TWO_MAC + "/" + HOST_TWO_VLAN;
+
+ private static final ApplicationId APPID = new TestApplicationId("foo");
+
+ private TrafficSelector selector = new IntentTestsMocks.MockSelector();
+ private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
+
+ private HostId hostOneId = HostId.hostId(HOST_ONE);
+ private HostId hostTwoId = HostId.hostId(HOST_TWO);
+ private HostService mockHostService;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ Host hostOne = createMock(Host.class);
+ expect(hostOne.mac()).andReturn(new MacAddress(HOST_ONE_MAC.getBytes())).anyTimes();
+ expect(hostOne.vlan()).andReturn(VlanId.vlanId()).anyTimes();
+ replay(hostOne);
+
+ Host hostTwo = createMock(Host.class);
+ expect(hostTwo.mac()).andReturn(new MacAddress(HOST_TWO_MAC.getBytes())).anyTimes();
+ expect(hostTwo.vlan()).andReturn(VlanId.vlanId()).anyTimes();
+ replay(hostTwo);
+
+ mockHostService = createMock(HostService.class);
+ expect(mockHostService.getHost(eq(hostOneId))).andReturn(hostOne).anyTimes();
+ expect(mockHostService.getHost(eq(hostTwoId))).andReturn(hostTwo).anyTimes();
+ replay(mockHostService);
+ }
+
+ /**
+ * Creates a HostToHost intent based on two host Ids.
+ *
+ * @param oneIdString string for host one id
+ * @param twoIdString string for host two id
+ * @return HostToHostIntent for the two hosts
+ */
+ private HostToHostIntent makeIntent(String oneIdString, String twoIdString) {
+ return HostToHostIntent.builder()
+ .appId(APPID)
+ .one(hid(oneIdString))
+ .two(hid(twoIdString))
+ .selector(selector)
+ .treatment(treatment)
+ .build();
+ }
+
+ /**
+ * Creates a compiler for HostToHost intents.
+ *
+ * @param hops string array describing the path hops to use when compiling
+ * @return HostToHost intent compiler
+ */
+ private HostToHostIntentCompiler makeCompiler(String[] hops) {
+ HostToHostIntentCompiler compiler =
+ new HostToHostIntentCompiler();
+ compiler.pathService = new IntentTestsMocks.MockPathService(hops);
+ compiler.hostService = mockHostService;
+ return compiler;
+ }
+
+
+ /**
+ * Tests a pair of hosts with 8 hops between them.
+ */
+ @Test
+ public void testSingleLongPathCompilation() {
+
+ HostToHostIntent intent = makeIntent(HOST_ONE,
+ HOST_TWO);
+ assertThat(intent, is(notNullValue()));
+
+ String[] hops = {HOST_ONE, "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", HOST_TWO};
+ HostToHostIntentCompiler compiler = makeCompiler(hops);
+ assertThat(compiler, is(notNullValue()));
+
+ List<Intent> result = compiler.compile(intent, null, null);
+ assertThat(result, is(Matchers.notNullValue()));
+ assertThat(result, hasSize(2));
+ Intent forwardResultIntent = result.get(0);
+ assertThat(forwardResultIntent instanceof PathIntent, is(true));
+ Intent reverseResultIntent = result.get(1);
+ assertThat(reverseResultIntent instanceof PathIntent, is(true));
+
+ if (forwardResultIntent instanceof PathIntent) {
+ PathIntent forwardPathIntent = (PathIntent) forwardResultIntent;
+ assertThat(forwardPathIntent.path().links(), hasSize(9));
+ assertThat(forwardPathIntent.path().links(), linksHasPath(HOST_ONE, "h1"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("h1", "h2"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("h2", "h3"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("h3", "h4"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("h4", "h5"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("h5", "h6"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("h6", "h7"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("h7", "h8"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("h8", HOST_TWO));
+ }
+
+ if (reverseResultIntent instanceof PathIntent) {
+ PathIntent reversePathIntent = (PathIntent) reverseResultIntent;
+ assertThat(reversePathIntent.path().links(), hasSize(9));
+ assertThat(reversePathIntent.path().links(), linksHasPath("h1", HOST_ONE));
+ assertThat(reversePathIntent.path().links(), linksHasPath("h2", "h1"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("h3", "h2"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("h4", "h3"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("h5", "h4"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("h6", "h5"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("h7", "h6"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("h8", "h7"));
+ assertThat(reversePathIntent.path().links(), linksHasPath(HOST_TWO, "h8"));
+ }
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java
new file mode 100644
index 00000000..c5fa3719
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl.compiler;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.Link;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.intent.MockIdGenerator;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.onosproject.net.Link.Type.DIRECT;
+import static org.onosproject.net.NetTestTools.APP_ID;
+import static org.onosproject.net.NetTestTools.PID;
+import static org.onosproject.net.NetTestTools.connectPoint;
+
+public class LinkCollectionIntentCompilerTest {
+
+ private final ApplicationId appId = new TestApplicationId("test");
+
+ private final ConnectPoint d1p1 = connectPoint("s1", 0);
+ private final ConnectPoint d2p0 = connectPoint("s2", 0);
+ private final ConnectPoint d2p1 = connectPoint("s2", 1);
+ private final ConnectPoint d3p1 = connectPoint("s3", 1);
+ private final ConnectPoint d3p0 = connectPoint("s3", 10);
+ private final ConnectPoint d1p0 = connectPoint("s1", 10);
+
+ private final Set<Link> links = ImmutableSet.of(
+ new DefaultLink(PID, d1p1, d2p0, DIRECT),
+ new DefaultLink(PID, d2p1, d3p1, DIRECT),
+ new DefaultLink(PID, d1p1, d3p1, DIRECT));
+
+ private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
+ private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ private CoreService coreService;
+ private IntentExtensionService intentExtensionService;
+ private IdGenerator idGenerator = new MockIdGenerator();
+
+ private LinkCollectionIntent intent;
+
+ private LinkCollectionIntentCompiler sut;
+
+ @Before
+ public void setUp() {
+ sut = new LinkCollectionIntentCompiler();
+ coreService = createMock(CoreService.class);
+ expect(coreService.registerApplication("org.onosproject.net.intent"))
+ .andReturn(appId);
+ sut.coreService = coreService;
+
+ Intent.bindIdGenerator(idGenerator);
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .links(links)
+ .ingressPoints(ImmutableSet.of(d1p1))
+ .egressPoints(ImmutableSet.of(d3p1))
+ .build();
+ intentExtensionService = createMock(IntentExtensionService.class);
+ intentExtensionService.registerCompiler(LinkCollectionIntent.class, sut);
+ intentExtensionService.unregisterCompiler(LinkCollectionIntent.class);
+ sut.intentManager = intentExtensionService;
+
+ replay(coreService, intentExtensionService);
+ }
+
+ @After
+ public void tearDown() {
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ @Test
+ public void testCompile() {
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList(), Collections.emptySet());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(links.size()));
+
+ // if not found, get() raises an exception
+ FlowRule rule1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .findFirst()
+ .get();
+ assertThat(rule1.selector(), is(
+ DefaultTrafficSelector.builder(intent.selector()).matchInPort(d1p1.port()).build()
+ ));
+ assertThat(rule1.treatment(), is(
+ DefaultTrafficTreatment.builder(intent.treatment()).setOutput(d1p1.port()).build()
+ ));
+ assertThat(rule1.priority(), is(intent.priority()));
+
+ FlowRule rule2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .findFirst()
+ .get();
+ assertThat(rule2.selector(), is(
+ DefaultTrafficSelector.builder(intent.selector()).matchInPort(d2p0.port()).build()
+ ));
+ assertThat(rule2.treatment(), is(
+ DefaultTrafficTreatment.builder().setOutput(d2p1.port()).build()
+ ));
+ assertThat(rule2.priority(), is(intent.priority()));
+
+ FlowRule rule3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .findFirst()
+ .get();
+ assertThat(rule3.selector(), is(
+ DefaultTrafficSelector.builder(intent.selector()).matchInPort(d3p1.port()).build()
+ ));
+ assertThat(rule3.treatment(), is(
+ DefaultTrafficTreatment.builder().setOutput(d3p1.port()).build()
+ ));
+ assertThat(rule3.priority(), is(intent.priority()));
+
+ sut.deactivate();
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsIntentCompilerTest.java
new file mode 100644
index 00000000..76b26f46
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsIntentCompilerTest.java
@@ -0,0 +1,188 @@
+package org.onosproject.net.intent.impl.compiler;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+
+import org.onlab.packet.MplsLabel;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.AbstractIntentTest;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentTestsMocks;
+import org.onosproject.net.intent.MplsIntent;
+import org.onosproject.net.intent.MplsPathIntent;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.NetTestTools.APP_ID;
+import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.PortNumber.portNumber;
+import static org.onosproject.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath;
+
+/**
+ * Unit tests for the HostToHost intent compiler.
+ */
+public class MplsIntentCompilerTest extends AbstractIntentTest {
+
+ private static final ApplicationId APPID = new TestApplicationId("foo");
+
+ private TrafficSelector selector = new IntentTestsMocks.MockSelector();
+ private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
+
+ /**
+ * Creates a PointToPoint intent based on ingress and egress device Ids.
+ *
+ * @param ingressIdString string for id of ingress device
+ * @param egressIdString string for id of egress device
+ * @return PointToPointIntent for the two devices
+ */
+ private MplsIntent makeIntent(String ingressIdString, Optional<MplsLabel> ingressLabel,
+ String egressIdString, Optional<MplsLabel> egressLabel) {
+
+ return MplsIntent.builder()
+ .appId(APPID)
+ .selector(selector)
+ .treatment(treatment)
+ .ingressPoint(connectPoint(ingressIdString, 1))
+ .ingressLabel(ingressLabel)
+ .egressPoint(connectPoint(egressIdString, 1))
+ .egressLabel(egressLabel).build();
+ }
+ /**
+ * Creates a compiler for HostToHost intents.
+ *
+ * @param hops string array describing the path hops to use when compiling
+ * @return HostToHost intent compiler
+ */
+ private MplsIntentCompiler makeCompiler(String[] hops) {
+ MplsIntentCompiler compiler =
+ new MplsIntentCompiler();
+ compiler.pathService = new IntentTestsMocks.MockPathService(hops);
+ return compiler;
+ }
+
+
+ /**
+ * Tests a pair of devices in an 8 hop path, forward direction.
+ */
+ @Test
+ public void testForwardPathCompilation() {
+ Optional<MplsLabel> ingressLabel = Optional.of(MplsLabel.mplsLabel(10));
+ Optional<MplsLabel> egressLabel = Optional.of(MplsLabel.mplsLabel(20));
+
+ MplsIntent intent = makeIntent("d1", ingressLabel, "d8", egressLabel);
+ assertThat(intent, is(notNullValue()));
+
+ String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
+ MplsIntentCompiler compiler = makeCompiler(hops);
+ assertThat(compiler, is(notNullValue()));
+
+ List<Intent> result = compiler.compile(intent, null, null);
+ assertThat(result, is(Matchers.notNullValue()));
+ assertThat(result, hasSize(1));
+ Intent forwardResultIntent = result.get(0);
+ assertThat(forwardResultIntent instanceof MplsPathIntent, is(true));
+
+ // if statement suppresses static analysis warnings about unchecked cast
+ if (forwardResultIntent instanceof MplsPathIntent) {
+ MplsPathIntent forwardPathIntent = (MplsPathIntent) forwardResultIntent;
+ // 7 links for the hops, plus one default lnk on ingress and egress
+ assertThat(forwardPathIntent.path().links(), hasSize(hops.length + 1));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d1", "d2"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d2", "d3"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d3", "d4"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d4", "d5"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d5", "d6"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d6", "d7"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d7", "d8"));
+ assertEquals(forwardPathIntent.egressLabel(), egressLabel);
+ assertEquals(forwardPathIntent.ingressLabel(), ingressLabel);
+ }
+ }
+
+ /**
+ * Tests a pair of devices in an 8 hop path, forward direction.
+ */
+ @Test
+ public void testReversePathCompilation() {
+ Optional<MplsLabel> ingressLabel = Optional.of(MplsLabel.mplsLabel(10));
+ Optional<MplsLabel> egressLabel = Optional.of(MplsLabel.mplsLabel(20));
+
+ MplsIntent intent = makeIntent("d8", ingressLabel, "d1", egressLabel);
+ assertThat(intent, is(notNullValue()));
+
+ String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
+ MplsIntentCompiler compiler = makeCompiler(hops);
+ assertThat(compiler, is(notNullValue()));
+
+ List<Intent> result = compiler.compile(intent, null, null);
+ assertThat(result, is(Matchers.notNullValue()));
+ assertThat(result, hasSize(1));
+ Intent reverseResultIntent = result.get(0);
+ assertThat(reverseResultIntent instanceof MplsPathIntent, is(true));
+
+ // if statement suppresses static analysis warnings about unchecked cast
+ if (reverseResultIntent instanceof MplsPathIntent) {
+ MplsPathIntent reversePathIntent = (MplsPathIntent) reverseResultIntent;
+ assertThat(reversePathIntent.path().links(), hasSize(hops.length + 1));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d2", "d1"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d3", "d2"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d4", "d3"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d5", "d4"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d6", "d5"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d7", "d6"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d8", "d7"));
+ assertEquals(reversePathIntent.egressLabel(), egressLabel);
+ assertEquals(reversePathIntent.ingressLabel(), ingressLabel);
+ }
+ }
+
+ /**
+ * Tests compilation of the intent which designates two different ports on the same switch.
+ */
+ @Test
+ public void testSameSwitchDifferentPortsIntentCompilation() {
+ ConnectPoint src = new ConnectPoint(deviceId("1"), portNumber(1));
+ ConnectPoint dst = new ConnectPoint(deviceId("1"), portNumber(2));
+ MplsIntent intent = MplsIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .ingressPoint(src)
+ .ingressLabel(Optional.empty())
+ .egressPoint(dst)
+ .egressLabel(Optional.empty())
+ .build();
+
+ String[] hops = {"1"};
+ MplsIntentCompiler sut = makeCompiler(hops);
+
+ List<Intent> compiled = sut.compile(intent, null, null);
+
+ assertThat(compiled, hasSize(1));
+ assertThat(compiled.get(0), is(instanceOf(MplsPathIntent.class)));
+ Path path = ((MplsPathIntent) compiled.get(0)).path();
+
+ assertThat(path.links(), hasSize(2));
+ Link firstLink = path.links().get(0);
+ assertThat(firstLink, is(createEdgeLink(src, true)));
+ Link secondLink = path.links().get(1);
+ assertThat(secondLink, is(createEdgeLink(dst, false)));
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java
new file mode 100644
index 00000000..771a9883
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl.compiler;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MplsLabel;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.DefaultPath;
+import org.onosproject.net.Link;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.IntentTestsMocks;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.intent.MplsPathIntent;
+import org.onosproject.store.trivial.SimpleLinkStore;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.onosproject.net.Link.Type.DIRECT;
+import static org.onosproject.net.NetTestTools.APP_ID;
+import static org.onosproject.net.NetTestTools.PID;
+import static org.onosproject.net.NetTestTools.connectPoint;
+
+public class MplsPathIntentCompilerTest {
+
+ private final ApplicationId appId = new TestApplicationId("test");
+
+ private final ConnectPoint d1p1 = connectPoint("s1", 0);
+ private final ConnectPoint d2p0 = connectPoint("s2", 0);
+ private final ConnectPoint d2p1 = connectPoint("s2", 1);
+ private final ConnectPoint d3p1 = connectPoint("s3", 1);
+
+ private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
+ private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+
+ private final Optional<MplsLabel> ingressLabel =
+ Optional.of(MplsLabel.mplsLabel(10));
+ private final Optional<MplsLabel> egressLabel =
+ Optional.of(MplsLabel.mplsLabel(20));
+
+ private final List<Link> links = Arrays.asList(
+ new DefaultLink(PID, d1p1, d2p0, DIRECT),
+ new DefaultLink(PID, d2p1, d3p1, DIRECT)
+ );
+
+ private IdGenerator idGenerator = new MockIdGenerator();
+
+ private final int hops = links.size() - 1;
+ private MplsPathIntent intent;
+ private MplsPathIntentCompiler sut;
+
+ @Before
+ public void setUp() {
+ sut = new MplsPathIntentCompiler();
+ CoreService coreService = createMock(CoreService.class);
+ expect(coreService.registerApplication("org.onosproject.net.intent"))
+ .andReturn(appId);
+ sut.coreService = coreService;
+ sut.linkStore = new SimpleLinkStore();
+ sut.resourceService = new IntentTestsMocks.MockResourceService();
+
+ Intent.bindIdGenerator(idGenerator);
+
+ intent = MplsPathIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .path(new DefaultPath(PID, links, hops))
+ .ingressLabel(ingressLabel)
+ .egressLabel(egressLabel)
+ .priority(55)
+ .build();
+
+ IntentExtensionService intentExtensionService = createMock(IntentExtensionService.class);
+ intentExtensionService.registerCompiler(MplsPathIntent.class, sut);
+ intentExtensionService.unregisterCompiler(MplsPathIntent.class);
+ sut.intentExtensionService = intentExtensionService;
+
+ replay(coreService, intentExtensionService);
+ }
+
+ @After
+ public void tearDown() {
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ @Test
+ public void testCompile() {
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList(), Collections.emptySet());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(1));
+
+ FlowRule rule = rules.stream()
+ .filter(x -> x.deviceId().equals(d2p0.deviceId()))
+ .findFirst()
+ .get();
+ assertThat(rule.deviceId(), is(d2p0.deviceId()));
+
+ sut.deactivate();
+
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java
new file mode 100644
index 00000000..eb7a3936
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl.compiler;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.ElementId;
+import org.onosproject.net.Path;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.AbstractIntentTest;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentTestsMocks;
+import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.intent.MultiPointToSinglePointIntent;
+import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.PathService;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.NetTestTools.createPath;
+import static org.onosproject.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath;
+
+/**
+ * Unit tests for the MultiPointToSinglePoint intent compiler.
+ */
+public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTest {
+
+ private static final ApplicationId APPID = new TestApplicationId("foo");
+
+ private TrafficSelector selector = new IntentTestsMocks.MockSelector();
+ private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
+
+ /**
+ * Mock path service for creating paths within the test.
+ */
+ private static class MockPathService implements PathService {
+
+ final String[] pathHops;
+
+ /**
+ * Constructor that provides a set of hops to mock.
+ *
+ * @param pathHops path hops to mock
+ */
+ MockPathService(String[] pathHops) {
+ this.pathHops = pathHops;
+ }
+
+ @Override
+ public Set<Path> getPaths(ElementId src, ElementId dst) {
+ Set<Path> result = new HashSet<>();
+
+ String[] allHops = new String[pathHops.length + 1];
+ allHops[0] = src.toString();
+ if (pathHops.length != 0) {
+ System.arraycopy(pathHops, 0, allHops, 1, pathHops.length);
+ }
+ result.add(createPath(allHops));
+
+ return result;
+ }
+
+ @Override
+ public Set<Path> getPaths(ElementId src, ElementId dst, LinkWeight weight) {
+ return null;
+ }
+ }
+
+ /**
+ * Mocks the device service so that a device appears available in the test.
+ */
+ private static class MockDeviceService extends DeviceServiceAdapter {
+ @Override
+ public boolean isAvailable(DeviceId deviceId) {
+ return true;
+ }
+ }
+
+ /**
+ * Creates a MultiPointToSinglePoint intent for a group of ingress points
+ * and an egress point.
+ *
+ * @param ingressIds array of ingress device ids
+ * @param egressId device id of the egress point
+ * @return MultiPointToSinglePoint intent
+ */
+ private MultiPointToSinglePointIntent makeIntent(String[] ingressIds, String egressId) {
+ Set<ConnectPoint> ingressPoints = new HashSet<>();
+ ConnectPoint egressPoint = connectPoint(egressId, 2);
+
+ for (String ingressId : ingressIds) {
+ ingressPoints.add(connectPoint(ingressId, 1));
+ }
+
+ return MultiPointToSinglePointIntent.builder()
+ .appId(APPID)
+ .selector(selector)
+ .treatment(treatment)
+ .ingressPoints(ingressPoints)
+ .egressPoint(egressPoint)
+ .build();
+ }
+
+ /**
+ * Creates a compiler for MultiPointToSinglePoint intents.
+ *
+ * @param hops hops to use while computing paths for this intent
+ * @return MultiPointToSinglePoint intent
+ */
+ private MultiPointToSinglePointIntentCompiler makeCompiler(String[] hops) {
+ MultiPointToSinglePointIntentCompiler compiler =
+ new MultiPointToSinglePointIntentCompiler();
+ compiler.pathService = new MockPathService(hops);
+ compiler.deviceService = new MockDeviceService();
+ return compiler;
+ }
+
+ /**
+ * Tests a single ingress point with 8 hops to its egress point.
+ */
+ @Test
+ public void testSingleLongPathCompilation() {
+
+ String[] ingress = {"ingress"};
+ String egress = "egress";
+
+ MultiPointToSinglePointIntent intent = makeIntent(ingress, egress);
+ assertThat(intent, is(notNullValue()));
+
+ String[] hops = {"h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8",
+ egress};
+ MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
+ assertThat(compiler, is(notNullValue()));
+
+ List<Intent> result = compiler.compile(intent, null, null);
+ assertThat(result, is(Matchers.notNullValue()));
+ assertThat(result, hasSize(1));
+ Intent resultIntent = result.get(0);
+ assertThat(resultIntent instanceof LinkCollectionIntent, is(true));
+
+ if (resultIntent instanceof LinkCollectionIntent) {
+ LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent;
+ assertThat(linkIntent.links(), hasSize(9));
+ assertThat(linkIntent.links(), linksHasPath("ingress", "h1"));
+ assertThat(linkIntent.links(), linksHasPath("h1", "h2"));
+ assertThat(linkIntent.links(), linksHasPath("h2", "h3"));
+ assertThat(linkIntent.links(), linksHasPath("h4", "h5"));
+ assertThat(linkIntent.links(), linksHasPath("h5", "h6"));
+ assertThat(linkIntent.links(), linksHasPath("h7", "h8"));
+ assertThat(linkIntent.links(), linksHasPath("h8", "egress"));
+ }
+ }
+
+ /**
+ * Tests a simple topology where two ingress points share some path segments
+ * and some path segments are not shared.
+ */
+ @Test
+ public void testTwoIngressCompilation() {
+ String[] ingress = {"ingress1", "ingress2"};
+ String egress = "egress";
+
+ MultiPointToSinglePointIntent intent = makeIntent(ingress, egress);
+ assertThat(intent, is(notNullValue()));
+
+ final String[] hops = {"inner1", "inner2", egress};
+ MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
+ assertThat(compiler, is(notNullValue()));
+
+ List<Intent> result = compiler.compile(intent, null, null);
+ assertThat(result, is(notNullValue()));
+ assertThat(result, hasSize(1));
+ Intent resultIntent = result.get(0);
+ assertThat(resultIntent instanceof LinkCollectionIntent, is(true));
+
+ if (resultIntent instanceof LinkCollectionIntent) {
+ LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent;
+ assertThat(linkIntent.links(), hasSize(4));
+ assertThat(linkIntent.links(), linksHasPath("ingress1", "inner1"));
+ assertThat(linkIntent.links(), linksHasPath("ingress2", "inner1"));
+ assertThat(linkIntent.links(), linksHasPath("inner1", "inner2"));
+ assertThat(linkIntent.links(), linksHasPath("inner2", "egress"));
+ }
+ }
+
+ /**
+ * Tests a large number of ingress points that share a common path to the
+ * egress point.
+ */
+ @Test
+ public void testMultiIngressCompilation() {
+ String[] ingress = {"i1", "i2", "i3", "i4", "i5",
+ "i6", "i7", "i8", "i9", "i10"};
+ String egress = "e";
+
+ MultiPointToSinglePointIntent intent = makeIntent(ingress, egress);
+ assertThat(intent, is(notNullValue()));
+
+ final String[] hops = {"n1", egress};
+ MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
+ assertThat(compiler, is(notNullValue()));
+
+ List<Intent> result = compiler.compile(intent, null, null);
+ assertThat(result, is(notNullValue()));
+ assertThat(result, hasSize(1));
+ Intent resultIntent = result.get(0);
+ assertThat(resultIntent instanceof LinkCollectionIntent, is(true));
+
+ if (resultIntent instanceof LinkCollectionIntent) {
+ LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent;
+ assertThat(linkIntent.links(), hasSize(ingress.length + 1));
+ for (String ingressToCheck : ingress) {
+ assertThat(linkIntent.links(),
+ linksHasPath(ingressToCheck,
+ "n1"));
+ }
+ assertThat(linkIntent.links(), linksHasPath("n1", egress));
+ }
+ }
+
+ /**
+ * Tests ingress and egress on the same device.
+ */
+ @Test
+ public void testSameDeviceCompilation() {
+ String[] ingress = {"i1", "i2"};
+ String egress = "i1";
+
+ MultiPointToSinglePointIntent intent = makeIntent(ingress, egress);
+ assertThat(intent, is(notNullValue()));
+
+ final String[] hops = {"i1", "i2"};
+ MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
+ assertThat(compiler, is(notNullValue()));
+
+ List<Intent> result = compiler.compile(intent, null, null);
+ assertThat(result, is(notNullValue()));
+ assertThat(result, hasSize(1));
+ Intent resultIntent = result.get(0);
+ assertThat(resultIntent, instanceOf(LinkCollectionIntent.class));
+
+ if (resultIntent instanceof LinkCollectionIntent) {
+ LinkCollectionIntent linkIntent = (LinkCollectionIntent) resultIntent;
+ assertThat(linkIntent.links(), hasSize(ingress.length));
+
+ assertThat(linkIntent.links(), linksHasPath("i2", "i1"));
+ }
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
new file mode 100644
index 00000000..2f40b37a
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl.compiler;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.DefaultPath;
+import org.onosproject.net.Link;
+import org.onosproject.net.OchSignalType;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.IntentTestsMocks;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.intent.OpticalPathIntent;
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertEquals;
+import static org.onosproject.net.Link.Type.DIRECT;
+import static org.onosproject.net.NetTestTools.PID;
+import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.NetTestTools.createLambda;
+
+public class OpticalPathIntentCompilerTest {
+
+ private CoreService coreService;
+ private IntentExtensionService intentExtensionService;
+ private final IdGenerator idGenerator = new MockIdGenerator();
+ private OpticalPathIntentCompiler sut;
+
+ private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
+ private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+ private final ApplicationId appId = new TestApplicationId("test");
+ private final ProviderId pid = new ProviderId("of", "test");
+ private final ConnectPoint d1p1 = connectPoint("s1", 0);
+ private final ConnectPoint d2p0 = connectPoint("s2", 0);
+ private final ConnectPoint d2p1 = connectPoint("s2", 1);
+ private final ConnectPoint d3p1 = connectPoint("s3", 1);
+ private final ConnectPoint d3p0 = connectPoint("s3", 10);
+ private final ConnectPoint d1p0 = connectPoint("s1", 10);
+
+ private final List<Link> links = Arrays.asList(
+ new DefaultLink(PID, d1p1, d2p0, DIRECT),
+ new DefaultLink(PID, d2p1, d3p1, DIRECT)
+ );
+ private final int hops = links.size() + 1;
+ private OpticalPathIntent intent;
+
+ @Before
+ public void setUp() {
+ sut = new OpticalPathIntentCompiler();
+ coreService = createMock(CoreService.class);
+ expect(coreService.registerApplication("org.onosproject.net.intent"))
+ .andReturn(appId);
+ sut.coreService = coreService;
+
+ Intent.bindIdGenerator(idGenerator);
+
+ intent = OpticalPathIntent.builder()
+ .appId(appId)
+ .src(d1p1)
+ .dst(d3p1)
+ .path(new DefaultPath(PID, links, hops))
+ .lambda(createLambda())
+ .signalType(OchSignalType.FIXED_GRID)
+ .build();
+ intentExtensionService = createMock(IntentExtensionService.class);
+ intentExtensionService.registerCompiler(OpticalPathIntent.class, sut);
+ intentExtensionService.unregisterCompiler(OpticalPathIntent.class);
+ sut.intentManager = intentExtensionService;
+ sut.resourceService = new IntentTestsMocks.MockResourceService();
+
+ replay(coreService, intentExtensionService);
+ }
+
+ @After
+ public void tearDown() {
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ @Test
+ public void testCompiler() {
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList(), Collections.emptySet());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ rules.stream()
+ .filter(x -> x.deviceId().equals(d1p1.deviceId()))
+ .findFirst()
+ .get();
+
+ rules.stream()
+ .filter(x -> x.deviceId().equals(d2p1.deviceId()))
+ .findFirst()
+ .get();
+
+ rules.stream()
+ .filter(x -> x.deviceId().equals(d3p1.deviceId()))
+ .findFirst()
+ .get();
+
+ rules.forEach(rule -> assertEquals("FlowRule priority is incorrect",
+ intent.priority(), rule.priority()));
+
+ sut.deactivate();
+ }
+
+ //TODO test bidirectional optical paths and verify rules
+
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
new file mode 100644
index 00000000..f07bf42c
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl.compiler;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.DefaultPath;
+import org.onosproject.net.Link;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.intent.PathIntent;
+import org.onosproject.net.provider.ProviderId;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
+import static org.onosproject.net.Link.Type.DIRECT;
+import static org.onosproject.net.NetTestTools.APP_ID;
+import static org.onosproject.net.NetTestTools.PID;
+import static org.onosproject.net.NetTestTools.connectPoint;
+
+/**
+ * Unit tests for PathIntentCompiler.
+ */
+public class PathIntentCompilerTest {
+
+ private CoreService coreService;
+ private IntentExtensionService intentExtensionService;
+ private IdGenerator idGenerator = new MockIdGenerator();
+ private PathIntentCompiler sut;
+
+ private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
+ private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+ private final ApplicationId appId = new TestApplicationId("test");
+ private final ProviderId pid = new ProviderId("of", "test");
+ private final ConnectPoint d1p1 = connectPoint("s1", 0);
+ private final ConnectPoint d2p0 = connectPoint("s2", 0);
+ private final ConnectPoint d2p1 = connectPoint("s2", 1);
+ private final ConnectPoint d3p1 = connectPoint("s3", 1);
+ private final ConnectPoint d3p0 = connectPoint("s3", 10);
+ private final ConnectPoint d1p0 = connectPoint("s1", 10);
+ private static final int PRIORITY = 555;
+
+ private final List<Link> links = Arrays.asList(
+ createEdgeLink(d1p0, true),
+ new DefaultLink(PID, d1p1, d2p0, DIRECT),
+ new DefaultLink(PID, d2p1, d3p1, DIRECT),
+ createEdgeLink(d3p0, false)
+ );
+ private final int hops = links.size() - 1;
+ private PathIntent intent;
+
+ /**
+ * Configures objects used in all the test cases.
+ */
+ @Before
+ public void setUp() {
+ sut = new PathIntentCompiler();
+ coreService = createMock(CoreService.class);
+ expect(coreService.registerApplication("org.onosproject.net.intent"))
+ .andReturn(appId);
+ sut.coreService = coreService;
+
+ Intent.bindIdGenerator(idGenerator);
+
+ intent = PathIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .priority(PRIORITY)
+ .path(new DefaultPath(pid, links, hops))
+ .build();
+ intentExtensionService = createMock(IntentExtensionService.class);
+ intentExtensionService.registerCompiler(PathIntent.class, sut);
+ intentExtensionService.unregisterCompiler(PathIntent.class);
+ sut.intentManager = intentExtensionService;
+
+ replay(coreService, intentExtensionService);
+ }
+
+ /**
+ * Tears down objects used in all the test cases.
+ */
+ @After
+ public void tearDown() {
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ /**
+ * Tests the compilation behavior of the path intent compiler.
+ */
+ @Test
+ public void testCompile() {
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList(), Collections.emptySet());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+
+ FlowRule rule1 = rules.stream()
+ .filter(x -> x.deviceId().equals(d1p0.deviceId()))
+ .findFirst()
+ .get();
+ assertThat(rule1.deviceId(), is(d1p0.deviceId()));
+ assertThat(rule1.selector(),
+ is(DefaultTrafficSelector.builder(selector).matchInPort(d1p0.port()).build()));
+ assertThat(rule1.treatment(),
+ is(DefaultTrafficTreatment.builder().setOutput(d1p1.port()).build()));
+ assertThat(rule1.priority(), is(intent.priority()));
+
+ FlowRule rule2 = rules.stream()
+ .filter(x -> x.deviceId().equals(d2p0.deviceId()))
+ .findFirst()
+ .get();
+ assertThat(rule2.deviceId(), is(d2p0.deviceId()));
+ assertThat(rule2.selector(),
+ is(DefaultTrafficSelector.builder(selector).matchInPort(d2p0.port()).build()));
+ assertThat(rule2.treatment(),
+ is(DefaultTrafficTreatment.builder().setOutput(d2p1.port()).build()));
+ assertThat(rule2.priority(), is(intent.priority()));
+
+ FlowRule rule3 = rules.stream()
+ .filter(x -> x.deviceId().equals(d3p0.deviceId()))
+ .findFirst()
+ .get();
+ assertThat(rule3.deviceId(), is(d3p1.deviceId()));
+ assertThat(rule3.selector(),
+ is(DefaultTrafficSelector.builder(selector).matchInPort(d3p1.port()).build()));
+ assertThat(rule3.treatment(),
+ is(DefaultTrafficTreatment.builder(treatment).setOutput(d3p0.port()).build()));
+ assertThat(rule3.priority(), is(intent.priority()));
+
+ sut.deactivate();
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompilerTest.java
new file mode 100644
index 00000000..e57d9dbe
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompilerTest.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl.compiler;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import org.onlab.util.Bandwidth;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.AbstractIntentTest;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentTestsMocks;
+import org.onosproject.net.intent.PathIntent;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.constraint.BandwidthConstraint;
+import org.onosproject.net.intent.constraint.LambdaConstraint;
+import org.onosproject.net.intent.impl.PathNotFoundException;
+import org.onosproject.net.resource.link.BandwidthResource;
+import org.onosproject.net.resource.link.LambdaResource;
+import org.onosproject.net.resource.link.LinkResourceService;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.fail;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.NetTestTools.APP_ID;
+import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.PortNumber.portNumber;
+import static org.onosproject.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath;
+
+/**
+ * Unit tests for the HostToHost intent compiler.
+ */
+public class PointToPointIntentCompilerTest extends AbstractIntentTest {
+
+ private static final ApplicationId APPID = new TestApplicationId("foo");
+
+ private TrafficSelector selector = new IntentTestsMocks.MockSelector();
+ private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
+
+ /**
+ * Creates a PointToPoint intent based on ingress and egress device Ids.
+ *
+ * @param ingressIdString string for id of ingress device
+ * @param egressIdString string for id of egress device
+ * @return PointToPointIntent for the two devices
+ */
+ private PointToPointIntent makeIntent(String ingressIdString,
+ String egressIdString) {
+ return PointToPointIntent.builder()
+ .appId(APPID)
+ .selector(selector)
+ .treatment(treatment)
+ .ingressPoint(connectPoint(ingressIdString, 1))
+ .egressPoint(connectPoint(egressIdString, 1))
+ .build();
+ }
+
+ /**
+ * Creates a PointToPoint intent based on ingress and egress deviceIds and constraints.
+ *
+ * @param ingressIdString string for id of ingress device
+ * @param egressIdString string for id of egress device
+ * @param constraints constraints
+ * @return PointToPointIntent for the two device with constraints
+ */
+ private PointToPointIntent makeIntent(String ingressIdString,
+ String egressIdString, List<Constraint> constraints) {
+ return PointToPointIntent.builder()
+ .appId(APPID)
+ .selector(selector)
+ .treatment(treatment)
+ .ingressPoint(connectPoint(ingressIdString, 1))
+ .egressPoint(connectPoint(egressIdString, 1))
+ .constraints(constraints)
+ .build();
+ }
+
+ /**
+ * Creates a compiler for HostToHost intents.
+ *
+ * @param hops string array describing the path hops to use when compiling
+ * @return HostToHost intent compiler
+ */
+ private PointToPointIntentCompiler makeCompiler(String[] hops) {
+ PointToPointIntentCompiler compiler = new PointToPointIntentCompiler();
+ compiler.pathService = new IntentTestsMocks.MockPathService(hops);
+ return compiler;
+ }
+
+ /**
+ * Creates a point to point intent compiler for a three switch linear
+ * topology.
+ *
+ * @param resourceService service to use for resource allocation requests
+ * @return point to point compiler
+ */
+ private PointToPointIntentCompiler makeCompiler(String[] hops, LinkResourceService resourceService) {
+ final PointToPointIntentCompiler compiler = new PointToPointIntentCompiler();
+ compiler.resourceService = resourceService;
+ compiler.pathService = new IntentTestsMocks.MockPathService(hops);
+ return compiler;
+ }
+
+ /**
+ * Tests a pair of devices in an 8 hop path, forward direction.
+ */
+ @Test
+ public void testForwardPathCompilation() {
+
+ PointToPointIntent intent = makeIntent("d1", "d8");
+
+ String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
+ PointToPointIntentCompiler compiler = makeCompiler(hops);
+
+ List<Intent> result = compiler.compile(intent, null, null);
+ assertThat(result, is(Matchers.notNullValue()));
+ assertThat(result, hasSize(1));
+ Intent forwardResultIntent = result.get(0);
+ assertThat(forwardResultIntent instanceof PathIntent, is(true));
+
+ if (forwardResultIntent instanceof PathIntent) {
+ PathIntent forwardPathIntent = (PathIntent) forwardResultIntent;
+ // 7 links for the hops, plus one default lnk on ingress and egress
+ assertThat(forwardPathIntent.path().links(), hasSize(hops.length + 1));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d1", "d2"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d2", "d3"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d3", "d4"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d4", "d5"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d5", "d6"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d6", "d7"));
+ assertThat(forwardPathIntent.path().links(), linksHasPath("d7", "d8"));
+ }
+ }
+
+ /**
+ * Tests a pair of devices in an 8 hop path, forward direction.
+ */
+ @Test
+ public void testReversePathCompilation() {
+
+ PointToPointIntent intent = makeIntent("d8", "d1");
+
+ String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
+ PointToPointIntentCompiler compiler = makeCompiler(hops);
+
+ List<Intent> result = compiler.compile(intent, null, null);
+ assertThat(result, is(Matchers.notNullValue()));
+ assertThat(result, hasSize(1));
+ Intent reverseResultIntent = result.get(0);
+ assertThat(reverseResultIntent instanceof PathIntent, is(true));
+
+ if (reverseResultIntent instanceof PathIntent) {
+ PathIntent reversePathIntent = (PathIntent) reverseResultIntent;
+ assertThat(reversePathIntent.path().links(), hasSize(hops.length + 1));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d2", "d1"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d3", "d2"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d4", "d3"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d5", "d4"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d6", "d5"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d7", "d6"));
+ assertThat(reversePathIntent.path().links(), linksHasPath("d8", "d7"));
+ }
+ }
+
+ /**
+ * Tests compilation of the intent which designates two different ports on the same switch.
+ */
+ @Test
+ public void testSameSwitchDifferentPortsIntentCompilation() {
+ ConnectPoint src = new ConnectPoint(deviceId("1"), portNumber(1));
+ ConnectPoint dst = new ConnectPoint(deviceId("1"), portNumber(2));
+ PointToPointIntent intent = PointToPointIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .ingressPoint(src)
+ .egressPoint(dst)
+ .build();
+
+ String[] hops = {"1"};
+ PointToPointIntentCompiler sut = makeCompiler(hops);
+
+ List<Intent> compiled = sut.compile(intent, null, null);
+
+ assertThat(compiled, hasSize(1));
+ assertThat(compiled.get(0), is(instanceOf(PathIntent.class)));
+ Path path = ((PathIntent) compiled.get(0)).path();
+
+ assertThat(path.links(), hasSize(2));
+ Link firstLink = path.links().get(0);
+ assertThat(firstLink, is(createEdgeLink(src, true)));
+ Link secondLink = path.links().get(1);
+ assertThat(secondLink, is(createEdgeLink(dst, false)));
+ }
+
+ /**
+ * Tests that requests with sufficient available bandwidth succeed.
+ */
+ @Test
+ public void testBandwidthConstrainedIntentSuccess() {
+
+ final LinkResourceService resourceService =
+ IntentTestsMocks.MockResourceService.makeBandwidthResourceService(1000.0);
+ final List<Constraint> constraints =
+ Collections.singletonList(new BandwidthConstraint(new BandwidthResource(Bandwidth.bps(100.0))));
+
+ final PointToPointIntent intent = makeIntent("s1", "s3", constraints);
+
+ String[] hops = {"s1", "s2", "s3"};
+ final PointToPointIntentCompiler compiler = makeCompiler(hops, resourceService);
+
+ final List<Intent> compiledIntents = compiler.compile(intent, null, null);
+
+ assertThat(compiledIntents, Matchers.notNullValue());
+ assertThat(compiledIntents, hasSize(1));
+ }
+
+ /**
+ * Tests that requests with insufficient available bandwidth fail.
+ */
+ @Test
+ public void testBandwidthConstrainedIntentFailure() {
+
+ final LinkResourceService resourceService =
+ IntentTestsMocks.MockResourceService.makeBandwidthResourceService(10.0);
+ final List<Constraint> constraints =
+ Collections.singletonList(new BandwidthConstraint(new BandwidthResource(Bandwidth.bps(100.0))));
+
+ try {
+ final PointToPointIntent intent = makeIntent("s1", "s3", constraints);
+
+ String[] hops = {"s1", "s2", "s3"};
+ final PointToPointIntentCompiler compiler = makeCompiler(hops, resourceService);
+
+ compiler.compile(intent, null, null);
+
+ fail("Point to Point compilation with insufficient bandwidth does "
+ + "not throw exception.");
+ } catch (PathNotFoundException noPath) {
+ assertThat(noPath.getMessage(), containsString("No path"));
+ }
+ }
+
+ /**
+ * Tests that requests for available lambdas are successful.
+ */
+ @Test
+ public void testLambdaConstrainedIntentSuccess() {
+
+ final List<Constraint> constraints =
+ Collections.singletonList(new LambdaConstraint(LambdaResource.valueOf(1)));
+ final LinkResourceService resourceService =
+ IntentTestsMocks.MockResourceService.makeLambdaResourceService(1);
+
+ final PointToPointIntent intent = makeIntent("s1", "s3", constraints);
+
+ String[] hops = {"s1", "s2", "s3"};
+ final PointToPointIntentCompiler compiler = makeCompiler(hops, resourceService);
+
+ final List<Intent> compiledIntents =
+ compiler.compile(intent, null, null);
+
+ assertThat(compiledIntents, Matchers.notNullValue());
+ assertThat(compiledIntents, hasSize(1));
+ }
+
+ /**
+ * Tests that requests for lambdas when there are no available lambdas
+ * fail.
+ */
+ @Test
+ public void testLambdaConstrainedIntentFailure() {
+
+ final List<Constraint> constraints =
+ Collections.singletonList(new LambdaConstraint(LambdaResource.valueOf(1)));
+ final LinkResourceService resourceService =
+ IntentTestsMocks.MockResourceService.makeBandwidthResourceService(10.0);
+ try {
+ final PointToPointIntent intent = makeIntent("s1", "s3", constraints);
+
+ String[] hops = {"s1", "s2", "s3"};
+ final PointToPointIntentCompiler compiler = makeCompiler(hops, resourceService);
+
+ compiler.compile(intent, null, null);
+
+ fail("Point to Point compilation with no available lambda does "
+ + "not throw exception.");
+ } catch (PathNotFoundException noPath) {
+ assertThat(noPath.getMessage(), containsString("No path"));
+ }
+ }
+
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/phase/CompilingTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/phase/CompilingTest.java
new file mode 100644
index 00000000..c15ecaec
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/phase/CompilingTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.intent.impl.phase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.DefaultPath;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.intent.PathIntent;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.impl.IntentCompilationException;
+import org.onosproject.net.intent.impl.IntentProcessor;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.Timestamp;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.Link.Type.DIRECT;
+import static org.onosproject.net.PortNumber.portNumber;
+import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
+
+/**
+ * Unit tests for Compiling phase.
+ */
+public class CompilingTest {
+
+ private final ApplicationId appId = new TestApplicationId("test");
+ private final ProviderId pid = new ProviderId("of", "test");
+ private final TrafficSelector selector = DefaultTrafficSelector.emptySelector();
+ private final TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+ private final ConnectPoint cp1 = new ConnectPoint(deviceId("1"), portNumber(1));
+ private final ConnectPoint cp2 = new ConnectPoint(deviceId("1"), portNumber(2));
+ private final ConnectPoint cp3 = new ConnectPoint(deviceId("2"), portNumber(1));
+ private final ConnectPoint cp4 = new ConnectPoint(deviceId("2"), portNumber(2));
+
+ private final List<Link> links = Collections.singletonList(new DefaultLink(pid, cp2, cp4, DIRECT));
+ private final Path path = new DefaultPath(pid, links, 10);
+
+ private PointToPointIntent input;
+ private PathIntent compiled;
+
+ private IdGenerator idGenerator;
+ private IntentProcessor processor;
+ private Timestamp version;
+
+ @Before
+ public void setUp() {
+ processor = createMock(IntentProcessor.class);
+ version = createMock(Timestamp.class);
+
+ idGenerator = new MockIdGenerator();
+
+ Intent.bindIdGenerator(idGenerator);
+
+ // Intent creation should be placed after binding an ID generator
+ input = PointToPointIntent.builder()
+ .appId(appId)
+ .selector(selector)
+ .treatment(treatment)
+ .ingressPoint(cp1)
+ .egressPoint(cp3)
+ .build();
+ compiled = PathIntent.builder()
+ .appId(appId)
+ .selector(selector)
+ .treatment(treatment)
+ .path(path)
+ .build();
+ }
+
+
+ @After
+ public void tearDown() {
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ /**
+ * Tests a next phase when no exception occurs.
+ */
+ @Test
+ public void testMoveToNextPhaseWithoutError() {
+ IntentData pending = new IntentData(input, INSTALL_REQ, version);
+
+ expect(processor.compile(input, null)).andReturn(Collections.singletonList(compiled));
+ replay(processor);
+
+ Compiling sut = new Compiling(processor, pending, Optional.empty());
+
+ Optional<IntentProcessPhase> output = sut.execute();
+
+ verify(processor);
+ assertThat(output.get(), is(instanceOf(Installing.class)));
+ }
+
+ /**
+ * Tests a next phase when IntentCompilationException occurs.
+ */
+ @Test
+ public void testWhenIntentCompilationExceptionOccurs() {
+ IntentData pending = new IntentData(input, INSTALL_REQ, version);
+
+ expect(processor.compile(input, null)).andThrow(new IntentCompilationException());
+ replay(processor);
+
+ Compiling sut = new Compiling(processor, pending, Optional.empty());
+
+ Optional<IntentProcessPhase> output = sut.execute();
+
+ verify(processor);
+ assertThat(output.get(), is(instanceOf(Failed.class)));
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/BasicLinkOperatorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/BasicLinkOperatorTest.java
new file mode 100644
index 00000000..fe9e37cd
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/BasicLinkOperatorTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.link.impl;
+
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.PortNumber.portNumber;
+import static org.junit.Assert.assertEquals;
+
+import java.time.Duration;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.net.config.basics.BasicLinkConfig;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.LinkKey;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.link.DefaultLinkDescription;
+import org.onosproject.net.link.LinkDescription;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+
+public class BasicLinkOperatorTest {
+
+ private static final DeviceId DID1 = deviceId("of:foo");
+ private static final DeviceId DID2 = deviceId("of:bar");
+ private static final PortNumber P1 = portNumber(1);
+
+ private static final ConnectPoint SRC = new ConnectPoint(DID1, P1);
+ private static final ConnectPoint DST = new ConnectPoint(DID2, P1);
+ private static final LinkKey LK = LinkKey.linkKey(SRC, DST);
+ private static final Duration NTIME = Duration.ofNanos(200);
+
+ private static final SparseAnnotations SA = DefaultAnnotations.builder()
+ .set(AnnotationKeys.DURABLE, "true").build();
+ private static final LinkDescription LD = new DefaultLinkDescription(SRC, DST, Link.Type.DIRECT, SA);
+ private final ConfigApplyDelegate delegate = new ConfigApplyDelegate() {
+ @Override
+ public void onApply(Config config) {
+ }
+ };
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ private static final BasicLinkConfig BLC = new BasicLinkConfig();
+
+ @Before
+ public void setUp() {
+ BLC.init(LK, "optest", JsonNodeFactory.instance.objectNode(), mapper, delegate);
+ BLC.latency(NTIME);
+ }
+
+ @Test
+ public void testDescOps() {
+ LinkDescription desc = BasicLinkOperator.combine(BLC, LD);
+ assertEquals(NTIME.toString(), desc.annotations().value(AnnotationKeys.LATENCY));
+ assertEquals("true", desc.annotations().value(AnnotationKeys.DURABLE));
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java
new file mode 100644
index 00000000..dad5429e
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.link.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.event.Event;
+import org.onosproject.net.config.NetworkConfigServiceAdapter;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.link.DefaultLinkDescription;
+import org.onosproject.net.link.LinkAdminService;
+import org.onosproject.net.link.LinkEvent;
+import org.onosproject.net.link.LinkListener;
+import org.onosproject.net.link.LinkProvider;
+import org.onosproject.net.link.LinkProviderRegistry;
+import org.onosproject.net.link.LinkProviderService;
+import org.onosproject.net.link.LinkService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.net.device.impl.DeviceManager;
+import org.onosproject.store.trivial.SimpleLinkStore;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.Link.Type.DIRECT;
+import static org.onosproject.net.Link.Type.INDIRECT;
+import static org.onosproject.net.NetTestTools.injectEventDispatcher;
+import static org.onosproject.net.link.LinkEvent.Type.*;
+
+/**
+ * Test codifying the link service & link provider service contracts.
+ */
+public class LinkManagerTest {
+
+ private static final ProviderId PID = new ProviderId("of", "foo");
+ private static final DeviceId DID1 = deviceId("of:foo");
+ private static final DeviceId DID2 = deviceId("of:bar");
+ private static final DeviceId DID3 = deviceId("of:goo");
+ private static final Device DEV1 = new DefaultDevice(
+ PID, DID1, Device.Type.SWITCH, "", "", "", "", null);
+ private static final Device DEV2 = new DefaultDevice(
+ PID, DID2, Device.Type.SWITCH, "", "", "", "", null);
+ private static final Device DEV3 = new DefaultDevice(
+ PID, DID2, Device.Type.SWITCH, "", "", "", "", null);
+
+ private static final PortNumber P1 = PortNumber.portNumber(1);
+ private static final PortNumber P2 = PortNumber.portNumber(2);
+ private static final PortNumber P3 = PortNumber.portNumber(3);
+ private static final Map<DeviceId, Device> DEVICEIDMAP = new HashMap<>();
+
+ private LinkManager mgr;
+
+ protected LinkService service;
+ protected LinkAdminService admin;
+ protected LinkProviderRegistry registry;
+ protected LinkProviderService providerService;
+ protected TestProvider provider;
+ protected TestListener listener = new TestListener();
+ protected DeviceManager devmgr = new TestDeviceManager();
+
+
+
+ @Before
+ public void setUp() {
+ mgr = new LinkManager();
+ service = mgr;
+ admin = mgr;
+ registry = mgr;
+ mgr.store = new SimpleLinkStore();
+ injectEventDispatcher(mgr, new TestEventDispatcher());
+ mgr.deviceService = devmgr;
+ mgr.networkConfigService = new TestNetworkConfigService();
+ mgr.activate();
+
+ DEVICEIDMAP.put(DID1, DEV1);
+ DEVICEIDMAP.put(DID2, DEV2);
+ DEVICEIDMAP.put(DID3, DEV3);
+
+ service.addListener(listener);
+
+ provider = new TestProvider();
+ providerService = registry.register(provider);
+ assertTrue("provider should be registered",
+ registry.getProviders().contains(provider.id()));
+ }
+
+ @After
+ public void tearDown() {
+ registry.unregister(provider);
+ assertFalse("provider should not be registered",
+ registry.getProviders().contains(provider.id()));
+ service.removeListener(listener);
+ mgr.deactivate();
+ }
+
+ @Test
+ public void createLink() {
+ addLink(DID1, P1, DID2, P2, DIRECT);
+ addLink(DID2, P2, DID1, P1, DIRECT);
+ assertEquals("incorrect link count", 2, service.getLinkCount());
+
+ Iterator<Link> it = service.getLinks().iterator();
+ it.next();
+ it.next();
+ assertFalse("incorrect link count", it.hasNext());
+ }
+
+ @Test
+ public void updateLink() {
+ addLink(DID1, P1, DID2, P2, DIRECT);
+ addLink(DID2, P2, DID1, P1, INDIRECT);
+ assertEquals("incorrect link count", 2, service.getLinkCount());
+
+ providerService.linkDetected(new DefaultLinkDescription(cp(DID2, P2), cp(DID1, P1), DIRECT));
+ validateEvents(LINK_UPDATED);
+ assertEquals("incorrect link count", 2, service.getLinkCount());
+
+ providerService.linkDetected(new DefaultLinkDescription(cp(DID2, P2), cp(DID1, P1), INDIRECT));
+ providerService.linkDetected(new DefaultLinkDescription(cp(DID2, P2), cp(DID1, P1), DIRECT));
+ assertEquals("no events expected", 0, listener.events.size());
+ }
+
+ @Test
+ public void removeLink() {
+ addLink(DID1, P1, DID2, P2, DIRECT);
+ addLink(DID2, P2, DID1, P1, DIRECT);
+ assertEquals("incorrect link count", 2, service.getLinkCount());
+
+ providerService.linkVanished(new DefaultLinkDescription(cp(DID1, P1), cp(DID2, P2), DIRECT));
+ validateEvents(LINK_REMOVED);
+ assertEquals("incorrect link count", 1, service.getLinkCount());
+ assertNull("link should not be found", service.getLink(cp(DID1, P1), cp(DID2, P2)));
+ assertNotNull("link should be found", service.getLink(cp(DID2, P2), cp(DID1, P1)));
+
+ providerService.linkVanished(new DefaultLinkDescription(cp(DID1, P1), cp(DID2, P2), DIRECT));
+ assertEquals("no events expected", 0, listener.events.size());
+ }
+
+ @Test
+ public void removeLinksByConnectionPoint() {
+ Link l1 = addLink(DID1, P1, DID2, P2, DIRECT);
+ Link l2 = addLink(DID2, P2, DID1, P1, DIRECT);
+ addLink(DID3, P3, DID2, P1, DIRECT);
+ addLink(DID2, P1, DID3, P3, DIRECT);
+ assertEquals("incorrect link count", 4, service.getLinkCount());
+
+ providerService.linksVanished(cp(DID1, P1));
+ assertEquals("incorrect link count", 2, service.getLinkCount());
+ assertNull("link should be gone", service.getLink(l1.src(), l1.dst()));
+ assertNull("link should be gone", service.getLink(l2.src(), l2.dst()));
+ }
+
+ @Test
+ public void removeLinksByDevice() {
+ addLink(DID1, P1, DID2, P2, DIRECT);
+ addLink(DID2, P2, DID1, P1, DIRECT);
+ addLink(DID3, P3, DID2, P1, DIRECT);
+ addLink(DID2, P1, DID3, P3, DIRECT);
+ Link l5 = addLink(DID3, P1, DID1, P2, DIRECT);
+ Link l6 = addLink(DID1, P2, DID3, P1, DIRECT);
+ assertEquals("incorrect link count", 6, service.getLinkCount());
+
+ providerService.linksVanished(DID2);
+ assertEquals("incorrect link count", 2, service.getLinkCount());
+ assertNotNull("link should not be gone", service.getLink(l5.src(), l5.dst()));
+ assertNotNull("link should not be gone", service.getLink(l6.src(), l6.dst()));
+ }
+
+ @Test
+ public void removeLinksAsAdminByConnectionPoint() {
+ Link l1 = addLink(DID1, P1, DID2, P2, DIRECT);
+ Link l2 = addLink(DID2, P2, DID1, P1, DIRECT);
+ addLink(DID3, P3, DID2, P1, DIRECT);
+ addLink(DID2, P1, DID3, P3, DIRECT);
+ assertEquals("incorrect link count", 4, service.getLinkCount());
+
+ admin.removeLinks(cp(DID1, P1));
+ assertEquals("incorrect link count", 2, service.getLinkCount());
+ assertNull("link should be gone", service.getLink(l1.src(), l1.dst()));
+ assertNull("link should be gone", service.getLink(l2.src(), l2.dst()));
+ }
+
+ @Test
+ public void removeLinksAsAdminByDevice() {
+ addLink(DID1, P1, DID2, P2, DIRECT);
+ addLink(DID2, P2, DID1, P1, DIRECT);
+ addLink(DID3, P3, DID2, P1, DIRECT);
+ addLink(DID2, P1, DID3, P3, DIRECT);
+ Link l5 = addLink(DID3, P1, DID1, P2, DIRECT);
+ Link l6 = addLink(DID1, P2, DID3, P1, DIRECT);
+ assertEquals("incorrect link count", 6, service.getLinkCount());
+
+ admin.removeLinks(DID2);
+ assertEquals("incorrect link count", 2, service.getLinkCount());
+ assertNotNull("link should not be gone", service.getLink(l5.src(), l5.dst()));
+ assertNotNull("link should not be gone", service.getLink(l6.src(), l6.dst()));
+ }
+
+ @Test
+ public void getLinks() {
+ Link l1 = addLink(DID1, P1, DID2, P2, DIRECT);
+ Link l2 = addLink(DID2, P2, DID1, P1, DIRECT);
+ Link l3 = addLink(DID3, P3, DID2, P1, DIRECT);
+ Link l4 = addLink(DID2, P1, DID3, P3, DIRECT);
+ assertEquals("incorrect link count", 4, service.getLinkCount());
+
+ Set<Link> links = service.getLinks(cp(DID1, P1));
+ assertEquals("incorrect links", ImmutableSet.of(l1, l2), links);
+ links = service.getEgressLinks(cp(DID1, P1));
+ assertEquals("incorrect links", ImmutableSet.of(l1), links);
+ links = service.getIngressLinks(cp(DID1, P1));
+ assertEquals("incorrect links", ImmutableSet.of(l2), links);
+
+ links = service.getDeviceLinks(DID2);
+ assertEquals("incorrect links", ImmutableSet.of(l1, l2, l3, l4), links);
+ links = service.getDeviceLinks(DID3);
+ assertEquals("incorrect links", ImmutableSet.of(l3, l4), links);
+
+ links = service.getDeviceEgressLinks(DID2);
+ assertEquals("incorrect links", ImmutableSet.of(l2, l4), links);
+ links = service.getDeviceIngressLinks(DID2);
+ assertEquals("incorrect links", ImmutableSet.of(l1, l3), links);
+ }
+
+
+ private Link addLink(DeviceId sd, PortNumber sp, DeviceId dd, PortNumber dp,
+ Link.Type type) {
+ providerService.linkDetected(new DefaultLinkDescription(cp(sd, sp), cp(dd, dp), type));
+ Link link = listener.events.get(0).subject();
+ validateEvents(LINK_ADDED);
+ return link;
+ }
+
+ private ConnectPoint cp(DeviceId id, PortNumber portNumber) {
+ return new ConnectPoint(id, portNumber);
+ }
+
+ protected void validateEvents(Enum... types) {
+ int i = 0;
+ assertEquals("wrong events received", types.length, listener.events.size());
+ for (Event event : listener.events) {
+ assertEquals("incorrect event type", types[i], event.type());
+ i++;
+ }
+ listener.events.clear();
+ }
+
+
+ private class TestProvider extends AbstractProvider implements LinkProvider {
+ private Device deviceReceived;
+ private MastershipRole roleReceived;
+
+ public TestProvider() {
+ super(PID);
+ }
+ }
+
+ private static class TestListener implements LinkListener {
+ final List<LinkEvent> events = new ArrayList<>();
+
+ @Override
+ public void event(LinkEvent event) {
+ events.add(event);
+ }
+ }
+
+ private static class TestDeviceManager extends DeviceManager {
+
+ @Override
+ public MastershipRole getRole(DeviceId deviceId) {
+ return MastershipRole.MASTER;
+ }
+
+ @Override
+ public Device getDevice(DeviceId deviceId) {
+ return DEVICEIDMAP.get(deviceId);
+ }
+
+ }
+ private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
new file mode 100644
index 00000000..1a160d98
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.proxyarp.impl;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.ARP;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultHost;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.Link;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.edgeservice.impl.EdgeManager;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.host.InterfaceIpAddress;
+import org.onosproject.net.link.LinkListener;
+import org.onosproject.net.link.LinkService;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketServiceAdapter;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.net.proxyarp.ProxyArpStore;
+import org.onosproject.net.proxyarp.ProxyArpStoreDelegate;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for the {@link ProxyArpManager} class.
+ */
+public class ProxyArpManagerTest {
+
+ private static final int NUM_DEVICES = 6;
+ private static final int NUM_PORTS_PER_DEVICE = 3;
+ private static final int NUM_ADDRESS_PORTS = NUM_DEVICES / 2;
+ private static final int NUM_FLOOD_PORTS = 3;
+
+ private static final Ip4Address IP1 = Ip4Address.valueOf("192.168.1.1");
+ private static final Ip4Address IP2 = Ip4Address.valueOf("192.168.1.2");
+
+ private static final ProviderId PID = new ProviderId("of", "foo");
+
+ private static final VlanId VLAN1 = VlanId.vlanId((short) 1);
+ private static final VlanId VLAN2 = VlanId.vlanId((short) 2);
+ private static final MacAddress MAC1 = MacAddress.valueOf("00:00:11:00:00:01");
+ private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02");
+ private static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
+ private static final HostId HID2 = HostId.hostId(MAC2, VLAN1);
+
+ private static final DeviceId DID1 = getDeviceId(1);
+ private static final DeviceId DID2 = getDeviceId(2);
+ private static final PortNumber P1 = PortNumber.portNumber(1);
+ private static final HostLocation LOC1 = new HostLocation(DID1, P1, 123L);
+ private static final HostLocation LOC2 = new HostLocation(DID2, P1, 123L);
+ private static final byte[] ZERO_MAC_ADDRESS = MacAddress.ZERO.toBytes();
+
+ //Return values used for various functions of the TestPacketService inner class.
+ private boolean isEdgePointReturn;
+ private List<ConnectPoint> getEdgePointsNoArg;
+
+
+ private ProxyArpManager proxyArp;
+
+ private TestPacketService packetService;
+ private DeviceService deviceService;
+ private LinkService linkService;
+ private HostService hostService;
+ private InterfaceService interfaceService;
+
+ @Before
+ public void setUp() throws Exception {
+ proxyArp = new ProxyArpManager();
+ packetService = new TestPacketService();
+ proxyArp.packetService = packetService;
+ proxyArp.store = new TestProxyArpStoreAdapter();
+
+ proxyArp.edgeService = new TestEdgePortService();
+
+ // Create a host service mock here. Must be replayed by tests once the
+ // expectations have been set up
+ hostService = createMock(HostService.class);
+ proxyArp.hostService = hostService;
+
+ interfaceService = createMock(InterfaceService.class);
+ proxyArp.interfaceService = interfaceService;
+
+ createTopology();
+ proxyArp.deviceService = deviceService;
+ proxyArp.linkService = linkService;
+
+ proxyArp.activate();
+ }
+
+ /**
+ * Creates a fake topology to feed into the ARP module.
+ * <p>
+ * The default topology is a unidirectional ring topology. Each switch has
+ * 3 ports. Ports 2 and 3 have the links to neighbor switches, and port 1
+ * is free (edge port).
+ * The first half of the switches have IP addresses configured on their
+ * free ports (port 1). The second half of the switches have no IP
+ * addresses configured.
+ */
+ private void createTopology() {
+ deviceService = createMock(DeviceService.class);
+ linkService = createMock(LinkService.class);
+
+ deviceService.addListener(anyObject(DeviceListener.class));
+ linkService.addListener(anyObject(LinkListener.class));
+
+ createDevices(NUM_DEVICES, NUM_PORTS_PER_DEVICE);
+ createLinks(NUM_DEVICES);
+ addAddressBindings();
+ }
+
+ /**
+ * Creates the devices for the fake topology.
+ */
+ private void createDevices(int numDevices, int numPorts) {
+ List<Device> devices = new ArrayList<>();
+
+ for (int i = 1; i <= numDevices; i++) {
+ DeviceId devId = getDeviceId(i);
+ Device device = createMock(Device.class);
+ expect(device.id()).andReturn(devId).anyTimes();
+ replay(device);
+
+ devices.add(device);
+
+ List<Port> ports = new ArrayList<>();
+ for (int j = 1; j <= numPorts; j++) {
+ Port port = createMock(Port.class);
+ expect(port.number()).andReturn(PortNumber.portNumber(j)).anyTimes();
+ replay(port);
+ ports.add(port);
+ }
+
+ expect(deviceService.getPorts(devId)).andReturn(ports).anyTimes();
+ expect(deviceService.getDevice(devId)).andReturn(device).anyTimes();
+ }
+
+ expect(deviceService.getDevices()).andReturn(devices).anyTimes();
+ replay(deviceService);
+ }
+
+ /**
+ * Creates the links for the fake topology.
+ * NB: Only unidirectional links are created, as for this purpose all we
+ * need is to occupy the ports with some link.
+ */
+ private void createLinks(int numDevices) {
+ List<Link> links = new ArrayList<>();
+
+ for (int i = 1; i <= numDevices; i++) {
+ ConnectPoint src = new ConnectPoint(
+ getDeviceId(i),
+ PortNumber.portNumber(2));
+ ConnectPoint dst = new ConnectPoint(
+ getDeviceId((i + 1 > numDevices) ? 1 : i + 1),
+ PortNumber.portNumber(3));
+
+ Link link = createMock(Link.class);
+ expect(link.src()).andReturn(src).anyTimes();
+ expect(link.dst()).andReturn(dst).anyTimes();
+ replay(link);
+
+ links.add(link);
+ }
+
+ expect(linkService.getLinks()).andReturn(links).anyTimes();
+ replay(linkService);
+ }
+
+ private void addAddressBindings() {
+ Set<Interface> interfaces = Sets.newHashSet();
+
+ for (int i = 1; i <= NUM_ADDRESS_PORTS; i++) {
+ ConnectPoint cp = new ConnectPoint(getDeviceId(i), P1);
+ Ip4Prefix prefix1 =
+ Ip4Prefix.valueOf("10.0." + (2 * i - 1) + ".0/24");
+ Ip4Address addr1 =
+ Ip4Address.valueOf("10.0." + (2 * i - 1) + ".1");
+ Ip4Prefix prefix2 = Ip4Prefix.valueOf("10.0." + (2 * i) + ".0/24");
+ Ip4Address addr2 = Ip4Address.valueOf("10.0." + (2 * i) + ".1");
+ InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1);
+ InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
+ Interface intf1 = new Interface(cp, Sets.newHashSet(ia1),
+ MacAddress.valueOf(2 * i - 1),
+ VlanId.vlanId((short) 1));
+ Interface intf2 = new Interface(cp, Sets.newHashSet(ia2),
+ MacAddress.valueOf(2 * i),
+ VlanId.NONE);
+
+ interfaces.add(intf1);
+ interfaces.add(intf2);
+
+ expect(interfaceService.getInterfacesByPort(cp))
+ .andReturn(Sets.newHashSet(intf1, intf2)).anyTimes();
+ }
+
+ expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
+
+ for (int i = 1; i <= NUM_FLOOD_PORTS; i++) {
+ ConnectPoint cp = new ConnectPoint(getDeviceId(i + NUM_ADDRESS_PORTS),
+ P1);
+
+ expect(interfaceService.getInterfacesByPort(cp))
+ .andReturn(Collections.emptySet()).anyTimes();
+ }
+ }
+
+ /**
+ * Tests {@link ProxyArpManager#isKnown(org.onlab.packet.IpAddress)} in the
+ * case where the IP address is not known.
+ * Verifies the method returns false.
+ */
+ @Test
+ public void testNotKnown() {
+ expect(hostService.getHostsByIp(IP1)).andReturn(Collections.<Host>emptySet());
+ replay(hostService);
+ replay(interfaceService);
+
+ assertFalse(proxyArp.isKnown(IP1));
+ }
+
+ /**
+ * Tests {@link ProxyArpManager#isKnown(org.onlab.packet.IpAddress)} in the
+ * case where the IP address is known.
+ * Verifies the method returns true.
+ */
+ @Test
+ public void testKnown() {
+ Host host1 = createMock(Host.class);
+ Host host2 = createMock(Host.class);
+
+ expect(hostService.getHostsByIp(IP1))
+ .andReturn(Sets.newHashSet(host1, host2));
+ replay(hostService);
+ replay(interfaceService);
+
+ assertTrue(proxyArp.isKnown(IP1));
+ }
+
+ /**
+ * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
+ * destination host is known.
+ * Verifies the correct ARP reply is sent out the correct port.
+ */
+ @Test
+ public void testReplyKnown() {
+ //Set the return value of isEdgePoint from the edgemanager.
+ isEdgePointReturn = true;
+
+ Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN1, getLocation(4),
+ Collections.singleton(IP1));
+
+ Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
+ Collections.singleton(IP2));
+
+ expect(hostService.getHostsByIp(IP1))
+ .andReturn(Collections.singleton(replyer));
+ expect(hostService.getHost(HID2)).andReturn(requestor);
+
+ replay(hostService);
+ replay(interfaceService);
+
+ Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
+
+ proxyArp.reply(arpRequest, getLocation(5));
+
+ assertEquals(1, packetService.packets.size());
+ Ethernet arpReply = buildArp(ARP.OP_REPLY, MAC1, MAC2, IP1, IP2);
+ verifyPacketOut(arpReply, getLocation(5), packetService.packets.get(0));
+ }
+
+ /**
+ * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
+ * destination host is not known.
+ * Verifies the ARP request is flooded out the correct edge ports.
+ */
+ @Test
+ public void testReplyUnknown() {
+ isEdgePointReturn = true;
+
+ Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
+ Collections.singleton(IP2));
+
+ expect(hostService.getHostsByIp(IP1))
+ .andReturn(Collections.emptySet());
+ expect(interfaceService.getInterfacesByIp(IP2))
+ .andReturn(Collections.emptySet());
+ expect(hostService.getHost(HID2)).andReturn(requestor);
+
+
+ replay(hostService);
+ replay(interfaceService);
+
+ Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
+
+ //Setup the set of edge ports to be used in the reply method
+ getEdgePointsNoArg = Lists.newLinkedList();
+ getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1)));
+ getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1)));
+
+ proxyArp.reply(arpRequest, getLocation(6));
+
+ verifyFlood(arpRequest);
+ }
+
+ /**
+ * Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
+ * destination host is known for that IP address, but is not on the same
+ * VLAN as the source host.
+ * Verifies the ARP request is flooded out the correct edge ports.
+ */
+ @Test
+ public void testReplyDifferentVlan() {
+
+ Host replyer = new DefaultHost(PID, HID1, MAC1, VLAN2, getLocation(4),
+ Collections.singleton(IP1));
+
+ Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, getLocation(5),
+ Collections.singleton(IP2));
+
+ expect(hostService.getHostsByIp(IP1))
+ .andReturn(Collections.singleton(replyer));
+ expect(interfaceService.getInterfacesByIp(IP2))
+ .andReturn(Collections.emptySet());
+ expect(hostService.getHost(HID2)).andReturn(requestor);
+
+ replay(hostService);
+ replay(interfaceService);
+
+ Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, IP2, IP1);
+
+ //Setup for flood test
+ getEdgePointsNoArg = Lists.newLinkedList();
+ getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1)));
+ getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1)));
+ proxyArp.reply(arpRequest, getLocation(6));
+
+ verifyFlood(arpRequest);
+ }
+
+ @Test
+ public void testReplyToRequestForUs() {
+ Ip4Address theirIp = Ip4Address.valueOf("10.0.1.254");
+ Ip4Address ourFirstIp = Ip4Address.valueOf("10.0.1.1");
+ Ip4Address ourSecondIp = Ip4Address.valueOf("10.0.2.1");
+ MacAddress firstMac = MacAddress.valueOf(1L);
+ MacAddress secondMac = MacAddress.valueOf(2L);
+
+ Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1,
+ Collections.singleton(theirIp));
+
+ expect(hostService.getHost(HID2)).andReturn(requestor);
+ replay(hostService);
+ replay(interfaceService);
+
+ Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourFirstIp);
+ isEdgePointReturn = true;
+ proxyArp.reply(arpRequest, LOC1);
+
+ assertEquals(1, packetService.packets.size());
+ Ethernet arpReply = buildArp(ARP.OP_REPLY, firstMac, MAC2, ourFirstIp, theirIp);
+ verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
+
+ // Test a request for the second address on that port
+ packetService.packets.clear();
+ arpRequest = buildArp(ARP.OP_REQUEST, MAC2, null, theirIp, ourSecondIp);
+
+ proxyArp.reply(arpRequest, LOC1);
+
+ assertEquals(1, packetService.packets.size());
+ arpReply = buildArp(ARP.OP_REPLY, secondMac, MAC2, ourSecondIp, theirIp);
+ verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
+ }
+
+ @Test
+ public void testReplyExternalPortBadRequest() {
+ replay(hostService); // no further host service expectations
+ replay(interfaceService);
+
+ Ip4Address theirIp = Ip4Address.valueOf("10.0.1.254");
+
+ // Request for a valid external IP address but coming in the wrong port
+ Ethernet arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp,
+ Ip4Address.valueOf("10.0.3.1"));
+ proxyArp.reply(arpRequest, LOC1);
+ assertEquals(0, packetService.packets.size());
+
+ // Request for a valid internal IP address but coming in an external port
+ packetService.packets.clear();
+ arpRequest = buildArp(ARP.OP_REQUEST, MAC1, null, theirIp, IP1);
+ proxyArp.reply(arpRequest, LOC1);
+ assertEquals(0, packetService.packets.size());
+ }
+
+ @Test
+ public void testReplyToRequestFromUs() {
+ Ip4Address ourIp = Ip4Address.valueOf("10.0.1.1");
+ MacAddress ourMac = MacAddress.valueOf(1L);
+ Ip4Address theirIp = Ip4Address.valueOf("10.0.1.100");
+
+ expect(hostService.getHostsByIp(theirIp)).andReturn(Collections.emptySet());
+ expect(interfaceService.getInterfacesByIp(ourIp))
+ .andReturn(Collections.singleton(new Interface(getLocation(1),
+ Collections.singleton(new InterfaceIpAddress(ourIp, IpPrefix.valueOf("10.0.1.1/24"))),
+ ourMac, VLAN1)));
+ expect(hostService.getHost(HostId.hostId(ourMac, VLAN1))).andReturn(null);
+ replay(hostService);
+ replay(interfaceService);
+
+ // This is a request from something inside our network (like a BGP
+ // daemon) to an external host.
+ Ethernet arpRequest = buildArp(ARP.OP_REQUEST, ourMac, null, ourIp, theirIp);
+ //Ensure the packet is allowed through (it is not to an internal port)
+ isEdgePointReturn = true;
+
+ proxyArp.reply(arpRequest, getLocation(5));
+ assertEquals(1, packetService.packets.size());
+ verifyPacketOut(arpRequest, getLocation(1), packetService.packets.get(0));
+
+ // The same request from a random external port should fail
+ packetService.packets.clear();
+ proxyArp.reply(arpRequest, getLocation(2));
+ assertEquals(0, packetService.packets.size());
+ }
+
+ /**
+ * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
+ * destination host is known.
+ * Verifies the correct ARP request is sent out the correct port.
+ */
+ @Test
+ public void testForwardToHost() {
+ Host host1 = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1,
+ Collections.singleton(IP1));
+ Host host2 = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC2,
+ Collections.singleton(IP2));
+
+ expect(hostService.getHost(HID1)).andReturn(host1);
+ expect(hostService.getHost(HID2)).andReturn(host2);
+ replay(hostService);
+ replay(interfaceService);
+
+ Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
+
+ proxyArp.forward(arpRequest, LOC2);
+
+ assertEquals(1, packetService.packets.size());
+ OutboundPacket packet = packetService.packets.get(0);
+
+ verifyPacketOut(arpRequest, LOC1, packet);
+ }
+
+ /**
+ * Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
+ * destination host is not known.
+ * Verifies the correct ARP request is flooded out the correct edge ports.
+ */
+ @Test
+ public void testForwardFlood() {
+ expect(hostService.getHost(HID1)).andReturn(null);
+ replay(hostService);
+ replay(interfaceService);
+
+ Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1);
+
+ //populate the list of edges when so that when forward hits flood in the manager it contains the values
+ //that should continue on
+ getEdgePointsNoArg = Lists.newLinkedList();
+ getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("3"), PortNumber.portNumber(1)));
+ getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("5"), PortNumber.portNumber(1)));
+ getEdgePointsNoArg.add(new ConnectPoint(DeviceId.deviceId("4"), PortNumber.portNumber(1)));
+
+ proxyArp.forward(arpRequest, getLocation(6));
+
+ verifyFlood(arpRequest);
+ }
+
+ /**
+ * Verifies that the given packet was flooded out all available edge ports,
+ * except for the input port.
+ *
+ * @param packet the packet that was expected to be flooded
+ */
+ private void verifyFlood(Ethernet packet) {
+ // There should be 1 less than NUM_FLOOD_PORTS; the inPort should be excluded.
+ assertEquals(NUM_FLOOD_PORTS - 1, packetService.packets.size());
+
+ Collections.sort(packetService.packets,
+ (o1, o2) -> o1.sendThrough().uri().compareTo(o2.sendThrough().uri()));
+
+
+ for (int i = 0; i < NUM_FLOOD_PORTS - 1; i++) {
+ ConnectPoint cp = new ConnectPoint(getDeviceId(NUM_ADDRESS_PORTS + i + 1),
+ PortNumber.portNumber(1));
+
+ OutboundPacket outboundPacket = packetService.packets.get(i);
+ verifyPacketOut(packet, cp, outboundPacket);
+ }
+ }
+
+ /**
+ * Verifies the given packet was sent out the given port.
+ *
+ * @param expected the packet that was expected to be sent
+ * @param outPort the port the packet was expected to be sent out
+ * @param actual the actual OutboundPacket to verify
+ */
+ private void verifyPacketOut(Ethernet expected, ConnectPoint outPort,
+ OutboundPacket actual) {
+ assertArrayEquals(expected.serialize(), actual.data().array());
+ assertEquals(1, actual.treatment().immediate().size());
+ assertEquals(outPort.deviceId(), actual.sendThrough());
+ Instruction instruction = actual.treatment().immediate().get(0);
+ assertTrue(instruction instanceof OutputInstruction);
+ assertEquals(outPort.port(), ((OutputInstruction) instruction).port());
+ }
+
+ /**
+ * Returns the device ID of the ith device.
+ *
+ * @param i device to get the ID of
+ * @return the device ID
+ */
+ private static DeviceId getDeviceId(int i) {
+ return DeviceId.deviceId("" + i);
+ }
+
+ private static HostLocation getLocation(int i) {
+ return new HostLocation(new ConnectPoint(getDeviceId(i), P1), 123L);
+ }
+
+ /**
+ * Builds an ARP packet with the given parameters.
+ *
+ * @param opcode opcode of the ARP packet
+ * @param srcMac source MAC address
+ * @param dstMac destination MAC address, or null if this is a request
+ * @param srcIp source IP address
+ * @param dstIp destination IP address
+ * @return the ARP packet
+ */
+ private Ethernet buildArp(short opcode, MacAddress srcMac, MacAddress dstMac,
+ Ip4Address srcIp, Ip4Address dstIp) {
+ Ethernet eth = new Ethernet();
+
+ if (dstMac == null) {
+ eth.setDestinationMACAddress(MacAddress.BROADCAST);
+ } else {
+ eth.setDestinationMACAddress(dstMac);
+ }
+
+ eth.setSourceMACAddress(srcMac);
+ eth.setEtherType(Ethernet.TYPE_ARP);
+ eth.setVlanID(VLAN1.toShort());
+
+ ARP arp = new ARP();
+ arp.setOpCode(opcode);
+ arp.setProtocolType(ARP.PROTO_TYPE_IP);
+ arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
+
+ arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
+ arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
+ arp.setSenderHardwareAddress(srcMac.toBytes());
+
+ if (dstMac == null) {
+ arp.setTargetHardwareAddress(ZERO_MAC_ADDRESS);
+ } else {
+ arp.setTargetHardwareAddress(dstMac.toBytes());
+ }
+
+ arp.setSenderProtocolAddress(srcIp.toOctets());
+ arp.setTargetProtocolAddress(dstIp.toOctets());
+
+ eth.setPayload(arp);
+ return eth;
+ }
+
+ /**
+ * Test PacketService implementation that simply stores OutboundPackets
+ * passed to {@link #emit(OutboundPacket)} for later verification.
+ */
+ class TestPacketService extends PacketServiceAdapter {
+
+ List<OutboundPacket> packets = new ArrayList<>();
+
+ @Override
+ public void emit(OutboundPacket packet) {
+ packets.add(packet);
+ }
+
+ }
+
+ class TestEdgePortService extends EdgeManager {
+
+ @Override
+ public boolean isEdgePoint(ConnectPoint connectPoint) {
+ return isEdgePointReturn;
+ }
+
+ @Override
+ public Iterable<ConnectPoint> getEdgePoints() {
+ return getEdgePointsNoArg;
+ }
+ }
+
+ private class TestProxyArpStoreAdapter implements ProxyArpStore {
+ @Override
+ public void forward(ConnectPoint outPort, Host subject, ByteBuffer packet) {
+ TrafficTreatment tt = DefaultTrafficTreatment.builder().setOutput(outPort.port()).build();
+ packetService.emit(new DefaultOutboundPacket(outPort.deviceId(), tt, packet));
+ }
+
+ @Override
+ public void setDelegate(ProxyArpStoreDelegate delegate) {
+ }
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java
new file mode 100644
index 00000000..022df23d
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.topology.impl;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.event.Event;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.net.Device;
+import org.onosproject.net.Link;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.impl.DeviceManager;
+import org.onosproject.net.link.LinkEvent;
+import org.onosproject.net.link.impl.LinkManager;
+import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.net.topology.GraphDescription;
+import org.onosproject.net.topology.TopologyProvider;
+import org.onosproject.net.topology.TopologyProviderRegistry;
+import org.onosproject.net.topology.TopologyProviderService;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.*;
+import static org.onosproject.net.NetTestTools.device;
+import static org.onosproject.net.NetTestTools.link;
+import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
+import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
+
+/**
+ * Test of the default topology provider implementation.
+ */
+public class DefaultTopologyProviderTest {
+
+ private DefaultTopologyProvider provider = new DefaultTopologyProvider();
+ private TestTopoRegistry topologyService = new TestTopoRegistry();
+ private TestDeviceService deviceService = new TestDeviceService();
+ private TestLinkService linkService = new TestLinkService();
+ private TestTopoProviderService providerService;
+
+ // phase corresponds to number of topologyChanged called
+ private Phaser topologyChangedCounts = new Phaser(1);
+
+ @Before
+ public void setUp() {
+ provider.deviceService = deviceService;
+ provider.linkService = linkService;
+ provider.providerRegistry = topologyService;
+ provider.cfgService = new ComponentConfigAdapter();
+ provider.activate(null);
+ }
+
+ @After
+ public void tearDown() {
+ provider.deactivate(null);
+ provider.providerRegistry = null;
+ provider.deviceService = null;
+ provider.linkService = null;
+ provider.cfgService = null;
+ }
+
+ private void validateSubmission() {
+ assertNotNull("registration expected", providerService);
+ assertEquals("incorrect provider", provider, providerService.provider());
+ assertNotNull("topo change should be submitted", providerService.graphDesc);
+ assertEquals("incorrect vertex count", 6, providerService.graphDesc.vertexes().size());
+ assertEquals("incorrect edge count", 10, providerService.graphDesc.edges().size());
+ }
+
+ @Test
+ public void basics() throws InterruptedException, TimeoutException {
+ assertEquals(1, topologyChangedCounts.awaitAdvanceInterruptibly(0, 1, TimeUnit.SECONDS));
+ validateSubmission();
+ }
+
+ @Test
+ public void eventDriven() throws InterruptedException, TimeoutException {
+ assertEquals(1, topologyChangedCounts.awaitAdvanceInterruptibly(0, 1, TimeUnit.SECONDS));
+ validateSubmission();
+
+ deviceService.postEvent(new DeviceEvent(DEVICE_ADDED, device("z"), null));
+ linkService.postEvent(new LinkEvent(LINK_ADDED, link("z", 1, "a", 4)));
+ assertThat(topologyChangedCounts.awaitAdvanceInterruptibly(1, 1, TimeUnit.SECONDS),
+ is(greaterThanOrEqualTo(2)));
+ // Note: posting event, to trigger topologyChanged call,
+ // but dummy topology will not change.
+ validateSubmission();
+ }
+
+
+ private class TestTopoRegistry implements TopologyProviderRegistry {
+
+ @Override
+ public TopologyProviderService register(TopologyProvider provider) {
+ providerService = new TestTopoProviderService(provider);
+ return providerService;
+ }
+
+ @Override
+ public void unregister(TopologyProvider provider) {
+ }
+
+ @Override
+ public Set<ProviderId> getProviders() {
+ return null;
+ }
+ }
+
+ private class TestTopoProviderService
+ extends AbstractProviderService<TopologyProvider>
+ implements TopologyProviderService {
+ GraphDescription graphDesc;
+
+ protected TestTopoProviderService(TopologyProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public void topologyChanged(GraphDescription graphDescription, List<Event> reasons) {
+ graphDesc = graphDescription;
+ topologyChangedCounts.arrive();
+ }
+ }
+
+ private class TestDeviceService extends DeviceManager {
+ TestDeviceService() {
+ eventDispatcher = new TestEventDispatcher();
+ eventDispatcher.addSink(DeviceEvent.class, listenerRegistry);
+ }
+
+ @Override
+ public Iterable<Device> getDevices() {
+ return ImmutableSet.of(device("a"), device("b"),
+ device("c"), device("d"),
+ device("e"), device("f"));
+ }
+
+ @Override
+ public Iterable<Device> getAvailableDevices() {
+ return getDevices();
+ }
+
+ void postEvent(DeviceEvent event) {
+ eventDispatcher.post(event);
+ }
+ }
+
+ private class TestLinkService extends LinkManager {
+ TestLinkService() {
+ eventDispatcher = new TestEventDispatcher();
+ eventDispatcher.addSink(LinkEvent.class, listenerRegistry);
+ }
+
+ @Override
+ public Iterable<Link> getLinks() {
+ return ImmutableSet.of(link("a", 1, "b", 1), link("b", 1, "a", 1),
+ link("b", 2, "c", 1), link("c", 1, "b", 2),
+ link("c", 2, "d", 1), link("d", 1, "c", 2),
+ link("d", 2, "a", 2), link("a", 2, "d", 2),
+ link("e", 1, "f", 1), link("f", 1, "e", 1));
+ }
+
+ @Override
+ public Iterable<Link> getActiveLinks() {
+ return getLinks();
+ }
+
+ void postEvent(LinkEvent event) {
+ eventDispatcher.post(event);
+ }
+ }
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java
new file mode 100644
index 00000000..2a2d0b54
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.topology.impl;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.ElementId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.Path;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.host.HostServiceAdapter;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.PathService;
+import org.onosproject.net.topology.Topology;
+import org.onosproject.net.topology.TopologyService;
+import org.onosproject.net.topology.TopologyServiceAdapter;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.NetTestTools.*;
+
+/**
+ * Test of the path selection subsystem.
+ */
+public class PathManagerTest {
+
+ private static final ProviderId PID = new ProviderId("of", "foo");
+
+ private PathManager mgr;
+ private PathService service;
+
+ private FakeTopoMgr fakeTopoMgr = new FakeTopoMgr();
+ private FakeHostMgr fakeHostMgr = new FakeHostMgr();
+
+ @Before
+ public void setUp() {
+ mgr = new PathManager();
+ service = mgr;
+ mgr.topologyService = fakeTopoMgr;
+ mgr.hostService = fakeHostMgr;
+ mgr.activate();
+ }
+
+ @After
+ public void tearDown() {
+ mgr.deactivate();
+ }
+
+ @Test
+ public void infraToInfra() {
+ DeviceId src = did("src");
+ DeviceId dst = did("dst");
+ fakeTopoMgr.paths.add(createPath("src", "middle", "dst"));
+ Set<Path> paths = service.getPaths(src, dst);
+ validatePaths(paths, 1, 2, src, dst);
+ }
+
+ @Test
+ public void infraToEdge() {
+ DeviceId src = did("src");
+ HostId dst = hid("12:34:56:78:90:ab/1");
+ fakeTopoMgr.paths.add(createPath("src", "middle", "edge"));
+ fakeHostMgr.hosts.put(dst, host("12:34:56:78:90:ab/1", "edge"));
+ Set<Path> paths = service.getPaths(src, dst);
+ validatePaths(paths, 1, 3, src, dst);
+ }
+
+ @Test
+ public void edgeToInfra() {
+ HostId src = hid("12:34:56:78:90:ab/1");
+ DeviceId dst = did("dst");
+ fakeTopoMgr.paths.add(createPath("edge", "middle", "dst"));
+ fakeHostMgr.hosts.put(src, host("12:34:56:78:90:ab/1", "edge"));
+ Set<Path> paths = service.getPaths(src, dst);
+ validatePaths(paths, 1, 3, src, dst);
+ }
+
+ @Test
+ public void edgeToEdge() {
+ HostId src = hid("12:34:56:78:90:ab/1");
+ HostId dst = hid("12:34:56:78:90:ef/1");
+ fakeTopoMgr.paths.add(createPath("srcEdge", "middle", "dstEdge"));
+ fakeHostMgr.hosts.put(src, host("12:34:56:78:90:ab/1", "srcEdge"));
+ fakeHostMgr.hosts.put(dst, host("12:34:56:78:90:ef/1", "dstEdge"));
+ Set<Path> paths = service.getPaths(src, dst);
+ validatePaths(paths, 1, 4, src, dst);
+ }
+
+ @Test
+ public void edgeToEdgeDirect() {
+ HostId src = hid("12:34:56:78:90:ab/1");
+ HostId dst = hid("12:34:56:78:90:ef/1");
+ fakeHostMgr.hosts.put(src, host("12:34:56:78:90:ab/1", "edge"));
+ fakeHostMgr.hosts.put(dst, host("12:34:56:78:90:ef/1", "edge"));
+ Set<Path> paths = service.getPaths(src, dst);
+ validatePaths(paths, 1, 2, src, dst);
+ }
+
+ @Test
+ public void noEdge() {
+ Set<Path> paths = service.getPaths(hid("12:34:56:78:90:ab/1"),
+ hid("12:34:56:78:90:ef/1"));
+ assertTrue("there should be no paths", paths.isEmpty());
+ }
+
+ // Makes sure the set of paths meets basic expectations.
+ private void validatePaths(Set<Path> paths, int count, int length,
+ ElementId src, ElementId dst) {
+ assertEquals("incorrect path count", count, paths.size());
+ for (Path path : paths) {
+ assertEquals("incorrect length", length, path.links().size());
+ assertEquals("incorrect source", src, path.src().elementId());
+ assertEquals("incorrect destination", dst, path.dst().elementId());
+ }
+ }
+
+ // Fake entity to give out paths.
+ private class FakeTopoMgr extends TopologyServiceAdapter implements TopologyService {
+ Set<Path> paths = new HashSet<>();
+
+ @Override
+ public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst) {
+ return paths;
+ }
+
+ @Override
+ public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeight weight) {
+ return paths;
+ }
+ }
+
+ // Fake entity to give out hosts.
+ private class FakeHostMgr extends HostServiceAdapter implements HostService {
+ private Map<HostId, Host> hosts = new HashMap<>();
+
+ @Override
+ public Host getHost(HostId hostId) {
+ return hosts.get(hostId);
+ }
+ }
+
+}
diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
new file mode 100644
index 00000000..f3cd28df
--- /dev/null
+++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed 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.onosproject.net.topology.impl;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.event.Event;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Device;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.net.topology.DefaultGraphDescription;
+import org.onosproject.net.topology.GraphDescription;
+import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.Topology;
+import org.onosproject.net.topology.TopologyCluster;
+import org.onosproject.net.topology.TopologyEvent;
+import org.onosproject.net.topology.TopologyGraph;
+import org.onosproject.net.topology.TopologyListener;
+import org.onosproject.net.topology.TopologyProvider;
+import org.onosproject.net.topology.TopologyProviderRegistry;
+import org.onosproject.net.topology.TopologyProviderService;
+import org.onosproject.net.topology.TopologyService;
+import org.onosproject.store.trivial.SimpleTopologyStore;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.collect.ImmutableSet.of;
+import static org.junit.Assert.*;
+import static org.onosproject.net.NetTestTools.*;
+import static org.onosproject.net.PortNumber.portNumber;
+import static org.onosproject.net.topology.ClusterId.clusterId;
+import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED;
+
+/**
+ * Test of the topology subsystem.
+ */
+public class TopologyManagerTest {
+
+ private static final ProviderId PID = new ProviderId("of", "foo");
+
+ private TopologyManager mgr;
+
+ protected TopologyService service;
+ protected TopologyProviderRegistry registry;
+ protected TopologyProviderService providerService;
+ protected TestProvider provider;
+ protected TestListener listener = new TestListener();
+
+ @Before
+ public void setUp() {
+ mgr = new TopologyManager();
+ service = mgr;
+ registry = mgr;
+
+ mgr.store = new SimpleTopologyStore();
+ injectEventDispatcher(mgr, new TestEventDispatcher());
+ mgr.activate();
+
+ service.addListener(listener);
+
+ provider = new TestProvider();
+ providerService = registry.register(provider);
+
+ assertTrue("provider should be registered",
+ registry.getProviders().contains(provider.id()));
+ }
+
+ @After
+ public void tearDown() {
+ mgr.deactivate();
+ service.removeListener(listener);
+ }
+
+ @Test
+ public void basics() {
+ Topology topology = service.currentTopology();
+ assertNull("no topo expected", topology);
+ submitTopologyGraph();
+ validateEvents(TOPOLOGY_CHANGED);
+ topology = service.currentTopology();
+ assertTrue("should be latest", service.isLatest(topology));
+
+ submitTopologyGraph();
+ validateEvents(TOPOLOGY_CHANGED);
+ assertFalse("should be latest", service.isLatest(topology));
+ }
+
+ private void submitTopologyGraph() {
+ Set<Device> devices = of(device("a"), device("b"),
+ device("c"), device("d"),
+ device("e"), device("f"));
+ Set<Link> links = of(link("a", 1, "b", 1), link("b", 1, "a", 1),
+ link("b", 2, "c", 1), link("c", 1, "b", 2),
+ link("c", 2, "d", 1), link("d", 1, "c", 2),
+ link("d", 2, "a", 2), link("a", 2, "d", 2),
+ link("e", 1, "f", 1), link("f", 1, "e", 1));
+ GraphDescription data = new DefaultGraphDescription(4321L, devices, links);
+ providerService.topologyChanged(data, null);
+ }
+
+ @Test
+ public void clusters() {
+ submitTopologyGraph();
+ Topology topology = service.currentTopology();
+ assertNotNull("topo expected", topology);
+ assertEquals("wrong cluster count", 2, topology.clusterCount());
+ assertEquals("wrong device count", 6, topology.deviceCount());
+ assertEquals("wrong link count", 10, topology.linkCount());
+
+ assertEquals("wrong cluster count", 2, service.getClusters(topology).size());
+
+ TopologyCluster cluster = service.getCluster(topology, clusterId(0));
+ assertEquals("wrong device count", 4, cluster.deviceCount());
+ assertEquals("wrong device count", 4, service.getClusterDevices(topology, cluster).size());
+ assertEquals("wrong link count", 8, cluster.linkCount());
+ assertEquals("wrong link count", 8, service.getClusterLinks(topology, cluster).size());
+ }
+
+ @Test
+ public void structure() {
+ submitTopologyGraph();
+ Topology topology = service.currentTopology();
+
+ assertTrue("should be infrastructure point",
+ service.isInfrastructure(topology, new ConnectPoint(did("a"), portNumber(1))));
+ assertFalse("should not be infrastructure point",
+ service.isInfrastructure(topology, new ConnectPoint(did("a"), portNumber(3))));
+
+ assertTrue("should be broadcast point",
+ service.isBroadcastPoint(topology, new ConnectPoint(did("a"), portNumber(3))));
+ }
+
+ @Test
+ public void graph() {
+ submitTopologyGraph();
+ Topology topology = service.currentTopology();
+ TopologyGraph graph = service.getGraph(topology);
+ assertEquals("wrong vertex count", 6, graph.getVertexes().size());
+ assertEquals("wrong edge count", 10, graph.getEdges().size());
+ }
+
+ @Test
+ public void precomputedPath() {
+ submitTopologyGraph();
+ Topology topology = service.currentTopology();
+ Set<Path> paths = service.getPaths(topology, did("a"), did("c"));
+ assertEquals("wrong path count", 2, paths.size());
+ Path path = paths.iterator().next();
+ assertEquals("wrong path length", 2, path.links().size());
+ assertEquals("wrong path cost", 2, path.cost(), 0.01);
+ }
+
+ @Test
+ public void onDemandPath() {
+ submitTopologyGraph();
+ Topology topology = service.currentTopology();
+ LinkWeight weight = edge -> 3.3;
+
+ Set<Path> paths = service.getPaths(topology, did("a"), did("c"), weight);
+ assertEquals("wrong path count", 2, paths.size());
+ Path path = paths.iterator().next();
+ assertEquals("wrong path length", 2, path.links().size());
+ assertEquals("wrong path cost", 6.6, path.cost(), 0.01);
+ }
+
+ protected void validateEvents(Enum... types) {
+ int i = 0;
+ assertEquals("wrong events received", types.length, listener.events.size());
+ for (Event event : listener.events) {
+ assertEquals("incorrect event type", types[i], event.type());
+ i++;
+ }
+ listener.events.clear();
+ }
+
+ private class TestProvider extends AbstractProvider implements TopologyProvider {
+ public TestProvider() {
+ super(PID);
+ }
+
+ @Override
+ public void triggerRecompute() {
+ }
+ }
+
+ private static class TestListener implements TopologyListener {
+ final List<TopologyEvent> events = new ArrayList<>();
+
+ @Override
+ public void event(TopologyEvent event) {
+ events.add(event);
+ }
+ }
+
+}