Jian Li
Committed by Gerrit Code Review

[ONOS-4409] Support applicationId registration and query via REST

With this commit, we can register and query on/off platform
applications through REST API.

Change-Id: I82e1e0e55bbc017d6c0cce7d9a6af7a578d7196e
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
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 + */
16 +package org.onosproject.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.node.ObjectNode;
19 +import org.onosproject.codec.CodecContext;
20 +import org.onosproject.codec.JsonCodec;
21 +import org.onosproject.core.ApplicationId;
22 +import org.onosproject.core.DefaultApplicationId;
23 +
24 +import static com.google.common.base.Preconditions.checkNotNull;
25 +import static org.onlab.util.Tools.nullIsIllegal;
26 +
27 +/**
28 + * ApplicationId JSON codec.
29 + */
30 +public final class ApplicationIdCodec extends JsonCodec<ApplicationId> {
31 +
32 + private static final String APP_ID = "id";
33 + private static final String APP_NAME = "name";
34 +
35 + private static final String MISSING_MEMBER_MESSAGE = " member is required in ApplicationId";
36 +
37 + @Override
38 + public ObjectNode encode(ApplicationId appId, CodecContext context) {
39 + checkNotNull(appId, "ApplicationId cannot be null");
40 +
41 + ObjectNode result = context.mapper().createObjectNode()
42 + .put("id", appId.id())
43 + .put("name", appId.name());
44 +
45 + return result;
46 + }
47 +
48 + @Override
49 + public ApplicationId decode(ObjectNode json, CodecContext context) {
50 + if (json == null || !json.isObject()) {
51 + return null;
52 + }
53 +
54 + // parse application identifier
55 + int id = nullIsIllegal(json.get(APP_ID), APP_ID + MISSING_MEMBER_MESSAGE).asInt();
56 +
57 + // parse application name
58 + String name = nullIsIllegal(json.get(APP_NAME), APP_NAME + MISSING_MEMBER_MESSAGE).asText();
59 +
60 + return new DefaultApplicationId(id, name);
61 + }
62 +}
...@@ -27,6 +27,7 @@ import org.onosproject.cluster.RoleInfo; ...@@ -27,6 +27,7 @@ import org.onosproject.cluster.RoleInfo;
27 import org.onosproject.codec.CodecService; 27 import org.onosproject.codec.CodecService;
28 import org.onosproject.codec.JsonCodec; 28 import org.onosproject.codec.JsonCodec;
29 import org.onosproject.core.Application; 29 import org.onosproject.core.Application;
30 +import org.onosproject.core.ApplicationId;
30 import org.onosproject.incubator.net.virtual.TenantId; 31 import org.onosproject.incubator.net.virtual.TenantId;
31 import org.onosproject.incubator.net.virtual.VirtualDevice; 32 import org.onosproject.incubator.net.virtual.VirtualDevice;
32 import org.onosproject.incubator.net.virtual.VirtualLink; 33 import org.onosproject.incubator.net.virtual.VirtualLink;
...@@ -95,6 +96,7 @@ public class CodecManager implements CodecService { ...@@ -95,6 +96,7 @@ public class CodecManager implements CodecService {
95 public void activate() { 96 public void activate() {
96 codecs.clear(); 97 codecs.clear();
97 registerCodec(Application.class, new ApplicationCodec()); 98 registerCodec(Application.class, new ApplicationCodec());
99 + registerCodec(ApplicationId.class, new ApplicationIdCodec());
98 registerCodec(ControllerNode.class, new ControllerNodeCodec()); 100 registerCodec(ControllerNode.class, new ControllerNodeCodec());
99 registerCodec(Annotations.class, new AnnotationsCodec()); 101 registerCodec(Annotations.class, new AnnotationsCodec());
100 registerCodec(Device.class, new DeviceCodec()); 102 registerCodec(Device.class, new DeviceCodec());
......
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
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 + */
16 +package org.onosproject.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import org.hamcrest.Description;
21 +import org.hamcrest.TypeSafeDiagnosingMatcher;
22 +import org.junit.Before;
23 +import org.junit.Test;
24 +import org.onosproject.codec.JsonCodec;
25 +import org.onosproject.core.ApplicationId;
26 +import org.onosproject.core.DefaultApplicationId;
27 +
28 +import java.io.IOException;
29 +import java.io.InputStream;
30 +
31 +import static org.hamcrest.MatcherAssert.assertThat;
32 +import static org.hamcrest.Matchers.is;
33 +import static org.hamcrest.Matchers.notNullValue;
34 +
35 +/**
36 + * Unit tests for ApplicationId codec.
37 + */
38 +public final class ApplicationIdCodecTest {
39 +
40 + MockCodecContext context;
41 + JsonCodec<ApplicationId> applicationIdCodec;
42 +
43 + /**
44 + * Sets up for each test. Creates a context and fetches the applicationId
45 + * codec.
46 + */
47 + @Before
48 + public void setUp() {
49 + context = new MockCodecContext();
50 + applicationIdCodec = context.codec(ApplicationId.class);
51 + assertThat(applicationIdCodec, notNullValue());
52 + }
53 +
54 + /**
55 + * Tests encoding of an application id object.
56 + */
57 + @Test
58 + public void testApplicationIdEncode() {
59 +
60 + int id = 1;
61 + String name = "org.onosproject.foo";
62 + ApplicationId appId = new DefaultApplicationId(id, name);
63 +
64 + ObjectNode applicationIdJson = applicationIdCodec.encode(appId, context);
65 + assertThat(applicationIdJson, ApplicationIdJsonMatcher.matchesApplicationId(appId));
66 + }
67 +
68 + /**
69 + * Tests decoding of an application id object.
70 + */
71 + @Test
72 + public void testApplicationIdDecode() throws IOException {
73 + ApplicationId appId = getApplicationId("ApplicationId.json");
74 +
75 + assertThat((int) appId.id(), is(1));
76 + assertThat(appId.name(), is("org.onosproject.foo"));
77 + }
78 +
79 + private static final class ApplicationIdJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
80 +
81 + private final ApplicationId applicationId;
82 +
83 + private ApplicationIdJsonMatcher(ApplicationId applicationId) {
84 + this.applicationId = applicationId;
85 + }
86 +
87 + @Override
88 + protected boolean matchesSafely(JsonNode jsonNode, Description description) {
89 +
90 + // check application role
91 + int jsonAppId = jsonNode.get("id").asInt();
92 + int appId = applicationId.id();
93 + if (jsonAppId != appId) {
94 + description.appendText("application ID was " + jsonAppId);
95 + return false;
96 + }
97 +
98 + String jsonAppName = jsonNode.get("name").asText();
99 + String appName = applicationId.name();
100 +
101 + if (!jsonAppName.equals(appName)) {
102 + description.appendText("application name was " + jsonAppName);
103 + return false;
104 + }
105 +
106 + return true;
107 + }
108 +
109 + @Override
110 + public void describeTo(Description description) {
111 + description.appendText(applicationId.toString());
112 + }
113 +
114 + static ApplicationIdJsonMatcher matchesApplicationId(ApplicationId applicationId) {
115 + return new ApplicationIdJsonMatcher(applicationId);
116 + }
117 + }
118 +
119 + /**
120 + * Reads in a application id from the given resource and decodes it.
121 + *
122 + * @param resourceName resource to use to read the JSON for the rule
123 + * @return decoded application id
124 + * @throws IOException if processing the resource fails
125 + */
126 + private ApplicationId getApplicationId(String resourceName) throws IOException {
127 + InputStream jsonStream = ApplicationIdCodecTest.class.getResourceAsStream(resourceName);
128 + JsonNode json = context.mapper().readTree(jsonStream);
129 + assertThat(json, notNullValue());
130 + ApplicationId applicationId = applicationIdCodec.decode((ObjectNode) json, context);
131 + assertThat(applicationId, notNullValue());
132 + return applicationId;
133 + }
134 +}
1 +{
2 + "id": 1,
3 + "name": "org.onosproject.foo"
4 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -18,6 +18,7 @@ package org.onosproject.rest.resources; ...@@ -18,6 +18,7 @@ package org.onosproject.rest.resources;
18 import org.onosproject.app.ApplicationAdminService; 18 import org.onosproject.app.ApplicationAdminService;
19 import org.onosproject.core.Application; 19 import org.onosproject.core.Application;
20 import org.onosproject.core.ApplicationId; 20 import org.onosproject.core.ApplicationId;
21 +import org.onosproject.core.CoreService;
21 import org.onosproject.rest.AbstractWebResource; 22 import org.onosproject.rest.AbstractWebResource;
22 23
23 import javax.ws.rs.Consumes; 24 import javax.ws.rs.Consumes;
...@@ -44,8 +45,8 @@ public class ApplicationsWebResource extends AbstractWebResource { ...@@ -44,8 +45,8 @@ public class ApplicationsWebResource extends AbstractWebResource {
44 * Get all installed applications. 45 * Get all installed applications.
45 * Returns array of all installed applications. 46 * Returns array of all installed applications.
46 * 47 *
47 - * @onos.rsModel Applications
48 * @return 200 OK 48 * @return 200 OK
49 + * @onos.rsModel Applications
49 */ 50 */
50 @GET 51 @GET
51 public Response getApps() { 52 public Response getApps() {
...@@ -57,9 +58,10 @@ public class ApplicationsWebResource extends AbstractWebResource { ...@@ -57,9 +58,10 @@ public class ApplicationsWebResource extends AbstractWebResource {
57 /** 58 /**
58 * Get application details. 59 * Get application details.
59 * Returns details of the specified application. 60 * Returns details of the specified application.
60 - * @onos.rsModel Application 61 + *
61 * @param name application name 62 * @param name application name
62 * @return 200 OK; 404; 401 63 * @return 200 OK; 404; 401
64 + * @onos.rsModel Application
63 */ 65 */
64 @GET 66 @GET
65 @Path("{name}") 67 @Path("{name}")
...@@ -143,9 +145,76 @@ public class ApplicationsWebResource extends AbstractWebResource { ...@@ -143,9 +145,76 @@ public class ApplicationsWebResource extends AbstractWebResource {
143 return response(service, appId); 145 return response(service, appId);
144 } 146 }
145 147
148 + /**
149 + * Registers an on or off platform application.
150 + *
151 + * @param name application name
152 + * @return 200 OK; 404; 401
153 + * @onos.rsModel ApplicationId
154 + */
155 + @POST
156 + @Produces(MediaType.APPLICATION_JSON)
157 + @Path("{name}/register")
158 + public Response registerAppId(@PathParam("name") String name) {
159 + CoreService service = get(CoreService.class);
160 + ApplicationId appId = service.registerApplication(name);
161 + return response(appId);
162 + }
163 +
164 + /**
165 + * Gets application Id entry by short id.
166 + *
167 + * @param shortId numerical id of application
168 + * @return 200 OK; 404; 401
169 + * @onos.rsModel ApplicationId
170 + */
171 + @GET
172 + @Produces(MediaType.APPLICATION_JSON)
173 + @Path("ids/short")
174 + public Response getAppIdByShortId(@QueryParam("id") int shortId) {
175 + CoreService service = get(CoreService.class);
176 + ApplicationId appId = service.getAppId((short) shortId);
177 + return response(appId);
178 + }
179 +
180 + /**
181 + * Gets application Id entry by name.
182 + *
183 + * @param name name of application
184 + * @return 200 OK; 404; 401
185 + * @onos.rsModel ApplicationId
186 + */
187 + @GET
188 + @Produces(MediaType.APPLICATION_JSON)
189 + @Path("ids/name")
190 + public Response getAppIdByName(@QueryParam("name") String name) {
191 + CoreService service = get(CoreService.class);
192 + ApplicationId appId = service.getAppId(name);
193 + return response(appId);
194 + }
195 +
196 + /**
197 + * Gets a collection of application ids.
198 + * Returns array of all registered application ids.
199 + *
200 + * @return 200 OK; 404; 401
201 + * @onos.rsModel ApplicationIds
202 + */
203 + @GET
204 + @Produces(MediaType.APPLICATION_JSON)
205 + @Path("ids")
206 + public Response getAppIds() {
207 + CoreService service = get(CoreService.class);
208 + Set<ApplicationId> appIds = service.getAppIds();
209 + return ok(encodeArray(ApplicationId.class, "applicationIds", appIds)).build();
210 + }
211 +
146 private Response response(ApplicationAdminService service, ApplicationId appId) { 212 private Response response(ApplicationAdminService service, ApplicationId appId) {
147 Application app = service.getApplication(appId); 213 Application app = service.getApplication(appId);
148 return ok(codec(Application.class).encode(app, this)).build(); 214 return ok(codec(Application.class).encode(app, this)).build();
149 } 215 }
150 216
217 + private Response response(ApplicationId appId) {
218 + return ok(codec(ApplicationId.class).encode(appId, this)).build();
219 + }
151 } 220 }
......
1 +{
2 + "type": "object",
3 + "title": "applicationId",
4 + "required": [
5 + "name",
6 + "id"
7 + ],
8 + "properties": {
9 + "name": {
10 + "type": "string",
11 + "example": "org.onosproject.distributedprimitives"
12 + },
13 + "id": {
14 + "type": "integer",
15 + "format": "int64",
16 + "example": 1
17 + }
18 + }
19 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "type": "object",
3 + "title": "applicationIds",
4 + "required": [
5 + "applicationIds"
6 + ],
7 + "properties": {
8 + "applicationIds": {
9 + "type": "array",
10 + "xml": {
11 + "name": "applicationIds",
12 + "wrapped": true
13 + },
14 + "items": {
15 + "type": "object",
16 + "title": "applicationId",
17 + "required": [
18 + "name",
19 + "id"
20 + ],
21 + "properties": {
22 + "name": {
23 + "type": "string",
24 + "example": "org.onosproject.distributedprimitives"
25 + },
26 + "id": {
27 + "type": "integer",
28 + "format": "int64",
29 + "example": 1
30 + }
31 + }
32 + }
33 + }
34 + }
35 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -22,7 +22,6 @@ import com.google.common.collect.ImmutableList; ...@@ -22,7 +22,6 @@ import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.ImmutableSet; 22 import com.google.common.collect.ImmutableSet;
23 import org.hamcrest.Description; 23 import org.hamcrest.Description;
24 import org.hamcrest.TypeSafeMatcher; 24 import org.hamcrest.TypeSafeMatcher;
25 -import org.junit.After;
26 import org.junit.Before; 25 import org.junit.Before;
27 import org.junit.Test; 26 import org.junit.Test;
28 import org.onlab.osgi.ServiceDirectory; 27 import org.onlab.osgi.ServiceDirectory;
...@@ -38,6 +37,7 @@ import org.onosproject.codec.impl.MockCodecContext; ...@@ -38,6 +37,7 @@ import org.onosproject.codec.impl.MockCodecContext;
38 import org.onosproject.core.Application; 37 import org.onosproject.core.Application;
39 import org.onosproject.core.ApplicationId; 38 import org.onosproject.core.ApplicationId;
40 import org.onosproject.core.ApplicationRole; 39 import org.onosproject.core.ApplicationRole;
40 +import org.onosproject.core.CoreService;
41 import org.onosproject.core.DefaultApplication; 41 import org.onosproject.core.DefaultApplication;
42 import org.onosproject.core.DefaultApplicationId; 42 import org.onosproject.core.DefaultApplicationId;
43 import org.onosproject.core.Version; 43 import org.onosproject.core.Version;
...@@ -67,21 +67,36 @@ import static org.hamcrest.Matchers.notNullValue; ...@@ -67,21 +67,36 @@ import static org.hamcrest.Matchers.notNullValue;
67 67
68 public class ApplicationsResourceTest extends ResourceTest { 68 public class ApplicationsResourceTest extends ResourceTest {
69 69
70 - private static class MockCodecContextWithService extends MockCodecContext { 70 + private static class MockCodecContextWithAppService extends MockCodecContext {
71 - private ApplicationAdminService service; 71 + private ApplicationAdminService appService;
72 72
73 - MockCodecContextWithService(ApplicationAdminService service) { 73 + MockCodecContextWithAppService(ApplicationAdminService appService) {
74 - this.service = service; 74 + this.appService = appService;
75 } 75 }
76 76
77 @Override 77 @Override
78 @SuppressWarnings("unchecked") 78 @SuppressWarnings("unchecked")
79 public <T> T getService(Class<T> serviceClass) { 79 public <T> T getService(Class<T> serviceClass) {
80 - return (T) service; 80 + return (T) appService;
81 } 81 }
82 } 82 }
83 83
84 - private ApplicationAdminService service; 84 + 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;
85 private ApplicationId id1 = new DefaultApplicationId(1, "app1"); 100 private ApplicationId id1 = new DefaultApplicationId(1, "app1");
86 private ApplicationId id2 = new DefaultApplicationId(2, "app2"); 101 private ApplicationId id2 = new DefaultApplicationId(2, "app2");
87 private ApplicationId id3 = new DefaultApplicationId(3, "app3"); 102 private ApplicationId id3 = new DefaultApplicationId(3, "app3");
...@@ -92,28 +107,28 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -92,28 +107,28 @@ public class ApplicationsResourceTest extends ResourceTest {
92 107
93 private Application app1 = 108 private Application app1 =
94 new DefaultApplication(id1, VER, "title1", 109 new DefaultApplication(id1, VER, "title1",
95 - "desc1", "origin1", "category1", "url1", 110 + "desc1", "origin1", "category1", "url1",
96 - "readme1", new byte[0], ApplicationRole.ADMIN, 111 + "readme1", new byte[0], ApplicationRole.ADMIN,
97 - ImmutableSet.of(), Optional.of(FURL), 112 + ImmutableSet.of(), Optional.of(FURL),
98 - ImmutableList.of("My Feature"), ImmutableList.of()); 113 + ImmutableList.of("My Feature"), ImmutableList.of());
99 private Application app2 = 114 private Application app2 =
100 new DefaultApplication(id2, VER, "title2", 115 new DefaultApplication(id2, VER, "title2",
101 - "desc2", "origin2", "category2", "url2", 116 + "desc2", "origin2", "category2", "url2",
102 - "readme2", new byte[0], ApplicationRole.ADMIN, 117 + "readme2", new byte[0], ApplicationRole.ADMIN,
103 - ImmutableSet.of(), Optional.of(FURL), 118 + ImmutableSet.of(), Optional.of(FURL),
104 - ImmutableList.of("My Feature"), ImmutableList.of()); 119 + ImmutableList.of("My Feature"), ImmutableList.of());
105 private Application app3 = 120 private Application app3 =
106 new DefaultApplication(id3, VER, "title3", 121 new DefaultApplication(id3, VER, "title3",
107 - "desc3", "origin3", "category3", "url3", 122 + "desc3", "origin3", "category3", "url3",
108 - "readme3", new byte[0], ApplicationRole.ADMIN, 123 + "readme3", new byte[0], ApplicationRole.ADMIN,
109 - ImmutableSet.of(), Optional.of(FURL), 124 + ImmutableSet.of(), Optional.of(FURL),
110 - ImmutableList.of("My Feature"), ImmutableList.of()); 125 + ImmutableList.of("My Feature"), ImmutableList.of());
111 private Application app4 = 126 private Application app4 =
112 new DefaultApplication(id4, VER, "title4", 127 new DefaultApplication(id4, VER, "title4",
113 - "desc4", "origin4", "category4", "url4", 128 + "desc4", "origin4", "category4", "url4",
114 - "readme4", new byte[0], ApplicationRole.ADMIN, 129 + "readme4", new byte[0], ApplicationRole.ADMIN,
115 - ImmutableSet.of(), Optional.of(FURL), 130 + ImmutableSet.of(), Optional.of(FURL),
116 - ImmutableList.of("My Feature"), ImmutableList.of()); 131 + ImmutableList.of("My Feature"), ImmutableList.of());
117 132
118 /** 133 /**
119 * Hamcrest matcher to check that an application representation in JSON matches 134 * Hamcrest matcher to check that an application representation in JSON matches
...@@ -160,6 +175,42 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -160,6 +175,42 @@ public class ApplicationsResourceTest extends ResourceTest {
160 } 175 }
161 176
162 /** 177 /**
178 + * 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 + /**
163 * Factory to allocate an application matcher. 214 * Factory to allocate an application matcher.
164 * 215 *
165 * @param app application object we are looking for 216 * @param app application object we are looking for
...@@ -170,29 +221,40 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -170,29 +221,40 @@ public class ApplicationsResourceTest extends ResourceTest {
170 } 221 }
171 222
172 /** 223 /**
224 + * 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 + /**
173 * Initializes test mocks and environment. 234 * Initializes test mocks and environment.
174 */ 235 */
175 @Before 236 @Before
176 public void setUpMocks() { 237 public void setUpMocks() {
177 - service = createMock(ApplicationAdminService.class); 238 + appService = createMock(ApplicationAdminService.class);
239 + coreService = createMock(CoreService.class);
178 240
179 - expect(service.getId("one")) 241 + expect(appService.getId("one"))
180 .andReturn(id1) 242 .andReturn(id1)
181 .anyTimes(); 243 .anyTimes();
182 - expect(service.getId("two")) 244 + expect(appService.getId("two"))
183 .andReturn(id2) 245 .andReturn(id2)
184 .anyTimes(); 246 .anyTimes();
185 - expect(service.getId("three")) 247 + expect(appService.getId("three"))
186 .andReturn(id3) 248 .andReturn(id3)
187 .anyTimes(); 249 .anyTimes();
188 - expect(service.getId("four")) 250 + expect(appService.getId("four"))
189 .andReturn(id4) 251 .andReturn(id4)
190 .anyTimes(); 252 .anyTimes();
191 253
192 - expect(service.getApplication(id3)) 254 + expect(appService.getApplication(id3))
193 .andReturn(app3) 255 .andReturn(app3)
194 .anyTimes(); 256 .anyTimes();
195 - expect(service.getState(isA(ApplicationId.class))) 257 + expect(appService.getState(isA(ApplicationId.class)))
196 .andReturn(ApplicationState.ACTIVE) 258 .andReturn(ApplicationState.ACTIVE)
197 .anyTimes(); 259 .anyTimes();
198 260
...@@ -201,33 +263,28 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -201,33 +263,28 @@ public class ApplicationsResourceTest extends ResourceTest {
201 codecService.activate(); 263 codecService.activate();
202 ServiceDirectory testDirectory = 264 ServiceDirectory testDirectory =
203 new TestServiceDirectory() 265 new TestServiceDirectory()
204 - .add(ApplicationAdminService.class, service) 266 + .add(ApplicationAdminService.class, appService)
205 - .add(ApplicationService.class, service) 267 + .add(ApplicationService.class, appService)
268 + .add(CoreService.class, coreService)
206 .add(CodecService.class, codecService); 269 .add(CodecService.class, codecService);
207 270
208 BaseResource.setServiceDirectory(testDirectory); 271 BaseResource.setServiceDirectory(testDirectory);
209 } 272 }
210 273
211 /** 274 /**
212 - * Verifies test mocks.
213 - */
214 - @After
215 - public void tearDownMocks() {
216 - verify(service);
217 - }
218 -
219 - /**
220 * Tests a GET of all applications when no applications are present. 275 * Tests a GET of all applications when no applications are present.
221 */ 276 */
222 @Test 277 @Test
223 public void getAllApplicationsEmpty() { 278 public void getAllApplicationsEmpty() {
224 - expect(service.getApplications()) 279 + expect(appService.getApplications())
225 .andReturn(ImmutableSet.of()); 280 .andReturn(ImmutableSet.of());
226 - replay(service); 281 + replay(appService);
227 282
228 WebTarget wt = target(); 283 WebTarget wt = target();
229 String response = wt.path("applications").request().get(String.class); 284 String response = wt.path("applications").request().get(String.class);
230 assertThat(response, is("{\"applications\":[]}")); 285 assertThat(response, is("{\"applications\":[]}"));
286 +
287 + verify(appService);
231 } 288 }
232 289
233 /** 290 /**
...@@ -235,9 +292,9 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -235,9 +292,9 @@ public class ApplicationsResourceTest extends ResourceTest {
235 */ 292 */
236 @Test 293 @Test
237 public void getAllApplicationsPopulated() { 294 public void getAllApplicationsPopulated() {
238 - expect(service.getApplications()) 295 + expect(appService.getApplications())
239 .andReturn(ImmutableSet.of(app1, app2, app3, app4)); 296 .andReturn(ImmutableSet.of(app1, app2, app3, app4));
240 - replay(service); 297 + replay(appService);
241 298
242 WebTarget wt = target(); 299 WebTarget wt = target();
243 String response = wt.path("applications").request().get(String.class); 300 String response = wt.path("applications").request().get(String.class);
...@@ -257,6 +314,8 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -257,6 +314,8 @@ public class ApplicationsResourceTest extends ResourceTest {
257 assertThat(jsonApps.get(1).asObject(), matchesApp(app2)); 314 assertThat(jsonApps.get(1).asObject(), matchesApp(app2));
258 assertThat(jsonApps.get(2).asObject(), matchesApp(app3)); 315 assertThat(jsonApps.get(2).asObject(), matchesApp(app3));
259 assertThat(jsonApps.get(3).asObject(), matchesApp(app4)); 316 assertThat(jsonApps.get(3).asObject(), matchesApp(app4));
317 +
318 + verify(appService);
260 } 319 }
261 320
262 /** 321 /**
...@@ -264,7 +323,7 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -264,7 +323,7 @@ public class ApplicationsResourceTest extends ResourceTest {
264 */ 323 */
265 @Test 324 @Test
266 public void getSingleApplication() { 325 public void getSingleApplication() {
267 - replay(service); 326 + replay(appService);
268 327
269 WebTarget wt = target(); 328 WebTarget wt = target();
270 String response = wt.path("applications/three").request().get(String.class); 329 String response = wt.path("applications/three").request().get(String.class);
...@@ -273,6 +332,8 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -273,6 +332,8 @@ public class ApplicationsResourceTest extends ResourceTest {
273 assertThat(result, notNullValue()); 332 assertThat(result, notNullValue());
274 333
275 assertThat(result, matchesApp(app3)); 334 assertThat(result, matchesApp(app3));
335 +
336 + verify(appService);
276 } 337 }
277 338
278 /** 339 /**
...@@ -281,13 +342,15 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -281,13 +342,15 @@ public class ApplicationsResourceTest extends ResourceTest {
281 */ 342 */
282 @Test 343 @Test
283 public void deleteApplication() { 344 public void deleteApplication() {
284 - service.uninstall(id3); 345 + appService.uninstall(id3);
285 expectLastCall(); 346 expectLastCall();
286 347
287 - replay(service); 348 + replay(appService);
288 349
289 WebTarget wt = target(); 350 WebTarget wt = target();
290 wt.path("applications/three").request().delete(); 351 wt.path("applications/three").request().delete();
352 +
353 + verify(appService);
291 } 354 }
292 355
293 /** 356 /**
...@@ -296,13 +359,15 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -296,13 +359,15 @@ public class ApplicationsResourceTest extends ResourceTest {
296 */ 359 */
297 @Test 360 @Test
298 public void deleteActiveApplication() { 361 public void deleteActiveApplication() {
299 - service.deactivate(id3); 362 + appService.deactivate(id3);
300 expectLastCall(); 363 expectLastCall();
301 364
302 - replay(service); 365 + replay(appService);
303 366
304 WebTarget wt = target(); 367 WebTarget wt = target();
305 wt.path("applications/three/active").request().delete(); 368 wt.path("applications/three/active").request().delete();
369 +
370 + verify(appService);
306 } 371 }
307 372
308 /** 373 /**
...@@ -311,13 +376,15 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -311,13 +376,15 @@ public class ApplicationsResourceTest extends ResourceTest {
311 */ 376 */
312 @Test 377 @Test
313 public void postActiveApplication() { 378 public void postActiveApplication() {
314 - service.activate(id3); 379 + appService.activate(id3);
315 expectLastCall(); 380 expectLastCall();
316 381
317 - replay(service); 382 + replay(appService);
318 383
319 WebTarget wt = target(); 384 WebTarget wt = target();
320 wt.path("applications/three/active").request().post(null); 385 wt.path("applications/three/active").request().post(null);
386 +
387 + verify(appService);
321 } 388 }
322 389
323 /** 390 /**
...@@ -326,15 +393,15 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -326,15 +393,15 @@ public class ApplicationsResourceTest extends ResourceTest {
326 */ 393 */
327 @Test 394 @Test
328 public void postApplication() { 395 public void postApplication() {
329 - expect(service.install(isA(InputStream.class))) 396 + expect(appService.install(isA(InputStream.class)))
330 .andReturn(app4) 397 .andReturn(app4)
331 .once(); 398 .once();
332 399
333 - replay(service); 400 + replay(appService);
334 401
335 ApplicationCodec codec = new ApplicationCodec(); 402 ApplicationCodec codec = new ApplicationCodec();
336 String app4Json = codec.encode(app4, 403 String app4Json = codec.encode(app4,
337 - new MockCodecContextWithService(service)) 404 + new MockCodecContextWithAppService(appService))
338 .asText(); 405 .asText();
339 406
340 WebTarget wt = target(); 407 WebTarget wt = target();
...@@ -345,5 +412,109 @@ public class ApplicationsResourceTest extends ResourceTest { ...@@ -345,5 +412,109 @@ public class ApplicationsResourceTest extends ResourceTest {
345 assertThat(result, notNullValue()); 412 assertThat(result, notNullValue());
346 413
347 assertThat(result, matchesApp(app4)); 414 assertThat(result, matchesApp(app4));
415 +
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);
348 } 519 }
349 } 520 }
......