| /* |
| * Copyright 2016-present Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onosproject.rest.resources; |
| |
| import com.eclipsesource.json.Json; |
| import com.eclipsesource.json.JsonArray; |
| import com.eclipsesource.json.JsonObject; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| import org.hamcrest.Description; |
| import org.hamcrest.TypeSafeMatcher; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.onlab.osgi.ServiceDirectory; |
| import org.onlab.osgi.TestServiceDirectory; |
| import org.onlab.rest.BaseResource; |
| import org.onosproject.app.ApplicationAdminService; |
| import org.onosproject.app.ApplicationService; |
| import org.onosproject.app.ApplicationState; |
| import org.onosproject.codec.CodecService; |
| import org.onosproject.codec.impl.ApplicationCodec; |
| import org.onosproject.codec.impl.CodecManager; |
| import org.onosproject.codec.impl.MockCodecContext; |
| import org.onosproject.core.Application; |
| import org.onosproject.core.ApplicationId; |
| import org.onosproject.core.ApplicationRole; |
| import org.onosproject.core.CoreService; |
| import org.onosproject.core.DefaultApplication; |
| import org.onosproject.core.DefaultApplicationId; |
| import org.onosproject.core.Version; |
| |
| import javax.ws.rs.NotFoundException; |
| import javax.ws.rs.client.Entity; |
| import javax.ws.rs.client.WebTarget; |
| import javax.ws.rs.core.MediaType; |
| import java.io.InputStream; |
| import java.net.URI; |
| import java.util.Optional; |
| |
| import static org.easymock.EasyMock.createMock; |
| import static org.easymock.EasyMock.expect; |
| import static org.easymock.EasyMock.expectLastCall; |
| import static org.easymock.EasyMock.isA; |
| import static org.easymock.EasyMock.replay; |
| import static org.easymock.EasyMock.verify; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.hamcrest.Matchers.containsString; |
| import static org.hamcrest.Matchers.hasSize; |
| import static org.hamcrest.Matchers.is; |
| import static org.hamcrest.Matchers.notNullValue; |
| |
| /** |
| * Unit tests for applications REST APIs. |
| */ |
| |
| public class ApplicationsResourceTest extends ResourceTest { |
| |
| private static class MockCodecContextWithAppService extends MockCodecContext { |
| private ApplicationAdminService appService; |
| |
| MockCodecContextWithAppService(ApplicationAdminService appService) { |
| this.appService = appService; |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public <T> T getService(Class<T> serviceClass) { |
| return (T) appService; |
| } |
| } |
| |
| private static class MockCodecContextWithCoreService extends MockCodecContext { |
| private CoreService coreService; |
| |
| MockCodecContextWithCoreService(CoreService coreService) { |
| this.coreService = coreService; |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public <T> T getService(Class<T> serviceClass) { |
| return (T) coreService; |
| } |
| } |
| |
| private ApplicationAdminService appService; |
| private CoreService coreService; |
| private ApplicationId id1 = new DefaultApplicationId(1, "app1"); |
| private ApplicationId id2 = new DefaultApplicationId(2, "app2"); |
| private ApplicationId id3 = new DefaultApplicationId(3, "app3"); |
| private ApplicationId id4 = new DefaultApplicationId(4, "app4"); |
| |
| private static final URI FURL = URI.create("mvn:org.foo-features/1.2a/xml/features"); |
| private static final Version VER = Version.version(1, 2, "a", null); |
| |
| private Application app1 = |
| new DefaultApplication(id1, VER, "title1", |
| "desc1", "origin1", "category1", "url1", |
| "readme1", new byte[0], ApplicationRole.ADMIN, |
| ImmutableSet.of(), Optional.of(FURL), |
| ImmutableList.of("My Feature"), ImmutableList.of()); |
| private Application app2 = |
| new DefaultApplication(id2, VER, "title2", |
| "desc2", "origin2", "category2", "url2", |
| "readme2", new byte[0], ApplicationRole.ADMIN, |
| ImmutableSet.of(), Optional.of(FURL), |
| ImmutableList.of("My Feature"), ImmutableList.of()); |
| private Application app3 = |
| new DefaultApplication(id3, VER, "title3", |
| "desc3", "origin3", "category3", "url3", |
| "readme3", new byte[0], ApplicationRole.ADMIN, |
| ImmutableSet.of(), Optional.of(FURL), |
| ImmutableList.of("My Feature"), ImmutableList.of()); |
| private Application app4 = |
| new DefaultApplication(id4, VER, "title4", |
| "desc4", "origin4", "category4", "url4", |
| "readme4", new byte[0], ApplicationRole.ADMIN, |
| ImmutableSet.of(), Optional.of(FURL), |
| ImmutableList.of("My Feature"), ImmutableList.of()); |
| |
| /** |
| * Hamcrest matcher to check that an application representation in JSON matches |
| * the actual device. |
| */ |
| private static class AppJsonMatcher extends TypeSafeMatcher<JsonObject> { |
| private final Application app; |
| private String reason = ""; |
| |
| public AppJsonMatcher(Application appValue) { |
| app = appValue; |
| } |
| |
| @Override |
| public boolean matchesSafely(JsonObject jsonApp) { |
| // check id |
| short jsonId = (short) jsonApp.get("id").asInt(); |
| if (jsonId != app.id().id()) { |
| reason = "id " + app.id().id(); |
| return false; |
| } |
| |
| // check name |
| String jsonName = jsonApp.get("name").asString(); |
| if (!jsonName.equals(app.id().name())) { |
| reason = "name " + app.id().name(); |
| return false; |
| } |
| |
| // check origin |
| String jsonOrigin = jsonApp.get("origin").asString(); |
| if (!jsonOrigin.equals(app.origin())) { |
| reason = "manufacturer " + app.origin(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public void describeTo(Description description) { |
| description.appendText(reason); |
| } |
| } |
| |
| /** |
| * Hamcrest matcher to check that an application id representation in JSON. |
| */ |
| private static final class AppIdJsonMatcher extends TypeSafeMatcher<JsonObject> { |
| private final ApplicationId appId; |
| private String reason = ""; |
| |
| private AppIdJsonMatcher(ApplicationId appId) { |
| this.appId = appId; |
| } |
| |
| @Override |
| protected boolean matchesSafely(JsonObject jsonAppId) { |
| // check id |
| short jsonId = (short) jsonAppId.get("id").asInt(); |
| if (jsonId != appId.id()) { |
| reason = "id " + appId.id(); |
| return false; |
| } |
| |
| // check name |
| String jsonName = jsonAppId.get("name").asString(); |
| if (!jsonName.equals(appId.name())) { |
| reason = "name " + appId.name(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public void describeTo(Description description) { |
| description.appendText(reason); |
| } |
| } |
| |
| /** |
| * Factory to allocate an application matcher. |
| * |
| * @param app application object we are looking for |
| * @return matcher |
| */ |
| private static AppJsonMatcher matchesApp(Application app) { |
| return new AppJsonMatcher(app); |
| } |
| |
| /** |
| * Factory to allocate an application Id matcher. |
| * |
| * @param appId application Id object we are looking for |
| * @return matcher |
| */ |
| private static AppIdJsonMatcher matchesAppId(ApplicationId appId) { |
| return new AppIdJsonMatcher(appId); |
| } |
| |
| /** |
| * Initializes test mocks and environment. |
| */ |
| @Before |
| public void setUpMocks() { |
| appService = createMock(ApplicationAdminService.class); |
| coreService = createMock(CoreService.class); |
| |
| expect(appService.getId("one")) |
| .andReturn(id1) |
| .anyTimes(); |
| expect(appService.getId("two")) |
| .andReturn(id2) |
| .anyTimes(); |
| expect(appService.getId("three")) |
| .andReturn(id3) |
| .anyTimes(); |
| expect(appService.getId("four")) |
| .andReturn(id4) |
| .anyTimes(); |
| |
| expect(appService.getApplication(id3)) |
| .andReturn(app3) |
| .anyTimes(); |
| expect(appService.getState(isA(ApplicationId.class))) |
| .andReturn(ApplicationState.ACTIVE) |
| .anyTimes(); |
| |
| // Register the services needed for the test |
| CodecManager codecService = new CodecManager(); |
| codecService.activate(); |
| ServiceDirectory testDirectory = |
| new TestServiceDirectory() |
| .add(ApplicationAdminService.class, appService) |
| .add(ApplicationService.class, appService) |
| .add(CoreService.class, coreService) |
| .add(CodecService.class, codecService); |
| |
| BaseResource.setServiceDirectory(testDirectory); |
| } |
| |
| /** |
| * Tests a GET of all applications when no applications are present. |
| */ |
| @Test |
| public void getAllApplicationsEmpty() { |
| expect(appService.getApplications()) |
| .andReturn(ImmutableSet.of()); |
| replay(appService); |
| |
| WebTarget wt = target(); |
| String response = wt.path("applications").request().get(String.class); |
| assertThat(response, is("{\"applications\":[]}")); |
| |
| verify(appService); |
| } |
| |
| /** |
| * Tests a GET of all applications with data. |
| */ |
| @Test |
| public void getAllApplicationsPopulated() { |
| expect(appService.getApplications()) |
| .andReturn(ImmutableSet.of(app1, app2, app3, app4)); |
| replay(appService); |
| |
| WebTarget wt = target(); |
| String response = wt.path("applications").request().get(String.class); |
| assertThat(response, containsString("{\"applications\":[")); |
| |
| JsonObject result = Json.parse(response).asObject(); |
| assertThat(result, notNullValue()); |
| |
| assertThat(result.names(), hasSize(1)); |
| assertThat(result.names().get(0), is("applications")); |
| |
| JsonArray jsonApps = result.get("applications").asArray(); |
| assertThat(jsonApps, notNullValue()); |
| assertThat(jsonApps.size(), is(4)); |
| |
| assertThat(jsonApps.get(0).asObject(), matchesApp(app1)); |
| assertThat(jsonApps.get(1).asObject(), matchesApp(app2)); |
| assertThat(jsonApps.get(2).asObject(), matchesApp(app3)); |
| assertThat(jsonApps.get(3).asObject(), matchesApp(app4)); |
| |
| verify(appService); |
| } |
| |
| /** |
| * Tests a GET of a single application. |
| */ |
| @Test |
| public void getSingleApplication() { |
| replay(appService); |
| |
| WebTarget wt = target(); |
| String response = wt.path("applications/three").request().get(String.class); |
| |
| JsonObject result = Json.parse(response).asObject(); |
| assertThat(result, notNullValue()); |
| |
| assertThat(result, matchesApp(app3)); |
| |
| verify(appService); |
| } |
| |
| /** |
| * Tests a DELETE of a single application - this should |
| * attempt to uninstall it. |
| */ |
| @Test |
| public void deleteApplication() { |
| appService.uninstall(id3); |
| expectLastCall(); |
| |
| replay(appService); |
| |
| WebTarget wt = target(); |
| wt.path("applications/three").request().delete(); |
| |
| verify(appService); |
| } |
| |
| /** |
| * Tests a DELETE of a single active application - this should |
| * attempt to uninstall it. |
| */ |
| @Test |
| public void deleteActiveApplication() { |
| appService.deactivate(id3); |
| expectLastCall(); |
| |
| replay(appService); |
| |
| WebTarget wt = target(); |
| wt.path("applications/three/active").request().delete(); |
| |
| verify(appService); |
| } |
| |
| /** |
| * Tests a POST operation to the "active" URL. This should attempt to |
| * activate the application. |
| */ |
| @Test |
| public void postActiveApplication() { |
| appService.activate(id3); |
| expectLastCall(); |
| |
| replay(appService); |
| |
| WebTarget wt = target(); |
| wt.path("applications/three/active").request().post(null); |
| |
| verify(appService); |
| } |
| |
| /** |
| * Tests a POST operation. This should attempt to |
| * install the application. |
| */ |
| @Test |
| public void postApplication() { |
| expect(appService.install(isA(InputStream.class))) |
| .andReturn(app4) |
| .once(); |
| |
| replay(appService); |
| |
| ApplicationCodec codec = new ApplicationCodec(); |
| String app4Json = codec.encode(app4, |
| new MockCodecContextWithAppService(appService)) |
| .asText(); |
| |
| WebTarget wt = target(); |
| String response = wt.path("applications").request().post( |
| Entity.entity(app4Json, MediaType.APPLICATION_OCTET_STREAM), String.class); |
| |
| JsonObject result = Json.parse(response).asObject(); |
| assertThat(result, notNullValue()); |
| |
| assertThat(result, matchesApp(app4)); |
| |
| verify(appService); |
| } |
| |
| /** |
| * Tests a POST operation. This should attempt to register an on/off platform |
| * application ID. |
| */ |
| @Test |
| public void postRegisterAppId() { |
| expect(coreService.registerApplication("app1")).andReturn(id1).anyTimes(); |
| replay(coreService); |
| |
| WebTarget wt = target(); |
| wt.path("applications/app1/register").request().post(null); |
| |
| verify(coreService); |
| } |
| |
| /** |
| * Tests a GET of all application Ids when no applications are present. |
| */ |
| @Test |
| public void getAllApplicationIdsEmpty() { |
| expect(coreService.getAppIds()).andReturn(ImmutableSet.of()); |
| replay(coreService); |
| |
| WebTarget wt = target(); |
| String response = wt.path("applications/ids").request().get(String.class); |
| assertThat(response, is("{\"applicationIds\":[]}")); |
| |
| verify(coreService); |
| } |
| |
| /** |
| * Tests a GET of all application Ids. |
| */ |
| @Test |
| public void getAllApplicationIdsPopulated() { |
| expect(coreService.getAppIds()) |
| .andReturn(ImmutableSet.of(id1, id2, id3, id4)); |
| replay(coreService); |
| |
| WebTarget wt = target(); |
| String response = wt.path("applications/ids").request().get(String.class); |
| |
| assertThat(response, containsString("{\"applicationIds\":[")); |
| |
| JsonObject result = Json.parse(response).asObject(); |
| assertThat(result, notNullValue()); |
| |
| assertThat(result.names(), hasSize(1)); |
| assertThat(result.names().get(0), is("applicationIds")); |
| |
| JsonArray jsonApps = result.get("applicationIds").asArray(); |
| assertThat(jsonApps, notNullValue()); |
| assertThat(jsonApps.size(), is(4)); |
| |
| assertThat(jsonApps.get(0).asObject(), matchesAppId(id1)); |
| assertThat(jsonApps.get(1).asObject(), matchesAppId(id2)); |
| assertThat(jsonApps.get(2).asObject(), matchesAppId(id3)); |
| assertThat(jsonApps.get(3).asObject(), matchesAppId(id4)); |
| |
| verify(coreService); |
| } |
| |
| /** |
| * Tests a GET of an applicationId entry with the given numeric id. |
| */ |
| @Test |
| public void getAppIdByShortId() { |
| expect(coreService.getAppId((short) 1)).andReturn(id1); |
| replay(coreService); |
| |
| WebTarget wt = target(); |
| String response = wt.path("applications/ids/entry") |
| .queryParam("id", 1).request().get(String.class); |
| |
| JsonObject result = Json.parse(response).asObject(); |
| assertThat(result, notNullValue()); |
| |
| assertThat(result, matchesAppId(id1)); |
| |
| verify(coreService); |
| } |
| |
| /** |
| * Tests a GET of an applicationId entry with the given application name. |
| */ |
| @Test |
| public void getAppIdByName() { |
| expect(coreService.getAppId("app2")).andReturn(id2); |
| replay(coreService); |
| |
| WebTarget wt = target(); |
| String response = wt.path("applications/ids/entry") |
| .queryParam("name", "app2").request().get(String.class); |
| |
| JsonObject result = Json.parse(response).asObject(); |
| assertThat(result, notNullValue()); |
| |
| assertThat(result, matchesAppId(id2)); |
| |
| verify(coreService); |
| } |
| |
| /** |
| * Tests a GET of an applicationId without specifying any parameters. |
| */ |
| @Test |
| public void getAppWithNoParam() { |
| WebTarget wt = target(); |
| |
| try { |
| wt.path("applications/ids/entry").request().get(); |
| } catch (NotFoundException ex) { |
| Assert.assertThat(ex.getMessage(), |
| containsString("HTTP 404 Not Found")); |
| } |
| } |
| } |