blob: 052c4320900fa955ba5887d57fbeb409aefef9a8 [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;
25import org.junit.After;
26import org.junit.Before;
27import org.junit.Test;
28import org.onlab.osgi.ServiceDirectory;
29import org.onlab.osgi.TestServiceDirectory;
30import org.onlab.rest.BaseResource;
31import org.onosproject.app.ApplicationAdminService;
32import org.onosproject.app.ApplicationService;
33import org.onosproject.app.ApplicationState;
34import org.onosproject.codec.CodecService;
35import org.onosproject.codec.impl.ApplicationCodec;
36import org.onosproject.codec.impl.CodecManager;
37import org.onosproject.codec.impl.MockCodecContext;
38import org.onosproject.core.Application;
39import org.onosproject.core.ApplicationId;
Changhoon Yoonbdeb88a2015-05-12 20:35:31 +090040import org.onosproject.core.ApplicationRole;
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
70 private static class MockCodecContextWithService extends MockCodecContext {
71 private ApplicationAdminService service;
72
73 MockCodecContextWithService(ApplicationAdminService service) {
74 this.service = service;
75 }
76
77 @Override
78 @SuppressWarnings("unchecked")
Ray Milkey3078fc02015-05-06 16:14:14 -070079 public <T> T getService(Class<T> serviceClass) {
Ray Milkeyf195b022015-02-03 15:13:11 -080080 return (T) service;
81 }
82 }
83
84 private ApplicationAdminService service;
85 private ApplicationId id1 = new DefaultApplicationId(1, "app1");
86 private ApplicationId id2 = new DefaultApplicationId(2, "app2");
87 private ApplicationId id3 = new DefaultApplicationId(3, "app3");
88 private ApplicationId id4 = new DefaultApplicationId(4, "app4");
89
90 private static final URI FURL = URI.create("mvn:org.foo-features/1.2a/xml/features");
91 private static final Version VER = Version.version(1, 2, "a", null);
92
93 private Application app1 =
Simon Huntafae2f72016-03-04 21:18:23 -080094 new DefaultApplication(id1, VER, "title1",
95 "desc1", "origin1", "category1", "url1",
Jian Lic35415d2016-01-14 17:22:31 -080096 "readme1", new byte[0], ApplicationRole.ADMIN,
97 ImmutableSet.of(), Optional.of(FURL),
Thomas Vachuska761f0042015-11-11 19:10:17 -080098 ImmutableList.of("My Feature"), ImmutableList.of());
Ray Milkeyf195b022015-02-03 15:13:11 -080099 private Application app2 =
Simon Huntafae2f72016-03-04 21:18:23 -0800100 new DefaultApplication(id2, VER, "title2",
101 "desc2", "origin2", "category2", "url2",
Jian Lic35415d2016-01-14 17:22:31 -0800102 "readme2", new byte[0], ApplicationRole.ADMIN,
103 ImmutableSet.of(), Optional.of(FURL),
Thomas Vachuska761f0042015-11-11 19:10:17 -0800104 ImmutableList.of("My Feature"), ImmutableList.of());
Ray Milkeyf195b022015-02-03 15:13:11 -0800105 private Application app3 =
Simon Huntafae2f72016-03-04 21:18:23 -0800106 new DefaultApplication(id3, VER, "title3",
107 "desc3", "origin3", "category3", "url3",
Jian Lic35415d2016-01-14 17:22:31 -0800108 "readme3", new byte[0], ApplicationRole.ADMIN,
109 ImmutableSet.of(), Optional.of(FURL),
Thomas Vachuska761f0042015-11-11 19:10:17 -0800110 ImmutableList.of("My Feature"), ImmutableList.of());
Ray Milkeyf195b022015-02-03 15:13:11 -0800111 private Application app4 =
Simon Huntafae2f72016-03-04 21:18:23 -0800112 new DefaultApplication(id4, VER, "title4",
113 "desc4", "origin4", "category4", "url4",
Jian Lic35415d2016-01-14 17:22:31 -0800114 "readme4", new byte[0], ApplicationRole.ADMIN,
115 ImmutableSet.of(), Optional.of(FURL),
Thomas Vachuska761f0042015-11-11 19:10:17 -0800116 ImmutableList.of("My Feature"), ImmutableList.of());
Ray Milkeyf195b022015-02-03 15:13:11 -0800117
118 /**
Ray Milkeyed0b1662015-02-05 09:34:29 -0800119 * Hamcrest matcher to check that an application representation in JSON matches
Ray Milkeyf195b022015-02-03 15:13:11 -0800120 * the actual device.
121 */
122 private static class AppJsonMatcher extends TypeSafeMatcher<JsonObject> {
123 private final Application app;
124 private String reason = "";
125
126 public AppJsonMatcher(Application appValue) {
127 app = appValue;
128 }
129
130 @Override
131 public boolean matchesSafely(JsonObject jsonApp) {
132 // check id
133 short jsonId = (short) jsonApp.get("id").asInt();
134 if (jsonId != app.id().id()) {
135 reason = "id " + app.id().id();
136 return false;
137 }
138
139 // check name
140 String jsonName = jsonApp.get("name").asString();
141 if (!jsonName.equals(app.id().name())) {
142 reason = "name " + app.id().name();
143 return false;
144 }
145
146 // check origin
147 String jsonOrigin = jsonApp.get("origin").asString();
148 if (!jsonOrigin.equals(app.origin())) {
149 reason = "manufacturer " + app.origin();
150 return false;
151 }
152
153 return true;
154 }
155
156 @Override
157 public void describeTo(Description description) {
158 description.appendText(reason);
159 }
160 }
161
162 /**
Ray Milkeyed0b1662015-02-05 09:34:29 -0800163 * Factory to allocate an application matcher.
Ray Milkeyf195b022015-02-03 15:13:11 -0800164 *
165 * @param app application object we are looking for
166 * @return matcher
167 */
168 private static AppJsonMatcher matchesApp(Application app) {
169 return new AppJsonMatcher(app);
170 }
171
Ray Milkeyed0b1662015-02-05 09:34:29 -0800172 /**
173 * Initializes test mocks and environment.
174 */
Ray Milkeyf195b022015-02-03 15:13:11 -0800175 @Before
Ray Milkeyed0b1662015-02-05 09:34:29 -0800176 public void setUpMocks() {
Ray Milkeyf195b022015-02-03 15:13:11 -0800177 service = createMock(ApplicationAdminService.class);
178
179 expect(service.getId("one"))
180 .andReturn(id1)
181 .anyTimes();
182 expect(service.getId("two"))
183 .andReturn(id2)
184 .anyTimes();
185 expect(service.getId("three"))
186 .andReturn(id3)
187 .anyTimes();
188 expect(service.getId("four"))
189 .andReturn(id4)
190 .anyTimes();
191
192 expect(service.getApplication(id3))
193 .andReturn(app3)
194 .anyTimes();
195 expect(service.getState(isA(ApplicationId.class)))
196 .andReturn(ApplicationState.ACTIVE)
197 .anyTimes();
198
199 // Register the services needed for the test
200 CodecManager codecService = new CodecManager();
201 codecService.activate();
202 ServiceDirectory testDirectory =
203 new TestServiceDirectory()
204 .add(ApplicationAdminService.class, service)
205 .add(ApplicationService.class, service)
206 .add(CodecService.class, codecService);
207
208 BaseResource.setServiceDirectory(testDirectory);
209 }
210
Ray Milkeyed0b1662015-02-05 09:34:29 -0800211 /**
212 * Verifies test mocks.
213 */
Ray Milkeyf195b022015-02-03 15:13:11 -0800214 @After
Ray Milkeyed0b1662015-02-05 09:34:29 -0800215 public void tearDownMocks() {
Ray Milkeyf195b022015-02-03 15:13:11 -0800216 verify(service);
217 }
218
219 /**
220 * Tests a GET of all applications when no applications are present.
221 */
222 @Test
223 public void getAllApplicationsEmpty() {
224 expect(service.getApplications())
225 .andReturn(ImmutableSet.of());
226 replay(service);
227
Jian Li9d616492016-03-09 10:52:49 -0800228 WebTarget wt = target();
229 String response = wt.path("applications").request().get(String.class);
Ray Milkeyf195b022015-02-03 15:13:11 -0800230 assertThat(response, is("{\"applications\":[]}"));
231 }
232
233 /**
234 * Tests a GET of all applications with data.
235 */
236 @Test
237 public void getAllApplicationsPopulated() {
238 expect(service.getApplications())
239 .andReturn(ImmutableSet.of(app1, app2, app3, app4));
240 replay(service);
241
Jian Li9d616492016-03-09 10:52:49 -0800242 WebTarget wt = target();
243 String response = wt.path("applications").request().get(String.class);
Ray Milkeyf195b022015-02-03 15:13:11 -0800244 assertThat(response, containsString("{\"applications\":["));
245
Jian Li80cfe452016-01-14 16:04:58 -0800246 JsonObject result = Json.parse(response).asObject();
Ray Milkeyf195b022015-02-03 15:13:11 -0800247 assertThat(result, notNullValue());
248
249 assertThat(result.names(), hasSize(1));
250 assertThat(result.names().get(0), is("applications"));
251
252 JsonArray jsonApps = result.get("applications").asArray();
253 assertThat(jsonApps, notNullValue());
254 assertThat(jsonApps.size(), is(4));
255
256 assertThat(jsonApps.get(0).asObject(), matchesApp(app1));
257 assertThat(jsonApps.get(1).asObject(), matchesApp(app2));
258 assertThat(jsonApps.get(2).asObject(), matchesApp(app3));
259 assertThat(jsonApps.get(3).asObject(), matchesApp(app4));
260 }
261
262 /**
263 * Tests a GET of a single application.
264 */
265 @Test
266 public void getSingleApplication() {
267 replay(service);
268
Jian Li9d616492016-03-09 10:52:49 -0800269 WebTarget wt = target();
270 String response = wt.path("applications/three").request().get(String.class);
Ray Milkeyf195b022015-02-03 15:13:11 -0800271
Jian Li80cfe452016-01-14 16:04:58 -0800272 JsonObject result = Json.parse(response).asObject();
Ray Milkeyf195b022015-02-03 15:13:11 -0800273 assertThat(result, notNullValue());
274
275 assertThat(result, matchesApp(app3));
276 }
277
278 /**
279 * Tests a DELETE of a single application - this should
280 * attempt to uninstall it.
281 */
282 @Test
283 public void deleteApplication() {
284 service.uninstall(id3);
285 expectLastCall();
286
287 replay(service);
288
Jian Li9d616492016-03-09 10:52:49 -0800289 WebTarget wt = target();
290 wt.path("applications/three").request().delete();
Ray Milkeyf195b022015-02-03 15:13:11 -0800291 }
292
293 /**
294 * Tests a DELETE of a single active application - this should
295 * attempt to uninstall it.
296 */
297 @Test
298 public void deleteActiveApplication() {
299 service.deactivate(id3);
300 expectLastCall();
301
302 replay(service);
303
Jian Li9d616492016-03-09 10:52:49 -0800304 WebTarget wt = target();
305 wt.path("applications/three/active").request().delete();
Ray Milkeyf195b022015-02-03 15:13:11 -0800306 }
307
308 /**
309 * Tests a POST operation to the "active" URL. This should attempt to
310 * activate the application.
311 */
312 @Test
313 public void postActiveApplication() {
314 service.activate(id3);
315 expectLastCall();
316
317 replay(service);
318
Jian Li9d616492016-03-09 10:52:49 -0800319 WebTarget wt = target();
320 wt.path("applications/three/active").request().post(null);
Ray Milkeyf195b022015-02-03 15:13:11 -0800321 }
322
323 /**
324 * Tests a POST operation. This should attempt to
325 * install the application.
326 */
327 @Test
328 public void postApplication() {
329 expect(service.install(isA(InputStream.class)))
330 .andReturn(app4)
331 .once();
332
333 replay(service);
334
335 ApplicationCodec codec = new ApplicationCodec();
336 String app4Json = codec.encode(app4,
337 new MockCodecContextWithService(service))
338 .asText();
339
Jian Li9d616492016-03-09 10:52:49 -0800340 WebTarget wt = target();
341 String response = wt.path("applications").request().post(
342 Entity.entity(app4Json, MediaType.APPLICATION_OCTET_STREAM), String.class);
Ray Milkeyf195b022015-02-03 15:13:11 -0800343
Jian Li80cfe452016-01-14 16:04:58 -0800344 JsonObject result = Json.parse(response).asObject();
Ray Milkeyf195b022015-02-03 15:13:11 -0800345 assertThat(result, notNullValue());
346
347 assertThat(result, matchesApp(app4));
348 }
349}