blob: 4d5f06da85a0570c8fb4a689db72f0d9cfc7912a [file] [log] [blame]
Jian Lic134c7a2017-04-25 12:51:28 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Jian Lic134c7a2017-04-25 12:51:28 +09003 *
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.mapping.web;
17
18import com.eclipsesource.json.Json;
19import com.eclipsesource.json.JsonArray;
20import com.eclipsesource.json.JsonObject;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Maps;
23import com.google.common.collect.Sets;
24import org.glassfish.jersey.server.ResourceConfig;
25import org.hamcrest.Description;
26import org.hamcrest.TypeSafeMatcher;
27import org.junit.After;
28import org.junit.Before;
29import org.junit.Test;
30import org.onlab.osgi.ServiceDirectory;
31import org.onlab.osgi.TestServiceDirectory;
32import org.onlab.packet.IpPrefix;
Jian Lic134c7a2017-04-25 12:51:28 +090033import org.onosproject.codec.CodecService;
34import org.onosproject.codec.impl.CodecManager;
35import org.onosproject.mapping.DefaultMappingKey;
36import org.onosproject.mapping.DefaultMappingTreatment;
37import org.onosproject.mapping.DefaultMappingValue;
38import org.onosproject.mapping.MappingEntry;
39import org.onosproject.mapping.MappingId;
40import org.onosproject.mapping.MappingKey;
41import org.onosproject.mapping.MappingService;
42import org.onosproject.mapping.MappingTreatment;
43import org.onosproject.mapping.MappingValue;
44import org.onosproject.mapping.actions.MappingAction;
45import org.onosproject.mapping.actions.MappingActions;
46import org.onosproject.mapping.addresses.MappingAddress;
47import org.onosproject.mapping.addresses.MappingAddresses;
48import org.onosproject.mapping.codec.MappingActionCodec;
49import org.onosproject.mapping.codec.MappingAddressCodec;
50import org.onosproject.mapping.codec.MappingEntryCodec;
51import org.onosproject.mapping.codec.MappingInstructionCodec;
52import org.onosproject.mapping.codec.MappingKeyCodec;
53import org.onosproject.mapping.codec.MappingTreatmentCodec;
54import org.onosproject.mapping.codec.MappingValueCodec;
55import org.onosproject.mapping.instructions.MappingInstruction;
Jian Lia23f46d2017-05-02 18:07:31 +090056import org.onosproject.mapping.web.api.MappingsWebApplication;
Jian Lic134c7a2017-04-25 12:51:28 +090057import org.onosproject.net.DefaultDevice;
58import org.onosproject.net.Device;
59import org.onosproject.net.DeviceId;
60import org.onosproject.net.device.DeviceService;
61import org.onosproject.rest.resources.ResourceTest;
62
63import javax.ws.rs.client.WebTarget;
64import java.util.Map;
65import java.util.Set;
66
67import static org.easymock.EasyMock.anyObject;
68import static org.easymock.EasyMock.createMock;
69import static org.easymock.EasyMock.expect;
70import static org.easymock.EasyMock.replay;
71import static org.easymock.EasyMock.verify;
72import static org.hamcrest.Matchers.hasSize;
73import static org.hamcrest.Matchers.is;
74import static org.hamcrest.Matchers.notNullValue;
75import static org.junit.Assert.assertThat;
76import static org.onosproject.mapping.MappingStore.Type.MAP_DATABASE;
77import static org.onosproject.mapping.instructions.MappingInstructions.multicastPriority;
78import static org.onosproject.mapping.instructions.MappingInstructions.multicastWeight;
79import static org.onosproject.mapping.instructions.MappingInstructions.unicastPriority;
80import static org.onosproject.mapping.instructions.MappingInstructions.unicastWeight;
81
82/**
83 * Unit tests for Mappings REST APIs.
84 */
85public class MappingsWebResourceTest extends ResourceTest {
86
87 private static final String IPV4_STRING_1 = "1.2.3.4";
88 private static final String IPV4_STRING_2 = "5.6.7.8";
89 private static final String PORT_STRING = "32";
90 private static final IpPrefix IPV4_PREFIX_1 =
91 IpPrefix.valueOf(IPV4_STRING_1 + "/" + PORT_STRING);
92 private static final IpPrefix IPV4_PREFIX_2 =
93 IpPrefix.valueOf(IPV4_STRING_2 + "/" + PORT_STRING);
94
95 private static final int UNICAST_WEIGHT = 1;
96 private static final int UNICAST_PRIORITY = 1;
97 private static final int MULTICAST_WEIGHT = 2;
98 private static final int MULTICAST_PRIORITY = 2;
99
100 private static final int DIFF_VALUE = 99;
101
102 private static final String ID = "id";
Jian Li6e960ef2017-05-03 16:38:19 +0900103 private static final String DATABASE = "database";
Jian Lic134c7a2017-04-25 12:51:28 +0900104
105 private static final String PREFIX = "mappings";
106
107 private final MappingService mockMappingService = createMock(MappingService.class);
108
109 private final Map<DeviceId, Set<MappingEntry>> mappings = Maps.newHashMap();
110
111 private final DeviceService mockDeviceService = createMock(DeviceService.class);
112 private final DeviceId deviceId1 = DeviceId.deviceId("1");
113 private final DeviceId deviceId2 = DeviceId.deviceId("2");
114 private final Device device1 = new DefaultDevice(null, deviceId1, Device.Type.ROUTER,
115 "", "", "", "", null);
116 private final Device device2 = new DefaultDevice(null, deviceId2, Device.Type.ROUTER,
117 "", "", "", "", null);
118
119 private final MockMappingEntry mapping1 = new MockMappingEntry(deviceId1, 1);
120 private final MockMappingEntry mapping2 = new MockMappingEntry(deviceId1, 2);
121
122 private final MockMappingEntry mapping3 = new MockMappingEntry(deviceId2, 3);
123 private final MockMappingEntry mapping4 = new MockMappingEntry(deviceId2, 4);
124
125 private final Set<MappingEntry> mappingEntries = ImmutableSet.of(mapping1, mapping2, mapping3, mapping4);
126
127 /**
128 * Constructs a mappings web resource test instance.
129 */
130 public MappingsWebResourceTest() {
131 super(ResourceConfig.forApplicationClass(MappingsWebApplication.class));
132 }
133
134 /**
135 * Mock class for a mapping entry.
136 */
137 private static class MockMappingEntry implements MappingEntry {
Yuta HIGUCHIf7089102017-05-03 10:31:46 -0700138 static final short UNIQUE_SHORT = 2;
Jian Lic134c7a2017-04-25 12:51:28 +0900139 final DeviceId deviceId;
140 MappingKey key;
141 MappingValue value;
142 final long baseValue;
143
144 MockMappingEntry(DeviceId deviceId, long id) {
145 this.deviceId = deviceId;
146 this.baseValue = id * 100;
147 }
148
149 @Override
150 public MappingId id() {
151 final long id = baseValue + 11;
152 return MappingId.valueOf(id);
153 }
154
155 @Override
156 public short appId() {
157 return UNIQUE_SHORT;
158 }
159
160 @Override
161 public DeviceId deviceId() {
162 return deviceId;
163 }
164
165 @Override
166 public MappingKey key() {
167 return key;
168 }
169
170 @Override
171 public MappingValue value() {
172 return value;
173 }
174
175 @Override
176 public MappingEntryState state() {
177 return MappingEntryState.ADDED;
178 }
179 }
180
181 /**
182 * Populates some mappings used as testing data.
183 */
184 private void setupMockMappings() {
185 MappingAddress address1 = MappingAddresses.ipv4MappingAddress(IPV4_PREFIX_1);
186 MappingAddress address2 = MappingAddresses.ipv4MappingAddress(IPV4_PREFIX_2);
187
188 MappingInstruction unicastWeight1 = unicastWeight(UNICAST_WEIGHT);
189 MappingInstruction unicastPriority1 = unicastPriority(UNICAST_PRIORITY);
190 MappingInstruction multicastWeight1 = multicastWeight(MULTICAST_WEIGHT);
191 MappingInstruction multicastPriority1 = multicastPriority(MULTICAST_PRIORITY);
192
193 MappingInstruction unicastWeight2 = unicastWeight(UNICAST_WEIGHT + DIFF_VALUE);
194 MappingInstruction unicastPriority2 = unicastPriority(UNICAST_PRIORITY + DIFF_VALUE);
195 MappingInstruction multicastWeight2 = multicastWeight(MULTICAST_WEIGHT + DIFF_VALUE);
196 MappingInstruction multicastPriority2 = multicastPriority(MULTICAST_PRIORITY + DIFF_VALUE);
197
198 MappingKey key1 = DefaultMappingKey.builder()
199 .withAddress(address1)
200 .build();
201
202 MappingTreatment treatment1 = DefaultMappingTreatment.builder()
203 .add(unicastWeight1)
204 .add(unicastPriority1)
205 .add(multicastWeight1)
206 .add(multicastPriority1)
207 .withAddress(address1)
208 .build();
209
210 MappingAction action1 = MappingActions.noAction();
211
212 MappingValue value1 = DefaultMappingValue.builder()
213 .add(treatment1)
214 .withAction(action1)
215 .build();
216
217 MappingKey key2 = DefaultMappingKey.builder()
218 .withAddress(address2)
219 .build();
220
221 MappingTreatment treatment2 = DefaultMappingTreatment.builder()
222 .add(unicastWeight2)
223 .add(unicastPriority2)
224 .add(multicastWeight2)
225 .add(multicastPriority2)
226 .withAddress(address2)
227 .build();
228
229 MappingAction action2 = MappingActions.forward();
230
231 MappingValue value2 = DefaultMappingValue.builder()
232 .add(treatment2)
233 .withAction(action2)
234 .build();
235
236 mapping1.key = key1;
237 mapping2.key = key2;
238 mapping3.key = key1;
239 mapping4.key = key2;
240
241 mapping1.value = value1;
242 mapping2.value = value2;
243 mapping3.value = value1;
244 mapping4.value = value2;
245
246 final Set<MappingEntry> mappings1 = Sets.newHashSet();
247 mappings1.add(mapping1);
248 mappings1.add(mapping2);
249
250 final Set<MappingEntry> mappings2 = Sets.newHashSet();
251 mappings2.add(mapping3);
252 mappings2.add(mapping4);
253
254 mappings.put(deviceId1, mappings1);
255 mappings.put(deviceId2, mappings2);
256 }
257
258 /**
259 * Sets up the global values for all the tests.
260 */
261 @Before
262 public void setUpTest() {
263
264 // Register the services needed for the test
265 final CodecManager codecService = new CodecManager();
266 codecService.activate();
267 codecService.registerCodec(MappingEntry.class, new MappingEntryCodec());
268 codecService.registerCodec(MappingAddress.class, new MappingAddressCodec());
269 codecService.registerCodec(MappingInstruction.class, new MappingInstructionCodec());
270 codecService.registerCodec(MappingAction.class, new MappingActionCodec());
271 codecService.registerCodec(MappingTreatment.class, new MappingTreatmentCodec());
272 codecService.registerCodec(MappingKey.class, new MappingKeyCodec());
273 codecService.registerCodec(MappingValue.class, new MappingValueCodec());
274 ServiceDirectory testDirectory =
275 new TestServiceDirectory()
276 .add(MappingService.class, mockMappingService)
277 .add(DeviceService.class, mockDeviceService)
278 .add(CodecService.class, codecService);
279
Ray Milkey094a1352018-01-22 14:03:54 -0800280 setServiceDirectory(testDirectory);
Jian Lic134c7a2017-04-25 12:51:28 +0900281 }
282
283 /**
284 * Cleans up and verifies the mocks.
285 */
286 @After
287 public void tearDownTest() {
288 verify(mockMappingService);
289 }
290
291 public static class MappingEntryJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
292
293 private final MappingEntry mapping;
294 private String reason = "";
295
296 MappingEntryJsonArrayMatcher(MappingEntry mappingValue) {
297 mapping = mappingValue;
298 }
299
300 @Override
301 protected boolean matchesSafely(JsonArray json) {
302
303 boolean mappingFound = false;
304
305 for (int jsonMappingIndex = 0; jsonMappingIndex < json.size();
306 jsonMappingIndex++) {
307
308 final JsonObject jsonMapping = json.get(jsonMappingIndex).asObject();
309
310 final String mappingId = Long.toString(mapping.id().value());
311 final String jsonMappingId = jsonMapping.get(ID).asString();
312 if (jsonMappingId.equals(mappingId)) {
313 mappingFound = true;
314 assertThat(jsonMapping, matchesMapping(mapping));
315 }
316 }
317
318 if (!mappingFound) {
319 reason = "Mapping with id " + mapping.id().toString() + " not found";
320 return false;
321 } else {
322 return true;
323 }
324 }
325
326 @Override
327 public void describeTo(Description description) {
328 description.appendText(reason);
329 }
330 }
331
332 /**
333 * Hamcrest matcher for mapping entry.
334 */
335 public static final class MappingEntryJsonMatcher
336 extends TypeSafeMatcher<JsonObject> {
337
338 private final MappingEntry mappingEntry;
339 private String reason = "";
340
341 /**
342 * A default constructor.
343 *
344 * @param mappingEntry mapping entry
345 */
346 private MappingEntryJsonMatcher(MappingEntry mappingEntry) {
347 this.mappingEntry = mappingEntry;
348 }
349
350 @Override
351 protected boolean matchesSafely(JsonObject jsonObject) {
352 // check mapping id
353 final String jsonId = jsonObject.get("id").asString();
354 final String mappingId = Long.toString(mappingEntry.id().value());
355
356 if (!jsonId.equals(mappingId)) {
357 reason = "id " + mappingEntry.id().toString();
358 return false;
359 }
360
361 // check device id
362 final String jsonDeviceId = jsonObject.get("deviceId").asString();
363 final String deviceId = mappingEntry.deviceId().toString();
364 if (!jsonDeviceId.equals(deviceId)) {
365 reason = "deviceId " + mappingEntry.deviceId();
366 return false;
367 }
368
369 // check state
370 final String jsonState = jsonObject.get("state").asString();
371 final String state = mappingEntry.state().name();
372 if (!jsonState.equals(state)) {
373 reason = "state " + mappingEntry.state().name();
374 return false;
375 }
376
377 return true;
378 }
379
380 @Override
381 public void describeTo(Description description) {
382 description.appendText(reason);
383 }
384 }
385
386 /**
387 * Factory to allocate a mapping matcher.
388 *
389 * @param mapping mapping object we are looking for
390 * @return matcher
391 */
392 private static MappingEntryJsonMatcher matchesMapping(MappingEntry mapping) {
393 return new MappingEntryJsonMatcher(mapping);
394 }
395
396 /**
397 * Factory to allocate a mapping array matcher.
398 *
399 * @param mapping mapping object we are looking for
400 * @return matcher
401 */
402 private static MappingEntryJsonArrayMatcher hasMapping(MappingEntry mapping) {
403 return new MappingEntryJsonArrayMatcher(mapping);
404 }
405
406 /**
407 * Tests the result of the rest api GET when there are no mappings.
408 */
409 @Test
410 public void testMappingsEmptyArray() {
411 expect(mockMappingService.getAllMappingEntries(anyObject()))
412 .andReturn(null).anyTimes();
413 replay(mockMappingService);
414 final WebTarget wt = target();
Jian Li6e960ef2017-05-03 16:38:19 +0900415 final String response = wt.path(PREFIX + "/" + DATABASE).request().get(String.class);
Jian Lic134c7a2017-04-25 12:51:28 +0900416 assertThat(response, is("{\"mappings\":[]}"));
417 }
418
419 /**
420 * Tests the result of the rest api GET when there are active mappings.
421 */
422 @Test
423 public void testMappingsPopulateArray() {
424 setupMockMappings();
425 expect(mockMappingService.getAllMappingEntries(anyObject()))
426 .andReturn(mappingEntries).once();
427 replay(mockMappingService);
428 final WebTarget wt = target();
Jian Li6e960ef2017-05-03 16:38:19 +0900429 final String response = wt.path(PREFIX + "/" + DATABASE).request().get(String.class);
Jian Lic134c7a2017-04-25 12:51:28 +0900430 final JsonObject result = Json.parse(response).asObject();
431 assertThat(result, notNullValue());
432
433 assertThat(result.names(), hasSize(1));
434 assertThat(result.names().get(0), is("mappings"));
435 final JsonArray jsonMappings = result.get("mappings").asArray();
436 assertThat(jsonMappings, notNullValue());
437 assertThat(jsonMappings, hasMapping(mapping1));
438 assertThat(jsonMappings, hasMapping(mapping2));
439 assertThat(jsonMappings, hasMapping(mapping3));
440 assertThat(jsonMappings, hasMapping(mapping4));
441 }
442
443 /**
444 * Tests the result of the rest api GET with a device ID when there are
445 * no mappings.
446 */
447 @Test
448 public void testMappingsByDevIdEmptyArray() {
449 expect(mockDeviceService.getDevice(deviceId1)).andReturn(device1);
450 expect(mockMappingService.getMappingEntries(MAP_DATABASE, deviceId1))
451 .andReturn(null).anyTimes();
452 replay(mockDeviceService);
453 replay(mockMappingService);
454
455 final WebTarget wt = target();
Jian Li6e960ef2017-05-03 16:38:19 +0900456 final String response = wt.path(PREFIX + "/" + deviceId1 + "/" + DATABASE)
Jian Lic134c7a2017-04-25 12:51:28 +0900457 .request().get(String.class);
458 assertThat(response, is("{\"mappings\":[]}"));
459 }
460
461 /**
462 * Tests the result of the rest api GET with a device ID when there are
463 * active mappings.
464 */
465 @Test
466 public void testMappingsByDevIdPopulateArray() {
467 setupMockMappings();
468 expect(mockDeviceService.getDevice(deviceId2)).andReturn(device2);
469 expect(mockMappingService.getMappingEntries(MAP_DATABASE, deviceId2))
470 .andReturn(mappings.get(deviceId2)).once();
471 replay(mockDeviceService);
472 replay(mockMappingService);
473
474 final WebTarget wt = target();
Jian Li6e960ef2017-05-03 16:38:19 +0900475 final String response = wt.path(PREFIX + "/" + deviceId2 + "/" + DATABASE)
Jian Lic134c7a2017-04-25 12:51:28 +0900476 .request().get(String.class);
477
478 final JsonObject result = Json.parse(response).asObject();
479 assertThat(result, notNullValue());
480
481 assertThat(result.names(), hasSize(1));
482 assertThat(result.names().get(0), is("mappings"));
483 final JsonArray jsonMappings = result.get("mappings").asArray();
484 assertThat(jsonMappings, notNullValue());
485 assertThat(jsonMappings, hasMapping(mapping3));
486 assertThat(jsonMappings, hasMapping(mapping4));
487 }
488}