blob: 808fb42fde5aae7a79aca1e99dc5c6115bd87538 [file] [log] [blame]
Ray Milkey1f95bd32014-12-10 11:11:00 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Ray Milkey1f95bd32014-12-10 11:11:00 -08003 *
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 */
Jian Li8ae91202016-03-24 14:36:16 -070016package org.onosproject.rest.resources;
Ray Milkey1f95bd32014-12-10 11:11:00 -080017
18
Jian Li80cfe452016-01-14 16:04:58 -080019import com.eclipsesource.json.Json;
Jian Li9d616492016-03-09 10:52:49 -080020import com.eclipsesource.json.JsonArray;
21import com.eclipsesource.json.JsonObject;
Charles Chancd06c692017-04-27 20:46:06 -070022import com.eclipsesource.json.JsonValue;
Jian Li9d616492016-03-09 10:52:49 -080023import com.google.common.collect.ImmutableSet;
Ray Milkey1f95bd32014-12-10 11:11:00 -080024import org.hamcrest.Description;
Kedar Gupta7c4d1962015-08-03 10:46:04 -070025import org.hamcrest.Matchers;
Ray Milkey1f95bd32014-12-10 11:11:00 -080026import 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.IpAddress;
33import org.onlab.packet.MacAddress;
Ray Milkey1f95bd32014-12-10 11:11:00 -080034import org.onosproject.codec.CodecService;
35import org.onosproject.codec.impl.CodecManager;
36import org.onosproject.net.DefaultHost;
37import org.onosproject.net.DeviceId;
38import org.onosproject.net.Host;
39import org.onosproject.net.HostId;
40import org.onosproject.net.HostLocation;
Thomas Vachuska58a7c342016-12-13 01:10:56 -080041import org.onosproject.net.host.HostAdminService;
Kedar Gupta7c4d1962015-08-03 10:46:04 -070042import org.onosproject.net.host.HostProviderRegistry;
43import org.onosproject.net.host.HostProviderService;
Ray Milkey1f95bd32014-12-10 11:11:00 -080044import org.onosproject.net.host.HostService;
45import org.onosproject.net.provider.ProviderId;
46
Jian Li9d616492016-03-09 10:52:49 -080047import javax.ws.rs.NotFoundException;
48import javax.ws.rs.client.Entity;
49import javax.ws.rs.client.WebTarget;
Kedar Gupta7c4d1962015-08-03 10:46:04 -070050import javax.ws.rs.core.MediaType;
Jian Li9d616492016-03-09 10:52:49 -080051import javax.ws.rs.core.Response;
52import java.io.InputStream;
53import java.net.HttpURLConnection;
54import java.util.HashSet;
Charles Chancd06c692017-04-27 20:46:06 -070055import java.util.Iterator;
Jian Li9d616492016-03-09 10:52:49 -080056import java.util.Set;
Kedar Gupta7c4d1962015-08-03 10:46:04 -070057
Jian Li9d616492016-03-09 10:52:49 -080058import static org.easymock.EasyMock.anyBoolean;
59import static org.easymock.EasyMock.anyObject;
60import static org.easymock.EasyMock.createMock;
61import static org.easymock.EasyMock.expect;
62import static org.easymock.EasyMock.expectLastCall;
63import static org.easymock.EasyMock.replay;
64import static org.easymock.EasyMock.verify;
Ray Milkey1f95bd32014-12-10 11:11:00 -080065import static org.hamcrest.Matchers.containsString;
66import static org.hamcrest.Matchers.hasSize;
67import static org.hamcrest.Matchers.is;
68import static org.hamcrest.Matchers.notNullValue;
69import static org.junit.Assert.assertThat;
Ray Milkey02f446b2014-12-11 20:19:43 -080070import static org.junit.Assert.fail;
Ray Milkey1f95bd32014-12-10 11:11:00 -080071import static org.onlab.packet.MacAddress.valueOf;
72import static org.onlab.packet.VlanId.vlanId;
73import static org.onosproject.net.PortNumber.portNumber;
74
75/**
76 * Simple example on how to write a JAX-RS unit test using Jersey test framework.
77 * A base class should/will be created to provide further assistance for testing.
78 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080079public class HostResourceTest extends ResourceTest {
Thomas Vachuska58a7c342016-12-13 01:10:56 -080080 final HostAdminService mockHostService = createMock(HostAdminService.class);
Kedar Gupta7c4d1962015-08-03 10:46:04 -070081 final HostProviderRegistry mockHostProviderRegistry = createMock(HostProviderRegistry.class);
82 final HostProviderService mockHostProviderService = createMock(HostProviderService.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -080083 final HashSet<Host> hosts = new HashSet<>();
84
Ray Milkeyed0b1662015-02-05 09:34:29 -080085 /**
86 * Initializes test mocks and environment.
87 */
Ray Milkey1f95bd32014-12-10 11:11:00 -080088 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -080089 public void setUpTest() {
Ray Milkey1f95bd32014-12-10 11:11:00 -080090 expect(mockHostService.getHosts()).andReturn(hosts).anyTimes();
91
92 // Register the services needed for the test
93 final CodecManager codecService = new CodecManager();
94 codecService.activate();
95 ServiceDirectory testDirectory =
96 new TestServiceDirectory()
97 .add(HostService.class, mockHostService)
Thomas Vachuska58a7c342016-12-13 01:10:56 -080098 .add(HostAdminService.class, mockHostService)
Kedar Gupta7c4d1962015-08-03 10:46:04 -070099 .add(CodecService.class, codecService)
100 .add(HostProviderRegistry.class, mockHostProviderRegistry);
Ray Milkey094a1352018-01-22 14:03:54 -0800101 setServiceDirectory(testDirectory);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800102 }
103
Ray Milkeyed0b1662015-02-05 09:34:29 -0800104 /**
105 * Verifies mocks.
106 */
Ray Milkey1f95bd32014-12-10 11:11:00 -0800107 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800108 public void tearDownTest() {
Ray Milkey1f95bd32014-12-10 11:11:00 -0800109 verify(mockHostService);
110 }
111
112 /**
113 * Hamcrest matcher to check that a host representation in JSON matches
114 * the actual host.
115 */
116 public static class HostJsonMatcher extends TypeSafeMatcher<JsonObject> {
117 private final Host host;
118 private String reason = "";
119
120 public HostJsonMatcher(Host hostValue) {
121 host = hostValue;
122 }
123
124 @Override
125 public boolean matchesSafely(JsonObject jsonHost) {
126 // Check id
127 final String jsonId = jsonHost.get("id").asString();
128 if (!jsonId.equals(host.id().toString())) {
129 reason = "id " + host.id().toString();
130 return false;
131 }
132
133 // Check vlan id
134 final String jsonVlanId = jsonHost.get("vlan").asString();
135 if (!jsonVlanId.equals(host.vlan().toString())) {
136 reason = "vlan id " + host.vlan().toString();
137 return false;
138 }
139
140 // Check mac address
141 final String jsonMacAddress = jsonHost.get("mac").asString();
142 if (!jsonMacAddress.equals(host.mac().toString())) {
143 reason = "mac address " + host.mac().toString();
144 return false;
145 }
146
Charles Chancd06c692017-04-27 20:46:06 -0700147 // Check host locations
148 final JsonArray jsonLocations = jsonHost.get("locations").asArray();
149 final Set<HostLocation> expectedLocations = host.locations();
150 if (jsonLocations.size() != expectedLocations.size()) {
151 reason = "locations arrays differ in size";
Ray Milkey1f95bd32014-12-10 11:11:00 -0800152 return false;
153 }
154
Charles Chancd06c692017-04-27 20:46:06 -0700155 Iterator<JsonValue> jsonIterator = jsonLocations.iterator();
156 Iterator<HostLocation> locIterator = expectedLocations.iterator();
157 while (jsonIterator.hasNext()) {
158 boolean result = verifyLocation(jsonIterator.next().asObject(), locIterator.next());
159 if (!result) {
160 return false;
161 }
Ray Milkey1f95bd32014-12-10 11:11:00 -0800162 }
163
Charles Chaneb5bd492019-12-18 15:49:39 -0800164 // Check host auxLocations
165 if (jsonHost.get("auxLocations") != null) {
166 final JsonArray jsonAuxLocations = jsonHost.get("auxLocations").asArray();
167 final Set<HostLocation> expectedAuxLocations = host.auxLocations();
168 if (jsonAuxLocations.size() != expectedAuxLocations.size()) {
169 reason = "auxLocations arrays differ in size";
170 return false;
171 }
172
173 jsonIterator = jsonAuxLocations.iterator();
174 locIterator = expectedAuxLocations.iterator();
175 while (jsonIterator.hasNext()) {
176 boolean result = verifyLocation(jsonIterator.next().asObject(), locIterator.next());
177 if (!result) {
178 return false;
179 }
180 }
181 }
182
Ray Milkey1f95bd32014-12-10 11:11:00 -0800183 // Check Ip Addresses
184 final JsonArray jsonHostIps = jsonHost.get("ipAddresses").asArray();
185 final Set<IpAddress> expectedHostIps = host.ipAddresses();
186 if (jsonHostIps.size() != expectedHostIps.size()) {
187 reason = "IP address arrays differ in size";
188 return false;
189 }
190
191 return true;
192 }
193
194 @Override
195 public void describeTo(Description description) {
196 description.appendText(reason);
197 }
Charles Chancd06c692017-04-27 20:46:06 -0700198
199 private boolean verifyLocation(JsonObject jsonLocation, HostLocation expectedLocation) {
200 final String jsonLocationElementId = jsonLocation.get("elementId").asString();
201 if (!jsonLocationElementId.equals(expectedLocation.elementId().toString())) {
202 reason = "location element id " + host.location().elementId().toString();
203 return false;
204 }
205 final String jsonLocationPortNumber = jsonLocation.get("port").asString();
206 if (!jsonLocationPortNumber.equals(expectedLocation.port().toString())) {
207 reason = "location portNumber " + expectedLocation.port().toString();
208 return false;
209 }
210 return true;
211 }
Ray Milkey1f95bd32014-12-10 11:11:00 -0800212 }
213
214 /**
215 * Factory to allocate a host array matcher.
216 *
217 * @param host host object we are looking for
218 * @return matcher
219 */
220 private static HostJsonMatcher matchesHost(Host host) {
221 return new HostJsonMatcher(host);
222 }
223
224 /**
225 * Hamcrest matcher to check that a host is represented properly in a JSON
226 * array of hosts.
227 */
228 public static class HostJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
229 private final Host host;
230 private String reason = "";
231
232 public HostJsonArrayMatcher(Host hostValue) {
233 host = hostValue;
234 }
235
236 @Override
237 public boolean matchesSafely(JsonArray json) {
238 boolean hostFound = false;
Jonghwan Hyun2c95acf2018-03-14 16:47:34 -0700239 final int expectedAttributes = 8;
Ray Milkey1f95bd32014-12-10 11:11:00 -0800240 for (int jsonHostIndex = 0; jsonHostIndex < json.size();
241 jsonHostIndex++) {
242
243 final JsonObject jsonHost = json.get(jsonHostIndex).asObject();
244
245 if (jsonHost.names().size() != expectedAttributes) {
246 reason = "Found a host with the wrong number of attributes";
247 return false;
248 }
249
250 final String jsonHostId = jsonHost.get("id").asString();
251 if (jsonHostId.equals(host.id().toString())) {
252 hostFound = true;
253
254 // We found the correct host, check attribute values
255 assertThat(jsonHost, matchesHost(host));
256 }
257 }
258 if (!hostFound) {
259 reason = "Host with id " + host.id().toString() + " not found";
260 return false;
261 } else {
262 return true;
263 }
264 }
265
266 @Override
267 public void describeTo(Description description) {
268 description.appendText(reason);
269 }
270 }
271
272 /**
273 * Factory to allocate a host array matcher.
274 *
275 * @param host host object we are looking for
276 * @return matcher
277 */
278 private static HostJsonArrayMatcher hasHost(Host host) {
279 return new HostJsonArrayMatcher(host);
280 }
281
282 /**
283 * Tests the result of the rest api GET when there are no hosts.
284 */
285 @Test
286 public void testHostsEmptyArray() {
287 replay(mockHostService);
Jian Li9d616492016-03-09 10:52:49 -0800288 WebTarget wt = target();
289 String response = wt.path("hosts").request().get(String.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800290 assertThat(response, is("{\"hosts\":[]}"));
291 }
292
293 /**
294 * Tests the result of the rest api GET when hosts are defined.
295 */
296 @Test
297 public void testHostsArray() {
298 replay(mockHostService);
299 final ProviderId pid = new ProviderId("of", "foo");
300 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
301 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
302 final Host host1 =
303 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
304 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
305 ips1);
306 final MacAddress mac2 = MacAddress.valueOf("00:00:11:00:00:02");
307 final Set<IpAddress> ips2 = ImmutableSet.of(
308 IpAddress.valueOf("2222:2222:2222:1::"),
309 IpAddress.valueOf("2222:2222:2222:2::"));
310 final Host host2 =
311 new DefaultHost(pid, HostId.hostId(mac2), valueOf(2), vlanId((short) 2),
312 new HostLocation(DeviceId.deviceId("2"), portNumber(22), 2),
313 ips2);
314 hosts.add(host1);
315 hosts.add(host2);
Jian Li9d616492016-03-09 10:52:49 -0800316 WebTarget wt = target();
317 String response = wt.path("hosts").request().get(String.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800318 assertThat(response, containsString("{\"hosts\":["));
319
Jian Li80cfe452016-01-14 16:04:58 -0800320 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800321 assertThat(result, notNullValue());
322
323 assertThat(result.names(), hasSize(1));
324 assertThat(result.names().get(0), is("hosts"));
325
326 final JsonArray hosts = result.get("hosts").asArray();
327 assertThat(hosts, notNullValue());
328
329 assertThat(hosts, hasHost(host1));
330 assertThat(hosts, hasHost(host2));
331 }
332
333 /**
334 * Tests fetch of one host by Id.
335 */
336 @Test
337 public void testSingleHostByIdFetch() {
338 final ProviderId pid = new ProviderId("of", "foo");
339 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
340 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
341 final Host host1 =
342 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
343 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
344 ips1);
345
346 hosts.add(host1);
347
348 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
349 .andReturn(host1)
350 .anyTimes();
351 replay(mockHostService);
352
Jian Li9d616492016-03-09 10:52:49 -0800353 WebTarget wt = target();
354 String response = wt.path("hosts/00:00:11:00:00:01%2F1").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800355 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800356 assertThat(result, matchesHost(host1));
357 }
358
359 /**
360 * Tests fetch of one host by mac and vlan.
361 */
362 @Test
363 public void testSingleHostByMacAndVlanFetch() {
364 final ProviderId pid = new ProviderId("of", "foo");
365 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
366 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
367 final Host host1 =
368 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
369 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
370 ips1);
371
372 hosts.add(host1);
373
374 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
375 .andReturn(host1)
376 .anyTimes();
377 replay(mockHostService);
378
Jian Li9d616492016-03-09 10:52:49 -0800379 WebTarget wt = target();
380 String response = wt.path("hosts/00:00:11:00:00:01/1").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800381 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800382 assertThat(result, matchesHost(host1));
383 }
384
Ray Milkey02f446b2014-12-11 20:19:43 -0800385 /**
386 * Tests that a fetch of a non-existent object throws an exception.
387 */
388 @Test
389 public void testBadGet() {
390
391 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
392 .andReturn(null)
393 .anyTimes();
394 replay(mockHostService);
395
Jian Li9d616492016-03-09 10:52:49 -0800396 WebTarget wt = target();
Ray Milkey02f446b2014-12-11 20:19:43 -0800397 try {
Jian Li9d616492016-03-09 10:52:49 -0800398 wt.path("hosts/00:00:11:00:00:01/1").request().get(String.class);
Ray Milkey02f446b2014-12-11 20:19:43 -0800399 fail("Fetch of non-existent host did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800400 } catch (NotFoundException ex) {
Ray Milkey02f446b2014-12-11 20:19:43 -0800401 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800402 containsString("HTTP 404 Not Found"));
Ray Milkey02f446b2014-12-11 20:19:43 -0800403 }
404 }
405
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700406 /**
407 * Tests post of a single host via JSON stream.
408 */
409 @Test
410 public void testPost() {
Ray Milkeydc083442016-02-22 11:27:57 -0800411 mockHostProviderService.hostDetected(anyObject(), anyObject(), anyBoolean());
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700412 expectLastCall();
413 replay(mockHostProviderService);
414
415 expect(mockHostProviderRegistry.register(anyObject())).andReturn(mockHostProviderService);
416 mockHostProviderRegistry.unregister(anyObject());
417 expectLastCall();
418 replay(mockHostProviderRegistry);
419
420 replay(mockHostService);
421
Phaneendra Manda2be2f882015-11-11 15:23:40 +0530422 InputStream jsonStream = HostResourceTest.class
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700423 .getResourceAsStream("post-host.json");
Jian Li9d616492016-03-09 10:52:49 -0800424 WebTarget wt = target();
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700425
Jian Li9d616492016-03-09 10:52:49 -0800426 Response response = wt.path("hosts")
427 .request(MediaType.APPLICATION_JSON_TYPE)
428 .post(Entity.json(jsonStream));
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700429 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
430 String location = response.getLocation().getPath();
Luca Prete283a9622016-03-29 16:12:20 -0700431 assertThat(location, Matchers.startsWith("/hosts/11:22:33:44:55:66/None"));
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700432 }
Thomas Vachuska58a7c342016-12-13 01:10:56 -0800433
434 /**
435 * Tests administrative removal of a host.
436 */
437 @Test
438 public void testDelete() {
439 HostId hostId = HostId.hostId("11:22:33:44:55:66/None");
440 mockHostService.removeHost(hostId);
441 expectLastCall();
442 replay(mockHostService);
443
444 WebTarget wt = target();
445 Response response = wt.path("hosts/11:22:33:44:55:66/None")
446 .request(MediaType.APPLICATION_JSON_TYPE)
447 .delete();
448 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
449 }
Ray Milkey1f95bd32014-12-10 11:11:00 -0800450}
451