Unit tets for instruction JSON codecs
Fixed several bugs in codecs turned up by unit tests Change-Id: Icddb31aa3d2cb58612a0578772d24ff5f113d073
Showing
11 changed files
with
749 additions
and
7 deletions
... | @@ -43,6 +43,13 @@ | ... | @@ -43,6 +43,13 @@ |
43 | <artifactId>easymock</artifactId> | 43 | <artifactId>easymock</artifactId> |
44 | <scope>test</scope> | 44 | <scope>test</scope> |
45 | </dependency> | 45 | </dependency> |
46 | + <dependency> | ||
47 | + <groupId>org.onosproject</groupId> | ||
48 | + <artifactId>onos-api</artifactId> | ||
49 | + <version>${project.version}</version> | ||
50 | + <scope>test</scope> | ||
51 | + <classifier>tests</classifier> | ||
52 | + </dependency> | ||
46 | </dependencies> | 53 | </dependencies> |
47 | 54 | ||
48 | <properties> | 55 | <properties> | ... | ... |
... | @@ -20,8 +20,10 @@ import org.onosproject.codec.JsonCodec; | ... | @@ -20,8 +20,10 @@ import org.onosproject.codec.JsonCodec; |
20 | import org.onosproject.net.flow.TrafficSelector; | 20 | import org.onosproject.net.flow.TrafficSelector; |
21 | import org.onosproject.net.flow.TrafficTreatment; | 21 | import org.onosproject.net.flow.TrafficTreatment; |
22 | import org.onosproject.net.intent.ConnectivityIntent; | 22 | import org.onosproject.net.intent.ConnectivityIntent; |
23 | +import org.onosproject.net.intent.Constraint; | ||
23 | import org.onosproject.net.intent.Intent; | 24 | import org.onosproject.net.intent.Intent; |
24 | 25 | ||
26 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
25 | import com.fasterxml.jackson.databind.node.ObjectNode; | 27 | import com.fasterxml.jackson.databind.node.ObjectNode; |
26 | 28 | ||
27 | import static com.google.common.base.Preconditions.checkNotNull; | 29 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -50,6 +52,17 @@ public class ConnectivityIntentCodec extends JsonCodec<ConnectivityIntent> { | ... | @@ -50,6 +52,17 @@ public class ConnectivityIntentCodec extends JsonCodec<ConnectivityIntent> { |
50 | result.set("treatment", treatmentCodec.encode(intent.treatment(), context)); | 52 | result.set("treatment", treatmentCodec.encode(intent.treatment(), context)); |
51 | } | 53 | } |
52 | 54 | ||
55 | + if (intent.constraints() != null) { | ||
56 | + final ArrayNode jsonConstraints = result.putArray("constraints"); | ||
57 | + | ||
58 | + if (intent.constraints() != null) { | ||
59 | + for (final Constraint constraint : intent.constraints()) { | ||
60 | + // TODO: constraint should have its own codec | ||
61 | + jsonConstraints.add(constraint.toString()); | ||
62 | + } | ||
63 | + } | ||
64 | + } | ||
65 | + | ||
53 | return result; | 66 | return result; |
54 | } | 67 | } |
55 | } | 68 | } | ... | ... |
... | @@ -50,6 +50,7 @@ public class CriterionCodec extends JsonCodec<Criterion> { | ... | @@ -50,6 +50,7 @@ public class CriterionCodec extends JsonCodec<Criterion> { |
50 | case ETH_SRC: | 50 | case ETH_SRC: |
51 | case ETH_DST: | 51 | case ETH_DST: |
52 | final Criteria.EthCriterion ethCriterion = (Criteria.EthCriterion) criterion; | 52 | final Criteria.EthCriterion ethCriterion = (Criteria.EthCriterion) criterion; |
53 | + result.put("mac", ethCriterion.mac().toString()); | ||
53 | break; | 54 | break; |
54 | 55 | ||
55 | case ETH_TYPE: | 56 | case ETH_TYPE: |
... | @@ -60,6 +61,8 @@ public class CriterionCodec extends JsonCodec<Criterion> { | ... | @@ -60,6 +61,8 @@ public class CriterionCodec extends JsonCodec<Criterion> { |
60 | 61 | ||
61 | case IPV4_SRC: | 62 | case IPV4_SRC: |
62 | case IPV6_SRC: | 63 | case IPV6_SRC: |
64 | + case IPV4_DST: | ||
65 | + case IPV6_DST: | ||
63 | final Criteria.IPCriterion iPCriterion = (Criteria.IPCriterion) criterion; | 66 | final Criteria.IPCriterion iPCriterion = (Criteria.IPCriterion) criterion; |
64 | result.put("ip", iPCriterion.ip().toString()); | 67 | result.put("ip", iPCriterion.ip().toString()); |
65 | break; | 68 | break; | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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 org.hamcrest.Description; | ||
19 | +import org.hamcrest.TypeSafeDiagnosingMatcher; | ||
20 | +import org.onosproject.net.ConnectPoint; | ||
21 | + | ||
22 | +import com.fasterxml.jackson.databind.JsonNode; | ||
23 | + | ||
24 | +/** | ||
25 | + * Hamcrest matcher for connect points. | ||
26 | + */ | ||
27 | + | ||
28 | +public final class ConnectPointJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { | ||
29 | + | ||
30 | + private final ConnectPoint connectPoint; | ||
31 | + | ||
32 | + private ConnectPointJsonMatcher(ConnectPoint connectPointValue) { | ||
33 | + connectPoint = connectPointValue; | ||
34 | + } | ||
35 | + | ||
36 | + @Override | ||
37 | + public boolean matchesSafely(JsonNode jsonConnectPoint, Description description) { | ||
38 | + // check device | ||
39 | + final String jsonDevice = jsonConnectPoint.get("device").asText(); | ||
40 | + final String device = connectPoint.deviceId().toString(); | ||
41 | + if (!jsonDevice.equals(device)) { | ||
42 | + description.appendText("device was " + jsonDevice); | ||
43 | + return false; | ||
44 | + } | ||
45 | + | ||
46 | + // check port | ||
47 | + final String jsonPort = jsonConnectPoint.get("port").asText(); | ||
48 | + final String port = connectPoint.port().toString(); | ||
49 | + if (!jsonPort.equals(port)) { | ||
50 | + description.appendText("port was " + jsonPort); | ||
51 | + return false; | ||
52 | + } | ||
53 | + | ||
54 | + return true; | ||
55 | + } | ||
56 | + | ||
57 | + @Override | ||
58 | + public void describeTo(Description description) { | ||
59 | + description.appendText(connectPoint.toString()); | ||
60 | + } | ||
61 | + | ||
62 | + /** | ||
63 | + * Factory to allocate an connect point matcher. | ||
64 | + * | ||
65 | + * @param connectPoint connect point object we are looking for | ||
66 | + * @return matcher | ||
67 | + */ | ||
68 | + public static ConnectPointJsonMatcher matchesConnectPoint(ConnectPoint connectPoint) { | ||
69 | + return new ConnectPointJsonMatcher(connectPoint); | ||
70 | + } | ||
71 | +} |
1 | +/* | ||
2 | + * Copyright 2015 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 org.hamcrest.Description; | ||
19 | +import org.hamcrest.TypeSafeDiagnosingMatcher; | ||
20 | +import org.onosproject.net.flow.criteria.Criteria; | ||
21 | +import org.onosproject.net.flow.criteria.Criterion; | ||
22 | + | ||
23 | +import com.fasterxml.jackson.databind.JsonNode; | ||
24 | + | ||
25 | +/** | ||
26 | + * Hamcrest matcher for criterion objects. | ||
27 | + */ | ||
28 | +public final class CriterionJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { | ||
29 | + | ||
30 | + final Criterion criterion; | ||
31 | + | ||
32 | + private CriterionJsonMatcher(Criterion criterionValue) { | ||
33 | + criterion = criterionValue; | ||
34 | + } | ||
35 | + | ||
36 | + @Override | ||
37 | + public boolean matchesSafely(JsonNode jsonCriterion, Description description) { | ||
38 | + final String type = criterion.type().name(); | ||
39 | + final String jsonType = jsonCriterion.get("type").asText(); | ||
40 | + if (!type.equals(jsonType)) { | ||
41 | + description.appendText("type was " + type); | ||
42 | + return false; | ||
43 | + } | ||
44 | + | ||
45 | + switch (criterion.type()) { | ||
46 | + | ||
47 | + case IN_PORT: | ||
48 | + final Criteria.PortCriterion portCriterion = (Criteria.PortCriterion) criterion; | ||
49 | + final long port = portCriterion.port().toLong(); | ||
50 | + final long jsonPort = jsonCriterion.get("port").asLong(); | ||
51 | + if (port != jsonPort) { | ||
52 | + description.appendText("port was " + Long.toString(jsonPort)); | ||
53 | + return false; | ||
54 | + } | ||
55 | + break; | ||
56 | + | ||
57 | + case ETH_SRC: | ||
58 | + case ETH_DST: | ||
59 | + final Criteria.EthCriterion ethCriterion = (Criteria.EthCriterion) criterion; | ||
60 | + final String mac = ethCriterion.mac().toString(); | ||
61 | + final String jsonMac = jsonCriterion.get("mac").textValue(); | ||
62 | + if (!mac.equals(jsonMac)) { | ||
63 | + description.appendText("mac was " + jsonMac); | ||
64 | + return false; | ||
65 | + } | ||
66 | + break; | ||
67 | + | ||
68 | + case ETH_TYPE: | ||
69 | + final Criteria.EthTypeCriterion ethTypeCriterion = | ||
70 | + (Criteria.EthTypeCriterion) criterion; | ||
71 | + final String ethType = ethTypeCriterion.ethType().toString(); | ||
72 | + final String jsonEthType = jsonCriterion.get("ethType").textValue(); | ||
73 | + if (!ethType.equals(jsonEthType)) { | ||
74 | + description.appendText("ethType was " + jsonEthType); | ||
75 | + return false; | ||
76 | + } | ||
77 | + break; | ||
78 | + | ||
79 | + case IPV4_SRC: | ||
80 | + case IPV6_SRC: | ||
81 | + case IPV4_DST: | ||
82 | + case IPV6_DST: | ||
83 | + final Criteria.IPCriterion ipCriterion = (Criteria.IPCriterion) criterion; | ||
84 | + final String ip = ipCriterion.ip().toString(); | ||
85 | + final String jsonIp = jsonCriterion.get("ip").textValue(); | ||
86 | + if (!ip.equals(jsonIp)) { | ||
87 | + description.appendText("ip was " + jsonIp); | ||
88 | + return false; | ||
89 | + } | ||
90 | + break; | ||
91 | + | ||
92 | + case IP_PROTO: | ||
93 | + final Criteria.IPProtocolCriterion iPProtocolCriterion = | ||
94 | + (Criteria.IPProtocolCriterion) criterion; | ||
95 | + final byte protocol = iPProtocolCriterion.protocol(); | ||
96 | + final byte jsonProtocol = (byte) jsonCriterion.get("protocol").shortValue(); | ||
97 | + if (protocol != jsonProtocol) { | ||
98 | + description.appendText("protocol was " + Byte.toString(jsonProtocol)); | ||
99 | + return false; | ||
100 | + } | ||
101 | + break; | ||
102 | + | ||
103 | + case VLAN_PCP: | ||
104 | + final Criteria.VlanPcpCriterion vlanPcpCriterion = | ||
105 | + (Criteria.VlanPcpCriterion) criterion; | ||
106 | + final byte priority = vlanPcpCriterion.priority(); | ||
107 | + final byte jsonPriority = (byte) jsonCriterion.get("protocol").shortValue(); | ||
108 | + if (priority != jsonPriority) { | ||
109 | + description.appendText("priority was " + Byte.toString(jsonPriority)); | ||
110 | + return false; | ||
111 | + } | ||
112 | + break; | ||
113 | + | ||
114 | + case VLAN_VID: | ||
115 | + final Criteria.VlanIdCriterion vlanIdCriterion = | ||
116 | + (Criteria.VlanIdCriterion) criterion; | ||
117 | + final short vlanId = vlanIdCriterion.vlanId().toShort(); | ||
118 | + final short jsonvlanId = jsonCriterion.get("vlanId").shortValue(); | ||
119 | + if (vlanId != jsonvlanId) { | ||
120 | + description.appendText("vlanId was " + Short.toString(jsonvlanId)); | ||
121 | + return false; | ||
122 | + } | ||
123 | + break; | ||
124 | + | ||
125 | + case TCP_SRC: | ||
126 | + case TCP_DST: | ||
127 | + final Criteria.TcpPortCriterion tcpPortCriterion = | ||
128 | + (Criteria.TcpPortCriterion) criterion; | ||
129 | + final byte tcpPort = tcpPortCriterion.tcpPort().byteValue(); | ||
130 | + final byte jsonTcpPort = (byte) jsonCriterion.get("tcpPort").shortValue(); | ||
131 | + if (tcpPort != jsonTcpPort) { | ||
132 | + description.appendText("tcp port was " + Byte.toString(jsonTcpPort)); | ||
133 | + return false; | ||
134 | + } | ||
135 | + break; | ||
136 | + | ||
137 | + case MPLS_LABEL: | ||
138 | + final Criteria.MplsCriterion mplsCriterion = | ||
139 | + (Criteria.MplsCriterion) criterion; | ||
140 | + final int label = mplsCriterion.label(); | ||
141 | + final int jsonLabel = jsonCriterion.get("label").intValue(); | ||
142 | + if (label != jsonLabel) { | ||
143 | + description.appendText("label was " + Integer.toString(jsonLabel)); | ||
144 | + return false; | ||
145 | + } | ||
146 | + break; | ||
147 | + | ||
148 | + case OCH_SIGID: | ||
149 | + final Criteria.LambdaCriterion lambdaCriterion = | ||
150 | + (Criteria.LambdaCriterion) criterion; | ||
151 | + final short lambda = lambdaCriterion.lambda(); | ||
152 | + final short jsonLambda = jsonCriterion.get("lambda").shortValue(); | ||
153 | + if (lambda != jsonLambda) { | ||
154 | + description.appendText("lambda was " + Short.toString(lambda)); | ||
155 | + return false; | ||
156 | + } | ||
157 | + break; | ||
158 | + | ||
159 | + case OCH_SIGTYPE: | ||
160 | + final Criteria.OpticalSignalTypeCriterion opticalSignalTypeCriterion = | ||
161 | + (Criteria.OpticalSignalTypeCriterion) criterion; | ||
162 | + final short signalType = opticalSignalTypeCriterion.signalType(); | ||
163 | + final short jsonSignalType = jsonCriterion.get("signalType").shortValue(); | ||
164 | + if (signalType != jsonSignalType) { | ||
165 | + description.appendText("signal type was " + Short.toString(signalType)); | ||
166 | + return false; | ||
167 | + } | ||
168 | + break; | ||
169 | + | ||
170 | + default: | ||
171 | + // Don't know how to format this type | ||
172 | + description.appendText("unknown criterion type " + | ||
173 | + criterion.type()); | ||
174 | + return false; | ||
175 | + } | ||
176 | + return true; | ||
177 | + } | ||
178 | + | ||
179 | + @Override | ||
180 | + public void describeTo(Description description) { | ||
181 | + description.appendText(criterion.toString()); | ||
182 | + } | ||
183 | + | ||
184 | + /** | ||
185 | + * Factory to allocate an criterion matcher. | ||
186 | + * | ||
187 | + * @param criterion criterion object we are looking for | ||
188 | + * @return matcher | ||
189 | + */ | ||
190 | + public static CriterionJsonMatcher matchesCriterion(Criterion criterion) { | ||
191 | + return new CriterionJsonMatcher(criterion); | ||
192 | + } | ||
193 | +} |
... | @@ -24,12 +24,12 @@ import com.fasterxml.jackson.databind.JsonNode; | ... | @@ -24,12 +24,12 @@ import com.fasterxml.jackson.databind.JsonNode; |
24 | /** | 24 | /** |
25 | * Hamcrest matcher for ethernet objects. | 25 | * Hamcrest matcher for ethernet objects. |
26 | */ | 26 | */ |
27 | -public class EthernetJsonMatcher extends TypeSafeMatcher<JsonNode> { | 27 | +public final class EthernetJsonMatcher extends TypeSafeMatcher<JsonNode> { |
28 | 28 | ||
29 | private final Ethernet ethernet; | 29 | private final Ethernet ethernet; |
30 | private String reason = ""; | 30 | private String reason = ""; |
31 | 31 | ||
32 | - public EthernetJsonMatcher(Ethernet ethernetValue) { | 32 | + private EthernetJsonMatcher(Ethernet ethernetValue) { |
33 | ethernet = ethernetValue; | 33 | ethernet = ethernetValue; |
34 | } | 34 | } |
35 | 35 | ... | ... |
... | @@ -44,7 +44,7 @@ public class InstructionCodecTest { | ... | @@ -44,7 +44,7 @@ public class InstructionCodecTest { |
44 | JsonCodec<Instruction> instructionCodec; | 44 | JsonCodec<Instruction> instructionCodec; |
45 | 45 | ||
46 | /** | 46 | /** |
47 | - * Sets up for each tests. Creates a context and fetches the instruction | 47 | + * Sets up for each test. Creates a context and fetches the instruction |
48 | * codec. | 48 | * codec. |
49 | */ | 49 | */ |
50 | @Before | 50 | @Before | ... | ... |
... | @@ -31,11 +31,11 @@ import static org.onosproject.net.flow.instructions.L3ModificationInstruction.*; | ... | @@ -31,11 +31,11 @@ import static org.onosproject.net.flow.instructions.L3ModificationInstruction.*; |
31 | /** | 31 | /** |
32 | * Hamcrest matcher for instructions. | 32 | * Hamcrest matcher for instructions. |
33 | */ | 33 | */ |
34 | -public class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { | 34 | +public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { |
35 | 35 | ||
36 | private final Instruction instruction; | 36 | private final Instruction instruction; |
37 | 37 | ||
38 | - public InstructionJsonMatcher(Instruction instructionValue) { | 38 | + private InstructionJsonMatcher(Instruction instructionValue) { |
39 | instruction = instructionValue; | 39 | instruction = instructionValue; |
40 | } | 40 | } |
41 | 41 | ||
... | @@ -134,7 +134,7 @@ public class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> | ... | @@ -134,7 +134,7 @@ public class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> |
134 | } | 134 | } |
135 | 135 | ||
136 | /** | 136 | /** |
137 | - * Matches the contents of a mod lambda instruction. | 137 | + * Matches the contents of a mod Ethernet instruction. |
138 | * | 138 | * |
139 | * @param instructionJson JSON instruction to match | 139 | * @param instructionJson JSON instruction to match |
140 | * @return true if contents match, false otherwise | 140 | * @return true if contents match, false otherwise |
... | @@ -262,7 +262,7 @@ public class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> | ... | @@ -262,7 +262,7 @@ public class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> |
262 | } | 262 | } |
263 | 263 | ||
264 | /** | 264 | /** |
265 | - * Matches the contents of a mod ip instruction. | 265 | + * Matches the contents of a mod MPLS label instruction. |
266 | * | 266 | * |
267 | * @param instructionJson JSON instruction to match | 267 | * @param instructionJson JSON instruction to match |
268 | * @return true if contents match, false otherwise | 268 | * @return true if contents match, false otherwise | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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 java.util.List; | ||
19 | + | ||
20 | +import org.junit.Test; | ||
21 | +import org.onlab.packet.IpPrefix; | ||
22 | +import org.onlab.packet.MacAddress; | ||
23 | +import org.onosproject.codec.CodecContext; | ||
24 | +import org.onosproject.codec.JsonCodec; | ||
25 | +import org.onosproject.core.ApplicationId; | ||
26 | +import org.onosproject.core.DefaultApplicationId; | ||
27 | +import org.onosproject.net.ConnectPoint; | ||
28 | +import org.onosproject.net.HostId; | ||
29 | +import org.onosproject.net.NetTestTools; | ||
30 | +import org.onosproject.net.PortNumber; | ||
31 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
32 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
33 | +import org.onosproject.net.flow.TrafficSelector; | ||
34 | +import org.onosproject.net.flow.TrafficTreatment; | ||
35 | +import org.onosproject.net.intent.Constraint; | ||
36 | +import org.onosproject.net.intent.HostToHostIntent; | ||
37 | +import org.onosproject.net.intent.AbstractIntentTest; | ||
38 | +import org.onosproject.net.intent.PointToPointIntent; | ||
39 | +import org.onosproject.net.intent.constraint.BandwidthConstraint; | ||
40 | +import org.onosproject.net.intent.constraint.LambdaConstraint; | ||
41 | +import org.onosproject.net.resource.Bandwidth; | ||
42 | +import org.onosproject.net.resource.Lambda; | ||
43 | + | ||
44 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
45 | +import com.google.common.collect.ImmutableList; | ||
46 | + | ||
47 | +import static org.onosproject.codec.impl.IntentJsonMatcher.matchesIntent; | ||
48 | +import static org.onosproject.net.NetTestTools.hid; | ||
49 | + | ||
50 | + | ||
51 | +import static org.hamcrest.MatcherAssert.assertThat; | ||
52 | +import static org.hamcrest.Matchers.notNullValue; | ||
53 | + | ||
54 | +/** | ||
55 | + * Unit tests for the host to host intent class codec. | ||
56 | + */ | ||
57 | +public class IntentCodecTest extends AbstractIntentTest { | ||
58 | + | ||
59 | + private final HostId id1 = hid("12:34:56:78:91:ab/1"); | ||
60 | + private final HostId id2 = hid("12:34:56:78:92:ab/1"); | ||
61 | + private final ApplicationId appId = | ||
62 | + new DefaultApplicationId((short) 3, "test"); | ||
63 | + final TrafficSelector emptySelector = | ||
64 | + DefaultTrafficSelector.builder().build(); | ||
65 | + final TrafficTreatment emptyTreatment = | ||
66 | + DefaultTrafficTreatment.builder().build(); | ||
67 | + private final CodecContext context = new MockCodecContext(); | ||
68 | + | ||
69 | + /** | ||
70 | + * Tests the encoding of a host to host intent. | ||
71 | + */ | ||
72 | + @Test | ||
73 | + public void hostToHostIntent() { | ||
74 | + final HostToHostIntent intent = | ||
75 | + new HostToHostIntent(appId, id1, id2); | ||
76 | + | ||
77 | + final JsonCodec<HostToHostIntent> intentCodec = | ||
78 | + context.codec(HostToHostIntent.class); | ||
79 | + assertThat(intentCodec, notNullValue()); | ||
80 | + | ||
81 | + final ObjectNode intentJson = intentCodec.encode(intent, context); | ||
82 | + assertThat(intentJson, matchesIntent(intent)); | ||
83 | + } | ||
84 | + | ||
85 | + /** | ||
86 | + * Tests the encoding of a point to point intent. | ||
87 | + */ | ||
88 | + @Test | ||
89 | + public void pointToPointIntent() { | ||
90 | + ConnectPoint ingress = NetTestTools.connectPoint("ingress", 1); | ||
91 | + ConnectPoint egress = NetTestTools.connectPoint("egress", 2); | ||
92 | + | ||
93 | + final PointToPointIntent intent = | ||
94 | + new PointToPointIntent(appId, emptySelector, | ||
95 | + emptyTreatment, ingress, egress); | ||
96 | + | ||
97 | + final CodecContext context = new MockCodecContext(); | ||
98 | + final JsonCodec<PointToPointIntent> intentCodec = | ||
99 | + context.codec(PointToPointIntent.class); | ||
100 | + assertThat(intentCodec, notNullValue()); | ||
101 | + | ||
102 | + final ObjectNode intentJson = intentCodec.encode(intent, context); | ||
103 | + assertThat(intentJson, matchesIntent(intent)); | ||
104 | + } | ||
105 | + | ||
106 | + /** | ||
107 | + * Tests the encoding of an intent with treatment, selector and constraints | ||
108 | + * specified. | ||
109 | + */ | ||
110 | + @Test | ||
111 | + public void intentWithTreatmentSelectorAndConstraints() { | ||
112 | + ConnectPoint ingress = NetTestTools.connectPoint("ingress", 1); | ||
113 | + ConnectPoint egress = NetTestTools.connectPoint("egress", 2); | ||
114 | + final TrafficSelector selector = DefaultTrafficSelector.builder() | ||
115 | + .matchIPProtocol((byte) 3) | ||
116 | + .matchMplsLabel(4) | ||
117 | + .matchOpticalSignalType((short) 5) | ||
118 | + .matchLambda((short) 6) | ||
119 | + .matchEthDst(MacAddress.BROADCAST) | ||
120 | + .matchIPDst(IpPrefix.valueOf("1.2.3.4/24")) | ||
121 | + .build(); | ||
122 | + final TrafficTreatment treatment = DefaultTrafficTreatment.builder() | ||
123 | + .setLambda((short) 33) | ||
124 | + .setMpls(44) | ||
125 | + .setOutput(PortNumber.CONTROLLER) | ||
126 | + .setEthDst(MacAddress.BROADCAST) | ||
127 | + .build(); | ||
128 | + final Constraint constraint1 = new BandwidthConstraint(Bandwidth.valueOf(1.0)); | ||
129 | + final Constraint constraint2 = new LambdaConstraint(Lambda.valueOf(3)); | ||
130 | + final List<Constraint> constraints = ImmutableList.of(constraint1, constraint2); | ||
131 | + | ||
132 | + final PointToPointIntent intent = | ||
133 | + new PointToPointIntent(appId, selector, treatment, | ||
134 | + ingress, egress, constraints); | ||
135 | + | ||
136 | + final CodecContext context = new MockCodecContext(); | ||
137 | + final JsonCodec<PointToPointIntent> intentCodec = | ||
138 | + context.codec(PointToPointIntent.class); | ||
139 | + assertThat(intentCodec, notNullValue()); | ||
140 | + | ||
141 | + final ObjectNode intentJson = intentCodec.encode(intent, context); | ||
142 | + assertThat(intentJson, matchesIntent(intent)); | ||
143 | + | ||
144 | + } | ||
145 | +} |
1 | +/* | ||
2 | + * Copyright 2015 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 java.util.List; | ||
19 | +import java.util.Set; | ||
20 | + | ||
21 | +import org.hamcrest.Description; | ||
22 | +import org.hamcrest.TypeSafeDiagnosingMatcher; | ||
23 | +import org.onosproject.net.ConnectPoint; | ||
24 | +import org.onosproject.net.NetworkResource; | ||
25 | +import org.onosproject.net.flow.TrafficSelector; | ||
26 | +import org.onosproject.net.flow.TrafficTreatment; | ||
27 | +import org.onosproject.net.flow.criteria.Criterion; | ||
28 | +import org.onosproject.net.flow.instructions.Instruction; | ||
29 | +import org.onosproject.net.intent.ConnectivityIntent; | ||
30 | +import org.onosproject.net.intent.Constraint; | ||
31 | +import org.onosproject.net.intent.HostToHostIntent; | ||
32 | +import org.onosproject.net.intent.Intent; | ||
33 | +import org.onosproject.net.intent.PointToPointIntent; | ||
34 | + | ||
35 | +import com.fasterxml.jackson.databind.JsonNode; | ||
36 | + | ||
37 | +/** | ||
38 | + * Hamcrest matcher to check that an intent representation in JSON matches | ||
39 | + * the actual intent. | ||
40 | + */ | ||
41 | +public final class IntentJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { | ||
42 | + | ||
43 | + private final Intent intent; | ||
44 | + | ||
45 | + /** | ||
46 | + * Constructor is private, use factory method. | ||
47 | + * | ||
48 | + * @param intentValue the intent object to compare against | ||
49 | + */ | ||
50 | + private IntentJsonMatcher(Intent intentValue) { | ||
51 | + intent = intentValue; | ||
52 | + } | ||
53 | + | ||
54 | + /** | ||
55 | + * Matches the JSON representation of a host to host intent. | ||
56 | + * | ||
57 | + * @param jsonIntent JSON representation of the intent | ||
58 | + * @param description Description object used for recording errors | ||
59 | + * @return true if the JSON matches the intent, false otherwise | ||
60 | + */ | ||
61 | + private boolean matchHostToHostIntent(JsonNode jsonIntent, Description description) { | ||
62 | + final HostToHostIntent hostToHostIntent = (HostToHostIntent) intent; | ||
63 | + | ||
64 | + // check host one | ||
65 | + final String host1 = hostToHostIntent.one().toString(); | ||
66 | + final String jsonHost1 = jsonIntent.get("one").asText(); | ||
67 | + if (!host1.equals(jsonHost1)) { | ||
68 | + description.appendText("host one was " + jsonHost1); | ||
69 | + return false; | ||
70 | + } | ||
71 | + | ||
72 | + // check host 2 | ||
73 | + final String host2 = hostToHostIntent.two().toString(); | ||
74 | + final String jsonHost2 = jsonIntent.get("two").asText(); | ||
75 | + if (!host2.equals(jsonHost2)) { | ||
76 | + description.appendText("host two was " + jsonHost2); | ||
77 | + return false; | ||
78 | + } | ||
79 | + return true; | ||
80 | + } | ||
81 | + | ||
82 | + /** | ||
83 | + * Matches the JSON representation of a point to point intent. | ||
84 | + * | ||
85 | + * @param jsonIntent JSON representation of the intent | ||
86 | + * @param description Description object used for recording errors | ||
87 | + * @return true if the JSON matches the intent, false otherwise | ||
88 | + */ | ||
89 | + private boolean matchPointToPointIntent(JsonNode jsonIntent, Description description) { | ||
90 | + final PointToPointIntent pointToPointIntent = (PointToPointIntent) intent; | ||
91 | + | ||
92 | + // check ingress connection | ||
93 | + final ConnectPoint ingress = pointToPointIntent.ingressPoint(); | ||
94 | + final ConnectPointJsonMatcher ingressMatcher = | ||
95 | + ConnectPointJsonMatcher.matchesConnectPoint(ingress); | ||
96 | + final JsonNode jsonIngress = jsonIntent.get("ingressPoint"); | ||
97 | + final boolean ingressMatches = | ||
98 | + ingressMatcher.matchesSafely(jsonIngress, description); | ||
99 | + | ||
100 | + if (!ingressMatches) { | ||
101 | + description.appendText("ingress was " + jsonIngress); | ||
102 | + return false; | ||
103 | + } | ||
104 | + | ||
105 | + // check egress connection | ||
106 | + final ConnectPoint egress = pointToPointIntent.egressPoint(); | ||
107 | + final ConnectPointJsonMatcher egressMatcher = | ||
108 | + ConnectPointJsonMatcher.matchesConnectPoint(egress); | ||
109 | + final JsonNode jsonEgress = jsonIntent.get("egressPoint"); | ||
110 | + final boolean egressMatches = | ||
111 | + egressMatcher.matchesSafely(jsonEgress, description); | ||
112 | + | ||
113 | + if (!egressMatches) { | ||
114 | + description.appendText("egress was " + jsonEgress); | ||
115 | + return false; | ||
116 | + } | ||
117 | + | ||
118 | + return true; | ||
119 | + } | ||
120 | + | ||
121 | + /** | ||
122 | + * Matches the JSON representation of a connectivity intent. Calls the | ||
123 | + * matcher for the connectivity intent subtype. | ||
124 | + * | ||
125 | + * @param jsonIntent JSON representation of the intent | ||
126 | + * @param description Description object used for recording errors | ||
127 | + * @return true if the JSON matches the intent, false otherwise | ||
128 | + */ | ||
129 | + private boolean matchConnectivityIntent(JsonNode jsonIntent, Description description) { | ||
130 | + final ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent; | ||
131 | + | ||
132 | + // check selector | ||
133 | + final JsonNode jsonSelector = jsonIntent.get("selector"); | ||
134 | + final TrafficSelector selector = connectivityIntent.selector(); | ||
135 | + final Set<Criterion> criteria = selector.criteria(); | ||
136 | + final JsonNode jsonCriteria = jsonSelector.get("criteria"); | ||
137 | + if (jsonCriteria.size() != criteria.size()) { | ||
138 | + description.appendText("size of criteria array is " | ||
139 | + + Integer.toString(jsonCriteria.size())); | ||
140 | + return false; | ||
141 | + } | ||
142 | + | ||
143 | + for (Criterion criterion : criteria) { | ||
144 | + boolean criterionFound = false; | ||
145 | + for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) { | ||
146 | + final CriterionJsonMatcher criterionMatcher = | ||
147 | + CriterionJsonMatcher.matchesCriterion(criterion); | ||
148 | + if (criterionMatcher.matches(jsonCriteria.get(criterionIndex))) { | ||
149 | + criterionFound = true; | ||
150 | + break; | ||
151 | + } | ||
152 | + } | ||
153 | + if (!criterionFound) { | ||
154 | + description.appendText("criterion not found " + criterion.toString()); | ||
155 | + return false; | ||
156 | + } | ||
157 | + } | ||
158 | + | ||
159 | + // check treatment | ||
160 | + final JsonNode jsonTreatment = jsonIntent.get("treatment"); | ||
161 | + final TrafficTreatment treatment = connectivityIntent.treatment(); | ||
162 | + final List<Instruction> instructions = treatment.instructions(); | ||
163 | + final JsonNode jsonInstructions = jsonTreatment.get("instructions"); | ||
164 | + if (jsonInstructions.size() != instructions.size()) { | ||
165 | + description.appendText("size of instructions array is " | ||
166 | + + Integer.toString(jsonInstructions.size())); | ||
167 | + return false; | ||
168 | + } | ||
169 | + | ||
170 | + for (Instruction instruction : instructions) { | ||
171 | + boolean instructionFound = false; | ||
172 | + for (int instructionIndex = 0; instructionIndex < jsonCriteria.size(); instructionIndex++) { | ||
173 | + final InstructionJsonMatcher instructionMatcher = | ||
174 | + InstructionJsonMatcher.matchesInstruction(instruction); | ||
175 | + if (instructionMatcher.matches(jsonInstructions.get(instructionIndex))) { | ||
176 | + instructionFound = true; | ||
177 | + break; | ||
178 | + } | ||
179 | + } | ||
180 | + if (!instructionFound) { | ||
181 | + description.appendText("instruction not found " + instruction.toString()); | ||
182 | + return false; | ||
183 | + } | ||
184 | + } | ||
185 | + | ||
186 | + // Check constraints | ||
187 | + final JsonNode jsonConstraints = jsonIntent.get("constraints"); | ||
188 | + if (connectivityIntent.constraints() != null) { | ||
189 | + if (connectivityIntent.constraints().size() != jsonConstraints.size()) { | ||
190 | + description.appendText("constraints array size was " | ||
191 | + + Integer.toString(jsonConstraints.size())); | ||
192 | + return false; | ||
193 | + } | ||
194 | + for (final Constraint constraint : connectivityIntent.constraints()) { | ||
195 | + boolean constraintFound = false; | ||
196 | + final String constraintString = constraint.toString(); | ||
197 | + for (int constraintIndex = 0; constraintIndex < jsonConstraints.size(); | ||
198 | + constraintIndex++) { | ||
199 | + final JsonNode value = jsonConstraints.get(constraintIndex); | ||
200 | + if (value.asText().equals(constraintString)) { | ||
201 | + constraintFound = true; | ||
202 | + } | ||
203 | + } | ||
204 | + if (!constraintFound) { | ||
205 | + description.appendText("resource missing " + constraintString); | ||
206 | + return false; | ||
207 | + } | ||
208 | + } | ||
209 | + } else if (jsonConstraints.size() != 0) { | ||
210 | + description.appendText("constraint array not empty"); | ||
211 | + return false; | ||
212 | + } | ||
213 | + | ||
214 | + if (connectivityIntent instanceof HostToHostIntent) { | ||
215 | + return matchHostToHostIntent(jsonIntent, description); | ||
216 | + } else if (connectivityIntent instanceof PointToPointIntent) { | ||
217 | + return matchPointToPointIntent(jsonIntent, description); | ||
218 | + } else { | ||
219 | + description.appendText("class of connectivity intent is unknown"); | ||
220 | + return false; | ||
221 | + } | ||
222 | + } | ||
223 | + | ||
224 | + @Override | ||
225 | + public boolean matchesSafely(JsonNode jsonIntent, Description description) { | ||
226 | + // check id | ||
227 | + final String jsonId = jsonIntent.get("id").asText(); | ||
228 | + final String id = intent.id().toString(); | ||
229 | + if (!jsonId.equals(id)) { | ||
230 | + description.appendText("id was " + jsonId); | ||
231 | + return false; | ||
232 | + } | ||
233 | + | ||
234 | + // check application id | ||
235 | + final String jsonAppId = jsonIntent.get("appId").asText(); | ||
236 | + final String appId = intent.appId().toString(); | ||
237 | + if (!jsonAppId.equals(appId)) { | ||
238 | + description.appendText("appId was " + jsonAppId); | ||
239 | + return false; | ||
240 | + } | ||
241 | + | ||
242 | + // check intent type | ||
243 | + final String jsonType = jsonIntent.get("type").asText(); | ||
244 | + final String type = intent.getClass().getSimpleName(); | ||
245 | + if (!jsonType.equals(type)) { | ||
246 | + description.appendText("type was " + jsonType); | ||
247 | + return false; | ||
248 | + } | ||
249 | + | ||
250 | + // check details field | ||
251 | + final String jsonDetails = jsonIntent.get("details").asText(); | ||
252 | + final String details = intent.toString(); | ||
253 | + if (!jsonDetails.equals(details)) { | ||
254 | + description.appendText("details were " + jsonDetails); | ||
255 | + return false; | ||
256 | + } | ||
257 | + | ||
258 | + // check resources array | ||
259 | + final JsonNode jsonResources = jsonIntent.get("resources"); | ||
260 | + if (intent.resources() != null) { | ||
261 | + if (intent.resources().size() != jsonResources.size()) { | ||
262 | + description.appendText("resources array size was " | ||
263 | + + Integer.toString(jsonResources.size())); | ||
264 | + return false; | ||
265 | + } | ||
266 | + for (final NetworkResource resource : intent.resources()) { | ||
267 | + boolean resourceFound = false; | ||
268 | + final String resourceString = resource.toString(); | ||
269 | + for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) { | ||
270 | + final JsonNode value = jsonResources.get(resourceIndex); | ||
271 | + if (value.asText().equals(resourceString)) { | ||
272 | + resourceFound = true; | ||
273 | + } | ||
274 | + } | ||
275 | + if (!resourceFound) { | ||
276 | + description.appendText("resource missing " + resourceString); | ||
277 | + return false; | ||
278 | + } | ||
279 | + } | ||
280 | + } else if (jsonResources.size() != 0) { | ||
281 | + description.appendText("resources array empty"); | ||
282 | + return false; | ||
283 | + } | ||
284 | + | ||
285 | + if (intent instanceof ConnectivityIntent) { | ||
286 | + return matchConnectivityIntent(jsonIntent, description); | ||
287 | + } else { | ||
288 | + description.appendText("class of intent is unknown"); | ||
289 | + return false; | ||
290 | + } | ||
291 | + } | ||
292 | + | ||
293 | + @Override | ||
294 | + public void describeTo(Description description) { | ||
295 | + description.appendText(intent.toString()); | ||
296 | + } | ||
297 | + | ||
298 | + /** | ||
299 | + * Factory to allocate an intent matcher. | ||
300 | + * | ||
301 | + * @param intent intent object we are looking for | ||
302 | + * @return matcher | ||
303 | + */ | ||
304 | + public static IntentJsonMatcher matchesIntent(Intent intent) { | ||
305 | + return new IntentJsonMatcher(intent); | ||
306 | + } | ||
307 | +} |
... | @@ -28,6 +28,9 @@ public final class MockCodecContext implements CodecContext { | ... | @@ -28,6 +28,9 @@ public final class MockCodecContext implements CodecContext { |
28 | private ObjectMapper mapper = new ObjectMapper(); | 28 | private ObjectMapper mapper = new ObjectMapper(); |
29 | private CodecManager manager = new CodecManager(); | 29 | private CodecManager manager = new CodecManager(); |
30 | 30 | ||
31 | + /** | ||
32 | + * Constructs a new mock codec context. | ||
33 | + */ | ||
31 | public MockCodecContext() { | 34 | public MockCodecContext() { |
32 | manager.activate(); | 35 | manager.activate(); |
33 | } | 36 | } | ... | ... |
-
Please register or login to post a comment