Implement IntentCompilers
For the following Intent types
- PointToPointIntent
- PathIntent
- MultiPointToSinglePointIntent
This resolves ONOS-1657, ONOS-1659, and ONOS-1660.
Change-Id: I7c68cec4b025a59f9c97bae4488801bea2716baf
diff --git a/src/main/java/net/onrc/onos/core/newintent/AbstractFlowGeneratingIntentCompiler.java b/src/main/java/net/onrc/onos/core/newintent/AbstractFlowGeneratingIntentCompiler.java
new file mode 100644
index 0000000..07041e9
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/AbstractFlowGeneratingIntentCompiler.java
@@ -0,0 +1,41 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.flowmanager.FlowId;
+import net.onrc.onos.api.flowmanager.FlowIdGenerator;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.IntentIdGenerator;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A base class of {@link net.onrc.onos.api.newintent.IntentCompiler},
+ * which generates Flow objects.
+ * @param <T>
+ */
+public abstract class AbstractFlowGeneratingIntentCompiler<T extends Intent>
+ extends AbstractIntentCompiler<T> {
+
+ private final FlowIdGenerator flowIdGenerator;
+
+ /**
+ * Constructs an object with the specified {@link IntentIdGenerator}
+ * and {@link FlowIdGenerator}.
+ *
+ * @param intentIdGenerator
+ * @param flowIdGenerator
+ */
+ protected AbstractFlowGeneratingIntentCompiler(IntentIdGenerator intentIdGenerator,
+ FlowIdGenerator flowIdGenerator) {
+ super(intentIdGenerator);
+ this.flowIdGenerator = checkNotNull(flowIdGenerator);
+ }
+
+ /**
+ * Returns the next {@link FlowId}.
+ *
+ * @return the next {@link FlowId}
+ */
+ protected FlowId getNextFlowId() {
+ return flowIdGenerator.getNewId();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/AbstractIntentCompiler.java b/src/main/java/net/onrc/onos/core/newintent/AbstractIntentCompiler.java
new file mode 100644
index 0000000..0b16f10
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/AbstractIntentCompiler.java
@@ -0,0 +1,54 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.newintent.ConnectivityIntent;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.IntentCompiler;
+import net.onrc.onos.api.newintent.IntentId;
+import net.onrc.onos.api.newintent.IntentIdGenerator;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.Actions;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.util.SwitchPort;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A base IntentCompiler implementation.
+ * @param <T> the type of intent
+ */
+public abstract class AbstractIntentCompiler<T extends Intent> implements IntentCompiler<T> {
+ private final IntentIdGenerator idGenerator;
+
+ /**
+ * Constructs an instance with the specified Intent ID generator.
+ * <p>
+ * Intent compiler generates intents from an input intent.
+ * To make sure to use unique IDs for generated intents, intent
+ * ID generator is given as the argument of a constructor in normal
+ * cases.
+ * </p>
+ * @param idGenerator intent ID generator
+ */
+ protected AbstractIntentCompiler(IntentIdGenerator idGenerator) {
+ this.idGenerator = checkNotNull(idGenerator);
+ }
+
+ protected IntentId getNextId() {
+ return idGenerator.getNewId();
+ }
+
+ protected List<Action> packActions(ConnectivityIntent intent, SwitchPort egress) {
+ List<Action> actions = new ArrayList<>();
+ Action intentAction = intent.getAction();
+ if (!intentAction.equals(Actions.nullAction())) {
+ actions.add(intentAction);
+ }
+
+ OutputAction output = new OutputAction(egress.getPortNumber());
+ actions.add(output);
+ return actions;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/IntentCompilationException.java b/src/main/java/net/onrc/onos/core/newintent/IntentCompilationException.java
new file mode 100644
index 0000000..23e7c72
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/IntentCompilationException.java
@@ -0,0 +1,22 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.newintent.IntentException;
+
+/**
+ * An exception thrown when a intent compilation fails.
+ */
+public class IntentCompilationException extends IntentException {
+ private static final long serialVersionUID = 235237603018210810L;
+
+ public IntentCompilationException() {
+ super();
+ }
+
+ public IntentCompilationException(String message) {
+ super(message);
+ }
+
+ public IntentCompilationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/MultiPointToSinglePointIntentCompiler.java b/src/main/java/net/onrc/onos/core/newintent/MultiPointToSinglePointIntentCompiler.java
new file mode 100644
index 0000000..eb31457
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/MultiPointToSinglePointIntentCompiler.java
@@ -0,0 +1,111 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.flowmanager.FlowIdGenerator;
+import net.onrc.onos.api.flowmanager.SingleDstTreeFlow;
+import net.onrc.onos.api.flowmanager.Tree;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.IntentIdGenerator;
+import net.onrc.onos.api.newintent.MultiPointToSinglePointIntent;
+import net.onrc.onos.core.intent.ConstrainedBFSTree;
+import net.onrc.onos.core.intent.Path;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
+import net.onrc.onos.core.topology.BaseTopology;
+import net.onrc.onos.core.topology.ITopologyService;
+import net.onrc.onos.core.topology.Switch;
+import net.onrc.onos.core.util.SwitchPort;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static net.onrc.onos.core.newintent.PointToPointIntentCompiler.convertPath;
+
+/**
+ * An intent compiler for {@link MultiPointToSinglePointIntent}.
+ */
+public class MultiPointToSinglePointIntentCompiler
+ extends AbstractFlowGeneratingIntentCompiler<MultiPointToSinglePointIntent> {
+
+ private final ITopologyService topologyService;
+
+ /**
+ * Constructs an intent compiler for {@link MultiPointToSinglePointIntent}.
+ *
+ * @param intentIdGenerator intent ID generator
+ * @param flowIdGenerator flow ID generator
+ * @param topologyService topology service
+ */
+ public MultiPointToSinglePointIntentCompiler(IntentIdGenerator intentIdGenerator,
+ FlowIdGenerator flowIdGenerator,
+ ITopologyService topologyService) {
+ super(intentIdGenerator, flowIdGenerator);
+ this.topologyService = checkNotNull(topologyService);
+ }
+
+ @Override
+ public List<Intent> compile(MultiPointToSinglePointIntent intent) {
+ Match match = intent.getMatch();
+ if (!(match instanceof PacketMatch)) {
+ throw new IntentCompilationException(
+ "intent has unsupported type of match object: " + match
+ );
+ }
+
+ SingleDstTreeFlow treeFlow = new SingleDstTreeFlow(
+ getNextFlowId(),
+ (PacketMatch) intent.getMatch(), // down-cast, but it is safe due to the guard above
+ intent.getIngressPorts(),
+ calculateTree(intent.getIngressPorts(), intent.getEgressPort()),
+ packActions(intent, intent.getEgressPort())
+ );
+ Intent compiled = new SingleDstTreeFlowIntent(getNextId(), treeFlow);
+ return Arrays.asList(compiled);
+ }
+
+ /**
+ * Calculates a tree with the specified ingress ports and egress port.
+ *
+ * {@link PathNotFoundException} is thrown when no tree found or
+ * the specified egress port is not found in the topology.
+ *
+ * @param ingressPorts ingress ports
+ * @param egressPort egress port
+ * @return tree
+ * @throws PathNotFoundException if the specified egress switch is not
+ * found or no tree is found.
+ */
+ private Tree calculateTree(Set<SwitchPort> ingressPorts, SwitchPort egressPort) {
+ BaseTopology topology = topologyService.getTopology();
+ Switch egressSwitch = topology.getSwitch(egressPort.getDpid());
+ if (egressSwitch == null) {
+ throw new PathNotFoundException("destination switch not found: " + egressPort.getDpid());
+ }
+
+ ConstrainedBFSTree bfs = new ConstrainedBFSTree(egressSwitch);
+ Tree tree = new Tree();
+
+ for (SwitchPort ingressPort: ingressPorts) {
+ Switch ingressSwitch = topology.getSwitch(ingressPort.getDpid());
+ if (ingressSwitch == null) {
+ continue;
+ }
+
+ Path path = bfs.getPath(ingressSwitch);
+ if (path.isEmpty()) {
+ continue;
+ }
+
+ tree.addAll(convertPath(path));
+ }
+
+ if (tree.isEmpty()) {
+ throw new PathNotFoundException(
+ String.format("No tree found (ingress: %s, egress: %s", ingressPorts, egressPort)
+ );
+ }
+
+ return tree;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/PathIntentCompiler.java b/src/main/java/net/onrc/onos/core/newintent/PathIntentCompiler.java
new file mode 100644
index 0000000..e7e2f87
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/PathIntentCompiler.java
@@ -0,0 +1,82 @@
+package net.onrc.onos.core.newintent;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import net.onrc.onos.api.flowmanager.FlowIdGenerator;
+import net.onrc.onos.api.flowmanager.FlowLink;
+import net.onrc.onos.api.flowmanager.PacketPathFlow;
+import net.onrc.onos.api.flowmanager.Path;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.IntentIdGenerator;
+import net.onrc.onos.api.newintent.PathIntent;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
+import net.onrc.onos.core.util.LinkTuple;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * An intent compiler for {@link PathIntent}.
+ */
+public class PathIntentCompiler
+ extends AbstractFlowGeneratingIntentCompiler<PathIntent> {
+
+ /**
+ * Construct an {@link net.onrc.onos.api.newintent.IntentCompiler}
+ * for {@link PathIntent}.
+ *
+ * @param intentIdGenerator intent ID generator
+ * @param flowIdGenerator flow ID generator
+ */
+ public PathIntentCompiler(IntentIdGenerator intentIdGenerator,
+ FlowIdGenerator flowIdGenerator) {
+ super(intentIdGenerator, flowIdGenerator);
+ }
+
+ @Override
+ public List<Intent> compile(PathIntent intent) {
+ Match match = intent.getMatch();
+ if (!(match instanceof PacketMatch)) {
+ throw new IntentCompilationException(
+ "intent has unsupported type of match object: " + match
+ );
+ }
+
+ Path path = convertPath(intent.getPath());
+ PacketPathFlow flow = new PacketPathFlow(
+ getNextFlowId(),
+ (PacketMatch) match,
+ intent.getIngressPort().getPortNumber(),
+ path,
+ packActions(intent, intent.getEgressPort()),
+ 0, 0
+ );
+ Intent compiled = new PathFlowIntent(getNextId(), flow);
+ return Arrays.asList(compiled);
+ }
+
+ /**
+ * Converts list of {@link LinkTuple LinkTuples} to a {@link Path}.
+ *
+ * @param tuples original list of {@link LinkTuple LinkTuples}
+ * @return converted {@link Path}
+ */
+ private Path convertPath(List<LinkTuple> tuples) {
+ // would like to use filter and transform, but Findbugs detects
+ // inconsistency of use of @Nullable annotation. Then, use of the
+ // transform is avoided.
+ // Ref: https://code.google.com/p/guava-libraries/issues/detail?id=1812
+ // TODO: replace with transform when the above issue is resolved
+ ImmutableList<LinkTuple> links = FluentIterable.from(tuples)
+ .filter(Predicates.notNull())
+ .toList();
+
+ Path path = new Path();
+ for (LinkTuple link: links) {
+ path.add(new FlowLink(link.getSrc(), link.getDst()));
+ }
+ return path;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/PathNotFoundException.java b/src/main/java/net/onrc/onos/core/newintent/PathNotFoundException.java
new file mode 100644
index 0000000..f08636e
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/PathNotFoundException.java
@@ -0,0 +1,22 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.newintent.IntentException;
+
+/**
+ * An exception thrown when a path is not found.
+ */
+public class PathNotFoundException extends IntentException {
+ private static final long serialVersionUID = -2087045731049914733L;
+
+ public PathNotFoundException() {
+ super();
+ }
+
+ public PathNotFoundException(String message) {
+ super(message);
+ }
+
+ public PathNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/PointToPointIntentCompiler.java b/src/main/java/net/onrc/onos/core/newintent/PointToPointIntentCompiler.java
new file mode 100644
index 0000000..fcf718d
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/PointToPointIntentCompiler.java
@@ -0,0 +1,117 @@
+package net.onrc.onos.core.newintent;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import net.onrc.onos.api.flowmanager.FlowId;
+import net.onrc.onos.api.flowmanager.FlowIdGenerator;
+import net.onrc.onos.api.flowmanager.FlowLink;
+import net.onrc.onos.api.flowmanager.PacketPathFlow;
+import net.onrc.onos.api.flowmanager.Path;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.IntentIdGenerator;
+import net.onrc.onos.api.newintent.PointToPointIntent;
+import net.onrc.onos.core.intent.ConstrainedBFSTree;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatch;
+import net.onrc.onos.core.topology.BaseTopology;
+import net.onrc.onos.core.topology.ITopologyService;
+import net.onrc.onos.core.topology.LinkEvent;
+import net.onrc.onos.core.topology.Switch;
+import net.onrc.onos.core.util.SwitchPort;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A intent compiler for {@link PointToPointIntent}.
+ */
+public class PointToPointIntentCompiler
+ extends AbstractFlowGeneratingIntentCompiler<PointToPointIntent> {
+
+ private final ITopologyService topologyService;
+
+ /**
+ * Constructs an intent compiler for {@link PointToPointIntent} with the specified
+ * ID generator and topology service.
+ *
+ * @param intentIdGenerator intent ID generator
+ * @param topologyService topology service
+ */
+ public PointToPointIntentCompiler(IntentIdGenerator intentIdGenerator,
+ FlowIdGenerator flowIdGenerator,
+ ITopologyService topologyService) {
+ super(intentIdGenerator, flowIdGenerator);
+ this.topologyService = checkNotNull(topologyService);
+ }
+
+ @Override
+ public List<Intent> compile(PointToPointIntent intent) {
+ Match match = intent.getMatch();
+ if (!(match instanceof PacketMatch)) {
+ throw new IntentCompilationException(
+ "intent has unsupported type of match object: " + match
+ );
+ }
+
+ SwitchPort ingress = intent.getIngressPort();
+ SwitchPort egress = intent.getEgressPort();
+ FlowId flowId = getNextFlowId();
+ Path path = calculatePath(ingress, egress);
+
+ List<Action> actions = packActions(intent, intent.getEgressPort());
+
+ PacketPathFlow flow = new PacketPathFlow(flowId, (PacketMatch) match,
+ ingress.getPortNumber(), path, actions, 0, 0);
+ return Arrays.asList((Intent) new PathFlowIntent(getNextId(), flow));
+ }
+
+ /**
+ * Calculates a path between the specified ingress port and the specified egress port.
+ * @param ingress ingress port
+ * @param egress egress port
+ * @return path
+ */
+ private Path calculatePath(SwitchPort ingress, SwitchPort egress) {
+ BaseTopology topology = topologyService.getTopology();
+ Switch source = topology.getSwitch(ingress.getDpid());
+ Switch destination = topology.getSwitch(egress.getDpid());
+
+ if (source == null) {
+ throw new PathNotFoundException("source switch not found: " + ingress.getDpid());
+ }
+ if (destination == null) {
+ throw new PathNotFoundException("destination switch not found: " + egress.getDpid());
+ }
+
+ ConstrainedBFSTree tree = new ConstrainedBFSTree(source);
+ net.onrc.onos.core.intent.Path path = tree.getPath(destination);
+ return convertPath(path);
+ }
+
+ /**
+ * Converts a {@link net.onrc.onos.core.intent.Path} to {@link Path}.
+ *
+ * @param path original {@link net.onrc.onos.core.intent.Path}
+ * @return converted {@link Path}
+ */
+ static Path convertPath(net.onrc.onos.core.intent.Path path) {
+ // would like to use filter and transform, but Findbugs detects
+ // inconsistency of use of @Nullable annotation. Then, use of the
+ // transform is avoided.
+ // Ref: https://code.google.com/p/guava-libraries/issues/detail?id=1812
+ // TODO: replace with transform when the above issue is resolved
+ ImmutableList<LinkEvent> events = FluentIterable.from(path)
+ .filter(Predicates.notNull())
+ .toList();
+
+ Path converted = new Path();
+ for (LinkEvent event: events) {
+ converted.add(new FlowLink(event.getSrc(), event.getDst()));
+ }
+ return converted;
+ }
+}
diff --git a/src/test/java/net/onrc/onos/core/newintent/IntentCompilerTest.java b/src/test/java/net/onrc/onos/core/newintent/IntentCompilerTest.java
new file mode 100644
index 0000000..f70e6d2
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/newintent/IntentCompilerTest.java
@@ -0,0 +1,65 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.flowmanager.FlowId;
+import net.onrc.onos.api.flowmanager.FlowIdGenerator;
+import net.onrc.onos.api.newintent.IntentId;
+import net.onrc.onos.api.newintent.IntentIdGenerator;
+import net.onrc.onos.core.topology.BaseTopology;
+import net.onrc.onos.core.topology.ITopologyService;
+import net.onrc.onos.core.topology.MockTopology;
+import net.onrc.onos.core.topology.MutableTopology;
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.PortNumber;
+import org.junit.Before;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
+/**
+ * A base test class for intent compiler aggregating
+ * common set up logic and variables.
+ */
+public class IntentCompilerTest {
+ protected final IntentId intentId1 = new IntentId(1L);
+ protected final IntentId intentId2 = new IntentId(2L);
+ protected final FlowId flowId = new FlowId(1L);
+ protected final Dpid dpid1 = new Dpid(1L);
+ protected final Dpid dpid2 = new Dpid(2L);
+ protected final Dpid dpid3 = new Dpid(3L);
+ protected final Dpid dpid4 = new Dpid(4L);
+ protected final PortNumber port1h = PortNumber.uint32(15);
+ protected final PortNumber port12 = PortNumber.uint32(12);
+ protected final PortNumber port14 = PortNumber.uint32(14);
+ protected final PortNumber port3h = PortNumber.uint32(35);
+ protected final PortNumber port32 = PortNumber.uint32(32);
+ protected final PortNumber port21 = PortNumber.uint32(21);
+ protected final PortNumber port23 = PortNumber.uint32(23);
+ protected final PortNumber port41 = PortNumber.uint32(41);
+ protected final PortNumber port43 = PortNumber.uint32(43);
+ protected IntentIdGenerator intentIdGenerator;
+ protected FlowIdGenerator flowIdGenerator;
+ protected ITopologyService topologyService;
+
+ @Before
+ public void commonSetUp() {
+ intentIdGenerator = createMock(IntentIdGenerator.class);
+ flowIdGenerator = createMock(FlowIdGenerator.class);
+ topologyService = createMock(ITopologyService.class);
+
+ // configure mocks
+ expect(intentIdGenerator.getNewId())
+ .andReturn(intentId1)
+ .andReturn(intentId2);
+ expect(flowIdGenerator.getNewId()).andReturn(flowId);
+ expect(topologyService.getTopology()).andReturn((MutableTopology) createFakeTopology());
+ replay(intentIdGenerator, flowIdGenerator, topologyService);
+ }
+
+ protected BaseTopology createFakeTopology() {
+ MockTopology mock = new MockTopology();
+ mock.createSampleTopology2();
+
+ return mock;
+ }
+}
diff --git a/src/test/java/net/onrc/onos/core/newintent/MultiPointToSinglePointIntentCompilerTest.java b/src/test/java/net/onrc/onos/core/newintent/MultiPointToSinglePointIntentCompilerTest.java
new file mode 100644
index 0000000..6795d72
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/newintent/MultiPointToSinglePointIntentCompilerTest.java
@@ -0,0 +1,78 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.flowmanager.FlowLink;
+import net.onrc.onos.api.flowmanager.SingleDstTreeFlow;
+import net.onrc.onos.api.flowmanager.Tree;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.MultiPointToSinglePointIntent;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.Actions;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
+import net.onrc.onos.core.util.SwitchPort;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Suites of test of {@link MultiPointToSinglePointIntentCompiler}.
+ */
+public class MultiPointToSinglePointIntentCompilerTest extends IntentCompilerTest {
+
+ private MultiPointToSinglePointIntentCompiler sut;
+
+ @Before
+ public void setUp() {
+ sut = new MultiPointToSinglePointIntentCompiler(
+ intentIdGenerator,
+ flowIdGenerator,
+ topologyService
+ );
+ }
+
+ /**
+ * Checks the compilation result.
+ */
+ @Test
+ public void testCompilation() {
+ MultiPointToSinglePointIntent intent = new MultiPointToSinglePointIntent(
+ intentIdGenerator.getNewId(),
+ new PacketMatchBuilder().build(),
+ Actions.nullAction(),
+ new HashSet<>(Arrays.asList(
+ new SwitchPort(dpid4, port43),
+ new SwitchPort(dpid2, port23)
+ )),
+ new SwitchPort(dpid1, port1h)
+ );
+ List<Intent> compiled = sut.compile(intent);
+
+ assertThat(compiled, hasSize(1));
+
+ SingleDstTreeFlowIntent lower = (SingleDstTreeFlowIntent) compiled.get(0);
+ assertTree(lower.getTree());
+ }
+
+ private void assertTree(SingleDstTreeFlow actual) {
+ assertThat(actual.getId(), is(flowId));
+ assertThat(actual.getIngressPorts(), hasSize(2));
+ assertThat(actual.getIngressPorts(), hasItems(new SwitchPort(dpid4, port43), new SwitchPort(dpid2, port23)));
+ assertThat(actual.getMatch(), is((Match) new PacketMatchBuilder().build()));
+ assertThat(actual.getEgressActions(), hasSize(1));
+ assertThat(actual.getEgressActions().get(0), is((Action) new OutputAction(port1h)));
+
+ Tree tree = new Tree();
+ tree.add(new FlowLink(dpid1, port14, dpid4, port41));
+ tree.add(new FlowLink(dpid1, port12, dpid2, port21));
+ assertThat(actual.getTree(), is(tree));
+ }
+}
diff --git a/src/test/java/net/onrc/onos/core/newintent/PathIntentCompilerTest.java b/src/test/java/net/onrc/onos/core/newintent/PathIntentCompilerTest.java
new file mode 100644
index 0000000..337cf33
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/newintent/PathIntentCompilerTest.java
@@ -0,0 +1,73 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.flowmanager.FlowLink;
+import net.onrc.onos.api.flowmanager.Path;
+import net.onrc.onos.api.flowmanager.PathFlow;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.PathIntent;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.Actions;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
+import net.onrc.onos.core.util.LinkTuple;
+import net.onrc.onos.core.util.SwitchPort;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Suites of test of {@link PathIntentCompiler}.
+ */
+public class PathIntentCompilerTest extends IntentCompilerTest {
+
+ private PathIntentCompiler sut;
+
+ @Before
+ public void setUp() {
+ sut = new PathIntentCompiler(intentIdGenerator, flowIdGenerator);
+ }
+
+ /**
+ * Checks the compilation result.
+ */
+ @Test
+ public void testCompilation() {
+ PathIntent intent = new PathIntent(
+ intentIdGenerator.getNewId(),
+ new PacketMatchBuilder().build(),
+ Actions.nullAction(),
+ new SwitchPort(dpid1, port1h),
+ new SwitchPort(dpid3, port3h),
+ Arrays.asList(
+ new LinkTuple(dpid1, port12, dpid2, port21),
+ new LinkTuple(dpid2, port23, dpid3, port32)
+ ));
+ List<Intent> compiled = sut.compile(intent);
+
+ assertThat(compiled, hasSize(1));
+
+ PathFlowIntent lower = (PathFlowIntent) compiled.get(0);
+ assertPathFlow(lower.getFlow());
+ }
+
+ private void assertPathFlow(PathFlow actual) {
+ assertThat(actual.getId(), is(flowId));
+ assertThat(actual.getIngressPortNumber(), is(port1h));
+ assertThat(actual.getMatch(), is((Match) new PacketMatchBuilder().build()));
+ assertThat(actual.getEgressActions(), hasSize(1));
+ assertThat(actual.getEgressActions().get(0), is((Action) new OutputAction(port3h)));
+
+ Path path = new Path(Arrays.asList(
+ new FlowLink(dpid1, port12, dpid2, port21),
+ new FlowLink(dpid2, port23, dpid3, port32)
+ ));
+ assertThat(actual.getPath(), is(path));
+ }
+}
diff --git a/src/test/java/net/onrc/onos/core/newintent/PointToPointIntentCompilerTest.java b/src/test/java/net/onrc/onos/core/newintent/PointToPointIntentCompilerTest.java
new file mode 100644
index 0000000..2327208
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/newintent/PointToPointIntentCompilerTest.java
@@ -0,0 +1,78 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.flowmanager.FlowLink;
+import net.onrc.onos.api.flowmanager.Path;
+import net.onrc.onos.api.flowmanager.PathFlow;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.PointToPointIntent;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.action.Actions;
+import net.onrc.onos.core.matchaction.action.OutputAction;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
+import net.onrc.onos.core.util.SwitchPort;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Suites of test of {@link PointToPointIntentCompiler}.
+ */
+public class PointToPointIntentCompilerTest extends IntentCompilerTest {
+
+ private PointToPointIntentCompiler sut;
+
+ @Before
+ public void setUp() {
+ sut = new PointToPointIntentCompiler(
+ intentIdGenerator,
+ flowIdGenerator,
+ topologyService
+ );
+ }
+
+ /**
+ * Checks the compilation result.
+ */
+ @Test
+ public void testCompilation() {
+ PointToPointIntent input = new PointToPointIntent(
+ intentIdGenerator.getNewId(),
+ new PacketMatchBuilder().build(),
+ Actions.nullAction(),
+ new SwitchPort(dpid1, port1h),
+ new SwitchPort(dpid3, port3h)
+ );
+ List<Intent> compiled = sut.compile(input);
+
+ assertThat(compiled, hasSize(1));
+
+ Intent one = compiled.get(0);
+ assertThat(one.getId(), is(intentId2));
+ assertThat(one, is(instanceOf(PathFlowIntent.class)));
+
+ PathFlowIntent lower = (PathFlowIntent) one;
+ assertPathFlow(lower.getFlow());
+ }
+
+ private void assertPathFlow(PathFlow actual) {
+ assertThat(actual.getId(), is(flowId));
+ assertThat(actual.getIngressPortNumber(), is(port1h));
+ assertThat(actual.getMatch(), is((Match) new PacketMatchBuilder().build()));
+ assertThat(actual.getEgressActions(), hasSize(1));
+ assertThat(actual.getEgressActions().get(0), is((Action) new OutputAction(port3h)));
+
+ Path path = new Path(Arrays.asList(
+ new FlowLink(dpid1, port12, dpid2, port21),
+ new FlowLink(dpid2, port23, dpid3, port32)
+ ));
+ assertThat(actual.getPath(), is(path));
+ }
+}