blob: 4c0ea918263bd9d10ea84a9b081ae91aee2530a7 [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;
22import com.google.common.collect.ImmutableSet;
Ray Milkey1f95bd32014-12-10 11:11:00 -080023import org.hamcrest.Description;
Kedar Gupta7c4d1962015-08-03 10:46:04 -070024import org.hamcrest.Matchers;
Ray Milkey1f95bd32014-12-10 11:11:00 -080025import org.hamcrest.TypeSafeMatcher;
26import org.junit.After;
27import org.junit.Before;
28import org.junit.Test;
29import org.onlab.osgi.ServiceDirectory;
30import org.onlab.osgi.TestServiceDirectory;
31import org.onlab.packet.IpAddress;
32import org.onlab.packet.MacAddress;
33import org.onlab.rest.BaseResource;
34import 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;
55import java.util.Set;
Kedar Gupta7c4d1962015-08-03 10:46:04 -070056
Jian Li9d616492016-03-09 10:52:49 -080057import static org.easymock.EasyMock.anyBoolean;
58import static org.easymock.EasyMock.anyObject;
59import static org.easymock.EasyMock.createMock;
60import static org.easymock.EasyMock.expect;
61import static org.easymock.EasyMock.expectLastCall;
62import static org.easymock.EasyMock.replay;
63import static org.easymock.EasyMock.verify;
Ray Milkey1f95bd32014-12-10 11:11:00 -080064import static org.hamcrest.Matchers.containsString;
65import static org.hamcrest.Matchers.hasSize;
66import static org.hamcrest.Matchers.is;
67import static org.hamcrest.Matchers.notNullValue;
68import static org.junit.Assert.assertThat;
Ray Milkey02f446b2014-12-11 20:19:43 -080069import static org.junit.Assert.fail;
Ray Milkey1f95bd32014-12-10 11:11:00 -080070import static org.onlab.packet.MacAddress.valueOf;
71import static org.onlab.packet.VlanId.vlanId;
72import static org.onosproject.net.PortNumber.portNumber;
73
74/**
75 * Simple example on how to write a JAX-RS unit test using Jersey test framework.
76 * A base class should/will be created to provide further assistance for testing.
77 */
Ray Milkey9c3d3362015-01-28 10:39:56 -080078public class HostResourceTest extends ResourceTest {
Thomas Vachuska58a7c342016-12-13 01:10:56 -080079 final HostAdminService mockHostService = createMock(HostAdminService.class);
Kedar Gupta7c4d1962015-08-03 10:46:04 -070080 final HostProviderRegistry mockHostProviderRegistry = createMock(HostProviderRegistry.class);
81 final HostProviderService mockHostProviderService = createMock(HostProviderService.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -080082 final HashSet<Host> hosts = new HashSet<>();
83
Ray Milkeyed0b1662015-02-05 09:34:29 -080084 /**
85 * Initializes test mocks and environment.
86 */
Ray Milkey1f95bd32014-12-10 11:11:00 -080087 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -080088 public void setUpTest() {
Ray Milkey1f95bd32014-12-10 11:11:00 -080089 expect(mockHostService.getHosts()).andReturn(hosts).anyTimes();
90
91 // Register the services needed for the test
92 final CodecManager codecService = new CodecManager();
93 codecService.activate();
94 ServiceDirectory testDirectory =
95 new TestServiceDirectory()
96 .add(HostService.class, mockHostService)
Thomas Vachuska58a7c342016-12-13 01:10:56 -080097 .add(HostAdminService.class, mockHostService)
Kedar Gupta7c4d1962015-08-03 10:46:04 -070098 .add(CodecService.class, codecService)
99 .add(HostProviderRegistry.class, mockHostProviderRegistry);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800100 BaseResource.setServiceDirectory(testDirectory);
101 }
102
Ray Milkeyed0b1662015-02-05 09:34:29 -0800103 /**
104 * Verifies mocks.
105 */
Ray Milkey1f95bd32014-12-10 11:11:00 -0800106 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800107 public void tearDownTest() {
Ray Milkey1f95bd32014-12-10 11:11:00 -0800108 verify(mockHostService);
109 }
110
111 /**
112 * Hamcrest matcher to check that a host representation in JSON matches
113 * the actual host.
114 */
115 public static class HostJsonMatcher extends TypeSafeMatcher<JsonObject> {
116 private final Host host;
117 private String reason = "";
118
119 public HostJsonMatcher(Host hostValue) {
120 host = hostValue;
121 }
122
123 @Override
124 public boolean matchesSafely(JsonObject jsonHost) {
125 // Check id
126 final String jsonId = jsonHost.get("id").asString();
127 if (!jsonId.equals(host.id().toString())) {
128 reason = "id " + host.id().toString();
129 return false;
130 }
131
132 // Check vlan id
133 final String jsonVlanId = jsonHost.get("vlan").asString();
134 if (!jsonVlanId.equals(host.vlan().toString())) {
135 reason = "vlan id " + host.vlan().toString();
136 return false;
137 }
138
139 // Check mac address
140 final String jsonMacAddress = jsonHost.get("mac").asString();
141 if (!jsonMacAddress.equals(host.mac().toString())) {
142 reason = "mac address " + host.mac().toString();
143 return false;
144 }
145
146 // Check location element id
147 final JsonObject jsonLocation = jsonHost.get("location").asObject();
148 final String jsonLocationElementId = jsonLocation.get("elementId").asString();
149 if (!jsonLocationElementId.equals(host.location().elementId().toString())) {
150 reason = "location element id " + host.location().elementId().toString();
151 return false;
152 }
153
154 // Check location port number
155 final String jsonLocationPortNumber = jsonLocation.get("port").asString();
156 if (!jsonLocationPortNumber.equals(host.location().port().toString())) {
157 reason = "location portNumber " + host.location().port().toString();
158 return false;
159 }
160
161 // Check Ip Addresses
162 final JsonArray jsonHostIps = jsonHost.get("ipAddresses").asArray();
163 final Set<IpAddress> expectedHostIps = host.ipAddresses();
164 if (jsonHostIps.size() != expectedHostIps.size()) {
165 reason = "IP address arrays differ in size";
166 return false;
167 }
168
169 return true;
170 }
171
172 @Override
173 public void describeTo(Description description) {
174 description.appendText(reason);
175 }
176 }
177
178 /**
179 * Factory to allocate a host array matcher.
180 *
181 * @param host host object we are looking for
182 * @return matcher
183 */
184 private static HostJsonMatcher matchesHost(Host host) {
185 return new HostJsonMatcher(host);
186 }
187
188 /**
189 * Hamcrest matcher to check that a host is represented properly in a JSON
190 * array of hosts.
191 */
192 public static class HostJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
193 private final Host host;
194 private String reason = "";
195
196 public HostJsonArrayMatcher(Host hostValue) {
197 host = hostValue;
198 }
199
200 @Override
201 public boolean matchesSafely(JsonArray json) {
202 boolean hostFound = false;
sdn5e935452016-08-30 04:12:54 -0700203 final int expectedAttributes = 6;
Ray Milkey1f95bd32014-12-10 11:11:00 -0800204 for (int jsonHostIndex = 0; jsonHostIndex < json.size();
205 jsonHostIndex++) {
206
207 final JsonObject jsonHost = json.get(jsonHostIndex).asObject();
208
209 if (jsonHost.names().size() != expectedAttributes) {
210 reason = "Found a host with the wrong number of attributes";
211 return false;
212 }
213
214 final String jsonHostId = jsonHost.get("id").asString();
215 if (jsonHostId.equals(host.id().toString())) {
216 hostFound = true;
217
218 // We found the correct host, check attribute values
219 assertThat(jsonHost, matchesHost(host));
220 }
221 }
222 if (!hostFound) {
223 reason = "Host with id " + host.id().toString() + " not found";
224 return false;
225 } else {
226 return true;
227 }
228 }
229
230 @Override
231 public void describeTo(Description description) {
232 description.appendText(reason);
233 }
234 }
235
236 /**
237 * Factory to allocate a host array matcher.
238 *
239 * @param host host object we are looking for
240 * @return matcher
241 */
242 private static HostJsonArrayMatcher hasHost(Host host) {
243 return new HostJsonArrayMatcher(host);
244 }
245
246 /**
247 * Tests the result of the rest api GET when there are no hosts.
248 */
249 @Test
250 public void testHostsEmptyArray() {
251 replay(mockHostService);
Jian Li9d616492016-03-09 10:52:49 -0800252 WebTarget wt = target();
253 String response = wt.path("hosts").request().get(String.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800254 assertThat(response, is("{\"hosts\":[]}"));
255 }
256
257 /**
258 * Tests the result of the rest api GET when hosts are defined.
259 */
260 @Test
261 public void testHostsArray() {
262 replay(mockHostService);
263 final ProviderId pid = new ProviderId("of", "foo");
264 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
265 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
266 final Host host1 =
267 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
268 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
269 ips1);
270 final MacAddress mac2 = MacAddress.valueOf("00:00:11:00:00:02");
271 final Set<IpAddress> ips2 = ImmutableSet.of(
272 IpAddress.valueOf("2222:2222:2222:1::"),
273 IpAddress.valueOf("2222:2222:2222:2::"));
274 final Host host2 =
275 new DefaultHost(pid, HostId.hostId(mac2), valueOf(2), vlanId((short) 2),
276 new HostLocation(DeviceId.deviceId("2"), portNumber(22), 2),
277 ips2);
278 hosts.add(host1);
279 hosts.add(host2);
Jian Li9d616492016-03-09 10:52:49 -0800280 WebTarget wt = target();
281 String response = wt.path("hosts").request().get(String.class);
Ray Milkey1f95bd32014-12-10 11:11:00 -0800282 assertThat(response, containsString("{\"hosts\":["));
283
Jian Li80cfe452016-01-14 16:04:58 -0800284 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800285 assertThat(result, notNullValue());
286
287 assertThat(result.names(), hasSize(1));
288 assertThat(result.names().get(0), is("hosts"));
289
290 final JsonArray hosts = result.get("hosts").asArray();
291 assertThat(hosts, notNullValue());
292
293 assertThat(hosts, hasHost(host1));
294 assertThat(hosts, hasHost(host2));
295 }
296
297 /**
298 * Tests fetch of one host by Id.
299 */
300 @Test
301 public void testSingleHostByIdFetch() {
302 final ProviderId pid = new ProviderId("of", "foo");
303 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
304 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
305 final Host host1 =
306 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
307 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
308 ips1);
309
310 hosts.add(host1);
311
312 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
313 .andReturn(host1)
314 .anyTimes();
315 replay(mockHostService);
316
Jian Li9d616492016-03-09 10:52:49 -0800317 WebTarget wt = target();
318 String response = wt.path("hosts/00:00:11:00:00:01%2F1").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800319 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800320 assertThat(result, matchesHost(host1));
321 }
322
323 /**
324 * Tests fetch of one host by mac and vlan.
325 */
326 @Test
327 public void testSingleHostByMacAndVlanFetch() {
328 final ProviderId pid = new ProviderId("of", "foo");
329 final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01");
330 final Set<IpAddress> ips1 = ImmutableSet.of(IpAddress.valueOf("1111:1111:1111:1::"));
331 final Host host1 =
332 new DefaultHost(pid, HostId.hostId(mac1), valueOf(1), vlanId((short) 1),
333 new HostLocation(DeviceId.deviceId("1"), portNumber(11), 1),
334 ips1);
335
336 hosts.add(host1);
337
338 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
339 .andReturn(host1)
340 .anyTimes();
341 replay(mockHostService);
342
Jian Li9d616492016-03-09 10:52:49 -0800343 WebTarget wt = target();
344 String response = wt.path("hosts/00:00:11:00:00:01/1").request().get(String.class);
Jian Li80cfe452016-01-14 16:04:58 -0800345 final JsonObject result = Json.parse(response).asObject();
Ray Milkey1f95bd32014-12-10 11:11:00 -0800346 assertThat(result, matchesHost(host1));
347 }
348
Ray Milkey02f446b2014-12-11 20:19:43 -0800349 /**
350 * Tests that a fetch of a non-existent object throws an exception.
351 */
352 @Test
353 public void testBadGet() {
354
355 expect(mockHostService.getHost(HostId.hostId("00:00:11:00:00:01/1")))
356 .andReturn(null)
357 .anyTimes();
358 replay(mockHostService);
359
Jian Li9d616492016-03-09 10:52:49 -0800360 WebTarget wt = target();
Ray Milkey02f446b2014-12-11 20:19:43 -0800361 try {
Jian Li9d616492016-03-09 10:52:49 -0800362 wt.path("hosts/00:00:11:00:00:01/1").request().get(String.class);
Ray Milkey02f446b2014-12-11 20:19:43 -0800363 fail("Fetch of non-existent host did not throw an exception");
Jian Li9d616492016-03-09 10:52:49 -0800364 } catch (NotFoundException ex) {
Ray Milkey02f446b2014-12-11 20:19:43 -0800365 assertThat(ex.getMessage(),
Jian Li9d616492016-03-09 10:52:49 -0800366 containsString("HTTP 404 Not Found"));
Ray Milkey02f446b2014-12-11 20:19:43 -0800367 }
368 }
369
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700370 /**
371 * Tests post of a single host via JSON stream.
372 */
373 @Test
374 public void testPost() {
Ray Milkeydc083442016-02-22 11:27:57 -0800375 mockHostProviderService.hostDetected(anyObject(), anyObject(), anyBoolean());
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700376 expectLastCall();
377 replay(mockHostProviderService);
378
379 expect(mockHostProviderRegistry.register(anyObject())).andReturn(mockHostProviderService);
380 mockHostProviderRegistry.unregister(anyObject());
381 expectLastCall();
382 replay(mockHostProviderRegistry);
383
384 replay(mockHostService);
385
Phaneendra Manda2be2f882015-11-11 15:23:40 +0530386 InputStream jsonStream = HostResourceTest.class
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700387 .getResourceAsStream("post-host.json");
Jian Li9d616492016-03-09 10:52:49 -0800388 WebTarget wt = target();
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700389
Jian Li9d616492016-03-09 10:52:49 -0800390 Response response = wt.path("hosts")
391 .request(MediaType.APPLICATION_JSON_TYPE)
392 .post(Entity.json(jsonStream));
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700393 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
394 String location = response.getLocation().getPath();
Luca Prete283a9622016-03-29 16:12:20 -0700395 assertThat(location, Matchers.startsWith("/hosts/11:22:33:44:55:66/None"));
Kedar Gupta7c4d1962015-08-03 10:46:04 -0700396 }
Thomas Vachuska58a7c342016-12-13 01:10:56 -0800397
398 /**
399 * Tests administrative removal of a host.
400 */
401 @Test
402 public void testDelete() {
403 HostId hostId = HostId.hostId("11:22:33:44:55:66/None");
404 mockHostService.removeHost(hostId);
405 expectLastCall();
406 replay(mockHostService);
407
408 WebTarget wt = target();
409 Response response = wt.path("hosts/11:22:33:44:55:66/None")
410 .request(MediaType.APPLICATION_JSON_TYPE)
411 .delete();
412 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_NO_CONTENT));
413 }
Ray Milkey1f95bd32014-12-10 11:11:00 -0800414}
415