blob: 2f4d65ba129b40f9d613521cad95581f840ce590 [file] [log] [blame]
/*
* 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.ImmutableSet;
import org.glassfish.jersey.client.ClientProperties;
import org.hamcrest.Description;
import org.hamcrest.Matchers;
import org.hamcrest.TypeSafeMatcher;
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.codec.CodecService;
import org.onosproject.codec.impl.CodecManager;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.HashSet;
import static org.easymock.EasyMock.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* Unit tests for tenant REST APIs.
*/
public class TenantWebResourceTest extends ResourceTest {
private final VirtualNetworkAdminService mockVnetAdminService = createMock(VirtualNetworkAdminService.class);
final HashSet<TenantId> tenantIdSet = new HashSet<>();
private static final String ID = "id";
private final TenantId tenantId1 = TenantId.tenantId("TenantId1");
private final TenantId tenantId2 = TenantId.tenantId("TenantId2");
private final TenantId tenantId3 = TenantId.tenantId("TenantId3");
private final TenantId tenantId4 = TenantId.tenantId("TenantId4");
/**
* Sets up the global values for all the tests.
*/
@Before
public void setUpTest() {
// Register the services needed for the test
CodecManager codecService = new CodecManager();
codecService.activate();
ServiceDirectory testDirectory =
new TestServiceDirectory()
.add(VirtualNetworkAdminService.class, mockVnetAdminService)
.add(CodecService.class, codecService);
BaseResource.setServiceDirectory(testDirectory);
}
/**
* Hamcrest matcher to check that a tenant id representation in JSON matches
* the actual tenant id.
*/
public static class TenantIdJsonMatcher extends TypeSafeMatcher<JsonObject> {
private final TenantId tenantId;
private String reason = "";
public TenantIdJsonMatcher(TenantId tenantIdValue) {
tenantId = tenantIdValue;
}
@Override
public boolean matchesSafely(JsonObject jsonHost) {
// Check the tenant id
final String jsonId = jsonHost.get(ID).asString();
if (!jsonId.equals(tenantId.id())) {
reason = ID + " " + tenantId.id();
return false;
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(reason);
}
}
/**
* Factory to allocate a tenant id array matcher.
*
* @param tenantId tenant id object we are looking for
* @return matcher
*/
private static TenantIdJsonMatcher matchesTenantId(TenantId tenantId) {
return new TenantIdJsonMatcher(tenantId);
}
/**
* Hamcrest matcher to check that a tenant id is represented properly in a JSON
* array of tenant ids.
*/
public static class TenantIdJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
private final TenantId tenantId;
private String reason = "";
public TenantIdJsonArrayMatcher(TenantId tenantIdValue) {
tenantId = tenantIdValue;
}
@Override
public boolean matchesSafely(JsonArray json) {
boolean tenantIdFound = false;
final int expectedAttributes = 1;
for (int tenantIdIndex = 0; tenantIdIndex < json.size();
tenantIdIndex++) {
final JsonObject jsonHost = json.get(tenantIdIndex).asObject();
// Only 1 attribute - ID.
if (jsonHost.names().size() < expectedAttributes) {
reason = "Found a tenant id with the wrong number of attributes";
return false;
}
final String jsonDeviceKeyId = jsonHost.get(ID).asString();
if (jsonDeviceKeyId.equals(tenantId.id())) {
tenantIdFound = true;
// We found the correct tenant id, check the tenant id attribute values
assertThat(jsonHost, matchesTenantId(tenantId));
}
}
if (!tenantIdFound) {
reason = "Tenant id " + tenantId.id() + " was not found";
return false;
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(reason);
}
}
/**
* Factory to allocate a tenant id array matcher.
*
* @param tenantId tenant id object we are looking for
* @return matcher
*/
private static TenantIdJsonArrayMatcher hasTenantId(TenantId tenantId) {
return new TenantIdJsonArrayMatcher(tenantId);
}
/**
* Tests the result of the REST API GET when there are no tenant ids.
*/
@Test
public void testGetTenantsEmptyArray() {
expect(mockVnetAdminService.getTenantIds()).andReturn(ImmutableSet.of()).anyTimes();
replay(mockVnetAdminService);
WebTarget wt = target();
String response = wt.path("tenants").request().get(String.class);
assertThat(response, is("{\"tenants\":[]}"));
verify(mockVnetAdminService);
}
/**
* Tests the result of the REST API GET when tenant ids are defined.
*/
@Test
public void testGetTenantIdsArray() {
tenantIdSet.add(tenantId1);
tenantIdSet.add(tenantId2);
tenantIdSet.add(tenantId3);
tenantIdSet.add(tenantId4);
expect(mockVnetAdminService.getTenantIds()).andReturn(tenantIdSet).anyTimes();
replay(mockVnetAdminService);
WebTarget wt = target();
String response = wt.path("tenants").request().get(String.class);
assertThat(response, containsString("{\"tenants\":["));
final JsonObject result = Json.parse(response).asObject();
assertThat(result, notNullValue());
assertThat(result.names(), hasSize(1));
assertThat(result.names().get(0), is("tenants"));
final JsonArray tenantIds = result.get("tenants").asArray();
assertThat(tenantIds, notNullValue());
assertEquals("Device keys array is not the correct size.",
tenantIdSet.size(), tenantIds.size());
tenantIdSet.forEach(tenantId -> assertThat(tenantIds, hasTenantId(tenantId)));
verify(mockVnetAdminService);
}
/**
* Tests adding of new tenant id using POST via JSON stream.
*/
@Test
public void testPost() {
mockVnetAdminService.registerTenantId(anyObject());
tenantIdSet.add(tenantId2);
expect(mockVnetAdminService.getTenantIds()).andReturn(tenantIdSet).anyTimes();
expectLastCall();
replay(mockVnetAdminService);
WebTarget wt = target();
InputStream jsonStream = TenantWebResourceTest.class
.getResourceAsStream("post-tenant.json");
Response response = wt.path("tenants").request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.json(jsonStream));
assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
String location = response.getLocation().getPath();
assertThat(location, Matchers.startsWith("/tenants/" + tenantId2));
verify(mockVnetAdminService);
}
/**
* Tests adding of a null tenant id using POST via JSON stream.
*/
@Test
public void testPostNullTenantId() {
replay(mockVnetAdminService);
WebTarget wt = target();
try {
String response = wt.path("tenants")
.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.json(null), String.class);
fail("POST of null tenant id did not throw an exception");
} catch (BadRequestException ex) {
assertThat(ex.getMessage(), containsString("HTTP 400 Bad Request"));
}
verify(mockVnetAdminService);
}
/**
* Tests removing a tenant id with DELETE request.
*/
@Test
public void testDelete() {
expect(mockVnetAdminService.getTenantIds())
.andReturn(ImmutableSet.of(tenantId2)).anyTimes();
mockVnetAdminService.unregisterTenantId(anyObject());
expectLastCall();
replay(mockVnetAdminService);
WebTarget wt = target()
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
Response response = wt.path("tenants/" + tenantId2)
.request(MediaType.APPLICATION_JSON_TYPE)
.delete();
assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
verify(mockVnetAdminService);
}
/**
* Tests that a DELETE of a non-existent tenant id throws an exception.
*/
@Test
public void testDeleteNonExistentDeviceKey() {
expect(mockVnetAdminService.getTenantIds())
.andReturn(ImmutableSet.of())
.anyTimes();
expectLastCall();
replay(mockVnetAdminService);
WebTarget wt = target();
try {
wt.path("tenants/" + "NON_EXISTENT_TENANT_ID")
.request()
.delete(String.class);
fail("Delete of a non-existent tenant did not throw an exception");
} catch (NotFoundException ex) {
assertThat(ex.getMessage(), containsString("HTTP 404 Not Found"));
}
verify(mockVnetAdminService);
}
}