blob: 94c390d0eb53f49835e5b646d1e757bf9aa5a7a7 [file] [log] [blame]
Ray Milkey1f95bd32014-12-10 11:11:00 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
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;
34import org.onlab.rest.BaseResource;
35import org.onosproject.codec.CodecService;
36import org.onosproject.codec.impl.CodecManager;
37import org.onosproject.net.DefaultHost;
38import org.onosproject.net.DeviceId;
39import org.onosproject.net.Host;
40import org.onosproject.net.HostId;
41import org.onosproject.net.HostLocation;
Thomas Vachuska58a7c342016-12-13 01:10:56 -080042import org.onosproject.net.host.HostAdminService;
Kedar Gupta7c4d1962015-08-03 10:46:04 -070043import org.onosproject.net.host.HostProviderRegistry;
44import org.onosproject.net.host.HostProviderService;
Ray Milkey1f95bd32014-12-10 11:11:00 -080045import org.onosproject.net.host.HostService;
46import org.onosproject.net.provider.ProviderId;
47
Jian Li9d616492016-03-09 10:52:49 -080048import javax.ws.rs.NotFoundException;
49import javax.ws.rs.client.Entity;
50import javax.ws.rs.client.WebTarget;
Kedar Gupta7c4d1962015-08-03 10:46:04 -070051import javax.ws.rs.core.MediaType;
Jian Li9d616492016-03-09 10:52:49 -080052import javax.ws.rs.core.Response;
53import java.io.InputStream;
54import java.net.HttpURLConnection;
55import java.util.HashSet;
Charles Chancd06c692017-04-27 20:46:06 -070056import java.util.Iterator;
Jian Li9d616492016-03-09 10:52:49 -080057import java.util.Set;
Kedar Gupta7c4d1962015-08-03 10:46:04 -070058
Jian Li9d616492016-03-09 10:52:49 -080059import static org.easymock.EasyMock.anyBoolean;
60import static org.easymock.EasyMock.anyObject;
61import static org.easymock.EasyMock.createMock;
62import static org.easymock.EasyMock.expect;
63import static org.easymock.EasyMock.expectLastCall;
64import static org.easymock.EasyMock.replay;
65import static org.easymock.EasyMock.verify;
Ray Milkey1f95bd32014-12-10 11:11:00 -080066import static org.hamcrest.Matchers.containsString;
67import static org.hamcrest.Matchers.hasSize;
68import static org.hamcrest.Matchers.is;
69import static org.hamcrest.Matchers.notNullValue;
70import static org.junit.Assert.assertThat;
Ray Milkey02f446b2014-12-11 20:19:43 -080071import static org.junit.Assert.fail;
Ray Milkey1f95bd32014-12-10 11:11:00 -080072import static org.onlab.packet.MacAddress.valueOf;
73import static org.onlab.packet.VlanId.vlanId;
74import static org.onosproject.net.PortNumber.portNumber;
75
76/**
77 * Simple example on how to write a JAX-RS unit test using Jersey test framework.
78 * A base class should/will be created to provide further assistance for testing.
79 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080080public class HostResourceTest extends ResourceTest {
Thomas Vachuska58a7c342016-12-13 01:10:56 -080081 final HostAdminService mockHostService = createMock(HostAdminService.class);
Kedar Gupta7c4d1962015-08-03 10:46:04 -070082 final HostProviderRegistry mockHostProviderRegistry = createMock(HostProviderRegistry.class);
83 final HostProviderService mockHostProviderService = createMock(HostProviderService.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -080084 final HashSet<Host> hosts = new HashSet<>();
85
Ray Milkeyed0b1662015-02-05 09:34:29 -080086 /**
87 * Initializes test mocks and environment.
88 */
Ray Milkey1f95bd32014-12-10 11:11:00 -080089 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -080090 public void setUpTest() {
Ray Milkey1f95bd32014-12-10 11:11:00 -080091 expect(mockHostService.getHosts()).andReturn(hosts).anyTimes();
92
93 // Register the services needed for the test
94 final CodecManager codecService = new CodecManager();
95 codecService.activate();
96 ServiceDirectory testDirectory =
97 new TestServiceDirectory()
98 .add(HostService.class, mockHostService)
Thomas Vachuska58a7c342016-12-13 01:10:56 -080099 .add(HostAdminService.class, mockHostService)
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700100 .add(CodecService.class, codecService)
101 .add(HostProviderRegistry.class, mockHostProviderRegistry);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800102 BaseResource.setServiceDirectory(testDirectory);
103 }
104
Ray Milkeyed0b1662015-02-05 09:34:29 -0800105 /**
106 * Verifies mocks.
107 */
Ray Milkey1f95bd32014-12-10 11:11:00 -0800108 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800109 public void tearDownTest() {
Ray Milkey1f95bd32014-12-10 11:11:00 -0800110 verify(mockHostService);
111 }
112
113 /**
114 * Hamcrest matcher to check that a host representation in JSON matches
115 * the actual host.
116 */
117 public static class HostJsonMatcher extends TypeSafeMatcher<JsonObject> {
118 private final Host host;
119 private String reason = "";
120
121 public HostJsonMatcher(Host hostValue) {
122 host = hostValue;
123 }
124
125 @Override
126 public boolean matchesSafely(JsonObject jsonHost) {
127 // Check id
128 final String jsonId = jsonHost.get("id").asString();
129 if (!jsonId.equals(host.id().toString())) {
130 reason = "id " + host.id().toString();
131 return false;
132 }
133
134 // Check vlan id
135 final String jsonVlanId = jsonHost.get("vlan").asString();
136 if (!jsonVlanId.equals(host.vlan().toString())) {
137 reason = "vlan id " + host.vlan().toString();
138 return false;
139 }
140
141 // Check mac address
142 final String jsonMacAddress = jsonHost.get("mac").asString();
143 if (!jsonMacAddress.equals(host.mac().toString())) {
144 reason = "mac address " + host.mac().toString();
145 return false;
146 }
147
Charles Chancd06c692017-04-27 20:46:06 -0700148 // Check host locations
149 final JsonArray jsonLocations = jsonHost.get("locations").asArray();
150 final Set<HostLocation> expectedLocations = host.locations();
151 if (jsonLocations.size() != expectedLocations.size()) {
152 reason = "locations arrays differ in size";
Ray Milkey1f95bd32014-12-10 11:11:00 -0800153 return false;
154 }
155
Charles Chancd06c692017-04-27 20:46:06 -0700156 Iterator<JsonValue> jsonIterator = jsonLocations.iterator();
157 Iterator<HostLocation> locIterator = expectedLocations.iterator();
158 while (jsonIterator.hasNext()) {
159 boolean result = verifyLocation(jsonIterator.next().asObject(), locIterator.next());
160 if (!result) {
161 return false;
162 }
Ray Milkey1f95bd32014-12-10 11:11:00 -0800163 }
164
165 // Check Ip Addresses
166 final JsonArray jsonHostIps = jsonHost.get("ipAddresses").asArray();
167 final Set<IpAddress> expectedHostIps = host.ipAddresses();
168 if (jsonHostIps.size() != expectedHostIps.size()) {
169 reason = "IP address arrays differ in size";
170 return false;
171 }
172
173 return true;
174 }
175
176 @Override
177 public void describeTo(Description description) {
178 description.appendText(reason);
179 }
Charles Chancd06c692017-04-27 20:46:06 -0700180
181 private boolean verifyLocation(JsonObject jsonLocation, HostLocation expectedLocation) {
182 final String jsonLocationElementId = jsonLocation.get("elementId").asString();
183 if (!jsonLocationElementId.equals(expectedLocation.elementId().toString())) {
184 reason = "location element id " + host.location().elementId().toString();
185 return false;
186 }
187 final String jsonLocationPortNumber = jsonLocation.get("port").asString();
188 if (!jsonLocationPortNumber.equals(expectedLocation.port().toString())) {
189 reason = "location portNumber " + expectedLocation.port().toString();
190 return false;
191 }
192 return true;
193 }
Ray Milkey1f95bd32014-12-10 11:11:00 -0800194 }
195
196 /**
197 * Factory to allocate a host array matcher.
198 *
199 * @param host host object we are looking for
200 * @return matcher
201 */
202 private static HostJsonMatcher matchesHost(Host host) {
203 return new HostJsonMatcher(host);
204 }
205
206 /**
207 * Hamcrest matcher to check that a host is represented properly in a JSON
208 * array of hosts.
209 */
210 public static class HostJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
211 private final Host host;
212 private String reason = "";
213
214 public HostJsonArrayMatcher(Host hostValue) {
215 host = hostValue;
216 }
217
218 @Override
219 public boolean matchesSafely(JsonArray json) {
220 boolean hostFound = false;
sdn5e935452016-08-30 04:12:54 -0700221 final int expectedAttributes = 6;
Ray Milkey1f95bd32014-12-10 11:11:00 -0800222 for (int jsonHostIndex = 0; jsonHostIndex < json.size();
223 jsonHostIndex++) {
224
225 final JsonObject jsonHost = json.get(jsonHostIndex).asObject();
226
227 if (jsonHost.names().size() != expectedAttributes) {
228 reason = "Found a host with the wrong number of attributes";
229 return false;
230 }
231
232 final String jsonHostId = jsonHost.get("id").asString();
233 if (jsonHostId.equals(host.id().toString())) {
234 hostFound = true;
235
236 // We found the correct host, check attribute values
237 assertThat(jsonHost, matchesHost(host));
238 }
239 }
240 if (!hostFound) {
241 reason = "Host with id " + host.id().toString() + " not found";
242 return false;
243 } else {
244 return true;
245 }
246 }
247
248 @Override
249 public void describeTo(Description description) {
250 description.appendText(reason);
251 }
252 }
253
254 /**
255 * Factory to allocate a host array matcher.
256 *
257 * @param host host object we are looking for
258 * @return matcher
259 */
260 private static HostJsonArrayMatcher hasHost(Host host) {
261 return new HostJsonArrayMatcher(host);
262 }
263
264 /**
265 * Tests the result of the rest api GET when there are no hosts.
266 */
267 @Test
268 public void testHostsEmptyArray() {
269 replay(mockHostService);
Jian Li9d616492016-03-09 10:52:49 -0800270 WebTarget wt = target();
271 String response = wt.path("hosts").request().get(String.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800272 assertThat(response, is("{\"hosts\":[]}"));
273 }
274
275 /**
276 * Tests the result of the rest api GET when hosts are defined.
277 */
278 @Test
279 public void testHostsArray() {
280 replay(mockHostService);
281 final ProviderId pid = new ProviderId("of", "foo");
282 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
283 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
284 final Host host1 =
285 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
286 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
287 ips1);
288 final MacAddress mac2 = MacAddress.valueOf("00:00:11:00:00:02");
289 final Set<IpAddress> ips2 = ImmutableSet.of(
290 IpAddress.valueOf("2222:2222:2222:1::"),
291 IpAddress.valueOf("2222:2222:2222:2::"));
292 final Host host2 =
293 new DefaultHost(pid, HostId.hostId(mac2), valueOf(2), vlanId((short) 2),
294 new HostLocation(DeviceId.deviceId("2"), portNumber(22), 2),
295 ips2);
296 hosts.add(host1);
297 hosts.add(host2);
Jian Li9d616492016-03-09 10:52:49 -0800298 WebTarget wt = target();
299 String response = wt.path("hosts").request().get(String.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800300 assertThat(response, containsString("{\"hosts\":["));
301
Jian Li80cfe452016-01-14 16:04:58 -0800302 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800303 assertThat(result, notNullValue());
304
305 assertThat(result.names(), hasSize(1));
306 assertThat(result.names().get(0), is("hosts"));
307
308 final JsonArray hosts = result.get("hosts").asArray();
309 assertThat(hosts, notNullValue());
310
311 assertThat(hosts, hasHost(host1));
312 assertThat(hosts, hasHost(host2));
313 }
314
315 /**
316 * Tests fetch of one host by Id.
317 */
318 @Test
319 public void testSingleHostByIdFetch() {
320 final ProviderId pid = new ProviderId("of", "foo");
321 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
322 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
323 final Host host1 =
324 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
325 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
326 ips1);
327
328 hosts.add(host1);
329
330 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
331 .andReturn(host1)
332 .anyTimes();
333 replay(mockHostService);
334
Jian Li9d616492016-03-09 10:52:49 -0800335 WebTarget wt = target();
336 String response = wt.path("hosts/00:00:11:00:00:01%2F1").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800337 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800338 assertThat(result, matchesHost(host1));
339 }
340
341 /**
342 * Tests fetch of one host by mac and vlan.
343 */
344 @Test
345 public void testSingleHostByMacAndVlanFetch() {
346 final ProviderId pid = new ProviderId("of", "foo");
347 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
348 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
349 final Host host1 =
350 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
351 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
352 ips1);
353
354 hosts.add(host1);
355
356 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
357 .andReturn(host1)
358 .anyTimes();
359 replay(mockHostService);
360
Jian Li9d616492016-03-09 10:52:49 -0800361 WebTarget wt = target();
362 String response = wt.path("hosts/00:00:11:00:00:01/1").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800363 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800364 assertThat(result, matchesHost(host1));
365 }
366
Ray Milkey02f446b2014-12-11 20:19:43 -0800367 /**
368 * Tests that a fetch of a non-existent object throws an exception.
369 */
370 @Test
371 public void testBadGet() {
372
373 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
374 .andReturn(null)
375 .anyTimes();
376 replay(mockHostService);
377
Jian Li9d616492016-03-09 10:52:49 -0800378 WebTarget wt = target();
Ray Milkey02f446b2014-12-11 20:19:43 -0800379 try {
Jian Li9d616492016-03-09 10:52:49 -0800380 wt.path("hosts/00:00:11:00:00:01/1").request().get(String.class);
Ray Milkey02f446b2014-12-11 20:19:43 -0800381 fail("Fetch of non-existent host did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800382 } catch (NotFoundException ex) {
Ray Milkey02f446b2014-12-11 20:19:43 -0800383 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800384 containsString("HTTP 404 Not Found"));
Ray Milkey02f446b2014-12-11 20:19:43 -0800385 }
386 }
387
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700388 /**
389 * Tests post of a single host via JSON stream.
390 */
391 @Test
392 public void testPost() {
Ray Milkeydc083442016-02-22 11:27:57 -0800393 mockHostProviderService.hostDetected(anyObject(), anyObject(), anyBoolean());
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700394 expectLastCall();
395 replay(mockHostProviderService);
396
397 expect(mockHostProviderRegistry.register(anyObject())).andReturn(mockHostProviderService);
398 mockHostProviderRegistry.unregister(anyObject());
399 expectLastCall();
400 replay(mockHostProviderRegistry);
401
402 replay(mockHostService);
403
Phaneendra Manda2be2f882015-11-11 15:23:40 +0530404 InputStream jsonStream = HostResourceTest.class
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700405 .getResourceAsStream("post-host.json");
Jian Li9d616492016-03-09 10:52:49 -0800406 WebTarget wt = target();
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700407
Jian Li9d616492016-03-09 10:52:49 -0800408 Response response = wt.path("hosts")
409 .request(MediaType.APPLICATION_JSON_TYPE)
410 .post(Entity.json(jsonStream));
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700411 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
412 String location = response.getLocation().getPath();
Luca Prete283a9622016-03-29 16:12:20 -0700413 assertThat(location, Matchers.startsWith("/hosts/11:22:33:44:55:66/None"));
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700414 }
Thomas Vachuska58a7c342016-12-13 01:10:56 -0800415
416 /**
417 * Tests administrative removal of a host.
418 */
419 @Test
420 public void testDelete() {
421 HostId hostId = HostId.hostId("11:22:33:44:55:66/None");
422 mockHostService.removeHost(hostId);
423 expectLastCall();
424 replay(mockHostService);
425
426 WebTarget wt = target();
427 Response response = wt.path("hosts/11:22:33:44:55:66/None")
428 .request(MediaType.APPLICATION_JSON_TYPE)
429 .delete();
430 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
431 }
Ray Milkey1f95bd32014-12-10 11:11:00 -0800432}
433