Committed by
Gerrit Code Review
[ONOS-3603] Add getGroupByDeviceIdAndAppCookie method in group REST API
* Add a new method for getting a specific group result * Add descriptions in swagger doc Change-Id: I62a476bd2cd774eed157dd3954349eb5aa335db3
Showing
4 changed files
with
256 additions
and
3 deletions
| ... | @@ -43,6 +43,8 @@ import java.io.InputStream; | ... | @@ -43,6 +43,8 @@ import java.io.InputStream; |
| 43 | import java.net.URI; | 43 | import java.net.URI; |
| 44 | import java.net.URISyntaxException; | 44 | import java.net.URISyntaxException; |
| 45 | 45 | ||
| 46 | +import static org.onlab.util.Tools.nullIsNotFound; | ||
| 47 | + | ||
| 46 | /** | 48 | /** |
| 47 | * Query and program group rules. | 49 | * Query and program group rules. |
| 48 | */ | 50 | */ |
| ... | @@ -50,6 +52,7 @@ import java.net.URISyntaxException; | ... | @@ -50,6 +52,7 @@ import java.net.URISyntaxException; |
| 50 | @Path("groups") | 52 | @Path("groups") |
| 51 | public class GroupsWebResource extends AbstractWebResource { | 53 | public class GroupsWebResource extends AbstractWebResource { |
| 52 | public static final String DEVICE_INVALID = "Invalid deviceId in group creation request"; | 54 | public static final String DEVICE_INVALID = "Invalid deviceId in group creation request"; |
| 55 | + public static final String GROUP_NOT_FOUND = "Group was not found"; | ||
| 53 | 56 | ||
| 54 | final GroupService groupService = get(GroupService.class); | 57 | final GroupService groupService = get(GroupService.class); |
| 55 | final ObjectNode root = mapper().createObjectNode(); | 58 | final ObjectNode root = mapper().createObjectNode(); |
| ... | @@ -57,8 +60,9 @@ public class GroupsWebResource extends AbstractWebResource { | ... | @@ -57,8 +60,9 @@ public class GroupsWebResource extends AbstractWebResource { |
| 57 | 60 | ||
| 58 | /** | 61 | /** |
| 59 | * Returns all groups of all devices. | 62 | * Returns all groups of all devices. |
| 60 | - * @onos.rsModel Groups | 63 | + * |
| 61 | * @return array of all the groups in the system | 64 | * @return array of all the groups in the system |
| 65 | + * @onos.rsModel Groups | ||
| 62 | */ | 66 | */ |
| 63 | @GET | 67 | @GET |
| 64 | @Produces(MediaType.APPLICATION_JSON) | 68 | @Produces(MediaType.APPLICATION_JSON) |
| ... | @@ -78,8 +82,8 @@ public class GroupsWebResource extends AbstractWebResource { | ... | @@ -78,8 +82,8 @@ public class GroupsWebResource extends AbstractWebResource { |
| 78 | * Returns all groups associated with the given device. | 82 | * Returns all groups associated with the given device. |
| 79 | * | 83 | * |
| 80 | * @param deviceId device identifier | 84 | * @param deviceId device identifier |
| 81 | - * @onos.rsModel Groups | ||
| 82 | * @return array of all the groups in the system | 85 | * @return array of all the groups in the system |
| 86 | + * @onos.rsModel Groups | ||
| 83 | */ | 87 | */ |
| 84 | @GET | 88 | @GET |
| 85 | @Produces(MediaType.APPLICATION_JSON) | 89 | @Produces(MediaType.APPLICATION_JSON) |
| ... | @@ -93,14 +97,37 @@ public class GroupsWebResource extends AbstractWebResource { | ... | @@ -93,14 +97,37 @@ public class GroupsWebResource extends AbstractWebResource { |
| 93 | } | 97 | } |
| 94 | 98 | ||
| 95 | /** | 99 | /** |
| 100 | + * Returns a group with the given deviceId and appCookie. | ||
| 101 | + * | ||
| 102 | + * @param deviceId device identifier | ||
| 103 | + * @param appCookie group key | ||
| 104 | + * @return a group entry in the system | ||
| 105 | + * @onos.rsModel Group | ||
| 106 | + */ | ||
| 107 | + @GET | ||
| 108 | + @Produces(MediaType.APPLICATION_JSON) | ||
| 109 | + @Path("{deviceId}/{appCookie}") | ||
| 110 | + public Response getGroupByDeviceIdAndAppCookie(@PathParam("deviceId") String deviceId, | ||
| 111 | + @PathParam("appCookie") String appCookie) { | ||
| 112 | + final DeviceId deviceIdInstance = DeviceId.deviceId(deviceId); | ||
| 113 | + final GroupKey appCookieInstance = new DefaultGroupKey(appCookie.getBytes()); | ||
| 114 | + | ||
| 115 | + Group group = nullIsNotFound(groupService.getGroup(deviceIdInstance, appCookieInstance), | ||
| 116 | + GROUP_NOT_FOUND); | ||
| 117 | + | ||
| 118 | + groupsNode.add(codec(Group.class).encode(group, this)); | ||
| 119 | + return ok(root).build(); | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + /** | ||
| 96 | * Create new group rule. Creates and installs a new group rule for the | 123 | * Create new group rule. Creates and installs a new group rule for the |
| 97 | * specified device. | 124 | * specified device. |
| 98 | * | 125 | * |
| 99 | * @param deviceId device identifier | 126 | * @param deviceId device identifier |
| 100 | * @param stream group rule JSON | 127 | * @param stream group rule JSON |
| 101 | - * @onos.rsModel GroupsPost | ||
| 102 | * @return status of the request - CREATED if the JSON is correct, | 128 | * @return status of the request - CREATED if the JSON is correct, |
| 103 | * BAD_REQUEST if the JSON is invalid | 129 | * BAD_REQUEST if the JSON is invalid |
| 130 | + * @onos.rsModel GroupsPost | ||
| 104 | */ | 131 | */ |
| 105 | @POST | 132 | @POST |
| 106 | @Path("{deviceId}") | 133 | @Path("{deviceId}") | ... | ... |
| 1 | +{ | ||
| 2 | + "type": "object", | ||
| 3 | + "title": "group", | ||
| 4 | + "required": [ | ||
| 5 | + "id", | ||
| 6 | + "state", | ||
| 7 | + "life", | ||
| 8 | + "packets", | ||
| 9 | + "bytes", | ||
| 10 | + "referenceCount", | ||
| 11 | + "type", | ||
| 12 | + "deviceId", | ||
| 13 | + "appId", | ||
| 14 | + "appCookie", | ||
| 15 | + "buckets" | ||
| 16 | + ], | ||
| 17 | + "properties": { | ||
| 18 | + "id": { | ||
| 19 | + "type": "string", | ||
| 20 | + "description": "group id", | ||
| 21 | + "example": "1" | ||
| 22 | + }, | ||
| 23 | + "state": { | ||
| 24 | + "type": "string", | ||
| 25 | + "description": "state of the group object", | ||
| 26 | + "example": "PENDING_ADD" | ||
| 27 | + }, | ||
| 28 | + "life": { | ||
| 29 | + "type": "integer", | ||
| 30 | + "format": "int64", | ||
| 31 | + "description": "number of milliseconds this group has been alive", | ||
| 32 | + "example": 69889 | ||
| 33 | + }, | ||
| 34 | + "packets": { | ||
| 35 | + "type": "integer", | ||
| 36 | + "format": "int64", | ||
| 37 | + "description": "number of packets processed by this group", | ||
| 38 | + "example": 22546 | ||
| 39 | + }, | ||
| 40 | + "bytes": { | ||
| 41 | + "type": "integer", | ||
| 42 | + "format": "int64", | ||
| 43 | + "description": "number of bytes processed by this group", | ||
| 44 | + "example": 1826226 | ||
| 45 | + }, | ||
| 46 | + "referenceCount": { | ||
| 47 | + "type": "integer", | ||
| 48 | + "format": "int64", | ||
| 49 | + "description": "number of flow rules or other groups reference this group", | ||
| 50 | + "example": 1826226 | ||
| 51 | + }, | ||
| 52 | + "type": { | ||
| 53 | + "type": "string", | ||
| 54 | + "description": "types of the group", | ||
| 55 | + "example": "ALL" | ||
| 56 | + }, | ||
| 57 | + "deviceId": { | ||
| 58 | + "type": "string", | ||
| 59 | + "description": "device identifier", | ||
| 60 | + "example": "of:0000000000000003" | ||
| 61 | + }, | ||
| 62 | + "appId": { | ||
| 63 | + "type": "string", | ||
| 64 | + "description": "application identifier", | ||
| 65 | + "example": "1" | ||
| 66 | + }, | ||
| 67 | + "appCookie": { | ||
| 68 | + "type": "string", | ||
| 69 | + "description": "application cookie", | ||
| 70 | + "example": "1" | ||
| 71 | + }, | ||
| 72 | + "buckets": { | ||
| 73 | + "type": "array", | ||
| 74 | + "xml": { | ||
| 75 | + "name": "buckets", | ||
| 76 | + "wrapped": true | ||
| 77 | + }, | ||
| 78 | + "items": { | ||
| 79 | + "type": "object", | ||
| 80 | + "title": "buckets", | ||
| 81 | + "required": [ | ||
| 82 | + "treatment", | ||
| 83 | + "weight", | ||
| 84 | + "watchPort", | ||
| 85 | + "watchGroup" | ||
| 86 | + ], | ||
| 87 | + "properties": { | ||
| 88 | + "treatment": { | ||
| 89 | + "type": "object", | ||
| 90 | + "title": "treatment", | ||
| 91 | + "required": [ | ||
| 92 | + "instructions", | ||
| 93 | + "deferred" | ||
| 94 | + ], | ||
| 95 | + "properties": { | ||
| 96 | + "instructions": { | ||
| 97 | + "type": "array", | ||
| 98 | + "title": "treatment", | ||
| 99 | + "required": [ | ||
| 100 | + "properties", | ||
| 101 | + "port" | ||
| 102 | + ], | ||
| 103 | + "items": { | ||
| 104 | + "type": "object", | ||
| 105 | + "title": "instructions", | ||
| 106 | + "required": [ | ||
| 107 | + "type", | ||
| 108 | + "port" | ||
| 109 | + ], | ||
| 110 | + "properties": { | ||
| 111 | + "type": { | ||
| 112 | + "type": "string", | ||
| 113 | + "description": "instruction type", | ||
| 114 | + "example": "OUTPUT" | ||
| 115 | + }, | ||
| 116 | + "port": { | ||
| 117 | + "type": "string", | ||
| 118 | + "description": "port number", | ||
| 119 | + "example": "2" | ||
| 120 | + } | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | + }, | ||
| 126 | + "weight": { | ||
| 127 | + "type": "integer", | ||
| 128 | + "format": "int16", | ||
| 129 | + "description": "weight of select group bucket", | ||
| 130 | + "example": "1.0" | ||
| 131 | + }, | ||
| 132 | + "watchPort": { | ||
| 133 | + "type": "string", | ||
| 134 | + "description": "port number used for liveness detection for a failover bucket", | ||
| 135 | + "example": "2" | ||
| 136 | + }, | ||
| 137 | + "watchGroup": { | ||
| 138 | + "type": "string", | ||
| 139 | + "description": "group identifier used for liveness detection for a failover bucket", | ||
| 140 | + "example": "1" | ||
| 141 | + } | ||
| 142 | + } | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -23,45 +23,65 @@ | ... | @@ -23,45 +23,65 @@ |
| 23 | "referenceCount", | 23 | "referenceCount", |
| 24 | "type", | 24 | "type", |
| 25 | "deviceId", | 25 | "deviceId", |
| 26 | + "appId", | ||
| 27 | + "appCookie", | ||
| 26 | "buckets" | 28 | "buckets" |
| 27 | ], | 29 | ], |
| 28 | "properties": { | 30 | "properties": { |
| 29 | "id": { | 31 | "id": { |
| 30 | "type": "string", | 32 | "type": "string", |
| 33 | + "description": "group id", | ||
| 31 | "example": "1" | 34 | "example": "1" |
| 32 | }, | 35 | }, |
| 33 | "state": { | 36 | "state": { |
| 34 | "type": "string", | 37 | "type": "string", |
| 38 | + "description": "state of the group object", | ||
| 35 | "example": "PENDING_ADD" | 39 | "example": "PENDING_ADD" |
| 36 | }, | 40 | }, |
| 37 | "life": { | 41 | "life": { |
| 38 | "type": "integer", | 42 | "type": "integer", |
| 39 | "format": "int64", | 43 | "format": "int64", |
| 44 | + "description": "number of milliseconds this group has been alive", | ||
| 40 | "example": 69889 | 45 | "example": 69889 |
| 41 | }, | 46 | }, |
| 42 | "packets": { | 47 | "packets": { |
| 43 | "type": "integer", | 48 | "type": "integer", |
| 44 | "format": "int64", | 49 | "format": "int64", |
| 50 | + "description": "number of packets processed by this group", | ||
| 45 | "example": 22546 | 51 | "example": 22546 |
| 46 | }, | 52 | }, |
| 47 | "bytes": { | 53 | "bytes": { |
| 48 | "type": "integer", | 54 | "type": "integer", |
| 49 | "format": "int64", | 55 | "format": "int64", |
| 56 | + "description": "number of bytes processed by this group", | ||
| 50 | "example": 1826226 | 57 | "example": 1826226 |
| 51 | }, | 58 | }, |
| 52 | "referenceCount": { | 59 | "referenceCount": { |
| 53 | "type": "integer", | 60 | "type": "integer", |
| 54 | "format": "int64", | 61 | "format": "int64", |
| 62 | + "description": "number of flow rules or other groups reference this group", | ||
| 55 | "example": 1826226 | 63 | "example": 1826226 |
| 56 | }, | 64 | }, |
| 57 | "type": { | 65 | "type": { |
| 58 | "type": "string", | 66 | "type": "string", |
| 67 | + "description": "types of the group", | ||
| 59 | "example": "ALL" | 68 | "example": "ALL" |
| 60 | }, | 69 | }, |
| 61 | "deviceId": { | 70 | "deviceId": { |
| 62 | "type": "string", | 71 | "type": "string", |
| 72 | + "description": "device identifier", | ||
| 63 | "example": "of:0000000000000003" | 73 | "example": "of:0000000000000003" |
| 64 | }, | 74 | }, |
| 75 | + "appId": { | ||
| 76 | + "type": "string", | ||
| 77 | + "description": "application identifier", | ||
| 78 | + "example": "1" | ||
| 79 | + }, | ||
| 80 | + "appCookie": { | ||
| 81 | + "type": "string", | ||
| 82 | + "description": "application cookie", | ||
| 83 | + "example": "1" | ||
| 84 | + }, | ||
| 65 | "buckets": { | 85 | "buckets": { |
| 66 | "type": "array", | 86 | "type": "array", |
| 67 | "xml": { | 87 | "xml": { |
| ... | @@ -103,16 +123,34 @@ | ... | @@ -103,16 +123,34 @@ |
| 103 | "properties": { | 123 | "properties": { |
| 104 | "type": { | 124 | "type": { |
| 105 | "type": "string", | 125 | "type": "string", |
| 126 | + "description": "instruction type", | ||
| 106 | "example": "OUTPUT" | 127 | "example": "OUTPUT" |
| 107 | }, | 128 | }, |
| 108 | "port": { | 129 | "port": { |
| 109 | "type": "string", | 130 | "type": "string", |
| 131 | + "description": "port number", | ||
| 110 | "example": "2" | 132 | "example": "2" |
| 111 | } | 133 | } |
| 112 | } | 134 | } |
| 113 | } | 135 | } |
| 114 | } | 136 | } |
| 115 | } | 137 | } |
| 138 | + }, | ||
| 139 | + "weight": { | ||
| 140 | + "type": "integer", | ||
| 141 | + "format": "int16", | ||
| 142 | + "description": "weight of select group bucket", | ||
| 143 | + "example": "1.0" | ||
| 144 | + }, | ||
| 145 | + "watchPort": { | ||
| 146 | + "type": "string", | ||
| 147 | + "description": "port number used for liveness detection for a failover bucket", | ||
| 148 | + "example": "2" | ||
| 149 | + }, | ||
| 150 | + "watchGroup": { | ||
| 151 | + "type": "string", | ||
| 152 | + "description": "group identifier used for liveness detection for a failover bucket", | ||
| 153 | + "example": "1" | ||
| 116 | } | 154 | } |
| 117 | } | 155 | } |
| 118 | } | 156 | } | ... | ... |
| ... | @@ -49,6 +49,7 @@ import org.onosproject.net.group.GroupBuckets; | ... | @@ -49,6 +49,7 @@ import org.onosproject.net.group.GroupBuckets; |
| 49 | import org.onosproject.net.group.GroupDescription; | 49 | import org.onosproject.net.group.GroupDescription; |
| 50 | import org.onosproject.net.group.GroupKey; | 50 | import org.onosproject.net.group.GroupKey; |
| 51 | import org.onosproject.net.group.GroupService; | 51 | import org.onosproject.net.group.GroupService; |
| 52 | +import org.onosproject.rest.resources.CoreWebApplication; | ||
| 52 | 53 | ||
| 53 | import javax.ws.rs.core.MediaType; | 54 | import javax.ws.rs.core.MediaType; |
| 54 | import java.io.InputStream; | 55 | import java.io.InputStream; |
| ... | @@ -70,6 +71,7 @@ import static org.hamcrest.Matchers.hasSize; | ... | @@ -70,6 +71,7 @@ import static org.hamcrest.Matchers.hasSize; |
| 70 | import static org.hamcrest.Matchers.is; | 71 | import static org.hamcrest.Matchers.is; |
| 71 | import static org.hamcrest.Matchers.notNullValue; | 72 | import static org.hamcrest.Matchers.notNullValue; |
| 72 | import static org.junit.Assert.assertThat; | 73 | import static org.junit.Assert.assertThat; |
| 74 | +import static org.junit.Assert.assertEquals; | ||
| 73 | import static org.onosproject.net.NetTestTools.APP_ID; | 75 | import static org.onosproject.net.NetTestTools.APP_ID; |
| 74 | 76 | ||
| 75 | /** | 77 | /** |
| ... | @@ -100,6 +102,10 @@ public class GroupsResourceTest extends ResourceTest { | ... | @@ -100,6 +102,10 @@ public class GroupsResourceTest extends ResourceTest { |
| 100 | final MockGroup group5 = new MockGroup(deviceId3, 5, "555", 5); | 102 | final MockGroup group5 = new MockGroup(deviceId3, 5, "555", 5); |
| 101 | final MockGroup group6 = new MockGroup(deviceId3, 6, "666", 6); | 103 | final MockGroup group6 = new MockGroup(deviceId3, 6, "666", 6); |
| 102 | 104 | ||
| 105 | + public GroupsResourceTest() { | ||
| 106 | + super(CoreWebApplication.class); | ||
| 107 | + } | ||
| 108 | + | ||
| 103 | /** | 109 | /** |
| 104 | * Mock class for a group. | 110 | * Mock class for a group. |
| 105 | */ | 111 | */ |
| ... | @@ -444,6 +450,42 @@ public class GroupsResourceTest extends ResourceTest { | ... | @@ -444,6 +450,42 @@ public class GroupsResourceTest extends ResourceTest { |
| 444 | } | 450 | } |
| 445 | 451 | ||
| 446 | /** | 452 | /** |
| 453 | + * Test the result of a rest api GET with specifying device id and appcookie. | ||
| 454 | + */ | ||
| 455 | + @Test | ||
| 456 | + public void testGroupByDeviceIdAndAppCookie() { | ||
| 457 | + setupMockGroups(); | ||
| 458 | + expect(mockGroupService.getGroup(anyObject(), anyObject())) | ||
| 459 | + .andReturn(group5).anyTimes(); | ||
| 460 | + replay(mockGroupService); | ||
| 461 | + final WebResource rs = resource(); | ||
| 462 | + final String response = rs.path("groups/" + deviceId3 + "/" + "111").get(String.class); | ||
| 463 | + final JsonObject result = JsonObject.readFrom(response); | ||
| 464 | + assertThat(result, notNullValue()); | ||
| 465 | + | ||
| 466 | + assertThat(result.names(), hasSize(1)); | ||
| 467 | + assertThat(result.names().get(0), is("groups")); | ||
| 468 | + final JsonArray jsonFlows = result.get("groups").asArray(); | ||
| 469 | + assertThat(jsonFlows, notNullValue()); | ||
| 470 | + assertThat(jsonFlows, hasGroup(group5)); | ||
| 471 | + } | ||
| 472 | + | ||
| 473 | + /** | ||
| 474 | + * Test whether the REST API returns 404 if no entry has been found. | ||
| 475 | + */ | ||
| 476 | + @Test | ||
| 477 | + public void testGroupByDeviceIdAndAppCookieNull() { | ||
| 478 | + setupMockGroups(); | ||
| 479 | + expect(mockGroupService.getGroup(anyObject(), anyObject())) | ||
| 480 | + .andReturn(null).anyTimes(); | ||
| 481 | + replay(mockGroupService); | ||
| 482 | + final WebResource rs = resource(); | ||
| 483 | + final ClientResponse response = rs.path("groups/" + deviceId3 + "/" + "222").get(ClientResponse.class); | ||
| 484 | + | ||
| 485 | + assertEquals(404, response.getStatus()); | ||
| 486 | + } | ||
| 487 | + | ||
| 488 | + /** | ||
| 447 | * Tests creating a group with POST. | 489 | * Tests creating a group with POST. |
| 448 | */ | 490 | */ |
| 449 | @Test | 491 | @Test | ... | ... |
-
Please register or login to post a comment