Committed by
Gerrit Code Review
[ONOS-4016] Add Region codec with unit test for Region REST API
Change-Id: Ib7d6daa3adf8b23bea681e7bd3ef64839be65d13
Showing
5 changed files
with
368 additions
and
0 deletions
| ... | @@ -58,6 +58,7 @@ import org.onosproject.net.mcast.McastRoute; | ... | @@ -58,6 +58,7 @@ import org.onosproject.net.mcast.McastRoute; |
| 58 | import org.onosproject.net.meter.Band; | 58 | import org.onosproject.net.meter.Band; |
| 59 | import org.onosproject.net.meter.Meter; | 59 | import org.onosproject.net.meter.Meter; |
| 60 | import org.onosproject.net.meter.MeterRequest; | 60 | import org.onosproject.net.meter.MeterRequest; |
| 61 | +import org.onosproject.net.region.Region; | ||
| 61 | import org.onosproject.net.statistic.Load; | 62 | import org.onosproject.net.statistic.Load; |
| 62 | import org.onosproject.net.topology.Topology; | 63 | import org.onosproject.net.topology.Topology; |
| 63 | import org.onosproject.net.topology.TopologyCluster; | 64 | import org.onosproject.net.topology.TopologyCluster; |
| ... | @@ -121,6 +122,7 @@ public class CodecManager implements CodecService { | ... | @@ -121,6 +122,7 @@ public class CodecManager implements CodecService { |
| 121 | registerCodec(NextObjective.class, new NextObjectiveCodec()); | 122 | registerCodec(NextObjective.class, new NextObjectiveCodec()); |
| 122 | registerCodec(McastRoute.class, new McastRouteCodec()); | 123 | registerCodec(McastRoute.class, new McastRouteCodec()); |
| 123 | registerCodec(DeviceKey.class, new DeviceKeyCodec()); | 124 | registerCodec(DeviceKey.class, new DeviceKeyCodec()); |
| 125 | + registerCodec(Region.class, new RegionCodec()); | ||
| 124 | log.info("Started"); | 126 | log.info("Started"); |
| 125 | } | 127 | } |
| 126 | 128 | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2016 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.ArrayNode; | ||
| 20 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 21 | +import com.google.common.collect.BiMap; | ||
| 22 | +import com.google.common.collect.HashBiMap; | ||
| 23 | +import com.google.common.collect.Sets; | ||
| 24 | +import org.onosproject.cluster.NodeId; | ||
| 25 | +import org.onosproject.codec.CodecContext; | ||
| 26 | +import org.onosproject.codec.JsonCodec; | ||
| 27 | +import org.onosproject.net.region.DefaultRegion; | ||
| 28 | +import org.onosproject.net.region.Region; | ||
| 29 | +import org.onosproject.net.region.RegionId; | ||
| 30 | + | ||
| 31 | +import java.util.ArrayList; | ||
| 32 | +import java.util.List; | ||
| 33 | +import java.util.Set; | ||
| 34 | +import java.util.stream.IntStream; | ||
| 35 | + | ||
| 36 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 37 | +import static org.onlab.util.Tools.nullIsIllegal; | ||
| 38 | + | ||
| 39 | +/** | ||
| 40 | + * Codec for the Region class. | ||
| 41 | + */ | ||
| 42 | +public class RegionCodec extends JsonCodec<Region> { | ||
| 43 | + | ||
| 44 | + // JSON field names | ||
| 45 | + private static final String REGION_ID = "id"; | ||
| 46 | + private static final String NAME = "name"; | ||
| 47 | + private static final String TYPE = "type"; | ||
| 48 | + private static final String MASTERS = "masters"; | ||
| 49 | + private static final String NODE_ID = "nodeId"; | ||
| 50 | + private static final String REGION_NOT_NULL_MSG = "Region cannot be null"; | ||
| 51 | + private static final String MISSING_MEMBER_MESSAGE = " member is required in Region"; | ||
| 52 | + | ||
| 53 | + private static final BiMap<String, Region.Type> REGION_TYPE_MAP = HashBiMap.create(); | ||
| 54 | + | ||
| 55 | + static { | ||
| 56 | + // key is String representation of Region.Type | ||
| 57 | + // value is Region.Type | ||
| 58 | + REGION_TYPE_MAP.put("CONTINENT", Region.Type.CONTINENT); | ||
| 59 | + REGION_TYPE_MAP.put("COUNTRY", Region.Type.COUNTRY); | ||
| 60 | + REGION_TYPE_MAP.put("METRO", Region.Type.METRO); | ||
| 61 | + REGION_TYPE_MAP.put("CAMPUS", Region.Type.CAMPUS); | ||
| 62 | + REGION_TYPE_MAP.put("BUILDING", Region.Type.BUILDING); | ||
| 63 | + REGION_TYPE_MAP.put("FLOOR", Region.Type.FLOOR); | ||
| 64 | + REGION_TYPE_MAP.put("ROOM", Region.Type.ROOM); | ||
| 65 | + REGION_TYPE_MAP.put("RACK", Region.Type.RACK); | ||
| 66 | + REGION_TYPE_MAP.put("LOGICAL_GROUP", Region.Type.LOGICAL_GROUP); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + @Override | ||
| 70 | + public ObjectNode encode(Region region, CodecContext context) { | ||
| 71 | + checkNotNull(region, REGION_NOT_NULL_MSG); | ||
| 72 | + | ||
| 73 | + ObjectNode result = context.mapper().createObjectNode() | ||
| 74 | + .put(REGION_ID, region.id().toString()) | ||
| 75 | + .put(NAME, region.name()) | ||
| 76 | + .put(TYPE, region.type().toString()); | ||
| 77 | + | ||
| 78 | + ArrayNode masters = context.mapper().createArrayNode(); | ||
| 79 | + | ||
| 80 | + region.masters().forEach(sets -> { | ||
| 81 | + ArrayNode setsJson = context.mapper().createArrayNode(); | ||
| 82 | + sets.forEach(nodeId -> setsJson.add(nodeId.toString())); | ||
| 83 | + masters.add(setsJson); | ||
| 84 | + }); | ||
| 85 | + result.set(MASTERS, masters); | ||
| 86 | + return result; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + @Override | ||
| 90 | + public Region decode(ObjectNode json, CodecContext context) { | ||
| 91 | + if (json == null || !json.isObject()) { | ||
| 92 | + return null; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + // parse masters | ||
| 96 | + List<Set<NodeId>> masters = new ArrayList<>(); | ||
| 97 | + JsonNode mastersJson = json.get(MASTERS); | ||
| 98 | + checkNotNull(mastersJson); | ||
| 99 | + | ||
| 100 | + if (mastersJson != null) { | ||
| 101 | + IntStream.range(0, mastersJson.size()).forEach(i -> { | ||
| 102 | + ObjectNode setsJson = get(mastersJson, i); | ||
| 103 | + final Set<NodeId> nodeIds = Sets.newHashSet(); | ||
| 104 | + if (setsJson != null && setsJson.isArray()) { | ||
| 105 | + Set<NodeId> localNodeIds = Sets.newHashSet(); | ||
| 106 | + IntStream.range(0, mastersJson.size()).forEach(j -> { | ||
| 107 | + ObjectNode nodeIdJson = get(setsJson, j); | ||
| 108 | + localNodeIds.add(decodeNodeId(nodeIdJson)); | ||
| 109 | + }); | ||
| 110 | + nodeIds.addAll(localNodeIds); | ||
| 111 | + } | ||
| 112 | + masters.add(nodeIds); | ||
| 113 | + }); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + // parse region id | ||
| 117 | + RegionId regionId = RegionId.regionId(nullIsIllegal(json.get(REGION_ID), | ||
| 118 | + REGION_ID + MISSING_MEMBER_MESSAGE).asText()); | ||
| 119 | + | ||
| 120 | + // parse region name | ||
| 121 | + String name = nullIsIllegal(json.get(NAME), NAME + | ||
| 122 | + MISSING_MEMBER_MESSAGE).asText(); | ||
| 123 | + | ||
| 124 | + // parse region type | ||
| 125 | + String typeText = nullIsIllegal(json.get(TYPE), TYPE + | ||
| 126 | + MISSING_MEMBER_MESSAGE).asText(); | ||
| 127 | + | ||
| 128 | + Region.Type type = REGION_TYPE_MAP.get(typeText); | ||
| 129 | + | ||
| 130 | + return new DefaultRegion(regionId, name, type, masters); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + /** | ||
| 134 | + * Decodes node id json to node id object. | ||
| 135 | + * | ||
| 136 | + * @param json json object | ||
| 137 | + * @return decoded node id object | ||
| 138 | + */ | ||
| 139 | + private NodeId decodeNodeId(ObjectNode json) { | ||
| 140 | + NodeId nodeId = NodeId.nodeId(nullIsIllegal(json, NODE_ID + | ||
| 141 | + MISSING_MEMBER_MESSAGE).asText()); | ||
| 142 | + | ||
| 143 | + return nodeId; | ||
| 144 | + } | ||
| 145 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 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 com.google.common.collect.ImmutableList; | ||
| 21 | +import com.google.common.collect.ImmutableSet; | ||
| 22 | +import org.hamcrest.MatcherAssert; | ||
| 23 | +import org.junit.Before; | ||
| 24 | +import org.junit.Test; | ||
| 25 | +import org.onosproject.cluster.NodeId; | ||
| 26 | +import org.onosproject.codec.JsonCodec; | ||
| 27 | +import org.onosproject.core.CoreService; | ||
| 28 | +import org.onosproject.net.region.DefaultRegion; | ||
| 29 | +import org.onosproject.net.region.Region; | ||
| 30 | +import org.onosproject.net.region.RegionId; | ||
| 31 | + | ||
| 32 | +import java.io.IOException; | ||
| 33 | +import java.io.InputStream; | ||
| 34 | +import java.util.List; | ||
| 35 | +import java.util.Set; | ||
| 36 | + | ||
| 37 | +import static org.easymock.EasyMock.createMock; | ||
| 38 | +import static org.hamcrest.Matchers.is; | ||
| 39 | +import static org.hamcrest.Matchers.notNullValue; | ||
| 40 | +import static org.junit.Assert.assertThat; | ||
| 41 | +import static org.onosproject.codec.impl.RegionJsonMatcher.matchesRegion; | ||
| 42 | + | ||
| 43 | +/** | ||
| 44 | + * Unit tests for region codec. | ||
| 45 | + */ | ||
| 46 | +public class RegionCodecTest { | ||
| 47 | + | ||
| 48 | + MockCodecContext context; | ||
| 49 | + JsonCodec<Region> regionCodec; | ||
| 50 | + final CoreService mockCoreService = createMock(CoreService.class); | ||
| 51 | + | ||
| 52 | + @Before | ||
| 53 | + public void setUp() { | ||
| 54 | + context = new MockCodecContext(); | ||
| 55 | + regionCodec = context.codec(Region.class); | ||
| 56 | + assertThat(regionCodec, notNullValue()); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * Tests encoding of a Region object. | ||
| 61 | + */ | ||
| 62 | + @Test | ||
| 63 | + public void testRegionEncode() { | ||
| 64 | + NodeId nodeId1 = NodeId.nodeId("1"); | ||
| 65 | + NodeId nodeId2 = NodeId.nodeId("2"); | ||
| 66 | + NodeId nodeId3 = NodeId.nodeId("3"); | ||
| 67 | + NodeId nodeId4 = NodeId.nodeId("4"); | ||
| 68 | + | ||
| 69 | + Set<NodeId> set1 = ImmutableSet.of(nodeId1); | ||
| 70 | + Set<NodeId> set2 = ImmutableSet.of(nodeId1, nodeId2); | ||
| 71 | + Set<NodeId> set3 = ImmutableSet.of(nodeId1, nodeId2, nodeId3); | ||
| 72 | + Set<NodeId> set4 = ImmutableSet.of(nodeId1, nodeId2, nodeId3, nodeId4); | ||
| 73 | + List<Set<NodeId>> masters = ImmutableList.of(set1, set2, set3, set4); | ||
| 74 | + | ||
| 75 | + RegionId regionId = RegionId.regionId("1"); | ||
| 76 | + String name = "foo"; | ||
| 77 | + Region.Type type = Region.Type.ROOM; | ||
| 78 | + | ||
| 79 | + Region region = new DefaultRegion(regionId, name, type, masters); | ||
| 80 | + | ||
| 81 | + ObjectNode regionJson = regionCodec.encode(region, context); | ||
| 82 | + assertThat(regionJson, matchesRegion(region)); | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + /** | ||
| 86 | + * Tests decoding of a json object. | ||
| 87 | + */ | ||
| 88 | + @Test | ||
| 89 | + public void testRegionDecode() throws IOException { | ||
| 90 | + Region region = getRegion("Region.json"); | ||
| 91 | + checkCommonData(region); | ||
| 92 | + | ||
| 93 | + assertThat(region.masters().size(), is(2)); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + /** | ||
| 97 | + * Checks that the data shared by all the resource is correct for a given region. | ||
| 98 | + * | ||
| 99 | + * @param region region to check | ||
| 100 | + */ | ||
| 101 | + private void checkCommonData(Region region) { | ||
| 102 | + assertThat(region.id().toString(), is("1")); | ||
| 103 | + assertThat(region.type().toString(), is("ROOM")); | ||
| 104 | + assertThat(region.name(), is("foo")); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + /** | ||
| 108 | + * Reads in a region from the given resource and decodes it. | ||
| 109 | + * | ||
| 110 | + * @param resourceName resource to use to read the JSON for the rule | ||
| 111 | + * @return decoded region | ||
| 112 | + * @throws IOException if processing the resource fails | ||
| 113 | + */ | ||
| 114 | + private Region getRegion(String resourceName) throws IOException { | ||
| 115 | + InputStream jsonStream = RegionCodecTest.class.getResourceAsStream(resourceName); | ||
| 116 | + JsonNode json = context.mapper().readTree(jsonStream); | ||
| 117 | + MatcherAssert.assertThat(json, notNullValue()); | ||
| 118 | + Region region = regionCodec.decode((ObjectNode) json, context); | ||
| 119 | + assertThat(region, notNullValue()); | ||
| 120 | + return region; | ||
| 121 | + } | ||
| 122 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 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 org.hamcrest.Description; | ||
| 20 | +import org.hamcrest.TypeSafeDiagnosingMatcher; | ||
| 21 | +import org.onosproject.net.region.Region; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * Hamcrest matcher for region. | ||
| 25 | + */ | ||
| 26 | +public final class RegionJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { | ||
| 27 | + | ||
| 28 | + private final Region region; | ||
| 29 | + | ||
| 30 | + private RegionJsonMatcher(Region region) { | ||
| 31 | + this.region = region; | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + @Override | ||
| 35 | + protected boolean matchesSafely(JsonNode jsonRegion, Description description) { | ||
| 36 | + // check id | ||
| 37 | + String jsonRegionId = jsonRegion.get("id").asText(); | ||
| 38 | + String regionId = region.id().toString(); | ||
| 39 | + if (!jsonRegionId.equals(regionId)) { | ||
| 40 | + description.appendText("region id was " + jsonRegionId); | ||
| 41 | + return false; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + // check type | ||
| 45 | + String jsonType = jsonRegion.get("type").asText(); | ||
| 46 | + String type = region.type().toString(); | ||
| 47 | + if (!jsonType.equals(type)) { | ||
| 48 | + description.appendText("type was " + jsonType); | ||
| 49 | + return false; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + // check name | ||
| 53 | + String jsonName = jsonRegion.get("name").asText(); | ||
| 54 | + String name = region.name(); | ||
| 55 | + if (!jsonName.equals(name)) { | ||
| 56 | + description.appendText("name was " + jsonName); | ||
| 57 | + return false; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + // check size of master array | ||
| 61 | + JsonNode jsonMasters = jsonRegion.get("masters"); | ||
| 62 | + if (jsonMasters.size() != region.masters().size()) { | ||
| 63 | + description.appendText("masters size was " + jsonMasters.size()); | ||
| 64 | + return false; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + // TODO: check the content inside masters | ||
| 68 | + | ||
| 69 | + return true; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Override | ||
| 73 | + public void describeTo(Description description) { | ||
| 74 | + description.appendText(region.toString()); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + /** | ||
| 78 | + * Factory to allocate a region matcher. | ||
| 79 | + * | ||
| 80 | + * @param region region object we are looking for | ||
| 81 | + * @return matcher | ||
| 82 | + */ | ||
| 83 | + public static RegionJsonMatcher matchesRegion(Region region) { | ||
| 84 | + return new RegionJsonMatcher(region); | ||
| 85 | + } | ||
| 86 | +} |
-
Please register or login to post a comment