blob: e2a6bb13462a0d57dc317a97f833e075fd93aa0b [file] [log] [blame]
Ray Milkeyf195b022015-02-03 15:13:11 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Ray Milkeyf195b022015-02-03 15:13:11 -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 Milkeyf195b022015-02-03 15:13:11 -080017
Jian Li80cfe452016-01-14 16:04:58 -080018import com.eclipsesource.json.Json;
Thomas Vachuskaebf5e542015-02-03 19:38:13 -080019import com.eclipsesource.json.JsonArray;
20import com.eclipsesource.json.JsonObject;
21import com.google.common.collect.ImmutableList;
22import com.google.common.collect.ImmutableSet;
Ray Milkeyf195b022015-02-03 15:13:11 -080023import org.hamcrest.Description;
24import org.hamcrest.TypeSafeMatcher;
Ray Milkeyf195b022015-02-03 15:13:11 -080025import org.junit.Before;
26import org.junit.Test;
27import org.onlab.osgi.ServiceDirectory;
28import org.onlab.osgi.TestServiceDirectory;
29import org.onlab.rest.BaseResource;
30import org.onosproject.app.ApplicationAdminService;
31import org.onosproject.app.ApplicationService;
32import org.onosproject.app.ApplicationState;
33import org.onosproject.codec.CodecService;
34import org.onosproject.codec.impl.ApplicationCodec;
35import org.onosproject.codec.impl.CodecManager;
36import org.onosproject.codec.impl.MockCodecContext;
37import org.onosproject.core.Application;
38import org.onosproject.core.ApplicationId;
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +090039import org.onosproject.core.ApplicationRole;
Jian Lie1c1c8d2016-05-09 16:24:40 -070040import org.onosproject.core.CoreService;
Ray Milkeyf195b022015-02-03 15:13:11 -080041import org.onosproject.core.DefaultApplication;
42import org.onosproject.core.DefaultApplicationId;
43import org.onosproject.core.Version;
44
Jian Li9d616492016-03-09 10:52:49 -080045import javax.ws.rs.client.Entity;
46import javax.ws.rs.client.WebTarget;
47import javax.ws.rs.core.MediaType;
Thomas Vachuskaebf5e542015-02-03 19:38:13 -080048import java.io.InputStream;
49import java.net.URI;
50import java.util.Optional;
Ray Milkeyf195b022015-02-03 15:13:11 -080051
Jian Li9d616492016-03-09 10:52:49 -080052import static org.easymock.EasyMock.createMock;
53import static org.easymock.EasyMock.expect;
54import static org.easymock.EasyMock.expectLastCall;
55import static org.easymock.EasyMock.isA;
56import static org.easymock.EasyMock.replay;
57import static org.easymock.EasyMock.verify;
Ray Milkeyf195b022015-02-03 15:13:11 -080058import static org.hamcrest.MatcherAssert.assertThat;
Yuta HIGUCHI293ede02015-02-05 00:08:41 -080059import static org.hamcrest.Matchers.containsString;
60import static org.hamcrest.Matchers.hasSize;
61import static org.hamcrest.Matchers.is;
62import static org.hamcrest.Matchers.notNullValue;
Ray Milkeyf195b022015-02-03 15:13:11 -080063
64/**
65 * Unit tests for applications REST APIs.
66 */
67
68public class ApplicationsResourceTest extends ResourceTest {
69
Jian Lie1c1c8d2016-05-09 16:24:40 -070070 private static class MockCodecContextWithAppService extends MockCodecContext {
71 private ApplicationAdminService appService;
Ray Milkeyf195b022015-02-03 15:13:11 -080072
Jian Lie1c1c8d2016-05-09 16:24:40 -070073 MockCodecContextWithAppService(ApplicationAdminService appService) {
74 this.appService = appService;
Ray Milkeyf195b022015-02-03 15:13:11 -080075 }
76
77 @Override
78 @SuppressWarnings("unchecked")
Ray Milkey3078fc02015-05-06 16:14:14 -070079 public <T> T getService(Class<T> serviceClass) {
Jian Lie1c1c8d2016-05-09 16:24:40 -070080 return (T) appService;
Ray Milkeyf195b022015-02-03 15:13:11 -080081 }
82 }
83
Jian Lie1c1c8d2016-05-09 16:24:40 -070084 private static class MockCodecContextWithCoreService extends MockCodecContext {
85 private CoreService coreService;
86
87 MockCodecContextWithCoreService(CoreService coreService) {
88 this.coreService = coreService;
89 }
90
91 @Override
92 @SuppressWarnings("unchecked")
93 public <T> T getService(Class<T> serviceClass) {
94 return (T) coreService;
95 }
96 }
97
98 private ApplicationAdminService appService;
99 private CoreService coreService;
Ray Milkeyf195b022015-02-03 15:13:11 -0800100 private ApplicationId id1 = new DefaultApplicationId(1, "app1");
101 private ApplicationId id2 = new DefaultApplicationId(2, "app2");
102 private ApplicationId id3 = new DefaultApplicationId(3, "app3");
103 private ApplicationId id4 = new DefaultApplicationId(4, "app4");
104
105 private static final URI FURL = URI.create("mvn:org.foo-features/1.2a/xml/features");
106 private static final Version VER = Version.version(1, 2, "a", null);
107
108 private Application app1 =
Simon Huntafae2f72016-03-04 21:18:23 -0800109 new DefaultApplication(id1, VER, "title1",
Jian Lie1c1c8d2016-05-09 16:24:40 -0700110 "desc1", "origin1", "category1", "url1",
111 "readme1", new byte[0], ApplicationRole.ADMIN,
112 ImmutableSet.of(), Optional.of(FURL),
113 ImmutableList.of("My Feature"), ImmutableList.of());
Ray Milkeyf195b022015-02-03 15:13:11 -0800114 private Application app2 =
Simon Huntafae2f72016-03-04 21:18:23 -0800115 new DefaultApplication(id2, VER, "title2",
Jian Lie1c1c8d2016-05-09 16:24:40 -0700116 "desc2", "origin2", "category2", "url2",
117 "readme2", new byte[0], ApplicationRole.ADMIN,
118 ImmutableSet.of(), Optional.of(FURL),
119 ImmutableList.of("My Feature"), ImmutableList.of());
Ray Milkeyf195b022015-02-03 15:13:11 -0800120 private Application app3 =
Simon Huntafae2f72016-03-04 21:18:23 -0800121 new DefaultApplication(id3, VER, "title3",
Jian Lie1c1c8d2016-05-09 16:24:40 -0700122 "desc3", "origin3", "category3", "url3",
123 "readme3", new byte[0], ApplicationRole.ADMIN,
124 ImmutableSet.of(), Optional.of(FURL),
125 ImmutableList.of("My Feature"), ImmutableList.of());
Ray Milkeyf195b022015-02-03 15:13:11 -0800126 private Application app4 =
Simon Huntafae2f72016-03-04 21:18:23 -0800127 new DefaultApplication(id4, VER, "title4",
Jian Lie1c1c8d2016-05-09 16:24:40 -0700128 "desc4", "origin4", "category4", "url4",
129 "readme4", new byte[0], ApplicationRole.ADMIN,
130 ImmutableSet.of(), Optional.of(FURL),
131 ImmutableList.of("My Feature"), ImmutableList.of());
Ray Milkeyf195b022015-02-03 15:13:11 -0800132
133 /**
Ray Milkeyed0b1662015-02-05 09:34:29 -0800134 * Hamcrest matcher to check that an application representation in JSON matches
Ray Milkeyf195b022015-02-03 15:13:11 -0800135 * the actual device.
136 */
137 private static class AppJsonMatcher extends TypeSafeMatcher<JsonObject> {
138 private final Application app;
139 private String reason = "";
140
141 public AppJsonMatcher(Application appValue) {
142 app = appValue;
143 }
144
145 @Override
146 public boolean matchesSafely(JsonObject jsonApp) {
147 // check id
148 short jsonId = (short) jsonApp.get("id").asInt();
149 if (jsonId != app.id().id()) {
150 reason = "id " + app.id().id();
151 return false;
152 }
153
154 // check name
155 String jsonName = jsonApp.get("name").asString();
156 if (!jsonName.equals(app.id().name())) {
157 reason = "name " + app.id().name();
158 return false;
159 }
160
161 // check origin
162 String jsonOrigin = jsonApp.get("origin").asString();
163 if (!jsonOrigin.equals(app.origin())) {
164 reason = "manufacturer " + app.origin();
165 return false;
166 }
167
168 return true;
169 }
170
171 @Override
172 public void describeTo(Description description) {
173 description.appendText(reason);
174 }
175 }
176
177 /**
Jian Lie1c1c8d2016-05-09 16:24:40 -0700178 * Hamcrest matcher to check that an application id representation in JSON.
179 */
180 private static final class AppIdJsonMatcher extends TypeSafeMatcher<JsonObject> {
181 private final ApplicationId appId;
182 private String reason = "";
183
184 private AppIdJsonMatcher(ApplicationId appId) {
185 this.appId = appId;
186 }
187
188 @Override
189 protected boolean matchesSafely(JsonObject jsonAppId) {
190 // check id
191 short jsonId = (short) jsonAppId.get("id").asInt();
192 if (jsonId != appId.id()) {
193 reason = "id " + appId.id();
194 return false;
195 }
196
197 // check name
198 String jsonName = jsonAppId.get("name").asString();
199 if (!jsonName.equals(appId.name())) {
200 reason = "name " + appId.name();
201 return false;
202 }
203
204 return true;
205 }
206
207 @Override
208 public void describeTo(Description description) {
209 description.appendText(reason);
210 }
211 }
212
213 /**
Ray Milkeyed0b1662015-02-05 09:34:29 -0800214 * Factory to allocate an application matcher.
Ray Milkeyf195b022015-02-03 15:13:11 -0800215 *
216 * @param app application object we are looking for
217 * @return matcher
218 */
219 private static AppJsonMatcher matchesApp(Application app) {
220 return new AppJsonMatcher(app);
221 }
222
Ray Milkeyed0b1662015-02-05 09:34:29 -0800223 /**
Jian Lie1c1c8d2016-05-09 16:24:40 -0700224 * Factory to allocate an application Id matcher.
225 *
226 * @param appId application Id object we are looking for
227 * @return matcher
228 */
229 private static AppIdJsonMatcher matchesAppId(ApplicationId appId) {
230 return new AppIdJsonMatcher(appId);
231 }
232
233 /**
Ray Milkeyed0b1662015-02-05 09:34:29 -0800234 * Initializes test mocks and environment.
235 */
Ray Milkeyf195b022015-02-03 15:13:11 -0800236 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800237 public void setUpMocks() {
Jian Lie1c1c8d2016-05-09 16:24:40 -0700238 appService = createMock(ApplicationAdminService.class);
239 coreService = createMock(CoreService.class);
Ray Milkeyf195b022015-02-03 15:13:11 -0800240
Jian Lie1c1c8d2016-05-09 16:24:40 -0700241 expect(appService.getId("one"))
Ray Milkeyf195b022015-02-03 15:13:11 -0800242 .andReturn(id1)
243 .anyTimes();
Jian Lie1c1c8d2016-05-09 16:24:40 -0700244 expect(appService.getId("two"))
Ray Milkeyf195b022015-02-03 15:13:11 -0800245 .andReturn(id2)
246 .anyTimes();
Jian Lie1c1c8d2016-05-09 16:24:40 -0700247 expect(appService.getId("three"))
Ray Milkeyf195b022015-02-03 15:13:11 -0800248 .andReturn(id3)
249 .anyTimes();
Jian Lie1c1c8d2016-05-09 16:24:40 -0700250 expect(appService.getId("four"))
Ray Milkeyf195b022015-02-03 15:13:11 -0800251 .andReturn(id4)
252 .anyTimes();
253
Jian Lie1c1c8d2016-05-09 16:24:40 -0700254 expect(appService.getApplication(id3))
Ray Milkeyf195b022015-02-03 15:13:11 -0800255 .andReturn(app3)
256 .anyTimes();
Jian Lie1c1c8d2016-05-09 16:24:40 -0700257 expect(appService.getState(isA(ApplicationId.class)))
Ray Milkeyf195b022015-02-03 15:13:11 -0800258 .andReturn(ApplicationState.ACTIVE)
259 .anyTimes();
260
261 // Register the services needed for the test
262 CodecManager codecService = new CodecManager();
263 codecService.activate();
264 ServiceDirectory testDirectory =
265 new TestServiceDirectory()
Jian Lie1c1c8d2016-05-09 16:24:40 -0700266 .add(ApplicationAdminService.class, appService)
267 .add(ApplicationService.class, appService)
268 .add(CoreService.class, coreService)
Ray Milkeyf195b022015-02-03 15:13:11 -0800269 .add(CodecService.class, codecService);
270
271 BaseResource.setServiceDirectory(testDirectory);
272 }
273
Ray Milkeyed0b1662015-02-05 09:34:29 -0800274 /**
Ray Milkeyf195b022015-02-03 15:13:11 -0800275 * Tests a GET of all applications when no applications are present.
276 */
277 @Test
278 public void getAllApplicationsEmpty() {
Jian Lie1c1c8d2016-05-09 16:24:40 -0700279 expect(appService.getApplications())
Ray Milkeyf195b022015-02-03 15:13:11 -0800280 .andReturn(ImmutableSet.of());
Jian Lie1c1c8d2016-05-09 16:24:40 -0700281 replay(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800282
Jian Li9d616492016-03-09 10:52:49 -0800283 WebTarget wt = target();
284 String response = wt.path("applications").request().get(String.class);
Ray Milkeyf195b022015-02-03 15:13:11 -0800285 assertThat(response, is("{\"applications\":[]}"));
Jian Lie1c1c8d2016-05-09 16:24:40 -0700286
287 verify(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800288 }
289
290 /**
291 * Tests a GET of all applications with data.
292 */
293 @Test
294 public void getAllApplicationsPopulated() {
Jian Lie1c1c8d2016-05-09 16:24:40 -0700295 expect(appService.getApplications())
Ray Milkeyf195b022015-02-03 15:13:11 -0800296 .andReturn(ImmutableSet.of(app1, app2, app3, app4));
Jian Lie1c1c8d2016-05-09 16:24:40 -0700297 replay(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800298
Jian Li9d616492016-03-09 10:52:49 -0800299 WebTarget wt = target();
300 String response = wt.path("applications").request().get(String.class);
Ray Milkeyf195b022015-02-03 15:13:11 -0800301 assertThat(response, containsString("{\"applications\":["));
302
Jian Li80cfe452016-01-14 16:04:58 -0800303 JsonObject result = Json.parse(response).asObject();
Ray Milkeyf195b022015-02-03 15:13:11 -0800304 assertThat(result, notNullValue());
305
306 assertThat(result.names(), hasSize(1));
307 assertThat(result.names().get(0), is("applications"));
308
309 JsonArray jsonApps = result.get("applications").asArray();
310 assertThat(jsonApps, notNullValue());
311 assertThat(jsonApps.size(), is(4));
312
313 assertThat(jsonApps.get(0).asObject(), matchesApp(app1));
314 assertThat(jsonApps.get(1).asObject(), matchesApp(app2));
315 assertThat(jsonApps.get(2).asObject(), matchesApp(app3));
316 assertThat(jsonApps.get(3).asObject(), matchesApp(app4));
Jian Lie1c1c8d2016-05-09 16:24:40 -0700317
318 verify(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800319 }
320
321 /**
322 * Tests a GET of a single application.
323 */
324 @Test
325 public void getSingleApplication() {
Jian Lie1c1c8d2016-05-09 16:24:40 -0700326 replay(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800327
Jian Li9d616492016-03-09 10:52:49 -0800328 WebTarget wt = target();
329 String response = wt.path("applications/three").request().get(String.class);
Ray Milkeyf195b022015-02-03 15:13:11 -0800330
Jian Li80cfe452016-01-14 16:04:58 -0800331 JsonObject result = Json.parse(response).asObject();
Ray Milkeyf195b022015-02-03 15:13:11 -0800332 assertThat(result, notNullValue());
333
334 assertThat(result, matchesApp(app3));
Jian Lie1c1c8d2016-05-09 16:24:40 -0700335
336 verify(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800337 }
338
339 /**
340 * Tests a DELETE of a single application - this should
341 * attempt to uninstall it.
342 */
343 @Test
344 public void deleteApplication() {
Jian Lie1c1c8d2016-05-09 16:24:40 -0700345 appService.uninstall(id3);
Ray Milkeyf195b022015-02-03 15:13:11 -0800346 expectLastCall();
347
Jian Lie1c1c8d2016-05-09 16:24:40 -0700348 replay(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800349
Jian Li9d616492016-03-09 10:52:49 -0800350 WebTarget wt = target();
351 wt.path("applications/three").request().delete();
Jian Lie1c1c8d2016-05-09 16:24:40 -0700352
353 verify(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800354 }
355
356 /**
357 * Tests a DELETE of a single active application - this should
358 * attempt to uninstall it.
359 */
360 @Test
361 public void deleteActiveApplication() {
Jian Lie1c1c8d2016-05-09 16:24:40 -0700362 appService.deactivate(id3);
Ray Milkeyf195b022015-02-03 15:13:11 -0800363 expectLastCall();
364
Jian Lie1c1c8d2016-05-09 16:24:40 -0700365 replay(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800366
Jian Li9d616492016-03-09 10:52:49 -0800367 WebTarget wt = target();
368 wt.path("applications/three/active").request().delete();
Jian Lie1c1c8d2016-05-09 16:24:40 -0700369
370 verify(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800371 }
372
373 /**
374 * Tests a POST operation to the "active" URL. This should attempt to
375 * activate the application.
376 */
377 @Test
378 public void postActiveApplication() {
Jian Lie1c1c8d2016-05-09 16:24:40 -0700379 appService.activate(id3);
Ray Milkeyf195b022015-02-03 15:13:11 -0800380 expectLastCall();
381
Jian Lie1c1c8d2016-05-09 16:24:40 -0700382 replay(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800383
Jian Li9d616492016-03-09 10:52:49 -0800384 WebTarget wt = target();
385 wt.path("applications/three/active").request().post(null);
Jian Lie1c1c8d2016-05-09 16:24:40 -0700386
387 verify(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800388 }
389
390 /**
391 * Tests a POST operation. This should attempt to
392 * install the application.
393 */
394 @Test
395 public void postApplication() {
Jian Lie1c1c8d2016-05-09 16:24:40 -0700396 expect(appService.install(isA(InputStream.class)))
Ray Milkeyf195b022015-02-03 15:13:11 -0800397 .andReturn(app4)
398 .once();
399
Jian Lie1c1c8d2016-05-09 16:24:40 -0700400 replay(appService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800401
402 ApplicationCodec codec = new ApplicationCodec();
403 String app4Json = codec.encode(app4,
Jian Lie1c1c8d2016-05-09 16:24:40 -0700404 new MockCodecContextWithAppService(appService))
Ray Milkeyf195b022015-02-03 15:13:11 -0800405 .asText();
406
Jian Li9d616492016-03-09 10:52:49 -0800407 WebTarget wt = target();
408 String response = wt.path("applications").request().post(
409 Entity.entity(app4Json, MediaType.APPLICATION_OCTET_STREAM), String.class);
Ray Milkeyf195b022015-02-03 15:13:11 -0800410
Jian Li80cfe452016-01-14 16:04:58 -0800411 JsonObject result = Json.parse(response).asObject();
Ray Milkeyf195b022015-02-03 15:13:11 -0800412 assertThat(result, notNullValue());
413
414 assertThat(result, matchesApp(app4));
Jian Lie1c1c8d2016-05-09 16:24:40 -0700415
416 verify(appService);
417 }
418
419 /**
420 * Tests a POST operation. This should attempt to register an on/off platform
421 * application ID.
422 */
423 @Test
424 public void postRegisterAppId() {
425 expect(coreService.registerApplication("app1")).andReturn(id1).anyTimes();
426 replay(coreService);
427
428 WebTarget wt = target();
429 wt.path("applications/app1/register").request().post(null);
430
431 verify(coreService);
432 }
433
434 /**
435 * Tests a GET of all application Ids when no applications are present.
436 */
437 @Test
438 public void getAllApplicationIdsEmpty() {
439 expect(coreService.getAppIds()).andReturn(ImmutableSet.of());
440 replay(coreService);
441
442 WebTarget wt = target();
443 String response = wt.path("applications/ids").request().get(String.class);
444 assertThat(response, is("{\"applicationIds\":[]}"));
445
446 verify(coreService);
447 }
448
449 /**
450 * Tests a GET of all application Ids.
451 */
452 @Test
453 public void getAllApplicationIdsPopulated() {
454 expect(coreService.getAppIds())
455 .andReturn(ImmutableSet.of(id1, id2, id3, id4));
456 replay(coreService);
457
458 WebTarget wt = target();
459 String response = wt.path("applications/ids").request().get(String.class);
460
461 assertThat(response, containsString("{\"applicationIds\":["));
462
463 JsonObject result = Json.parse(response).asObject();
464 assertThat(result, notNullValue());
465
466 assertThat(result.names(), hasSize(1));
467 assertThat(result.names().get(0), is("applicationIds"));
468
469 JsonArray jsonApps = result.get("applicationIds").asArray();
470 assertThat(jsonApps, notNullValue());
471 assertThat(jsonApps.size(), is(4));
472
473 assertThat(jsonApps.get(0).asObject(), matchesAppId(id1));
474 assertThat(jsonApps.get(1).asObject(), matchesAppId(id2));
475 assertThat(jsonApps.get(2).asObject(), matchesAppId(id3));
476 assertThat(jsonApps.get(3).asObject(), matchesAppId(id4));
477
478 verify(coreService);
479 }
480
481 /**
482 * Tests a GET of an applicationId entry with the given numeric id.
483 */
484 @Test
485 public void getAppIdByShortId() {
486 expect(coreService.getAppId((short) 1)).andReturn(id1);
487 replay(coreService);
488
489 WebTarget wt = target();
490 String response = wt.path("applications/ids/short")
491 .queryParam("id", 1).request().get(String.class);
492
493 JsonObject result = Json.parse(response).asObject();
494 assertThat(result, notNullValue());
495
496 assertThat(result, matchesAppId(id1));
497
498 verify(coreService);
499 }
500
501 /**
502 * Tests a GET of an applicationId entry with the given application name.
503 */
504 @Test
505 public void getAppIdByName() {
506 expect(coreService.getAppId("app2")).andReturn(id2);
507 replay(coreService);
508
509 WebTarget wt = target();
510 String response = wt.path("applications/ids/name")
511 .queryParam("name", "app2").request().get(String.class);
512
513 JsonObject result = Json.parse(response).asObject();
514 assertThat(result, notNullValue());
515
516 assertThat(result, matchesAppId(id2));
517
518 verify(coreService);
Ray Milkeyf195b022015-02-03 15:13:11 -0800519 }
520}