blob: a49307bfda2e356b9107b0a50396a604097f573e [file] [log] [blame]
Ray Milkeydb358082015-01-13 16:34:38 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.codec.impl;
17
18import java.util.List;
19import java.util.Set;
20
21import org.hamcrest.Description;
22import org.hamcrest.TypeSafeDiagnosingMatcher;
23import org.onosproject.net.ConnectPoint;
24import org.onosproject.net.NetworkResource;
25import org.onosproject.net.flow.TrafficSelector;
26import org.onosproject.net.flow.TrafficTreatment;
27import org.onosproject.net.flow.criteria.Criterion;
28import org.onosproject.net.flow.instructions.Instruction;
29import org.onosproject.net.intent.ConnectivityIntent;
30import org.onosproject.net.intent.Constraint;
31import org.onosproject.net.intent.HostToHostIntent;
32import org.onosproject.net.intent.Intent;
33import org.onosproject.net.intent.PointToPointIntent;
34
35import com.fasterxml.jackson.databind.JsonNode;
36
37/**
38 * Hamcrest matcher to check that an intent representation in JSON matches
39 * the actual intent.
40 */
41public final class IntentJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
42
43 private final Intent intent;
44
45 /**
46 * Constructor is private, use factory method.
47 *
48 * @param intentValue the intent object to compare against
49 */
50 private IntentJsonMatcher(Intent intentValue) {
51 intent = intentValue;
52 }
53
54 /**
55 * Matches the JSON representation of a host to host intent.
56 *
57 * @param jsonIntent JSON representation of the intent
58 * @param description Description object used for recording errors
59 * @return true if the JSON matches the intent, false otherwise
60 */
61 private boolean matchHostToHostIntent(JsonNode jsonIntent, Description description) {
62 final HostToHostIntent hostToHostIntent = (HostToHostIntent) intent;
63
64 // check host one
65 final String host1 = hostToHostIntent.one().toString();
66 final String jsonHost1 = jsonIntent.get("one").asText();
67 if (!host1.equals(jsonHost1)) {
68 description.appendText("host one was " + jsonHost1);
69 return false;
70 }
71
72 // check host 2
73 final String host2 = hostToHostIntent.two().toString();
74 final String jsonHost2 = jsonIntent.get("two").asText();
75 if (!host2.equals(jsonHost2)) {
76 description.appendText("host two was " + jsonHost2);
77 return false;
78 }
79 return true;
80 }
81
82 /**
83 * Matches the JSON representation of a point to point intent.
84 *
85 * @param jsonIntent JSON representation of the intent
86 * @param description Description object used for recording errors
87 * @return true if the JSON matches the intent, false otherwise
88 */
89 private boolean matchPointToPointIntent(JsonNode jsonIntent, Description description) {
90 final PointToPointIntent pointToPointIntent = (PointToPointIntent) intent;
91
92 // check ingress connection
93 final ConnectPoint ingress = pointToPointIntent.ingressPoint();
94 final ConnectPointJsonMatcher ingressMatcher =
95 ConnectPointJsonMatcher.matchesConnectPoint(ingress);
96 final JsonNode jsonIngress = jsonIntent.get("ingressPoint");
97 final boolean ingressMatches =
98 ingressMatcher.matchesSafely(jsonIngress, description);
99
100 if (!ingressMatches) {
101 description.appendText("ingress was " + jsonIngress);
102 return false;
103 }
104
105 // check egress connection
106 final ConnectPoint egress = pointToPointIntent.egressPoint();
107 final ConnectPointJsonMatcher egressMatcher =
108 ConnectPointJsonMatcher.matchesConnectPoint(egress);
109 final JsonNode jsonEgress = jsonIntent.get("egressPoint");
110 final boolean egressMatches =
111 egressMatcher.matchesSafely(jsonEgress, description);
112
113 if (!egressMatches) {
114 description.appendText("egress was " + jsonEgress);
115 return false;
116 }
117
118 return true;
119 }
120
121 /**
122 * Matches the JSON representation of a connectivity intent. Calls the
123 * matcher for the connectivity intent subtype.
124 *
125 * @param jsonIntent JSON representation of the intent
126 * @param description Description object used for recording errors
127 * @return true if the JSON matches the intent, false otherwise
128 */
129 private boolean matchConnectivityIntent(JsonNode jsonIntent, Description description) {
130 final ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent;
131
132 // check selector
133 final JsonNode jsonSelector = jsonIntent.get("selector");
134 final TrafficSelector selector = connectivityIntent.selector();
135 final Set<Criterion> criteria = selector.criteria();
136 final JsonNode jsonCriteria = jsonSelector.get("criteria");
137 if (jsonCriteria.size() != criteria.size()) {
138 description.appendText("size of criteria array is "
139 + Integer.toString(jsonCriteria.size()));
140 return false;
141 }
142
143 for (Criterion criterion : criteria) {
144 boolean criterionFound = false;
145 for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) {
146 final CriterionJsonMatcher criterionMatcher =
147 CriterionJsonMatcher.matchesCriterion(criterion);
148 if (criterionMatcher.matches(jsonCriteria.get(criterionIndex))) {
149 criterionFound = true;
150 break;
151 }
152 }
153 if (!criterionFound) {
154 description.appendText("criterion not found " + criterion.toString());
155 return false;
156 }
157 }
158
159 // check treatment
160 final JsonNode jsonTreatment = jsonIntent.get("treatment");
161 final TrafficTreatment treatment = connectivityIntent.treatment();
162 final List<Instruction> instructions = treatment.instructions();
163 final JsonNode jsonInstructions = jsonTreatment.get("instructions");
164 if (jsonInstructions.size() != instructions.size()) {
165 description.appendText("size of instructions array is "
166 + Integer.toString(jsonInstructions.size()));
167 return false;
168 }
169
170 for (Instruction instruction : instructions) {
171 boolean instructionFound = false;
172 for (int instructionIndex = 0; instructionIndex < jsonCriteria.size(); instructionIndex++) {
173 final InstructionJsonMatcher instructionMatcher =
174 InstructionJsonMatcher.matchesInstruction(instruction);
175 if (instructionMatcher.matches(jsonInstructions.get(instructionIndex))) {
176 instructionFound = true;
177 break;
178 }
179 }
180 if (!instructionFound) {
181 description.appendText("instruction not found " + instruction.toString());
182 return false;
183 }
184 }
185
186 // Check constraints
187 final JsonNode jsonConstraints = jsonIntent.get("constraints");
188 if (connectivityIntent.constraints() != null) {
189 if (connectivityIntent.constraints().size() != jsonConstraints.size()) {
190 description.appendText("constraints array size was "
191 + Integer.toString(jsonConstraints.size()));
192 return false;
193 }
194 for (final Constraint constraint : connectivityIntent.constraints()) {
195 boolean constraintFound = false;
196 final String constraintString = constraint.toString();
197 for (int constraintIndex = 0; constraintIndex < jsonConstraints.size();
198 constraintIndex++) {
199 final JsonNode value = jsonConstraints.get(constraintIndex);
200 if (value.asText().equals(constraintString)) {
201 constraintFound = true;
202 }
203 }
204 if (!constraintFound) {
205 description.appendText("resource missing " + constraintString);
206 return false;
207 }
208 }
209 } else if (jsonConstraints.size() != 0) {
210 description.appendText("constraint array not empty");
211 return false;
212 }
213
214 if (connectivityIntent instanceof HostToHostIntent) {
215 return matchHostToHostIntent(jsonIntent, description);
216 } else if (connectivityIntent instanceof PointToPointIntent) {
217 return matchPointToPointIntent(jsonIntent, description);
218 } else {
219 description.appendText("class of connectivity intent is unknown");
220 return false;
221 }
222 }
223
224 @Override
225 public boolean matchesSafely(JsonNode jsonIntent, Description description) {
226 // check id
227 final String jsonId = jsonIntent.get("id").asText();
228 final String id = intent.id().toString();
229 if (!jsonId.equals(id)) {
230 description.appendText("id was " + jsonId);
231 return false;
232 }
233
234 // check application id
235 final String jsonAppId = jsonIntent.get("appId").asText();
236 final String appId = intent.appId().toString();
237 if (!jsonAppId.equals(appId)) {
238 description.appendText("appId was " + jsonAppId);
239 return false;
240 }
241
242 // check intent type
243 final String jsonType = jsonIntent.get("type").asText();
244 final String type = intent.getClass().getSimpleName();
245 if (!jsonType.equals(type)) {
246 description.appendText("type was " + jsonType);
247 return false;
248 }
249
250 // check details field
251 final String jsonDetails = jsonIntent.get("details").asText();
252 final String details = intent.toString();
253 if (!jsonDetails.equals(details)) {
254 description.appendText("details were " + jsonDetails);
255 return false;
256 }
257
258 // check resources array
259 final JsonNode jsonResources = jsonIntent.get("resources");
260 if (intent.resources() != null) {
261 if (intent.resources().size() != jsonResources.size()) {
262 description.appendText("resources array size was "
263 + Integer.toString(jsonResources.size()));
264 return false;
265 }
266 for (final NetworkResource resource : intent.resources()) {
267 boolean resourceFound = false;
268 final String resourceString = resource.toString();
269 for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) {
270 final JsonNode value = jsonResources.get(resourceIndex);
271 if (value.asText().equals(resourceString)) {
272 resourceFound = true;
273 }
274 }
275 if (!resourceFound) {
276 description.appendText("resource missing " + resourceString);
277 return false;
278 }
279 }
280 } else if (jsonResources.size() != 0) {
281 description.appendText("resources array empty");
282 return false;
283 }
284
285 if (intent instanceof ConnectivityIntent) {
286 return matchConnectivityIntent(jsonIntent, description);
287 } else {
288 description.appendText("class of intent is unknown");
289 return false;
290 }
291 }
292
293 @Override
294 public void describeTo(Description description) {
295 description.appendText(intent.toString());
296 }
297
298 /**
299 * Factory to allocate an intent matcher.
300 *
301 * @param intent intent object we are looking for
302 * @return matcher
303 */
304 public static IntentJsonMatcher matchesIntent(Intent intent) {
305 return new IntentJsonMatcher(intent);
306 }
307}