Return intent collection with details
Added backwards compatible flag to GET /intents/ to return full intent JSON.
Added GET /intents/application/{appId} to return application specifc intents.
Extended IntentService to include getIntentsByAppId(appId).
Removed hard-coded intent codec lookup in IntentWebResource.
Change-Id: I38e7b1dbd7669e654afe723f6ec3a4eb7a9af6fb
diff --git a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java
index f4c1137..475bf6e 100644
--- a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java
+++ b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java
@@ -16,6 +16,7 @@
package org.onosproject.incubator.net.virtual.impl;
+import com.google.common.collect.ImmutableSet;
import org.onlab.util.Tools;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
@@ -33,6 +34,7 @@
import org.onosproject.incubator.net.virtual.impl.intent.phase.VirtualIntentProcessPhase;
import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentProcessor;
import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentSkipped;
+import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
@@ -223,6 +225,18 @@
}
@Override
+ public Iterable<Intent> getIntentsByAppId(ApplicationId id) {
+ ImmutableSet.Builder<Intent> builder = ImmutableSet.builder();
+ for (Intent intent : intentStore.getIntents(networkId)) {
+ if (intent.appId().equals(id)) {
+ builder.add(intent);
+ }
+ }
+
+ return builder.build();
+ }
+
+ @Override
public void addPending(IntentData intentData) {
checkNotNull(intentData, INTENT_NULL);
//TODO we might consider further checking / assertions
diff --git a/core/api/src/main/java/org/onosproject/net/intent/IntentService.java b/core/api/src/main/java/org/onosproject/net/intent/IntentService.java
index 595e7e3..745d7f4 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/IntentService.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/IntentService.java
@@ -17,6 +17,7 @@
import com.google.common.annotations.Beta;
+import org.onosproject.core.ApplicationId;
import org.onosproject.event.ListenerService;
import java.util.List;
@@ -72,6 +73,14 @@
Iterable<Intent> getIntents();
/**
+ * Returns an iterable of all intents with this application ID.
+ *
+ * @param id the application ID to look up
+ * @return collection of intents
+ */
+ Iterable<Intent> getIntentsByAppId(ApplicationId id);
+
+ /**
* Adds an intent data object to the pending map for processing.
* <p>
* This method is intended to only be called by core components, not
diff --git a/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java b/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java
index e3e6277..870ad0b 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java
@@ -16,6 +16,7 @@
package org.onosproject.net.intent;
import com.google.common.collect.ImmutableMap;
+import org.onosproject.core.ApplicationId;
import java.util.ArrayList;
import java.util.Collections;
@@ -26,6 +27,7 @@
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
/**
* Fake implementation of the intent service to assist in developing tests of
@@ -179,6 +181,15 @@
}
@Override
+ public Set<Intent> getIntentsByAppId(ApplicationId id) {
+ return Collections.unmodifiableSet(
+ intents.values().stream()
+ .filter(intent -> intent.appId().equals(id))
+ .collect(Collectors.toSet())
+ );
+ }
+
+ @Override
public void addPending(IntentData intentData) {
throw new UnsupportedOperationException();
}
diff --git a/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java
index 8503447..17f489e 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java
@@ -16,6 +16,8 @@
package org.onosproject.net.intent;
+import org.onosproject.core.ApplicationId;
+
import java.util.List;
/**
@@ -43,6 +45,11 @@
}
@Override
+ public Iterable<Intent> getIntentsByAppId(ApplicationId id) {
+ return null;
+ }
+
+ @Override
public void addPending(IntentData intentData) {
}
diff --git a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
index 642830e..bdfa106 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
@@ -19,6 +19,7 @@
import com.google.common.collect.Sets;
import org.onlab.graph.ScalarWeight;
import org.onlab.graph.Weight;
+import org.onosproject.core.ApplicationId;
import org.onosproject.core.GroupId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultLink;
@@ -557,6 +558,12 @@
this.number = number;
}
+ public MockIntent(Long number, ApplicationId appId) {
+ super(appId, null, Collections.emptyList(),
+ Intent.DEFAULT_INTENT_PRIORITY, null);
+ this.number = number;
+ }
+
public MockIntent(Long number, Collection<NetworkResource> resources) {
super(NetTestTools.APP_ID, null, resources, Intent.DEFAULT_INTENT_PRIORITY, null);
this.number = number;
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
index 2b83fa8..da13b76 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
@@ -15,8 +15,10 @@
*/
package org.onosproject.net.intent.impl;
+import com.google.common.collect.ImmutableSet;
import org.onlab.util.Tools;
import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.core.IdGenerator;
import org.onosproject.event.AbstractListenerManager;
@@ -87,8 +89,7 @@
import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
import static org.onosproject.security.AppGuard.checkPermission;
-import static org.onosproject.security.AppPermission.Type.INTENT_READ;
-import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
+import static org.onosproject.security.AppPermission.Type.*;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -291,6 +292,20 @@
}
@Override
+ public Iterable<Intent> getIntentsByAppId(ApplicationId id) {
+ checkPermission(INTENT_READ);
+
+ ImmutableSet.Builder<Intent> builder = ImmutableSet.builder();
+ for (Intent intent : store.getIntents()) {
+ if (intent.appId().equals(id)) {
+ builder.add(intent);
+ }
+ }
+
+ return builder.build();
+ }
+
+ @Override
public void addPending(IntentData intentData) {
checkPermission(INTENT_WRITE);
checkNotNull(intentData, INTENT_NULL);
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
index 14fb380..db92800 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
@@ -32,6 +32,7 @@
import org.onosproject.common.event.impl.TestEventDispatcher;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.impl.TestCoreManager;
+import org.onosproject.net.NetTestTools;
import org.onosproject.net.NetworkResource;
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.flow.FlowRuleOperationsContext;
@@ -557,8 +558,8 @@
intents = Lists.newArrayList(service.getIntents());
assertThat(intents, hasSize(0));
- final MockIntent intent1 = new MockIntent(MockIntent.nextId());
- final MockIntent intent2 = new MockIntent(MockIntent.nextId());
+ final MockIntent intent1 = new MockIntent(MockIntent.nextId(), NetTestTools.APP_ID);
+ final MockIntent intent2 = new MockIntent(MockIntent.nextId(), NetTestTools.APP_ID_2);
listener.setLatch(2, Type.INSTALL_REQ);
listener.setLatch(2, Type.INSTALLED);
@@ -575,6 +576,15 @@
assertThat(intents, hasIntentWithId(intent1.id()));
assertThat(intents, hasIntentWithId(intent2.id()));
verifyState();
+
+ List<Intent> intentsAppId = Lists.newArrayList(service.getIntentsByAppId(NetTestTools.APP_ID));
+ assertThat(intentsAppId, hasSize(1));
+ assertThat(intentsAppId, hasIntentWithId(intent1.id()));
+
+ List<Intent> intentsAppId2 = Lists.newArrayList(service.getIntentsByAppId(NetTestTools.APP_ID_2));
+ assertThat(intentsAppId2, hasSize(1));
+ assertThat(intentsAppId2, hasIntentWithId(intent2.id()));
+ verifyState();
}
/**
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
index 297f70e..4a76749 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/IntentsWebResource.java
@@ -17,14 +17,11 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.JsonCodec;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRuleService;
-import org.onosproject.net.intent.SinglePointToMultiPointIntent;
-import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.net.intent.PointToPointIntent;
-import org.onosproject.net.intent.HostToHostIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.IntentEvent;
@@ -43,6 +40,7 @@
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@@ -53,6 +51,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -72,14 +71,7 @@
private static final int WITHDRAW_EVENT_TIMEOUT_SECONDS = 5;
private static final String APP_ID_NOT_FOUND = "Application Id not found";
- private static final String HOST_TO_HOST_INTENT = "HostToHostIntent";
- private static final String POINT_TO_POINT_INTENT = "PointToPointIntent";
- private static final String SINGLE_TO_MULTI_POINT_INTENT =
- "SinglePointToMultiPointIntent";
- private static final String MULTI_TO_SINGLE_POINT_INTENT =
- "MultiPointToSinglePointIntent";
-
- private static final String INTENT = "Intent";
+ private static final String INTENTS = "intents";
private static final String APP_ID = "appId";
private static final String ID = "id";
private static final String INTENT_PATHS = "paths";
@@ -90,17 +82,37 @@
private UriInfo uriInfo;
/**
+ * Returns the JSON codec for the specified intent.
+ *
+ * @param intent the intent instance
+ * @return JSON codec
+ */
+ public JsonCodec<Intent> codec(Intent intent) {
+ return Optional.ofNullable((JsonCodec<Intent>) codec(intent.getClass()))
+ .orElse(codec(Intent.class));
+ }
+
+ /**
* Gets all intents.
* Returns array containing all the intents in the system.
+ * @param detail flag to return full details of intents in list.
*
* @return 200 OK with array of all the intents in the system
* @onos.rsModel Intents
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
- public Response getIntents() {
+ public Response getIntents(@QueryParam("detail") boolean detail) {
+ ObjectNode root = null;
final Iterable<Intent> intents = get(IntentService.class).getIntents();
- final ObjectNode root = encodeArray(Intent.class, "intents", intents);
+ if (detail) {
+ root = mapper().createObjectNode();
+ ArrayNode intentsNode = root.putArray(INTENTS);
+ intents.forEach(intent -> intentsNode.add(codec(intent).encode(intent, this)));
+ } else {
+ root = encodeArray(Intent.class, INTENTS, intents);
+ }
+
return ok(root).build();
}
@@ -179,18 +191,37 @@
}
nullIsNotFound(intent, INTENT_NOT_FOUND);
- final ObjectNode root;
- if (intent instanceof HostToHostIntent) {
- root = codec(HostToHostIntent.class).encode((HostToHostIntent) intent, this);
- } else if (intent instanceof PointToPointIntent) {
- root = codec(PointToPointIntent.class).encode((PointToPointIntent) intent, this);
- } else if (intent instanceof SinglePointToMultiPointIntent) {
- root = codec(SinglePointToMultiPointIntent.class).encode((SinglePointToMultiPointIntent) intent, this);
- } else if (intent instanceof MultiPointToSinglePointIntent) {
- root = codec(MultiPointToSinglePointIntent.class).encode((MultiPointToSinglePointIntent) intent, this);
+ final ObjectNode root = codec(intent).encode(intent, this);
+
+ return ok(root).build();
+ }
+
+ /**
+ * Gets intents by application.
+ * Returns the intents specified by the application id.
+ * @param detail flag to return full details of intents in list.
+ *
+ * @param appId application identifier
+ * @return 200 OK with a collection of intents of given application id
+ * @onos.rsModel Intents
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("application/{appId}")
+ public Response getIntentsByAppId(@PathParam("appId") String appId, @QueryParam("detail") boolean detail) {
+ final ApplicationId app = get(CoreService.class).getAppId(appId);
+ nullIsNotFound(app, APP_ID_NOT_FOUND);
+
+ final Iterable<Intent> intents = get(IntentService.class).getIntentsByAppId(app);
+ ObjectNode root = null;
+ if (detail) {
+ root = mapper().createObjectNode();
+ ArrayNode intentsNode = root.putArray(INTENTS);
+ intents.forEach(intent -> intentsNode.add(codec(intent).encode(intent, this)));
} else {
- root = codec(Intent.class).encode(intent, this);
+ root = encodeArray(Intent.class, INTENTS, intents);
}
+
return ok(root).build();
}
@@ -230,17 +261,7 @@
List<Intent> installables =
intentService.getInstallableIntents(intent.key());
- if (intent instanceof HostToHostIntent) {
- root.put(INTENT_TYPE, HOST_TO_HOST_INTENT);
- } else if (intent instanceof PointToPointIntent) {
- root.put(INTENT_TYPE, POINT_TO_POINT_INTENT);
- } else if (intent instanceof SinglePointToMultiPointIntent) {
- root.put(INTENT_TYPE, SINGLE_TO_MULTI_POINT_INTENT);
- } else if (intent instanceof MultiPointToSinglePointIntent) {
- root.put(INTENT_TYPE, MULTI_TO_SINGLE_POINT_INTENT);
- } else {
- root.put(INTENT_TYPE, INTENT);
- }
+ root.put(INTENT_TYPE, intent.getClass().getSimpleName());
ArrayNode pathsNode = root.putArray(INTENT_PATHS);
diff --git a/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java b/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java
index 318f90d..7867ab6 100644
--- a/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java
+++ b/web/api/src/test/java/org/onosproject/rest/resources/IntentsResourceTest.java
@@ -39,6 +39,8 @@
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultLink;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.HostId;
import org.onosproject.net.Link;
import org.onosproject.net.NetworkResource;
import org.onosproject.net.PortNumber;
@@ -54,14 +56,17 @@
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.intent.ConnectivityIntent;
import org.onosproject.net.intent.FakeIntentManager;
import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.HostToHostIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.MockIdGenerator;
import org.onosproject.net.intent.PathIntent;
+import org.onosproject.net.intent.PointToPointIntent;
import org.onosproject.net.provider.ProviderId;
@@ -85,6 +90,7 @@
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
+import static org.onosproject.net.NetTestTools.hid;
import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
/**
@@ -116,6 +122,10 @@
final HashSet<Intent> intents = new HashSet<>();
final List<org.onosproject.net.intent.Intent> installableIntents = new ArrayList<>();
private static final ApplicationId APP_ID = new DefaultApplicationId(1, "test");
+ private static final ApplicationId APP_ID_2 = new DefaultApplicationId(2, "test2");
+
+ private final HostId hostId1 = hid("12:34:56:78:91:ab/1");
+ private final HostId hostId2 = hid("12:34:56:78:92:ab/1");
final DeviceId deviceId1 = DeviceId.deviceId("1");
final DeviceId deviceId2 = DeviceId.deviceId("2");
@@ -364,12 +374,18 @@
*/
public static class IntentJsonMatcher extends TypeSafeMatcher<JsonObject> {
private final Intent intent;
+ private boolean detail = false;
private String reason = "";
public IntentJsonMatcher(Intent intentValue) {
intent = intentValue;
}
+ public IntentJsonMatcher(Intent intentValue, boolean detailValue) {
+ intent = intentValue;
+ detail = detailValue;
+ }
+
@Override
public boolean matchesSafely(JsonObject jsonIntent) {
// check id
@@ -449,9 +465,139 @@
reason = "resources array empty";
return false;
}
+
+ if (intent instanceof ConnectivityIntent && detail) {
+ return matchConnectivityIntent(jsonIntent);
+ }
+
return true;
}
+ public boolean matchesConnectPoint(ConnectPoint connectPoint, JsonObject jsonConnectPoint) {
+ // check device
+ final String jsonDevice = jsonConnectPoint.get("device").asString();
+ final String device = connectPoint.deviceId().toString();
+ if (!jsonDevice.equals(device)) {
+ reason = "device was " + jsonDevice;
+ return false;
+ }
+
+ // check port
+ final String jsonPort = jsonConnectPoint.get("port").asString();
+ final String port = connectPoint.port().toString();
+ if (!jsonPort.equals(port)) {
+ reason = "port was " + jsonPort;
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean matchHostToHostIntent(JsonObject jsonIntent) {
+ final HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
+
+ // check host one
+ final String host1 = hostToHostIntent.one().toString();
+ final String jsonHost1 = jsonIntent.get("one").asString();
+ if (!host1.equals(jsonHost1)) {
+ reason = "host one was " + jsonHost1;
+ return false;
+ }
+
+ // check host 2
+ final String host2 = hostToHostIntent.two().toString();
+ final String jsonHost2 = jsonIntent.get("two").asString();
+ if (!host2.equals(jsonHost2)) {
+ reason = "host two was " + jsonHost2;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Matches the JSON representation of a point to point intent.
+ *
+ * @param jsonIntent JSON representation of the intent
+ * @return true if the JSON matches the intent, false otherwise
+ */
+ private boolean matchPointToPointIntent(JsonObject jsonIntent) {
+ final PointToPointIntent pointToPointIntent = (PointToPointIntent) intent;
+
+ // check ingress connection
+ final ConnectPoint ingress = pointToPointIntent.filteredIngressPoint().connectPoint();
+ final JsonObject jsonIngress = jsonIntent.get("ingressPoint").asObject();
+ final boolean ingressMatches = matchesConnectPoint(ingress, jsonIngress);
+
+ if (!ingressMatches) {
+ reason = "ingress was " + jsonIngress;
+ return false;
+ }
+
+ // check egress connection
+ final ConnectPoint egress = pointToPointIntent.filteredEgressPoint().connectPoint();
+ final JsonObject jsonEgress = jsonIntent.get("egressPoint").asObject();
+ final boolean egressMatches = matchesConnectPoint(egress, jsonEgress);
+
+ if (!egressMatches) {
+ reason = "egress was " + jsonEgress;
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Matches the JSON representation of a connectivity intent. Calls the
+ * matcher for the connectivity intent subtype.
+ *
+ * @param jsonIntent JSON representation of the intent
+ * @return true if the JSON matches the intent, false otherwise
+ */
+ private boolean matchConnectivityIntent(JsonObject jsonIntent) {
+ final ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent;
+
+ // check selector
+ final JsonObject jsonSelector = jsonIntent.get("selector").asObject();
+ final TrafficSelector selector = connectivityIntent.selector();
+ final Set<Criterion> criteria = selector.criteria();
+ final JsonArray jsonCriteria = jsonSelector.get("criteria").asArray();
+ if (jsonCriteria.size() != criteria.size()) {
+ reason = "size of criteria array is " + Integer.toString(jsonCriteria.size());
+ return false;
+ }
+
+ // check treatment
+ final JsonObject jsonTreatment = jsonIntent.get("treatment").asObject();
+ final TrafficTreatment treatment = connectivityIntent.treatment();
+ final List<Instruction> instructions = treatment.immediate();
+ final JsonArray jsonInstructions = jsonTreatment.get("instructions").asArray();
+ if (jsonInstructions.size() != instructions.size()) {
+ reason = "size of instructions array is " + Integer.toString(jsonInstructions.size());
+ return false;
+ }
+
+ // Check constraints
+ final JsonArray jsonConstraints = jsonIntent.get("constraints").asArray();
+ if (connectivityIntent.constraints() != null) {
+ if (connectivityIntent.constraints().size() != jsonConstraints.size()) {
+ reason = "constraints array size was " + Integer.toString(jsonConstraints.size());
+ return false;
+ }
+ } else if (jsonConstraints.size() != 0) {
+ reason = "constraint array not empty";
+ return false;
+ }
+
+ if (connectivityIntent instanceof HostToHostIntent) {
+ return matchHostToHostIntent(jsonIntent);
+ } else if (connectivityIntent instanceof PointToPointIntent) {
+ return matchPointToPointIntent(jsonIntent);
+ } else {
+ reason = "class of connectivity intent is unknown";
+ return false;
+ }
+ }
+
@Override
public void describeTo(Description description) {
description.appendText(reason);
@@ -462,10 +608,11 @@
* Factory to allocate an intent matcher.
*
* @param intent intent object we are looking for
+ * @param detail flag to verify if JSON contains detailed attributes for the intent's implementation class.
* @return matcher
*/
- private static IntentJsonMatcher matchesIntent(Intent intent) {
- return new IntentJsonMatcher(intent);
+ private static IntentJsonMatcher matchesIntent(Intent intent, boolean detail) {
+ return new IntentJsonMatcher(intent, detail);
}
/**
@@ -668,10 +815,12 @@
*/
public static class IntentJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
private final Intent intent;
+ private boolean detail = false;
private String reason = "";
- public IntentJsonArrayMatcher(Intent intentValue) {
+ public IntentJsonArrayMatcher(Intent intentValue, boolean detailValue) {
intent = intentValue;
+ detail = detailValue;
}
@Override
@@ -683,7 +832,7 @@
final JsonObject jsonIntent = json.get(jsonIntentIndex).asObject();
- if (jsonIntent.names().size() != expectedAttributes) {
+ if (jsonIntent.names().size() != expectedAttributes && !detail) {
reason = "Found an intent with the wrong number of attributes";
return false;
}
@@ -693,7 +842,7 @@
intentFound = true;
// We found the correct intent, check attribute values
- assertThat(jsonIntent, matchesIntent(intent));
+ assertThat(jsonIntent, matchesIntent(intent, detail));
}
}
if (!intentFound) {
@@ -714,10 +863,11 @@
* Factory to allocate an intent array matcher.
*
* @param intent intent object we are looking for
+ * @param detail flag to verify if JSON contains detailed attributes for the intent's implementation class.
* @return matcher
*/
- private static IntentJsonArrayMatcher hasIntent(Intent intent) {
- return new IntentJsonArrayMatcher(intent);
+ private static IntentJsonArrayMatcher hasIntent(Intent intent, boolean detail) {
+ return new IntentJsonArrayMatcher(intent, detail);
}
/**
@@ -793,8 +943,8 @@
final JsonArray jsonIntents = result.get("intents").asArray();
assertThat(jsonIntents, notNullValue());
- assertThat(jsonIntents, hasIntent(intent1));
- assertThat(jsonIntents, hasIntent(intent2));
+ assertThat(jsonIntents, hasIntent(intent1, false));
+ assertThat(jsonIntents, hasIntent(intent2, false));
}
/**
@@ -832,13 +982,282 @@
final String response = wt.path("intents/" + APP_ID.name()
+ "/0").request().get(String.class);
final JsonObject result = Json.parse(response).asObject();
- assertThat(result, matchesIntent(intent));
+ assertThat(result, matchesIntent(intent, true));
// Test get using numeric value
final String responseNumeric = wt.path("intents/" + APP_ID.name()
+ "/0x0").request().get(String.class);
final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
- assertThat(resultNumeric, matchesIntent(intent));
+ assertThat(resultNumeric, matchesIntent(intent, true));
+ }
+
+ /**
+ * Tests the result of the rest api GET when intents are defined and the detail flag is false.
+ */
+ @Test
+ public void testIntentsArrayWithoutDetail() {
+ replay(mockIntentService);
+
+ final PointToPointIntent intent1 =
+ PointToPointIntent.builder()
+ .appId(APP_ID)
+ .selector(selector1)
+ .treatment(treatment1)
+ .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
+ .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
+ .build();
+
+ final HashSet<NetworkResource> resources = new HashSet<>();
+ resources.add(new MockResource(1));
+ resources.add(new MockResource(2));
+ resources.add(new MockResource(3));
+
+ final HostToHostIntent intent2 =
+ HostToHostIntent.builder()
+ .appId(APP_ID)
+ .selector(selector2)
+ .treatment(treatment2)
+ .one(hostId1)
+ .two(hostId2)
+ .build();
+
+ intents.add(intent1);
+ intents.add(intent2);
+
+ final WebTarget wt = target();
+ final String response = wt.path("intents").queryParam("detail", false).request().get(String.class);
+ assertThat(response, containsString("{\"intents\":["));
+
+ final JsonObject result = Json.parse(response).asObject();
+ assertThat(result, notNullValue());
+
+ assertThat(result.names(), hasSize(1));
+ assertThat(result.names().get(0), is("intents"));
+
+ final JsonArray jsonIntents = result.get("intents").asArray();
+ assertThat(jsonIntents, notNullValue());
+
+ assertThat(jsonIntents, hasIntent(intent1, false));
+ }
+
+ /**
+ * Tests the result of the rest api GET when intents are defined and the detail flag is true.
+ */
+ @Test
+ public void testIntentsArrayWithDetail() {
+ replay(mockIntentService);
+
+ final PointToPointIntent intent1 =
+ PointToPointIntent.builder()
+ .appId(APP_ID)
+ .selector(selector1)
+ .treatment(treatment1)
+ .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
+ .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
+ .build();
+
+ final HashSet<NetworkResource> resources = new HashSet<>();
+ resources.add(new MockResource(1));
+ resources.add(new MockResource(2));
+ resources.add(new MockResource(3));
+
+ final HostToHostIntent intent2 =
+ HostToHostIntent.builder()
+ .appId(APP_ID)
+ .selector(selector2)
+ .treatment(treatment2)
+ .one(hostId1)
+ .two(hostId2)
+ .build();
+
+ intents.add(intent1);
+ intents.add(intent2);
+
+ final WebTarget wt = target();
+ final String response = wt.path("intents").queryParam("detail", true).request().get(String.class);
+ assertThat(response, containsString("{\"intents\":["));
+
+ final JsonObject result = Json.parse(response).asObject();
+ assertThat(result, notNullValue());
+
+ assertThat(result.names(), hasSize(1));
+ assertThat(result.names().get(0), is("intents"));
+
+ final JsonArray jsonIntents = result.get("intents").asArray();
+ assertThat(jsonIntents, notNullValue());
+
+ assertThat(jsonIntents, hasIntent(intent1, true));
+ }
+
+ /**
+ * Tests the result of the rest api GET when intents are defined.
+ */
+ @Test
+ public void testIntentsForApplicationWithoutDetail() {
+ final Intent intent1 =
+ PointToPointIntent.builder()
+ .key(Key.of(0, APP_ID))
+ .appId(APP_ID)
+ .selector(selector1)
+ .treatment(treatment1)
+ .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
+ .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
+ .build();
+
+ final HostToHostIntent intent2 =
+ HostToHostIntent.builder()
+ .key(Key.of(1, APP_ID_2))
+ .appId(APP_ID_2)
+ .selector(selector2)
+ .treatment(treatment2)
+ .one(hostId1)
+ .two(hostId2)
+ .build();
+
+ intents.add(intent1);
+ List<Intent> appIntents1 = new ArrayList<>();
+ appIntents1.add(intent1);
+
+ intents.add(intent2);
+ List<Intent> appIntents2 = new ArrayList<>();
+ appIntents2.add(intent2);
+
+ expect(mockIntentService.getIntentsByAppId(APP_ID))
+ .andReturn(appIntents1)
+ .anyTimes();
+ expect(mockIntentService.getIntentsByAppId(APP_ID_2))
+ .andReturn(appIntents2)
+ .anyTimes();
+ replay(mockIntentService);
+
+ expect(mockCoreService.getAppId(APP_ID.name()))
+ .andReturn(APP_ID).anyTimes();
+ expect(mockCoreService.getAppId(APP_ID_2.name()))
+ .andReturn(APP_ID_2).anyTimes();
+ replay(mockCoreService);
+
+
+ final WebTarget wt = target();
+ // Verify intents for app_id
+ final String response1 = wt.path("intents/application/" + APP_ID.name()).request().get(String.class);
+ assertThat(response1, containsString("{\"intents\":["));
+
+ final JsonObject result1 = Json.parse(response1).asObject();
+ assertThat(result1, notNullValue());
+
+ assertThat(result1.names(), hasSize(1));
+ assertThat(result1.names().get(0), is("intents"));
+
+ final JsonArray jsonIntents1 = result1.get("intents").asArray();
+ assertThat(jsonIntents1, notNullValue());
+ assertThat(jsonIntents1.size(), is(1));
+
+ assertThat(jsonIntents1, hasIntent(intent1, false));
+ assertThat(jsonIntents1, is(not(hasIntent(intent2, false))));
+
+ // Verify intents for app_id_2 with detail = false
+ final String response2 = wt.path("intents/application/" + APP_ID_2.name())
+ .queryParam("detail", false).request().get(String.class);
+ assertThat(response2, containsString("{\"intents\":["));
+
+ final JsonObject result2 = Json.parse(response2).asObject();
+ assertThat(result2, notNullValue());
+
+ assertThat(result2.names(), hasSize(1));
+ assertThat(result2.names().get(0), is("intents"));
+
+ final JsonArray jsonIntents2 = result2.get("intents").asArray();
+ assertThat(jsonIntents2, notNullValue());
+ assertThat(jsonIntents2.size(), is(1));
+
+ assertThat(jsonIntents2, hasIntent(intent2, false));
+ assertThat(jsonIntents2, is(not(hasIntent(intent1, false))));
+ }
+
+ /**
+ * Tests the result of the rest api GET when intents are defined and the detail flag is true.
+ */
+ @Test
+ public void testIntentsForApplicationWithDetail() {
+ final Intent intent1 =
+ PointToPointIntent.builder()
+ .key(Key.of(0, APP_ID))
+ .appId(APP_ID)
+ .selector(selector1)
+ .treatment(treatment1)
+ .filteredIngressPoint(new FilteredConnectPoint(connectPoint1))
+ .filteredEgressPoint(new FilteredConnectPoint(connectPoint2))
+ .build();
+
+ final HostToHostIntent intent2 =
+ HostToHostIntent.builder()
+ .key(Key.of(1, APP_ID_2))
+ .appId(APP_ID_2)
+ .selector(selector2)
+ .treatment(treatment2)
+ .one(hostId1)
+ .two(hostId2)
+ .build();
+
+ intents.add(intent1);
+ List<Intent> appIntents1 = new ArrayList<>();
+ appIntents1.add(intent1);
+
+ intents.add(intent2);
+ List<Intent> appIntents2 = new ArrayList<>();
+ appIntents2.add(intent2);
+
+ expect(mockIntentService.getIntentsByAppId(APP_ID))
+ .andReturn(appIntents1)
+ .anyTimes();
+ expect(mockIntentService.getIntentsByAppId(APP_ID_2))
+ .andReturn(appIntents2)
+ .anyTimes();
+ replay(mockIntentService);
+
+ expect(mockCoreService.getAppId(APP_ID.name()))
+ .andReturn(APP_ID).anyTimes();
+ expect(mockCoreService.getAppId(APP_ID_2.name()))
+ .andReturn(APP_ID_2).anyTimes();
+ replay(mockCoreService);
+
+
+ final WebTarget wt = target();
+ // Verify intents for app_id
+ final String response1 = wt.path("intents/application/" + APP_ID.name())
+ .queryParam("detail", true).request().get(String.class);
+ assertThat(response1, containsString("{\"intents\":["));
+
+ final JsonObject result1 = Json.parse(response1).asObject();
+ assertThat(result1, notNullValue());
+
+ assertThat(result1.names(), hasSize(1));
+ assertThat(result1.names().get(0), is("intents"));
+
+ final JsonArray jsonIntents1 = result1.get("intents").asArray();
+ assertThat(jsonIntents1, notNullValue());
+ assertThat(jsonIntents1.size(), is(1));
+
+ assertThat(jsonIntents1, hasIntent(intent1, true));
+ assertThat(jsonIntents1, is(not(hasIntent(intent2, true))));
+
+ // Verify intents for app_id_2
+ final String response2 = wt.path("intents/application/" + APP_ID_2.name())
+ .queryParam("detail", true).request().get(String.class);
+ assertThat(response2, containsString("{\"intents\":["));
+
+ final JsonObject result2 = Json.parse(response2).asObject();
+ assertThat(result2, notNullValue());
+
+ assertThat(result2.names(), hasSize(1));
+ assertThat(result2.names().get(0), is("intents"));
+
+ final JsonArray jsonIntents2 = result2.get("intents").asArray();
+ assertThat(jsonIntents2, notNullValue());
+ assertThat(jsonIntents2.size(), is(1));
+
+ assertThat(jsonIntents2, hasIntent(intent2, true));
+ assertThat(jsonIntents2, is(not(hasIntent(intent1, true))));
}
/**
@@ -975,13 +1394,13 @@
final String response = wt.path("intents/installables/" + APP_ID.name()
+ "/" + intentId).request().get(String.class);
final JsonObject result = Json.parse(response).asObject();
- assertThat(result.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent));
+ assertThat(result.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent, false));
// Test get using numeric value
final String responseNumeric = wt.path("intents/installables/" + APP_ID.name()
+ "/" + Long.toHexString(intentId)).request().get(String.class);
final JsonObject resultNumeric = Json.parse(responseNumeric).asObject();
- assertThat(resultNumeric.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent));
+ assertThat(resultNumeric.get(INSTALLABLES).asArray(), hasIntent(flowRuleIntent, false));
}
/**