blob: 4bb9523c91d1dd9bb4e9fbe44a5d017f69bc8402 [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
164 // Check Ip Addresses
165 final JsonArray jsonHostIps = jsonHost.get("ipAddresses").asArray();
166 final Set<IpAddress> expectedHostIps = host.ipAddresses();
167 if (jsonHostIps.size() != expectedHostIps.size()) {
168 reason = "IP address arrays differ in size";
169 return false;
170 }
171
172 return true;
173 }
174
175 @Override
176 public void describeTo(Description description) {
177 description.appendText(reason);
178 }
Charles Chancd06c692017-04-27 20:46:06 -0700179
180 private boolean verifyLocation(JsonObject jsonLocation, HostLocation expectedLocation) {
181 final String jsonLocationElementId = jsonLocation.get("elementId").asString();
182 if (!jsonLocationElementId.equals(expectedLocation.elementId().toString())) {
183 reason = "location element id " + host.location().elementId().toString();
184 return false;
185 }
186 final String jsonLocationPortNumber = jsonLocation.get("port").asString();
187 if (!jsonLocationPortNumber.equals(expectedLocation.port().toString())) {
188 reason = "location portNumber " + expectedLocation.port().toString();
189 return false;
190 }
191 return true;
192 }
Ray Milkey1f95bd32014-12-10 11:11:00 -0800193 }
194
195 /**
196 * Factory to allocate a host array matcher.
197 *
198 * @param host host object we are looking for
199 * @return matcher
200 */
201 private static HostJsonMatcher matchesHost(Host host) {
202 return new HostJsonMatcher(host);
203 }
204
205 /**
206 * Hamcrest matcher to check that a host is represented properly in a JSON
207 * array of hosts.
208 */
209 public static class HostJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
210 private final Host host;
211 private String reason = "";
212
213 public HostJsonArrayMatcher(Host hostValue) {
214 host = hostValue;
215 }
216
217 @Override
218 public boolean matchesSafely(JsonArray json) {
219 boolean hostFound = false;
sdn5e935452016-08-30 04:12:54 -0700220 final int expectedAttributes = 6;
Ray Milkey1f95bd32014-12-10 11:11:00 -0800221 for (int jsonHostIndex = 0; jsonHostIndex < json.size();
222 jsonHostIndex++) {
223
224 final JsonObject jsonHost = json.get(jsonHostIndex).asObject();
225
226 if (jsonHost.names().size() != expectedAttributes) {
227 reason = "Found a host with the wrong number of attributes";
228 return false;
229 }
230
231 final String jsonHostId = jsonHost.get("id").asString();
232 if (jsonHostId.equals(host.id().toString())) {
233 hostFound = true;
234
235 // We found the correct host, check attribute values
236 assertThat(jsonHost, matchesHost(host));
237 }
238 }
239 if (!hostFound) {
240 reason = "Host with id " + host.id().toString() + " not found";
241 return false;
242 } else {
243 return true;
244 }
245 }
246
247 @Override
248 public void describeTo(Description description) {
249 description.appendText(reason);
250 }
251 }
252
253 /**
254 * Factory to allocate a host array matcher.
255 *
256 * @param host host object we are looking for
257 * @return matcher
258 */
259 private static HostJsonArrayMatcher hasHost(Host host) {
260 return new HostJsonArrayMatcher(host);
261 }
262
263 /**
264 * Tests the result of the rest api GET when there are no hosts.
265 */
266 @Test
267 public void testHostsEmptyArray() {
268 replay(mockHostService);
Jian Li9d616492016-03-09 10:52:49 -0800269 WebTarget wt = target();
270 String response = wt.path("hosts").request().get(String.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800271 assertThat(response, is("{\"hosts\":[]}"));
272 }
273
274 /**
275 * Tests the result of the rest api GET when hosts are defined.
276 */
277 @Test
278 public void testHostsArray() {
279 replay(mockHostService);
280 final ProviderId pid = new ProviderId("of", "foo");
281 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
282 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
283 final Host host1 =
284 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
285 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
286 ips1);
287 final MacAddress mac2 = MacAddress.valueOf("00:00:11:00:00:02");
288 final Set<IpAddress> ips2 = ImmutableSet.of(
289 IpAddress.valueOf("2222:2222:2222:1::"),
290 IpAddress.valueOf("2222:2222:2222:2::"));
291 final Host host2 =
292 new DefaultHost(pid, HostId.hostId(mac2), valueOf(2), vlanId((short) 2),
293 new HostLocation(DeviceId.deviceId("2"), portNumber(22), 2),
294 ips2);
295 hosts.add(host1);
296 hosts.add(host2);
Jian Li9d616492016-03-09 10:52:49 -0800297 WebTarget wt = target();
298 String response = wt.path("hosts").request().get(String.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800299 assertThat(response, containsString("{\"hosts\":["));
300
Jian Li80cfe452016-01-14 16:04:58 -0800301 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800302 assertThat(result, notNullValue());
303
304 assertThat(result.names(), hasSize(1));
305 assertThat(result.names().get(0), is("hosts"));
306
307 final JsonArray hosts = result.get("hosts").asArray();
308 assertThat(hosts, notNullValue());
309
310 assertThat(hosts, hasHost(host1));
311 assertThat(hosts, hasHost(host2));
312 }
313
314 /**
315 * Tests fetch of one host by Id.
316 */
317 @Test
318 public void testSingleHostByIdFetch() {
319 final ProviderId pid = new ProviderId("of", "foo");
320 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
321 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
322 final Host host1 =
323 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
324 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
325 ips1);
326
327 hosts.add(host1);
328
329 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
330 .andReturn(host1)
331 .anyTimes();
332 replay(mockHostService);
333
Jian Li9d616492016-03-09 10:52:49 -0800334 WebTarget wt = target();
335 String response = wt.path("hosts/00:00:11:00:00:01%2F1").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800336 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800337 assertThat(result, matchesHost(host1));
338 }
339
340 /**
341 * Tests fetch of one host by mac and vlan.
342 */
343 @Test
344 public void testSingleHostByMacAndVlanFetch() {
345 final ProviderId pid = new ProviderId("of", "foo");
346 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
347 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
348 final Host host1 =
349 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
350 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
351 ips1);
352
353 hosts.add(host1);
354
355 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
356 .andReturn(host1)
357 .anyTimes();
358 replay(mockHostService);
359
Jian Li9d616492016-03-09 10:52:49 -0800360 WebTarget wt = target();
361 String response = wt.path("hosts/00:00:11:00:00:01/1").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800362 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800363 assertThat(result, matchesHost(host1));
364 }
365
Ray Milkey02f446b2014-12-11 20:19:43 -0800366 /**
367 * Tests that a fetch of a non-existent object throws an exception.
368 */
369 @Test
370 public void testBadGet() {
371
372 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
373 .andReturn(null)
374 .anyTimes();
375 replay(mockHostService);
376
Jian Li9d616492016-03-09 10:52:49 -0800377 WebTarget wt = target();
Ray Milkey02f446b2014-12-11 20:19:43 -0800378 try {
Jian Li9d616492016-03-09 10:52:49 -0800379 wt.path("hosts/00:00:11:00:00:01/1").request().get(String.class);
Ray Milkey02f446b2014-12-11 20:19:43 -0800380 fail("Fetch of non-existent host did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800381 } catch (NotFoundException ex) {
Ray Milkey02f446b2014-12-11 20:19:43 -0800382 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800383 containsString("HTTP 404 Not Found"));
Ray Milkey02f446b2014-12-11 20:19:43 -0800384 }
385 }
386
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700387 /**
388 * Tests post of a single host via JSON stream.
389 */
390 @Test
391 public void testPost() {
Ray Milkeydc083442016-02-22 11:27:57 -0800392 mockHostProviderService.hostDetected(anyObject(), anyObject(), anyBoolean());
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700393 expectLastCall();
394 replay(mockHostProviderService);
395
396 expect(mockHostProviderRegistry.register(anyObject())).andReturn(mockHostProviderService);
397 mockHostProviderRegistry.unregister(anyObject());
398 expectLastCall();
399 replay(mockHostProviderRegistry);
400
401 replay(mockHostService);
402
Phaneendra Manda2be2f882015-11-11 15:23:40 +0530403 InputStream jsonStream = HostResourceTest.class
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700404 .getResourceAsStream("post-host.json");
Jian Li9d616492016-03-09 10:52:49 -0800405 WebTarget wt = target();
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700406
Jian Li9d616492016-03-09 10:52:49 -0800407 Response response = wt.path("hosts")
408 .request(MediaType.APPLICATION_JSON_TYPE)
409 .post(Entity.json(jsonStream));
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700410 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
411 String location = response.getLocation().getPath();
Luca Prete283a9622016-03-29 16:12:20 -0700412 assertThat(location, Matchers.startsWith("/hosts/11:22:33:44:55:66/None"));
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700413 }
Thomas Vachuska58a7c342016-12-13 01:10:56 -0800414
415 /**
416 * Tests administrative removal of a host.
417 */
418 @Test
419 public void testDelete() {
420 HostId hostId = HostId.hostId("11:22:33:44:55:66/None");
421 mockHostService.removeHost(hostId);
422 expectLastCall();
423 replay(mockHostService);
424
425 WebTarget wt = target();
426 Response response = wt.path("hosts/11:22:33:44:55:66/None")
427 .request(MediaType.APPLICATION_JSON_TYPE)
428 .delete();
429 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
430 }
Ray Milkey1f95bd32014-12-10 11:11:00 -0800431}
432