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