Claudine Chiu
Committed by Gerrit Code Review

ONOS-4077: REST API's for virtual links.

Change-Id: Idc838f24735e75ad2729393a03dcac4d256239bb
......@@ -28,6 +28,7 @@ import org.onosproject.codec.JsonCodec;
import org.onosproject.core.Application;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.net.Annotations;
......@@ -134,6 +135,7 @@ public class CodecManager implements CodecService {
registerCodec(VirtualNetwork.class, new VirtualNetworkCodec());
registerCodec(VirtualDevice.class, new VirtualDeviceCodec());
registerCodec(VirtualPort.class, new VirtualPortCodec());
registerCodec(VirtualLink.class, new VirtualLinkCodec());
log.info("Started");
}
......
package org.onosproject.codec.impl;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.incubator.net.tunnel.TunnelId;
import org.onosproject.incubator.net.virtual.DefaultVirtualLink;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.net.Link;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.nullIsIllegal;
/**
* Codec for the VirtualLink class.
*/
public class VirtualLinkCodec extends JsonCodec<VirtualLink> {
// JSON field names
private static final String NETWORK_ID = "networkId";
private static final String TUNNEL_ID = "tunnelId";
private static final String NULL_OBJECT_MSG = "VirtualLink cannot be null";
private static final String MISSING_MEMBER_MSG = " member is required in VirtualLink";
@Override
public ObjectNode encode(VirtualLink vLink, CodecContext context) {
checkNotNull(vLink, NULL_OBJECT_MSG);
JsonCodec<Link> codec = context.codec(Link.class);
ObjectNode result = codec.encode(vLink, context);
result.put(NETWORK_ID, vLink.networkId().toString());
// TODO check if tunnelId needs to be part of VirtualLink interface.
if (vLink instanceof DefaultVirtualLink) {
result.put(TUNNEL_ID, ((DefaultVirtualLink) vLink).tunnelId().toString());
}
return result;
}
@Override
public VirtualLink decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
JsonCodec<Link> codec = context.codec(Link.class);
Link link = codec.decode(json, context);
NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
String tunnelIdStr = json.path(TUNNEL_ID).asText();
TunnelId tunnelId = tunnelIdStr != null ? TunnelId.valueOf(tunnelIdStr)
: TunnelId.valueOf(0);
return new DefaultVirtualLink(nId, link.src(), link.dst(), tunnelId);
}
/**
* Extract member from JSON ObjectNode.
*
* @param key key for which value is needed
* @param json JSON ObjectNode
* @return member value
*/
private String extractMember(String key, ObjectNode json) {
return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
}
}
......@@ -131,7 +131,7 @@ public class TenantWebResource extends AbstractWebResource {
*
* @param stream TenantId JSON stream
* @return TenantId
* @throws IOException
* @throws IOException if unable to parse the request
*/
private TenantId getTenantIdFromJsonStream(InputStream stream) throws IOException {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
......@@ -146,11 +146,11 @@ public class TenantWebResource extends AbstractWebResource {
/**
* Get the matching tenant identifier from existing tenant identifiers in system.
*
* @param vnetAdminSvc
* @param vnetAdminSvc virtual network administration service
* @param tidIn tenant identifier
* @return TenantId
*/
private static TenantId getExistingTenantId(VirtualNetworkAdminService vnetAdminSvc,
static TenantId getExistingTenantId(VirtualNetworkAdminService vnetAdminSvc,
TenantId tidIn) {
final TenantId resultTid = vnetAdminSvc
.getTenantIds()
......
......@@ -18,9 +18,12 @@ package org.onosproject.rest.resources;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.incubator.net.tunnel.TunnelId;
import org.onosproject.incubator.net.virtual.DefaultVirtualLink;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
......@@ -38,6 +41,7 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
......@@ -69,7 +73,6 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
UriInfo uriInfo;
// VirtualNetwork
// TODO Query vnets by tenant
/**
* Returns all virtual networks.
......@@ -88,6 +91,22 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
}
/**
* Returns the virtual networks with the specified tenant identifier.
*
* @param tenantId tenant identifier
* @return 200 OK, 404 not found
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{tenantId}")
public Response getVirtualNetworkById(@PathParam("tenantId") String tenantId) {
final TenantId existingTid = TenantWebResource.getExistingTenantId(vnetAdminService,
TenantId.tenantId(tenantId));
Set<VirtualNetwork> vnets = vnetService.getVirtualNetworks(existingTid);
return ok(encodeArray(VirtualNetwork.class, "vnets", vnets)).build();
}
/**
* Creates a virtual network from the JSON input stream.
*
* @param stream TenantId JSON stream
......@@ -122,7 +141,7 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
@DELETE
@Path("{networkId}")
public Response removeVirtualNetwork(@PathParam("networkId") long networkId) {
final NetworkId nid = NetworkId.networkId(networkId);
NetworkId nid = NetworkId.networkId(networkId);
vnetAdminService.removeVirtualNetwork(nid);
return Response.ok().build();
}
......@@ -139,7 +158,7 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
@Produces(MediaType.APPLICATION_JSON)
@Path("{networkId}/devices")
public Response getVirtualDevices(@PathParam("networkId") long networkId) {
final NetworkId nid = NetworkId.networkId(networkId);
NetworkId nid = NetworkId.networkId(networkId);
Set<VirtualDevice> vdevs = vnetService.getVirtualDevices(nid);
return ok(encodeArray(VirtualDevice.class, "devices", vdevs)).build();
}
......@@ -154,7 +173,7 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
* @onos.rsModel VirtualDevice
*/
@POST
@Path("{networkId}/devices/")
@Path("{networkId}/devices")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createVirtualDevice(@PathParam("networkId") long networkId,
......@@ -162,15 +181,14 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
final VirtualDevice vdevReq = codec(VirtualDevice.class).decode(jsonTree, this);
JsonNode specifiedRegionId = jsonTree.get("networkId");
if (specifiedRegionId != null &&
specifiedRegionId.asLong() != (networkId)) {
JsonNode specifiedNetworkId = jsonTree.get("networkId");
if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
final VirtualDevice vdevRes = vnetAdminService.createVirtualDevice(vdevReq.networkId(),
vdevReq.id());
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path("vnets").path(specifiedRegionId.asText())
.path("vnets").path(specifiedNetworkId.asText())
.path("devices").path(vdevRes.id().toString());
return Response
.created(locationBuilder.build())
......@@ -191,8 +209,8 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
@Path("{networkId}/devices/{deviceId}")
public Response removeVirtualDevice(@PathParam("networkId") long networkId,
@PathParam("deviceId") String deviceId) {
final NetworkId nid = NetworkId.networkId(networkId);
final DeviceId did = DeviceId.deviceId(deviceId);
NetworkId nid = NetworkId.networkId(networkId);
DeviceId did = DeviceId.deviceId(deviceId);
vnetAdminService.removeVirtualDevice(nid, did);
return Response.ok().build();
}
......@@ -211,7 +229,7 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
@Path("{networkId}/devices/{deviceId}/ports")
public Response getVirtualPorts(@PathParam("networkId") long networkId,
@PathParam("deviceId") String deviceId) {
final NetworkId nid = NetworkId.networkId(networkId);
NetworkId nid = NetworkId.networkId(networkId);
Iterable<VirtualPort> vports = vnetService.getVirtualPorts(nid, DeviceId.deviceId(deviceId));
return ok(encodeArray(VirtualPort.class, "ports", vports)).build();
}
......@@ -238,12 +256,10 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
// final VirtualPort vportReq = codec(VirtualPort.class).decode(jsonTree, this);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
JsonNode specifiedDeviceId = jsonTree.get("deviceId");
if (specifiedNetworkId != null &&
specifiedNetworkId.asLong() != (networkId)) {
if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
if (specifiedDeviceId != null &&
!specifiedDeviceId.asText().equals(virtDeviceId)) {
if (specifiedDeviceId == null || !specifiedDeviceId.asText().equals(virtDeviceId)) {
throw new IllegalArgumentException(INVALID_FIELD + "deviceId");
}
JsonNode specifiedPortNum = jsonTree.get("portNum");
......@@ -283,13 +299,129 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
public Response removeVirtualPort(@PathParam("networkId") long networkId,
@PathParam("deviceId") String deviceId,
@PathParam("portNum") long portNum) {
final NetworkId nid = NetworkId.networkId(networkId);
NetworkId nid = NetworkId.networkId(networkId);
vnetAdminService.removeVirtualPort(nid, DeviceId.deviceId(deviceId),
PortNumber.portNumber(portNum));
return Response.ok().build();
}
// TODO VirtualLink
// VirtualLink
/**
* Returns all virtual network links in a virtual network.
*
* @param networkId network identifier
* @return 200 OK
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{networkId}/links")
public Response getVirtualLinks(@PathParam("networkId") long networkId) {
NetworkId nid = NetworkId.networkId(networkId);
Set<VirtualLink> vlinks = vnetService.getVirtualLinks(nid);
return ok(encodeArray(VirtualLink.class, "links", vlinks)).build();
}
/**
* Creates a virtual network link from the JSON input stream.
*
* @param networkId network identifier
* @param stream Virtual device JSON stream
* @return status of the request - CREATED if the JSON is correct,
* BAD_REQUEST if the JSON is invalid
* @onos.rsModel VirtualLink
*/
@POST
@Path("{networkId}/links")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createVirtualLink(@PathParam("networkId") long networkId,
InputStream stream) {
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
final VirtualLink vlinkReq = codec(VirtualLink.class).decode(jsonTree, this);
TunnelId tunnelId = TunnelId.valueOf(0);
if (vlinkReq instanceof DefaultVirtualLink) {
tunnelId = ((DefaultVirtualLink) vlinkReq).tunnelId();
}
vnetAdminService.createVirtualLink(vlinkReq.networkId(),
vlinkReq.src(), vlinkReq.dst(), tunnelId);
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path("vnets").path(specifiedNetworkId.asText())
.path("links");
return Response
.created(locationBuilder.build())
.build();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Removes the virtual network link from the JSON input stream.
*
* @param networkId network identifier
* @param stream deviceIds JSON stream
* @return 200 OK, 404 not found
* @onos.rsModel VirtualLink
*/
@DELETE
@Path("{networkId}/links")
@Consumes(MediaType.APPLICATION_JSON)
public Response removeVirtualLink(@PathParam("networkId") long networkId,
InputStream stream) {
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
if (specifiedNetworkId != null &&
specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
final VirtualLink vlinkReq = codec(VirtualLink.class).decode(jsonTree, this);
vnetAdminService.removeVirtualLink(vlinkReq.networkId(),
vlinkReq.src(), vlinkReq.dst());
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return Response.ok().build();
}
/**
* Removes the virtual network link from the JSON input stream.
*
* @param networkId network identifier
* @param stream deviceIds JSON stream
* @return 200 OK, 404 not found
* @onos.rsModel VirtualLink
*/
@PUT
@Path("{networkId}/links/remove")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response removeVirtualLink2(@PathParam("networkId") long networkId,
InputStream stream) {
try {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
JsonNode specifiedNetworkId = jsonTree.get("networkId");
if (specifiedNetworkId != null &&
specifiedNetworkId.asLong() != (networkId)) {
throw new IllegalArgumentException(INVALID_FIELD + "networkId");
}
final VirtualLink vlinkReq = codec(VirtualLink.class).decode(jsonTree, this);
vnetAdminService.removeVirtualLink(vlinkReq.networkId(),
vlinkReq.src(), vlinkReq.dst());
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return Response.ok().build();
}
/**
* Get the tenant identifier from the JSON stream.
......@@ -297,7 +429,7 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
* @param stream TenantId JSON stream
* @param jsonFieldName field name
* @return JsonNode
* @throws IOException
* @throws IOException if unable to parse the request
*/
private JsonNode getFromJsonStream(InputStream stream, String jsonFieldName) throws IOException {
ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
......
{
"type": "object",
"title": "vlink",
"required": [
"networkId",
"src",
"dst",
"type",
"state"
],
"properties": {
"networkId": {
"type": "String",
"example": "Network identifier"
},
"src": {
"type": "object",
"title": "src",
"required": [
"port",
"device"
],
"properties": {
"port": {
"type": "string",
"example": "3"
},
"device": {
"type": "string",
"example": "of:0000000000000002"
}
}
},
"dst": {
"type": "object",
"title": "dst",
"required": [
"port",
"device"
],
"properties": {
"port": {
"type": "string",
"example": "2"
},
"device": {
"type": "string",
"example": "of:0000000000000003"
}
}
},
"type": {
"type": "string",
"example": "DIRECT"
},
"state": {
"type": "string",
"example": "ACTIVE"
},
"tunnelId": {
"type": "int64",
"example": "Tunnel identifier"
}
}
}
......@@ -32,16 +32,20 @@ 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.tunnel.TunnelId;
import org.onosproject.incubator.net.virtual.DefaultVirtualDevice;
import org.onosproject.incubator.net.virtual.DefaultVirtualLink;
import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
import org.onosproject.incubator.net.virtual.DefaultVirtualPort;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.DefaultPort;
......@@ -61,6 +65,7 @@ import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
......@@ -80,7 +85,6 @@ public class VirtualNetworkWebResourceTest extends ResourceTest {
private CodecManager codecService;
final HashSet<TenantId> tenantIdSet = new HashSet<>();
final HashSet<VirtualNetwork> vnetSet = new HashSet<>();
final HashSet<VirtualDevice> vdevSet = new HashSet<>();
final HashSet<VirtualPort> vportSet = new HashSet<>();
......@@ -90,6 +94,7 @@ public class VirtualNetworkWebResourceTest extends ResourceTest {
private static final String PORT_NUM = "portNum";
private static final String PHYS_DEVICE_ID = "physDeviceId";
private static final String PHYS_PORT_NUM = "physPortNum";
private static final String TUNNEL_ID = "tunnelId";
private final TenantId tenantId1 = TenantId.tenantId("TenantId1");
private final TenantId tenantId2 = TenantId.tenantId("TenantId2");
......@@ -106,8 +111,8 @@ public class VirtualNetworkWebResourceTest extends ResourceTest {
private final VirtualNetwork vnet3 = new DefaultVirtualNetwork(networkId3, tenantId3);
private final VirtualNetwork vnet4 = new DefaultVirtualNetwork(networkId4, tenantId3);
private final DeviceId devId1 = DeviceId.deviceId("devId1");
private final DeviceId devId2 = DeviceId.deviceId("devId2");
private final DeviceId devId1 = DeviceId.deviceId("devid1");
private final DeviceId devId2 = DeviceId.deviceId("devid2");
private final DeviceId devId22 = DeviceId.deviceId("dev22");
private final VirtualDevice vdev1 = new DefaultVirtualDevice(networkId3, devId1);
......@@ -115,6 +120,7 @@ public class VirtualNetworkWebResourceTest extends ResourceTest {
private final Device dev1 = NetTestTools.device("dev1");
private final Device dev2 = NetTestTools.device("dev2");
private final Device dev21 = NetTestTools.device("dev21");
private final Device dev22 = NetTestTools.device("dev22");
Port port1 = new DefaultPort(dev1, portNumber(1), true);
......@@ -125,6 +131,15 @@ public class VirtualNetworkWebResourceTest extends ResourceTest {
private final VirtualPort vport23 = new DefaultVirtualPort(networkId3,
dev22, portNumber(23), port2);
private final ConnectPoint cp11 = NetTestTools.connectPoint(devId1.toString(), 21);
private final ConnectPoint cp21 = NetTestTools.connectPoint(devId2.toString(), 22);
private final ConnectPoint cp12 = NetTestTools.connectPoint(devId1.toString(), 2);
private final ConnectPoint cp22 = NetTestTools.connectPoint(devId2.toString(), 22);
private final TunnelId tunnelId = TunnelId.valueOf(31);
private final VirtualLink vlink1 = new DefaultVirtualLink(networkId3, cp22, cp11, tunnelId);
private final VirtualLink vlink2 = new DefaultVirtualLink(networkId3, cp12, cp21, tunnelId);
/**
* Sets up the global values for all the tests.
*/
......@@ -313,12 +328,9 @@ public class VirtualNetworkWebResourceTest extends ResourceTest {
*/
@Test
public void testGetVirtualNetworksArray() {
final Set<VirtualNetwork> vnetSet = ImmutableSet.of(vnet1, vnet2, vnet3, vnet4);
expect(mockVnetAdminService.getTenantIds()).andReturn(ImmutableSet.of(tenantId3)).anyTimes();
replay(mockVnetAdminService);
vnetSet.add(vnet1);
vnetSet.add(vnet2);
vnetSet.add(vnet3);
vnetSet.add(vnet4);
expect(mockVnetService.getVirtualNetworks(tenantId3)).andReturn(vnetSet).anyTimes();
replay(mockVnetService);
......@@ -344,6 +356,64 @@ public class VirtualNetworkWebResourceTest extends ResourceTest {
}
/**
* Tests the result of the REST API GET for virtual networks with tenant id.
*/
@Test
public void testGetVirtualNetworksByTenantId() {
final Set<VirtualNetwork> vnetSet = ImmutableSet.of(vnet1, vnet2, vnet3, vnet4);
expect(mockVnetAdminService.getTenantIds()).andReturn(ImmutableSet.of(tenantId3)).anyTimes();
replay(mockVnetAdminService);
expect(mockVnetService.getVirtualNetworks(tenantId3)).andReturn(vnetSet).anyTimes();
replay(mockVnetService);
WebTarget wt = target();
String response = wt.path("vnets/" + tenantId3.id()).request().get(String.class);
assertThat(response, containsString("{\"vnets\":["));
final JsonObject result = Json.parse(response).asObject();
assertThat(result, notNullValue());
assertThat(result.names(), hasSize(1));
assertThat(result.names().get(0), is("vnets"));
final JsonArray vnetJsonArray = result.get("vnets").asArray();
assertThat(vnetJsonArray, notNullValue());
assertEquals("Virtual networks array is not the correct size.",
vnetSet.size(), vnetJsonArray.size());
vnetSet.forEach(vnet -> assertThat(vnetJsonArray, hasVnet(vnet)));
verify(mockVnetService);
verify(mockVnetAdminService);
}
/**
* Tests the result of the REST API GET for virtual networks with tenant id.
*/
@Test
public void testGetVirtualNetworksByNonExistentTenantId() {
String tenantIdName = "NON_EXISTENT_TENANT_ID";
expect(mockVnetAdminService.getTenantIds()).andReturn(ImmutableSet.of(tenantId3)).anyTimes();
replay(mockVnetAdminService);
expect(mockVnetService.getVirtualNetworks(anyObject())).andReturn(ImmutableSet.of()).anyTimes();
replay(mockVnetService);
WebTarget wt = target();
try {
wt.path("vnets/" + tenantIdName)
.request()
.get(String.class);
fail("Get of a non-existent virtual network did not throw an exception");
} catch (NotFoundException ex) {
assertThat(ex.getMessage(), containsString("HTTP 404 Not Found"));
}
verify(mockVnetService);
verify(mockVnetAdminService);
}
/**
* Tests adding of new virtual network using POST via JSON stream.
*/
@Test
......@@ -756,5 +826,243 @@ public class VirtualNetworkWebResourceTest extends ResourceTest {
verify(mockVnetAdminService);
}
// TODO Tests for Virtual Links
// Tests for Virtual Links
/**
* Tests the result of the REST API GET when there are no virtual links.
*/
@Test
public void testGetVirtualLinksEmptyArray() {
NetworkId networkId = networkId4;
expect(mockVnetService.getVirtualLinks(networkId)).andReturn(ImmutableSet.of()).anyTimes();
replay(mockVnetService);
WebTarget wt = target();
String location = "vnets/" + networkId.toString() + "/links";
String response = wt.path(location).request().get(String.class);
assertThat(response, is("{\"links\":[]}"));
verify(mockVnetService);
}
/**
* Tests the result of the REST API GET when virtual links are defined.
*/
@Test
public void testGetVirtualLinksArray() {
NetworkId networkId = networkId3;
final Set<VirtualLink> vlinkSet = ImmutableSet.of(vlink1, vlink2);
expect(mockVnetService.getVirtualLinks(networkId)).andReturn(vlinkSet).anyTimes();
replay(mockVnetService);
WebTarget wt = target();
String location = "vnets/" + networkId.toString() + "/links";
String response = wt.path(location).request().get(String.class);
assertThat(response, containsString("{\"links\":["));
final JsonObject result = Json.parse(response).asObject();
assertThat(result, notNullValue());
assertThat(result.names(), hasSize(1));
assertThat(result.names().get(0), is("links"));
final JsonArray vnetJsonArray = result.get("links").asArray();
assertThat(vnetJsonArray, notNullValue());
assertEquals("Virtual links array is not the correct size.",
vlinkSet.size(), vnetJsonArray.size());
vlinkSet.forEach(vlink -> assertThat(vnetJsonArray, hasVlink(vlink)));
verify(mockVnetService);
}
/**
* Hamcrest matcher to check that a virtual link representation in JSON matches
* the actual virtual link.
*/
public static class VirtualLinkJsonMatcher extends LinksResourceTest.LinkJsonMatcher {
private final VirtualLink vlink;
private String reason = "";
public VirtualLinkJsonMatcher(VirtualLink vlinkValue) {
super(vlinkValue);
vlink = vlinkValue;
}
@Override
public boolean matchesSafely(JsonObject jsonLink) {
if (!super.matchesSafely(jsonLink)) {
return false;
}
// check NetworkId
String jsonNetworkId = jsonLink.get(ID).asString();
String networkId = vlink.networkId().toString();
if (!jsonNetworkId.equals(networkId)) {
reason = ID + " was " + jsonNetworkId;
return false;
}
// check TunnelId
String jsonTunnelId = jsonLink.get(TUNNEL_ID).asString();
if (jsonTunnelId != null && vlink instanceof DefaultVirtualLink) {
String tunnelId = ((DefaultVirtualLink) vlink).tunnelId().toString();
if (!jsonTunnelId.equals(tunnelId)) {
reason = TUNNEL_ID + " was " + jsonTunnelId;
return false;
}
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(reason);
}
}
/**
* Factory to allocate a virtual link matcher.
*
* @param vlink virtual link object we are looking for
* @return matcher
*/
private static VirtualLinkJsonMatcher matchesVirtualLink(VirtualLink vlink) {
return new VirtualLinkJsonMatcher(vlink);
}
/**
* Hamcrest matcher to check that a virtual link is represented properly in a JSON
* array of links.
*/
private static class VirtualLinkJsonArrayMatcher extends TypeSafeMatcher<JsonArray> {
private final VirtualLink vlink;
private String reason = "";
public VirtualLinkJsonArrayMatcher(VirtualLink vlinkValue) {
vlink = vlinkValue;
}
@Override
public boolean matchesSafely(JsonArray json) {
final int expectedAttributes = 2;
for (int jsonLinkIndex = 0; jsonLinkIndex < json.size();
jsonLinkIndex++) {
JsonObject jsonLink = json.get(jsonLinkIndex).asObject();
if (matchesVirtualLink(vlink).matchesSafely(jsonLink)) {
return true;
}
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText(reason);
}
}
/**
* Factory to allocate a virtual link array matcher.
*
* @param vlink virtual link object we are looking for
* @return matcher
*/
private VirtualLinkJsonArrayMatcher hasVlink(VirtualLink vlink) {
return new VirtualLinkJsonArrayMatcher(vlink);
}
/**
* Tests adding of new virtual link using POST via JSON stream.
*/
@Test
public void testPostVirtualLink() {
NetworkId networkId = networkId3;
expect(mockVnetAdminService.createVirtualLink(networkId, cp22, cp11, tunnelId))
.andReturn(vlink1);
replay(mockVnetAdminService);
WebTarget wt = target();
InputStream jsonStream = VirtualNetworkWebResourceTest.class
.getResourceAsStream("post-virtual-link.json");
String reqLocation = "vnets/" + networkId.toString() + "/links";
Response response = wt.path(reqLocation).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("/" + reqLocation));
verify(mockVnetAdminService);
}
/**
* Tests adding of a null virtual link using POST via JSON stream.
*/
@Test
public void testPostVirtualLinkNullJsonStream() {
NetworkId networkId = networkId3;
replay(mockVnetAdminService);
WebTarget wt = target();
try {
String reqLocation = "vnets/" + networkId.toString() + "/links";
wt.path(reqLocation)
.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.json(null), String.class);
fail("POST of null virtual link did not throw an exception");
} catch (BadRequestException ex) {
assertThat(ex.getMessage(), containsString("HTTP 400 Bad Request"));
}
verify(mockVnetAdminService);
}
/**
* Tests removing a virtual link with DELETE request.
*/
@Test
public void testDeleteVirtualLink() {
NetworkId networkId = networkId3;
mockVnetAdminService.removeVirtualLink(networkId, cp22, cp11);
expectLastCall();
replay(mockVnetAdminService);
WebTarget wt = target()
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
InputStream jsonStream = VirtualNetworkWebResourceTest.class
.getResourceAsStream("post-virtual-link.json");
String reqLocation = "vnets/" + networkId.toString() + "/links";
Response response = wt.path(reqLocation).request().accept(MediaType.APPLICATION_JSON_TYPE)
.method("DELETE", Entity.json(jsonStream));
// Response response = wt.path(reqLocation).request().method("DELETE", Entity.json(jsonStream));
// assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
// verify(mockVnetAdminService);
}
/**
* Tests removing a virtual link with PUT request.
*/
@Test
public void testDeleteVirtualLink2() {
NetworkId networkId = networkId3;
mockVnetAdminService.removeVirtualLink(networkId, cp22, cp11);
expectLastCall();
replay(mockVnetAdminService);
WebTarget wt = target()
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
InputStream jsonStream = VirtualNetworkWebResourceTest.class
.getResourceAsStream("post-virtual-link.json");
String reqLocation = "vnets/" + networkId.toString() + "/links/remove";
Response response = wt.path(reqLocation).request().accept(MediaType.APPLICATION_JSON_TYPE)
.method("PUT", Entity.json(jsonStream));
assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
verify(mockVnetAdminService);
}
// All Tests done
}
......
{
"networkId": "3",
"src": {
"device": "of:devid2",
"port": "22"
},
"dst": {
"device": "of:devid1",
"port": "21"
},
"type": "VIRTUAL",
"state": "ACTIVE",
"tunnelId": "31"
}