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