aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java')
-rw-r--r--framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java512
1 files changed, 512 insertions, 0 deletions
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java
new file mode 100644
index 00000000..e485a5fa
--- /dev/null
+++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java
@@ -0,0 +1,512 @@
+/*
+ * 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.codec.impl;
+
+import java.util.List;
+import java.util.Set;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.NetworkResource;
+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.intent.ConnectivityIntent;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.HostToHostIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.constraint.AnnotationConstraint;
+import org.onosproject.net.intent.constraint.BandwidthConstraint;
+import org.onosproject.net.intent.constraint.LambdaConstraint;
+import org.onosproject.net.intent.constraint.LatencyConstraint;
+import org.onosproject.net.intent.constraint.LinkTypeConstraint;
+import org.onosproject.net.intent.constraint.ObstacleConstraint;
+import org.onosproject.net.intent.constraint.WaypointConstraint;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Hamcrest matcher to check that an intent representation in JSON matches
+ * the actual intent.
+ */
+public final class IntentJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final Intent intent;
+
+ /**
+ * Constructor is private, use factory method.
+ *
+ * @param intentValue the intent object to compare against
+ */
+ private IntentJsonMatcher(Intent intentValue) {
+ intent = intentValue;
+ }
+
+ /**
+ * Matches the JSON representation of a host to host intent.
+ *
+ * @param jsonIntent JSON representation of the intent
+ * @param description Description object used for recording errors
+ * @return true if the JSON matches the intent, false otherwise
+ */
+ private boolean matchHostToHostIntent(JsonNode jsonIntent, Description description) {
+ final HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
+
+ // check host one
+ final String host1 = hostToHostIntent.one().toString();
+ final String jsonHost1 = jsonIntent.get("one").asText();
+ if (!host1.equals(jsonHost1)) {
+ description.appendText("host one was " + jsonHost1);
+ return false;
+ }
+
+ // check host 2
+ final String host2 = hostToHostIntent.two().toString();
+ final String jsonHost2 = jsonIntent.get("two").asText();
+ if (!host2.equals(jsonHost2)) {
+ description.appendText("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
+ * @param description Description object used for recording errors
+ * @return true if the JSON matches the intent, false otherwise
+ */
+ private boolean matchPointToPointIntent(JsonNode jsonIntent, Description description) {
+ final PointToPointIntent pointToPointIntent = (PointToPointIntent) intent;
+
+ // check ingress connection
+ final ConnectPoint ingress = pointToPointIntent.ingressPoint();
+ final ConnectPointJsonMatcher ingressMatcher =
+ ConnectPointJsonMatcher.matchesConnectPoint(ingress);
+ final JsonNode jsonIngress = jsonIntent.get("ingressPoint");
+ final boolean ingressMatches =
+ ingressMatcher.matchesSafely(jsonIngress, description);
+
+ if (!ingressMatches) {
+ description.appendText("ingress was " + jsonIngress);
+ return false;
+ }
+
+ // check egress connection
+ final ConnectPoint egress = pointToPointIntent.egressPoint();
+ final ConnectPointJsonMatcher egressMatcher =
+ ConnectPointJsonMatcher.matchesConnectPoint(egress);
+ final JsonNode jsonEgress = jsonIntent.get("egressPoint");
+ final boolean egressMatches =
+ egressMatcher.matchesSafely(jsonEgress, description);
+
+ if (!egressMatches) {
+ description.appendText("egress was " + jsonEgress);
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Matches a bandwidth constraint against a JSON representation of the
+ * constraint.
+ *
+ * @param bandwidthConstraint constraint object to match
+ * @param constraintJson JSON representation of the constraint
+ * @return true if the constraint and JSON match, false otherwise.
+ */
+ private boolean matchBandwidthConstraint(BandwidthConstraint bandwidthConstraint,
+ JsonNode constraintJson) {
+ final JsonNode bandwidthJson = constraintJson.get("bandwidth");
+ return bandwidthJson != null
+ && constraintJson.get("bandwidth").asDouble()
+ == bandwidthConstraint.bandwidth().toDouble();
+ }
+
+ /**
+ * Matches a lamdba constraint against a JSON representation of the
+ * constraint.
+ *
+ * @param lambdaConstraint constraint object to match
+ * @param constraintJson JSON representation of the constraint
+ * @return true if the constraint and JSON match, false otherwise.
+ */
+ private boolean matchLambdaConstraint(LambdaConstraint lambdaConstraint,
+ JsonNode constraintJson) {
+ final JsonNode lambdaJson = constraintJson.get("lambda");
+ return lambdaJson != null
+ && constraintJson.get("lambda").asInt()
+ == lambdaConstraint.lambda().toInt();
+ }
+
+ /**
+ * Matches a link type constraint against a JSON representation of the
+ * constraint.
+ *
+ * @param linkTypeConstraint constraint object to match
+ * @param constraintJson JSON representation of the constraint
+ * @return true if the constraint and JSON match, false otherwise.
+ */
+ private boolean matchLinkTypeConstraint(LinkTypeConstraint linkTypeConstraint,
+ JsonNode constraintJson) {
+ final JsonNode inclusiveJson = constraintJson.get("inclusive");
+ final JsonNode typesJson = constraintJson.get("types");
+
+ if (typesJson.size() != linkTypeConstraint.types().size()) {
+ return false;
+ }
+
+ int foundType = 0;
+ for (Link.Type type : linkTypeConstraint.types()) {
+ for (int jsonIndex = 0; jsonIndex < typesJson.size(); jsonIndex++) {
+ if (type.name().equals(typesJson.get(jsonIndex).asText())) {
+ foundType++;
+ break;
+ }
+ }
+ }
+ return (inclusiveJson != null &&
+ inclusiveJson.asBoolean() == linkTypeConstraint.isInclusive()) &&
+ foundType == typesJson.size();
+ }
+
+ /**
+ * Matches an annotation constraint against a JSON representation of the
+ * constraint.
+ *
+ * @param annotationConstraint constraint object to match
+ * @param constraintJson JSON representation of the constraint
+ * @return true if the constraint and JSON match, false otherwise.
+ */
+ private boolean matchAnnotationConstraint(AnnotationConstraint annotationConstraint,
+ JsonNode constraintJson) {
+ final JsonNode keyJson = constraintJson.get("key");
+ final JsonNode thresholdJson = constraintJson.get("threshold");
+ return (keyJson != null
+ && keyJson.asText().equals(annotationConstraint.key())) &&
+ (thresholdJson != null
+ && thresholdJson.asDouble() == annotationConstraint.threshold());
+ }
+
+ /**
+ * Matches a latency constraint against a JSON representation of the
+ * constraint.
+ *
+ * @param latencyConstraint constraint object to match
+ * @param constraintJson JSON representation of the constraint
+ * @return true if the constraint and JSON match, false otherwise.
+ */
+ private boolean matchLatencyConstraint(LatencyConstraint latencyConstraint,
+ JsonNode constraintJson) {
+ final JsonNode latencyJson = constraintJson.get("latencyMillis");
+ return (latencyJson != null
+ && latencyJson.asInt() == latencyConstraint.latency().toMillis());
+ }
+
+ /**
+ * Matches an obstacle constraint against a JSON representation of the
+ * constraint.
+ *
+ * @param obstacleConstraint constraint object to match
+ * @param constraintJson JSON representation of the constraint
+ * @return true if the constraint and JSON match, false otherwise.
+ */
+ private boolean matchObstacleConstraint(ObstacleConstraint obstacleConstraint,
+ JsonNode constraintJson) {
+ final JsonNode obstaclesJson = constraintJson.get("obstacles");
+
+ if (obstaclesJson.size() != obstacleConstraint.obstacles().size()) {
+ return false;
+ }
+
+ for (int obstaclesIndex = 0; obstaclesIndex < obstaclesJson.size();
+ obstaclesIndex++) {
+ boolean obstacleFound = false;
+ final String obstacleJson = obstaclesJson.get(obstaclesIndex)
+ .asText();
+ for (DeviceId obstacle : obstacleConstraint.obstacles()) {
+ if (obstacle.toString().equals(obstacleJson)) {
+ obstacleFound = true;
+ }
+ }
+ if (!obstacleFound) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Matches a waypoint constraint against a JSON representation of the
+ * constraint.
+ *
+ * @param waypointConstraint constraint object to match
+ * @param constraintJson JSON representation of the constraint
+ * @return true if the constraint and JSON match, false otherwise.
+ */
+ private boolean matchWaypointConstraint(WaypointConstraint waypointConstraint,
+ JsonNode constraintJson) {
+ final JsonNode waypointsJson = constraintJson.get("waypoints");
+
+ if (waypointsJson.size() != waypointConstraint.waypoints().size()) {
+ return false;
+ }
+
+ for (int waypointsIndex = 0; waypointsIndex < waypointsJson.size();
+ waypointsIndex++) {
+ boolean waypointFound = false;
+ final String waypointJson = waypointsJson.get(waypointsIndex)
+ .asText();
+ for (DeviceId waypoint : waypointConstraint.waypoints()) {
+ if (waypoint.toString().equals(waypointJson)) {
+ waypointFound = true;
+ }
+ }
+ if (!waypointFound) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * Matches a constraint against a JSON representation of the
+ * constraint.
+ *
+ * @param constraint constraint object to match
+ * @param constraintJson JSON representation of the constraint
+ * @return true if the constraint and JSON match, false otherwise.
+ */
+ private boolean matchConstraint(Constraint constraint, JsonNode constraintJson) {
+ final JsonNode typeJson = constraintJson.get("type");
+ if (!typeJson.asText().equals(constraint.getClass().getSimpleName())) {
+ return false;
+ }
+ if (constraint instanceof BandwidthConstraint) {
+ return matchBandwidthConstraint((BandwidthConstraint) constraint,
+ constraintJson);
+ } else if (constraint instanceof LambdaConstraint) {
+ return matchLambdaConstraint((LambdaConstraint) constraint,
+ constraintJson);
+ } else if (constraint instanceof LinkTypeConstraint) {
+ return matchLinkTypeConstraint((LinkTypeConstraint) constraint,
+ constraintJson);
+ } else if (constraint instanceof AnnotationConstraint) {
+ return matchAnnotationConstraint((AnnotationConstraint) constraint,
+ constraintJson);
+ } else if (constraint instanceof LatencyConstraint) {
+ return matchLatencyConstraint((LatencyConstraint) constraint,
+ constraintJson);
+ } else if (constraint instanceof ObstacleConstraint) {
+ return matchObstacleConstraint((ObstacleConstraint) constraint,
+ constraintJson);
+ } else if (constraint instanceof WaypointConstraint) {
+ return matchWaypointConstraint((WaypointConstraint) constraint,
+ constraintJson);
+ }
+ 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
+ * @param description Description object used for recording errors
+ * @return true if the JSON matches the intent, false otherwise
+ */
+ private boolean matchConnectivityIntent(JsonNode jsonIntent, Description description) {
+ final ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent;
+
+ // check selector
+ final JsonNode jsonSelector = jsonIntent.get("selector");
+ final TrafficSelector selector = connectivityIntent.selector();
+ final Set<Criterion> criteria = selector.criteria();
+ final JsonNode jsonCriteria = jsonSelector.get("criteria");
+ if (jsonCriteria.size() != criteria.size()) {
+ description.appendText("size of criteria array is "
+ + Integer.toString(jsonCriteria.size()));
+ return false;
+ }
+
+ for (Criterion criterion : criteria) {
+ boolean criterionFound = false;
+ for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) {
+ final CriterionJsonMatcher criterionMatcher =
+ CriterionJsonMatcher.matchesCriterion(criterion);
+ if (criterionMatcher.matches(jsonCriteria.get(criterionIndex))) {
+ criterionFound = true;
+ break;
+ }
+ }
+ if (!criterionFound) {
+ description.appendText("criterion not found " + criterion.toString());
+ return false;
+ }
+ }
+
+ // check treatment
+ final JsonNode jsonTreatment = jsonIntent.get("treatment");
+ final TrafficTreatment treatment = connectivityIntent.treatment();
+ final List<Instruction> instructions = treatment.immediate();
+ final JsonNode jsonInstructions = jsonTreatment.get("instructions");
+ if (jsonInstructions.size() != instructions.size()) {
+ description.appendText("size of instructions array is "
+ + Integer.toString(jsonInstructions.size()));
+ return false;
+ }
+
+ for (Instruction instruction : instructions) {
+ boolean instructionFound = false;
+ for (int instructionIndex = 0; instructionIndex < jsonInstructions.size(); instructionIndex++) {
+ final InstructionJsonMatcher instructionMatcher =
+ InstructionJsonMatcher.matchesInstruction(instruction);
+ if (instructionMatcher.matches(jsonInstructions.get(instructionIndex))) {
+ instructionFound = true;
+ break;
+ }
+ }
+ if (!instructionFound) {
+ description.appendText("instruction not found " + instruction.toString());
+ return false;
+ }
+ }
+
+ // Check constraints
+ final JsonNode jsonConstraints = jsonIntent.get("constraints");
+ if (connectivityIntent.constraints() != null) {
+ if (connectivityIntent.constraints().size() != jsonConstraints.size()) {
+ description.appendText("constraints array size was "
+ + Integer.toString(jsonConstraints.size()));
+ return false;
+ }
+ for (final Constraint constraint : connectivityIntent.constraints()) {
+ boolean constraintFound = false;
+ for (int constraintIndex = 0; constraintIndex < jsonConstraints.size();
+ constraintIndex++) {
+ final JsonNode value = jsonConstraints.get(constraintIndex);
+ if (matchConstraint(constraint, value)) {
+ constraintFound = true;
+ }
+ }
+ if (!constraintFound) {
+ final String constraintString = constraint.toString();
+ description.appendText("constraint missing " + constraintString);
+ return false;
+ }
+ }
+ } else if (jsonConstraints.size() != 0) {
+ description.appendText("constraint array not empty");
+ return false;
+ }
+
+ if (connectivityIntent instanceof HostToHostIntent) {
+ return matchHostToHostIntent(jsonIntent, description);
+ } else if (connectivityIntent instanceof PointToPointIntent) {
+ return matchPointToPointIntent(jsonIntent, description);
+ } else {
+ description.appendText("class of connectivity intent is unknown");
+ return false;
+ }
+ }
+
+ @Override
+ public boolean matchesSafely(JsonNode jsonIntent, Description description) {
+ // check id
+ final String jsonId = jsonIntent.get("id").asText();
+ final String id = intent.id().toString();
+ if (!jsonId.equals(id)) {
+ description.appendText("id was " + jsonId);
+ return false;
+ }
+
+ // check application id
+ final JsonNode jsonAppIdNode = jsonIntent.get("appId");
+
+ final String jsonAppId = jsonAppIdNode.asText();
+ final String appId = intent.appId().name();
+ if (!jsonAppId.equals(appId)) {
+ description.appendText("appId was " + jsonAppId);
+ return false;
+ }
+
+ // check intent type
+ final String jsonType = jsonIntent.get("type").asText();
+ final String type = intent.getClass().getSimpleName();
+ if (!jsonType.equals(type)) {
+ description.appendText("type was " + jsonType);
+ return false;
+ }
+
+ // check resources array
+ final JsonNode jsonResources = jsonIntent.get("resources");
+ if (intent.resources() != null) {
+ if (intent.resources().size() != jsonResources.size()) {
+ description.appendText("resources array size was "
+ + Integer.toString(jsonResources.size()));
+ return false;
+ }
+ for (final NetworkResource resource : intent.resources()) {
+ boolean resourceFound = false;
+ final String resourceString = resource.toString();
+ for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
+ final JsonNode value = jsonResources.get(resourceIndex);
+ if (value.asText().equals(resourceString)) {
+ resourceFound = true;
+ }
+ }
+ if (!resourceFound) {
+ description.appendText("resource missing " + resourceString);
+ return false;
+ }
+ }
+ } else if (jsonResources.size() != 0) {
+ description.appendText("resources array empty");
+ return false;
+ }
+
+ if (intent instanceof ConnectivityIntent) {
+ return matchConnectivityIntent(jsonIntent, description);
+ } else {
+ description.appendText("class of intent is unknown");
+ return false;
+ }
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(intent.toString());
+ }
+
+ /**
+ * Factory to allocate an intent matcher.
+ *
+ * @param intent intent object we are looking for
+ * @return matcher
+ */
+ public static IntentJsonMatcher matchesIntent(Intent intent) {
+ return new IntentJsonMatcher(intent);
+ }
+}