Jian Li
Committed by Gerrit Code Review

[ONOS-4016] Add Region codec with unit test for Region REST API

Change-Id: Ib7d6daa3adf8b23bea681e7bd3ef64839be65d13
...@@ -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 +}
1 +{
2 + "id": 1,
3 + "type": "ROOM",
4 + "name": "foo",
5 + "masters": [
6 + [
7 + "1"
8 + ],
9 + [
10 + "1", "2"
11 + ]
12 + ]
13 +}
...\ No newline at end of file ...\ No newline at end of file