diff options
author | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:15:21 -0700 |
---|---|---|
committer | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:15:21 -0700 |
commit | 13d05bc8458758ee39cb829098241e89616717ee (patch) | |
tree | 22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl | |
parent | 6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff) |
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl')
23 files changed, 4424 insertions, 0 deletions
diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConnectPointJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConnectPointJsonMatcher.java new file mode 100644 index 00000000..8d85751e --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConnectPointJsonMatcher.java @@ -0,0 +1,71 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.ConnectPoint; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for connect points. + */ + +public final class ConnectPointJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { + + private final ConnectPoint connectPoint; + + private ConnectPointJsonMatcher(ConnectPoint connectPointValue) { + connectPoint = connectPointValue; + } + + @Override + public boolean matchesSafely(JsonNode jsonConnectPoint, Description description) { + // check device + final String jsonDevice = jsonConnectPoint.get("device").asText(); + final String device = connectPoint.deviceId().toString(); + if (!jsonDevice.equals(device)) { + description.appendText("device was " + jsonDevice); + return false; + } + + // check port + final String jsonPort = jsonConnectPoint.get("port").asText(); + final String port = connectPoint.port().toString(); + if (!jsonPort.equals(port)) { + description.appendText("port was " + jsonPort); + return false; + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(connectPoint.toString()); + } + + /** + * Factory to allocate an connect point matcher. + * + * @param connectPoint connect point object we are looking for + * @return matcher + */ + public static ConnectPointJsonMatcher matchesConnectPoint(ConnectPoint connectPoint) { + return new ConnectPointJsonMatcher(connectPoint); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java new file mode 100644 index 00000000..2a47d115 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java @@ -0,0 +1,202 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.CoreService; +import org.onosproject.net.Link; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.constraint.AnnotationConstraint; +import org.onosproject.net.intent.constraint.AsymmetricPathConstraint; +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.intent.constraint.LatencyConstraint; +import org.onosproject.net.intent.constraint.LinkTypeConstraint; +import org.onosproject.net.intent.constraint.ObstacleConstraint; +import org.onosproject.net.intent.constraint.WaypointConstraint; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.did; + +/** + * Unit tests for Constraint codec. + */ +public class ConstraintCodecTest { + + MockCodecContext context; + JsonCodec<Constraint> constraintCodec; + final CoreService mockCoreService = createMock(CoreService.class); + + /** + * Sets up for each test. Creates a context and fetches the flow rule + * codec. + */ + @Before + public void setUp() { + context = new MockCodecContext(); + constraintCodec = context.codec(Constraint.class); + assertThat(constraintCodec, notNullValue()); + + expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID)) + .andReturn(APP_ID).anyTimes(); + replay(mockCoreService); + context.registerService(CoreService.class, mockCoreService); + } + + /** + * Reads in a constraint from the given resource and decodes it. + * + * @param resourceName resource to use to read the JSON for the constraint + * @return decoded constraint + */ + private Constraint getConstraint(String resourceName) { + InputStream jsonStream = ConstraintCodecTest.class + .getResourceAsStream(resourceName); + try { + JsonNode json = context.mapper().readTree(jsonStream); + assertThat(json, notNullValue()); + Constraint constraint = constraintCodec.decode((ObjectNode) json, context); + assertThat(constraint, notNullValue()); + return checkNotNull(constraint); + } catch (IOException ioe) { + Assert.fail(ioe.getMessage()); + throw new IllegalStateException("cannot happen"); + } + } + + + /** + * Tests link type constraint. + */ + @Test + public void linkTypeConstraint() { + Constraint constraint = getConstraint("LinkTypeConstraint.json"); + assertThat(constraint, instanceOf(LinkTypeConstraint.class)); + + LinkTypeConstraint linkTypeConstraint = (LinkTypeConstraint) constraint; + assertThat(linkTypeConstraint.isInclusive(), is(false)); + assertThat(linkTypeConstraint.types(), hasSize(2)); + assertThat(linkTypeConstraint.types(), hasItem(Link.Type.OPTICAL)); + assertThat(linkTypeConstraint.types(), hasItem(Link.Type.DIRECT)); + } + + /** + * Tests annotation constraint. + */ + @Test + public void annotationConstraint() { + Constraint constraint = getConstraint("AnnotationConstraint.json"); + assertThat(constraint, instanceOf(AnnotationConstraint.class)); + + AnnotationConstraint annotationConstraint = (AnnotationConstraint) constraint; + assertThat(annotationConstraint.key(), is("key")); + assertThat(annotationConstraint.threshold(), is(123.0D)); + } + + /** + * Tests bandwidth constraint. + */ + @Test + public void bandwidthConstraint() { + Constraint constraint = getConstraint("BandwidthConstraint.json"); + assertThat(constraint, instanceOf(BandwidthConstraint.class)); + + BandwidthConstraint bandwidthConstraint = (BandwidthConstraint) constraint; + assertThat(bandwidthConstraint.bandwidth().toDouble(), is(345.678D)); + } + + /** + * Tests lambda constraint. + */ + @Test + public void lambdaConstraint() { + Constraint constraint = getConstraint("LambdaConstraint.json"); + assertThat(constraint, instanceOf(LambdaConstraint.class)); + + LambdaConstraint lambdaConstraint = (LambdaConstraint) constraint; + assertThat(lambdaConstraint.lambda().toInt(), is(444)); + } + + /** + * Tests latency constraint. + */ + @Test + public void latencyConstraint() { + Constraint constraint = getConstraint("LatencyConstraint.json"); + assertThat(constraint, instanceOf(LatencyConstraint.class)); + + LatencyConstraint latencyConstraint = (LatencyConstraint) constraint; + assertThat(latencyConstraint.latency().toMillis(), is(111L)); + } + + /** + * Tests obstacle constraint. + */ + @Test + public void obstacleConstraint() { + Constraint constraint = getConstraint("ObstacleConstraint.json"); + assertThat(constraint, instanceOf(ObstacleConstraint.class)); + + ObstacleConstraint obstacleConstraint = (ObstacleConstraint) constraint; + + assertThat(obstacleConstraint.obstacles(), hasItem(did("dev1"))); + assertThat(obstacleConstraint.obstacles(), hasItem(did("dev2"))); + assertThat(obstacleConstraint.obstacles(), hasItem(did("dev3"))); + } + + /** + * Tests waypoint constaint. + */ + @Test + public void waypointConstraint() { + Constraint constraint = getConstraint("WaypointConstraint.json"); + assertThat(constraint, instanceOf(WaypointConstraint.class)); + + WaypointConstraint waypointConstraint = (WaypointConstraint) constraint; + + assertThat(waypointConstraint.waypoints(), hasItem(did("devA"))); + assertThat(waypointConstraint.waypoints(), hasItem(did("devB"))); + assertThat(waypointConstraint.waypoints(), hasItem(did("devC"))); + } + + /** + * Tests asymmetric path constraint. + */ + @Test + public void asymmetricPathConstraint() { + Constraint constraint = getConstraint("AsymmetricPathConstraint.json"); + assertThat(constraint, instanceOf(AsymmetricPathConstraint.class)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java new file mode 100644 index 00000000..6bf46803 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java @@ -0,0 +1,445 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import java.util.EnumMap; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.Lambda; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.criteria.Criteria; +import org.onosproject.net.flow.criteria.Criterion; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.TestUtils.getField; +import static org.onlab.junit.TestUtils.setField; +import static org.onosproject.codec.impl.CriterionJsonMatcher.matchesCriterion; + +/** + * Unit tests for criterion codec. + */ +public class CriterionCodecTest { + + CodecContext context; + JsonCodec<Criterion> criterionCodec; + final PortNumber port = PortNumber.portNumber(1); + final IpPrefix ipPrefix4 = IpPrefix.valueOf("10.1.1.0/24"); + final IpPrefix ipPrefix6 = IpPrefix.valueOf("fe80::/64"); + final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01"); + final TpPort tpPort = TpPort.tpPort(40000); + + /** + * Sets up for each test. Creates a context and fetches the criterion + * codec. + */ + @Before + public void setUp() { + context = new MockCodecContext(); + criterionCodec = context.codec(Criterion.class); + assertThat(criterionCodec, notNullValue()); + } + + + /** + * Checks that all criterion types are covered by the codec. + */ + @Test + public void checkCriterionTypes() throws Exception { + EncodeCriterionCodecHelper encoder = new EncodeCriterionCodecHelper( + Criteria.dummy(), context); + EnumMap<Criterion.Type, Object> formatMap = + getField(encoder, "formatMap"); + assertThat(formatMap, notNullValue()); + + for (Criterion.Type type : Criterion.Type.values()) { + assertThat("Entry not found for " + type.toString(), + formatMap.get(type), notNullValue()); + } + } + + /** + * Tests in port criterion. + */ + @Test + public void matchInPortTest() { + Criterion criterion = Criteria.matchInPort(port); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests in physical port criterion. + */ + @Test + public void matchInPhyPortTest() { + Criterion criterion = Criteria.matchInPhyPort(port); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests metadata criterion. + */ + @Test + public void matchMetadataTest() { + Criterion criterion = Criteria.matchMetadata(0xabcdL); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ethernet destination criterion. + */ + @Test + public void matchEthDstTest() { + Criterion criterion = Criteria.matchEthDst(mac1); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ethernet source criterion. + */ + @Test + public void matchEthSrcTest() { + Criterion criterion = Criteria.matchEthSrc(mac1); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ethernet type criterion. + */ + @Test + public void matchEthTypeTest() { + Criterion criterion = Criteria.matchEthType((short) 0x8844); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests VLAN Id criterion. + */ + @Test + public void matchVlanIdTest() { + Criterion criterion = Criteria.matchVlanId(VlanId.ANY); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests VLAN PCP criterion. + */ + @Test + public void matchVlanPcpTest() { + Criterion criterion = Criteria.matchVlanPcp((byte) 7); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP DSCP criterion. + */ + @Test + public void matchIPDscpTest() { + Criterion criterion = Criteria.matchIPDscp((byte) 63); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP ECN criterion. + */ + @Test + public void matchIPEcnTest() { + Criterion criterion = Criteria.matchIPEcn((byte) 3); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP protocol criterion. + */ + @Test + public void matchIPProtocolTest() { + Criterion criterion = Criteria.matchIPProtocol((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP source criterion. + */ + @Test + public void matchIPSrcTest() { + Criterion criterion = Criteria.matchIPSrc(ipPrefix4); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP destination criterion. + */ + @Test + public void matchIPDstTest() { + Criterion criterion = Criteria.matchIPDst(ipPrefix4); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests source TCP port criterion. + */ + @Test + public void matchTcpSrcTest() { + Criterion criterion = Criteria.matchTcpSrc(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests destination TCP port criterion. + */ + @Test + public void matchTcpDstTest() { + Criterion criterion = Criteria.matchTcpDst(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests source UDP port criterion. + */ + @Test + public void matchUdpSrcTest() { + Criterion criterion = Criteria.matchUdpSrc(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests destination UDP criterion. + */ + @Test + public void matchUdpDstTest() { + Criterion criterion = Criteria.matchUdpDst(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests source SCTP criterion. + */ + @Test + public void matchSctpSrcTest() { + Criterion criterion = Criteria.matchSctpSrc(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests destination SCTP criterion. + */ + @Test + public void matchSctpDstTest() { + Criterion criterion = Criteria.matchSctpDst(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ICMP type criterion. + */ + @Test + public void matchIcmpTypeTest() { + Criterion criterion = Criteria.matchIcmpType((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ICMP code criterion. + */ + @Test + public void matchIcmpCodeTest() { + Criterion criterion = Criteria.matchIcmpCode((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPv6 source criterion. + */ + @Test + public void matchIPv6SrcTest() { + Criterion criterion = Criteria.matchIPv6Src(ipPrefix6); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPv6 destination criterion. + */ + @Test + public void matchIPv6DstTest() { + Criterion criterion = Criteria.matchIPv6Dst(ipPrefix6); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPv6 flow label criterion. + */ + @Test + public void matchIPv6FlowLabelTest() { + Criterion criterion = Criteria.matchIPv6FlowLabel(0xffffe); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ICMP v6 type criterion. + */ + @Test + public void matchIcmpv6TypeTest() { + Criterion criterion = Criteria.matchIcmpv6Type((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ICMP v6 code criterion. + */ + @Test + public void matchIcmpv6CodeTest() { + Criterion criterion = Criteria.matchIcmpv6Code((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPV6 target address criterion. + */ + @Test + public void matchIPv6NDTargetAddressTest() { + Criterion criterion = + Criteria.matchIPv6NDTargetAddress( + Ip6Address.valueOf("1111:2222::")); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPV6 SLL criterion. + */ + @Test + public void matchIPv6NDSourceLinkLayerAddressTest() { + Criterion criterion = Criteria.matchIPv6NDSourceLinkLayerAddress(mac1); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPV6 TLL criterion. + */ + @Test + public void matchIPv6NDTargetLinkLayerAddressTest() { + Criterion criterion = Criteria.matchIPv6NDTargetLinkLayerAddress(mac1); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests MPLS label criterion. + */ + @Test + public void matchMplsLabelTest() { + Criterion criterion = Criteria.matchMplsLabel(MplsLabel.mplsLabel(0xffffe)); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPv6 Extension Header pseudo-field flags criterion. + */ + @Test + public void matchIPv6ExthdrFlagsTest() { + int exthdrFlags = + Criterion.IPv6ExthdrFlags.NONEXT.getValue() | + Criterion.IPv6ExthdrFlags.ESP.getValue() | + Criterion.IPv6ExthdrFlags.AUTH.getValue() | + Criterion.IPv6ExthdrFlags.DEST.getValue() | + Criterion.IPv6ExthdrFlags.FRAG.getValue() | + Criterion.IPv6ExthdrFlags.ROUTER.getValue() | + Criterion.IPv6ExthdrFlags.HOP.getValue() | + Criterion.IPv6ExthdrFlags.UNREP.getValue() | + Criterion.IPv6ExthdrFlags.UNSEQ.getValue(); + Criterion criterion = Criteria.matchIPv6ExthdrFlags(exthdrFlags); + ObjectNode result = criterionCodec.encode(criterion, context); + + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests lambda criterion. + */ + @Test + public void matchOchSignal() { + Lambda ochSignal = Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8); + Criterion criterion = Criteria.matchLambda(ochSignal); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests Och signal type criterion. + */ + @Test + public void matchOchSignalTypeTest() { + Criterion criterion = Criteria.matchOchSignalType(OchSignalType.FIXED_GRID); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests that an unimplemented criterion type only returns the type and + * no other data. + */ + @Test + public void matchUnknownTypeTest() throws Exception { + Criterion criterion = Criteria.matchOpticalSignalType((byte) 250); + setField(criterion, "type", Criterion.Type.UNASSIGNED_40); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result.get("type").textValue(), is(criterion.type().toString())); + assertThat(result.size(), is(1)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java new file mode 100644 index 00000000..bb3acad5 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java @@ -0,0 +1,609 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import com.google.common.base.Joiner; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.OchSignal; +import org.onosproject.net.flow.criteria.Criterion; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.IPDscpCriterion; +import org.onosproject.net.flow.criteria.IPEcnCriterion; +import org.onosproject.net.flow.criteria.IPProtocolCriterion; +import org.onosproject.net.flow.criteria.IPv6ExthdrFlagsCriterion; +import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion; +import org.onosproject.net.flow.criteria.IPv6NDLinkLayerAddressCriterion; +import org.onosproject.net.flow.criteria.IPv6NDTargetAddressCriterion; +import org.onosproject.net.flow.criteria.IcmpCodeCriterion; +import org.onosproject.net.flow.criteria.IcmpTypeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion; +import org.onosproject.net.flow.criteria.MetadataCriterion; +import org.onosproject.net.flow.criteria.MplsCriterion; +import org.onosproject.net.flow.criteria.OchSignalCriterion; +import org.onosproject.net.flow.criteria.OchSignalTypeCriterion; +import org.onosproject.net.flow.criteria.PortCriterion; +import org.onosproject.net.flow.criteria.SctpPortCriterion; +import org.onosproject.net.flow.criteria.TcpPortCriterion; +import org.onosproject.net.flow.criteria.UdpPortCriterion; +import org.onosproject.net.flow.criteria.VlanIdCriterion; +import org.onosproject.net.flow.criteria.VlanPcpCriterion; + +import java.util.Objects; + +/** + * Hamcrest matcher for criterion objects. + */ +public final class CriterionJsonMatcher extends + TypeSafeDiagnosingMatcher<JsonNode> { + + final Criterion criterion; + Description description; + JsonNode jsonCriterion; + + /** + * Constructs a matcher object. + * + * @param criterionValue criterion to match + */ + private CriterionJsonMatcher(Criterion criterionValue) { + criterion = criterionValue; + } + + /** + * Factory to allocate an criterion matcher. + * + * @param criterion criterion object we are looking for + * @return matcher + */ + public static CriterionJsonMatcher matchesCriterion(Criterion criterion) { + return new CriterionJsonMatcher(criterion); + } + + /** + * Matches a port criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(PortCriterion criterion) { + final long port = criterion.port().toLong(); + final long jsonPort = jsonCriterion.get("port").asLong(); + if (port != jsonPort) { + description.appendText("port was " + Long.toString(jsonPort)); + return false; + } + return true; + } + + /** + * Matches a metadata criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(MetadataCriterion criterion) { + final long metadata = criterion.metadata(); + final long jsonMetadata = jsonCriterion.get("metadata").asLong(); + if (metadata != jsonMetadata) { + description.appendText("metadata was " + + Long.toString(jsonMetadata)); + return false; + } + return true; + } + + /** + * Matches an eth criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(EthCriterion criterion) { + final String mac = criterion.mac().toString(); + final String jsonMac = jsonCriterion.get("mac").textValue(); + if (!mac.equals(jsonMac)) { + description.appendText("mac was " + jsonMac); + return false; + } + return true; + } + + /** + * Matches an eth type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(EthTypeCriterion criterion) { + final int ethType = criterion.ethType().toShort(); + final int jsonEthType = jsonCriterion.get("ethType").intValue(); + if (ethType != jsonEthType) { + description.appendText("ethType was " + + Integer.toString(jsonEthType)); + return false; + } + return true; + } + + /** + * Matches a VLAN ID criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(VlanIdCriterion criterion) { + final short vlanId = criterion.vlanId().toShort(); + final short jsonVlanId = jsonCriterion.get("vlanId").shortValue(); + if (vlanId != jsonVlanId) { + description.appendText("vlanId was " + Short.toString(jsonVlanId)); + return false; + } + return true; + } + + /** + * Matches a VLAN PCP criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(VlanPcpCriterion criterion) { + final byte priority = criterion.priority(); + final byte jsonPriority = + (byte) jsonCriterion.get("priority").shortValue(); + if (priority != jsonPriority) { + description.appendText("priority was " + Byte.toString(jsonPriority)); + return false; + } + return true; + } + + /** + * Matches an IP DSCP criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPDscpCriterion criterion) { + final byte ipDscp = criterion.ipDscp(); + final byte jsonIpDscp = (byte) jsonCriterion.get("ipDscp").shortValue(); + if (ipDscp != jsonIpDscp) { + description.appendText("IP DSCP was " + Byte.toString(jsonIpDscp)); + return false; + } + return true; + } + + /** + * Matches an IP ECN criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPEcnCriterion criterion) { + final byte ipEcn = criterion.ipEcn(); + final byte jsonIpEcn = (byte) jsonCriterion.get("ipEcn").shortValue(); + if (ipEcn != jsonIpEcn) { + description.appendText("IP ECN was " + Byte.toString(jsonIpEcn)); + return false; + } + return true; + } + + /** + * Matches an IP protocol criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPProtocolCriterion criterion) { + final short protocol = criterion.protocol(); + final short jsonProtocol = jsonCriterion.get("protocol").shortValue(); + if (protocol != jsonProtocol) { + description.appendText("protocol was " + + Short.toString(jsonProtocol)); + return false; + } + return true; + } + + /** + * Matches an IP address criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPCriterion criterion) { + final String ip = criterion.ip().toString(); + final String jsonIp = jsonCriterion.get("ip").textValue(); + if (!ip.equals(jsonIp)) { + description.appendText("ip was " + jsonIp); + return false; + } + return true; + } + + /** + * Matches a TCP port criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(TcpPortCriterion criterion) { + final int tcpPort = criterion.tcpPort().toInt(); + final int jsonTcpPort = jsonCriterion.get("tcpPort").intValue(); + if (tcpPort != jsonTcpPort) { + description.appendText("tcp port was " + + Integer.toString(jsonTcpPort)); + return false; + } + return true; + } + + /** + * Matches a UDP port criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(UdpPortCriterion criterion) { + final int udpPort = criterion.udpPort().toInt(); + final int jsonUdpPort = jsonCriterion.get("udpPort").intValue(); + if (udpPort != jsonUdpPort) { + description.appendText("udp port was " + + Integer.toString(jsonUdpPort)); + return false; + } + return true; + } + + /** + * Matches an SCTP port criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(SctpPortCriterion criterion) { + final int sctpPort = criterion.sctpPort().toInt(); + final int jsonSctpPort = jsonCriterion.get("sctpPort").intValue(); + if (sctpPort != jsonSctpPort) { + description.appendText("sctp port was " + + Integer.toString(jsonSctpPort)); + return false; + } + return true; + } + + /** + * Matches an ICMP type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IcmpTypeCriterion criterion) { + final short icmpType = criterion.icmpType(); + final short jsonIcmpType = jsonCriterion.get("icmpType").shortValue(); + if (icmpType != jsonIcmpType) { + description.appendText("icmp type was " + + Short.toString(jsonIcmpType)); + return false; + } + return true; + } + + /** + * Matches an ICMP code criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IcmpCodeCriterion criterion) { + final short icmpCode = criterion.icmpCode(); + final short jsonIcmpCode = jsonCriterion.get("icmpCode").shortValue(); + if (icmpCode != jsonIcmpCode) { + description.appendText("icmp code was " + + Short.toString(jsonIcmpCode)); + return false; + } + return true; + } + + /** + * Matches an IPV6 flow label criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPv6FlowLabelCriterion criterion) { + final int flowLabel = criterion.flowLabel(); + final int jsonFlowLabel = jsonCriterion.get("flowLabel").intValue(); + if (flowLabel != jsonFlowLabel) { + description.appendText("IPv6 flow label was " + + Integer.toString(jsonFlowLabel)); + return false; + } + return true; + } + + /** + * Matches an ICMP V6 type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(Icmpv6TypeCriterion criterion) { + final short icmpv6Type = criterion.icmpv6Type(); + final short jsonIcmpv6Type = + jsonCriterion.get("icmpv6Type").shortValue(); + if (icmpv6Type != jsonIcmpv6Type) { + description.appendText("icmpv6 type was " + + Short.toString(jsonIcmpv6Type)); + return false; + } + return true; + } + + /** + * Matches an IPV6 code criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(Icmpv6CodeCriterion criterion) { + final short icmpv6Code = criterion.icmpv6Code(); + final short jsonIcmpv6Code = + jsonCriterion.get("icmpv6Code").shortValue(); + if (icmpv6Code != jsonIcmpv6Code) { + description.appendText("icmpv6 code was " + + Short.toString(jsonIcmpv6Code)); + return false; + } + return true; + } + + /** + * Matches an IPV6 ND target criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPv6NDTargetAddressCriterion criterion) { + final String targetAddress = + criterion.targetAddress().toString(); + final String jsonTargetAddress = + jsonCriterion.get("targetAddress").textValue(); + if (!targetAddress.equals(jsonTargetAddress)) { + description.appendText("target address was " + + jsonTargetAddress); + return false; + } + return true; + } + + /** + * Matches an IPV6 ND link layer criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPv6NDLinkLayerAddressCriterion criterion) { + final String llAddress = + criterion.mac().toString(); + final String jsonLlAddress = + jsonCriterion.get("mac").textValue(); + if (!llAddress.equals(jsonLlAddress)) { + description.appendText("mac was " + jsonLlAddress); + return false; + } + return true; + } + + /** + * Matches an MPLS label criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(MplsCriterion criterion) { + final int label = criterion.label().toInt(); + final int jsonLabel = jsonCriterion.get("label").intValue(); + if (label != jsonLabel) { + description.appendText("label was " + Integer.toString(jsonLabel)); + return false; + } + return true; + } + + /** + * Matches an IPV6 exthdr criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPv6ExthdrFlagsCriterion criterion) { + final int exthdrFlags = criterion.exthdrFlags(); + final int jsonExthdrFlags = + jsonCriterion.get("exthdrFlags").intValue(); + if (exthdrFlags != jsonExthdrFlags) { + description.appendText("exthdrFlags was " + + Long.toHexString(jsonExthdrFlags)); + return false; + } + return true; + } + + /** + * Matches an Och signal criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(OchSignalCriterion criterion) { + final OchSignal ochSignal = criterion.lambda(); + final JsonNode jsonOchSignal = jsonCriterion.get("ochSignalId"); + String jsonGridType = jsonOchSignal.get("gridType").textValue(); + String jsonChannelSpacing = jsonOchSignal.get("channelSpacing").textValue(); + int jsonSpacingMultiplier = jsonOchSignal.get("spacingMultiplier").intValue(); + int jsonSlotGranularity = jsonOchSignal.get("slotGranularity").intValue(); + + boolean equality = Objects.equals(ochSignal.gridType().name(), jsonGridType) + && Objects.equals(ochSignal.channelSpacing().name(), jsonChannelSpacing) + && Objects.equals(ochSignal.spacingMultiplier(), jsonSpacingMultiplier) + && Objects.equals(ochSignal.slotGranularity(), jsonSlotGranularity); + + if (!equality) { + String joined = Joiner.on(", ") + .join(jsonGridType, jsonChannelSpacing, jsonSpacingMultiplier, jsonSlotGranularity); + + description.appendText("och signal id was " + joined); + return false; + } + return true; + } + + /** + * Matches an Och signal type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(OchSignalTypeCriterion criterion) { + final String signalType = criterion.signalType().name(); + final String jsonSignalType = jsonCriterion.get("ochSignalType").textValue(); + if (!signalType.equals(jsonSignalType)) { + description.appendText("signal type was " + jsonSignalType); + return false; + } + return true; + } + + @Override + public boolean matchesSafely(JsonNode jsonCriterion, + Description description) { + this.description = description; + this.jsonCriterion = jsonCriterion; + final String type = criterion.type().name(); + final String jsonType = jsonCriterion.get("type").asText(); + if (!type.equals(jsonType)) { + description.appendText("type was " + type); + return false; + } + + switch (criterion.type()) { + + case IN_PORT: + case IN_PHY_PORT: + return matchCriterion((PortCriterion) criterion); + + case METADATA: + return matchCriterion((MetadataCriterion) criterion); + + case ETH_DST: + case ETH_SRC: + return matchCriterion((EthCriterion) criterion); + + case ETH_TYPE: + return matchCriterion((EthTypeCriterion) criterion); + + case VLAN_VID: + return matchCriterion((VlanIdCriterion) criterion); + + case VLAN_PCP: + return matchCriterion((VlanPcpCriterion) criterion); + + case IP_DSCP: + return matchCriterion((IPDscpCriterion) criterion); + + case IP_ECN: + return matchCriterion((IPEcnCriterion) criterion); + + case IP_PROTO: + return matchCriterion((IPProtocolCriterion) criterion); + + case IPV4_SRC: + case IPV4_DST: + case IPV6_SRC: + case IPV6_DST: + return matchCriterion((IPCriterion) criterion); + + case TCP_SRC: + case TCP_DST: + return matchCriterion((TcpPortCriterion) criterion); + + case UDP_SRC: + case UDP_DST: + return matchCriterion((UdpPortCriterion) criterion); + + case SCTP_SRC: + case SCTP_DST: + return matchCriterion((SctpPortCriterion) criterion); + + case ICMPV4_TYPE: + return matchCriterion((IcmpTypeCriterion) criterion); + + case ICMPV4_CODE: + return matchCriterion((IcmpCodeCriterion) criterion); + + case IPV6_FLABEL: + return matchCriterion((IPv6FlowLabelCriterion) criterion); + + case ICMPV6_TYPE: + return matchCriterion((Icmpv6TypeCriterion) criterion); + + case ICMPV6_CODE: + return matchCriterion((Icmpv6CodeCriterion) criterion); + + case IPV6_ND_TARGET: + return matchCriterion( + (IPv6NDTargetAddressCriterion) criterion); + + case IPV6_ND_SLL: + case IPV6_ND_TLL: + return matchCriterion( + (IPv6NDLinkLayerAddressCriterion) criterion); + + case MPLS_LABEL: + return matchCriterion((MplsCriterion) criterion); + + case IPV6_EXTHDR: + return matchCriterion( + (IPv6ExthdrFlagsCriterion) criterion); + + case OCH_SIGID: + return matchCriterion((OchSignalCriterion) criterion); + + case OCH_SIGTYPE: + return matchCriterion((OchSignalTypeCriterion) criterion); + + default: + // Don't know how to format this type + description.appendText("unknown criterion type " + + criterion.type()); + return false; + } + } + + @Override + public void describeTo(Description description) { + description.appendText(criterion.toString()); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.java new file mode 100644 index 00000000..c7196e8b --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.codec.impl; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.is; +import static org.onosproject.codec.impl.JsonCodecUtils.assertJsonEncodable; + +import org.junit.Test; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.Device; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.device.DeviceServiceAdapter; + +/** + * Unit test for DeviceCodec. + */ +public class DeviceCodecTest { + + private Device device = new DefaultDevice(JsonCodecUtils.PID, + JsonCodecUtils.DID1, + Device.Type.SWITCH, + JsonCodecUtils.MFR, + JsonCodecUtils.HW, + JsonCodecUtils.SW1, + JsonCodecUtils.SN, + JsonCodecUtils.CID, + JsonCodecUtils.A1); + + + + @Test + public void deviceCodecTest() { + final MockCodecContext context = new MockCodecContext(); + context.registerService(DeviceService.class, new DeviceServiceAdapter()); + final JsonCodec<Device> codec = context.codec(Device.class); + assertThat(codec, is(notNullValue())); + final Device pojoIn = device; + + assertJsonEncodable(context, codec, pojoIn); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java new file mode 100644 index 00000000..a1c95176 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + + +import java.util.Map; + +import org.junit.Test; +import org.onosproject.net.driver.Behaviour; +import org.onosproject.net.driver.DefaultDriver; +import org.onosproject.net.driver.Driver; +import org.onosproject.net.driver.TestBehaviour; +import org.onosproject.net.driver.TestBehaviourImpl; +import org.onosproject.net.driver.TestBehaviourTwo; +import org.onosproject.net.driver.TestBehaviourTwoImpl; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableMap; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.onosproject.codec.impl.DriverJsonMatcher.matchesDriver; + +/** + * Unit tests for the driver codec. + */ +public class DriverCodecTest { + + @Test + public void codecTest() { + Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours = + ImmutableMap.of(TestBehaviour.class, + TestBehaviourImpl.class, + TestBehaviourTwo.class, + TestBehaviourTwoImpl.class); + Map<String, String> properties = + ImmutableMap.of("key1", "value1", "key2", "value2"); + + DefaultDriver parent = new DefaultDriver("parent", null, "Acme", + "HW1.2.3", "SW1.2.3", + behaviours, + properties); + DefaultDriver child = new DefaultDriver("child", parent, "Acme", + "HW1.2.3.1", "SW1.2.3.1", + behaviours, + properties); + + MockCodecContext context = new MockCodecContext(); + ObjectNode driverJson = context.codec(Driver.class).encode(child, context); + + assertThat(driverJson, matchesDriver(child)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverJsonMatcher.java new file mode 100644 index 00000000..6f0070e5 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverJsonMatcher.java @@ -0,0 +1,118 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import java.util.Map; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.driver.Driver; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for drivers. + */ +public final class DriverJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { + private final Driver driver; + + private DriverJsonMatcher(Driver driver) { + this.driver = driver; + } + + @Override + public boolean matchesSafely(JsonNode jsonDriver, Description description) { + // check id + String jsonDriverName = jsonDriver.get("name").asText(); + String driverName = driver.name(); + if (!jsonDriverName.equals(driverName)) { + description.appendText("name was " + jsonDriverName); + return false; + } + + + // check parent + String jsonParent = jsonDriver.get("parent").asText(); + String parent = driver.parent().name(); + if (!jsonParent.equals(parent)) { + description.appendText("parent was " + jsonParent); + return false; + } + + // check manufacturer + String jsonManufacturer = jsonDriver.get("manufacturer").asText(); + String manufacturer = driver.manufacturer(); + if (!jsonManufacturer.equals(manufacturer)) { + description.appendText("manufacturer was " + jsonManufacturer); + return false; + } + + // check HW version + String jsonHWVersion = jsonDriver.get("hwVersion").asText(); + String hwVersion = driver.hwVersion(); + if (!jsonHWVersion.equals(hwVersion)) { + description.appendText("HW version was " + jsonHWVersion); + return false; + } + + // check SW version + String jsonSWVersion = jsonDriver.get("swVersion").asText(); + String swVersion = driver.swVersion(); + if (!jsonSWVersion.equals(swVersion)) { + description.appendText("SW version was " + jsonSWVersion); + return false; + } + + // Check properties + JsonNode jsonProperties = jsonDriver.get("properties"); + if (driver.properties().size() != jsonProperties.size()) { + description.appendText("properties map size was was " + jsonProperties.size()); + return false; + } + for (Map.Entry<String, String> entry : driver.properties().entrySet()) { + boolean propertyFound = false; + for (int propertyIndex = 0; propertyIndex < jsonProperties.size(); propertyIndex++) { + String jsonName = jsonProperties.get(propertyIndex).get("name").asText(); + String jsonValue = jsonProperties.get(propertyIndex).get("value").asText(); + if (!jsonName.equals(entry.getKey()) || + !jsonValue.equals(entry.getValue())) { + propertyFound = true; + break; + } + } + if (!propertyFound) { + description.appendText("property not found " + entry.getKey()); + return false; + } + } + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(driver.toString()); + } + + /** + * Factory to allocate a driver matcher. + * + * @param driver driver object we are looking for + * @return matcher + */ + public static DriverJsonMatcher matchesDriver(Driver driver) { + return new DriverJsonMatcher(driver); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetCodecTest.java new file mode 100644 index 00000000..847b0d09 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetCodecTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.junit.Test; +import org.onlab.packet.Ethernet; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.EthernetJsonMatcher.matchesEthernet; + +/** + * Unit test for Ethernet class codec. + */ +public class EthernetCodecTest { + + /** + * Unit test for the ethernet object codec. + */ + @Test + public void ethernetCodecTest() { + final CodecContext context = new MockCodecContext(); + final JsonCodec<Ethernet> ethernetCodec = context.codec(Ethernet.class); + assertThat(ethernetCodec, notNullValue()); + + final Ethernet eth1 = new Ethernet(); + eth1.setSourceMACAddress("11:22:33:44:55:01"); + eth1.setDestinationMACAddress("11:22:33:44:55:02"); + eth1.setPad(true); + eth1.setEtherType(Ethernet.TYPE_ARP); + eth1.setPriorityCode((byte) 7); + eth1.setVlanID((short) 33); + + final ObjectNode eth1Json = ethernetCodec.encode(eth1, context); + assertThat(eth1Json, notNullValue()); + assertThat(eth1Json, matchesEthernet(eth1)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetJsonMatcher.java new file mode 100644 index 00000000..c5827b91 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetJsonMatcher.java @@ -0,0 +1,122 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; +import org.onlab.packet.Ethernet; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for ethernet objects. + */ +public final class EthernetJsonMatcher extends TypeSafeMatcher<JsonNode> { + + private final Ethernet ethernet; + private String reason = ""; + + private EthernetJsonMatcher(Ethernet ethernetValue) { + ethernet = ethernetValue; + } + + @Override + public boolean matchesSafely(JsonNode jsonEthernet) { + + // check source MAC + final JsonNode jsonSourceMacNode = jsonEthernet.get("srcMac"); + if (ethernet.getSourceMAC() != null) { + final String jsonSourceMac = jsonSourceMacNode.textValue(); + final String sourceMac = ethernet.getSourceMAC().toString(); + if (!jsonSourceMac.equals(sourceMac)) { + reason = "source MAC " + ethernet.getSourceMAC().toString(); + return false; + } + } else { + // source MAC not specified, JSON representation must be empty + if (jsonSourceMacNode != null) { + reason = "source mac should be null "; + return false; + } + } + + // check destination MAC + final JsonNode jsonDestinationMacNode = jsonEthernet.get("destMac"); + if (ethernet.getDestinationMAC() != null) { + final String jsonDestinationMac = jsonDestinationMacNode.textValue(); + final String destinationMac = ethernet.getDestinationMAC().toString(); + if (!jsonDestinationMac.equals(destinationMac)) { + reason = "destination MAC " + ethernet.getDestinationMAC().toString(); + return false; + } + } else { + // destination MAC not specified, JSON representation must be empty + if (jsonDestinationMacNode != null) { + reason = "destination mac should be null "; + return false; + } + } + + // check priority code + final short jsonPriorityCode = jsonEthernet.get("priorityCode").shortValue(); + final short priorityCode = ethernet.getPriorityCode(); + if (jsonPriorityCode != priorityCode) { + reason = "priority code " + Short.toString(ethernet.getPriorityCode()); + return false; + } + + // check vlanId + final short jsonVlanId = jsonEthernet.get("vlanId").shortValue(); + final short vlanId = ethernet.getVlanID(); + if (jsonVlanId != vlanId) { + reason = "vlan id " + Short.toString(ethernet.getVlanID()); + return false; + } + + // check etherType + final short jsonEtherType = jsonEthernet.get("etherType").shortValue(); + final short etherType = ethernet.getEtherType(); + if (jsonEtherType != etherType) { + reason = "etherType " + Short.toString(ethernet.getEtherType()); + return false; + } + + // check pad + final boolean jsonPad = jsonEthernet.get("pad").asBoolean(); + final boolean pad = ethernet.isPad(); + if (jsonPad != pad) { + reason = "pad " + Boolean.toString(ethernet.isPad()); + return false; + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(reason); + } + + /** + * Factory to allocate a ethernet matcher. + * + * @param ethernet ethernet object we are looking for + * @return matcher + */ + public static EthernetJsonMatcher matchesEthernet(Ethernet ethernet) { + return new EthernetJsonMatcher(ethernet); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java new file mode 100644 index 00000000..6c88ac1e --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java @@ -0,0 +1,546 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.EthType; +import org.onlab.packet.Ethernet; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.VlanId; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.CoreService; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.Lambda; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.IPDscpCriterion; +import org.onosproject.net.flow.criteria.IPEcnCriterion; +import org.onosproject.net.flow.criteria.IPProtocolCriterion; +import org.onosproject.net.flow.criteria.IPv6ExthdrFlagsCriterion; +import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion; +import org.onosproject.net.flow.criteria.IPv6NDLinkLayerAddressCriterion; +import org.onosproject.net.flow.criteria.IPv6NDTargetAddressCriterion; +import org.onosproject.net.flow.criteria.IcmpCodeCriterion; +import org.onosproject.net.flow.criteria.IcmpTypeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion; +import org.onosproject.net.flow.criteria.IndexedLambdaCriterion; +import org.onosproject.net.flow.criteria.MplsCriterion; +import org.onosproject.net.flow.criteria.OchSignalCriterion; +import org.onosproject.net.flow.criteria.PortCriterion; +import org.onosproject.net.flow.criteria.SctpPortCriterion; +import org.onosproject.net.flow.criteria.TcpPortCriterion; +import org.onosproject.net.flow.criteria.TunnelIdCriterion; +import org.onosproject.net.flow.criteria.UdpPortCriterion; +import org.onosproject.net.flow.criteria.VlanIdCriterion; +import org.onosproject.net.flow.criteria.VlanPcpCriterion; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction; +import org.onosproject.net.flow.instructions.L4ModificationInstruction; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.net.NetTestTools.APP_ID; + +/** + * Flow rule codec unit tests. + */ +public class FlowRuleCodecTest { + + MockCodecContext context; + JsonCodec<FlowRule> flowRuleCodec; + final CoreService mockCoreService = createMock(CoreService.class); + + /** + * Sets up for each test. Creates a context and fetches the flow rule + * codec. + */ + @Before + public void setUp() { + context = new MockCodecContext(); + flowRuleCodec = context.codec(FlowRule.class); + assertThat(flowRuleCodec, notNullValue()); + + expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID)) + .andReturn(APP_ID).anyTimes(); + replay(mockCoreService); + context.registerService(CoreService.class, mockCoreService); + } + + /** + * Reads in a rule from the given resource and decodes it. + * + * @param resourceName resource to use to read the JSON for the rule + * @return decoded flow rule + * @throws IOException if processing the resource fails + */ + private FlowRule getRule(String resourceName) throws IOException { + InputStream jsonStream = FlowRuleCodecTest.class + .getResourceAsStream(resourceName); + JsonNode json = context.mapper().readTree(jsonStream); + assertThat(json, notNullValue()); + FlowRule rule = flowRuleCodec.decode((ObjectNode) json, context); + assertThat(rule, notNullValue()); + return rule; + } + + /** + * Checks that the data shared by all the resources is correct for a + * given rule. + * + * @param rule rule to check + */ + private void checkCommonData(FlowRule rule) { + assertThat(rule.appId(), is(APP_ID.id())); + assertThat(rule.isPermanent(), is(false)); + assertThat(rule.timeout(), is(1)); + assertThat(rule.priority(), is(1)); + assertThat(rule.deviceId().toString(), is("of:0000000000000001")); + } + + /** + * Checks that a simple rule decodes properly. + * + * @throws IOException if the resource cannot be processed + */ + @Test + public void codecSimpleFlowTest() throws IOException { + FlowRule rule = getRule("simple-flow.json"); + + checkCommonData(rule); + + assertThat(rule.selector().criteria().size(), is(1)); + Criterion criterion1 = rule.selector().criteria().iterator().next(); + assertThat(criterion1.type(), is(Criterion.Type.ETH_TYPE)); + assertThat(((EthTypeCriterion) criterion1).ethType(), is(new EthType(2054))); + + assertThat(rule.treatment().allInstructions().size(), is(1)); + Instruction instruction1 = rule.treatment().allInstructions().get(0); + assertThat(instruction1.type(), is(Instruction.Type.OUTPUT)); + assertThat(((Instructions.OutputInstruction) instruction1).port(), is(PortNumber.CONTROLLER)); + } + + SortedMap<String, Instruction> instructions = new TreeMap<>(); + + /** + * Looks up an instruction in the instruction map based on type and subtype. + * + * @param type type string + * @param subType subtype string + * @return instruction that matches + */ + private Instruction getInstruction(Instruction.Type type, String subType) { + Instruction instruction = instructions.get(type.name() + "/" + subType); + assertThat(instruction, notNullValue()); + assertThat(instruction.type(), is(type)); + return instruction; + } + + /** + * Checks that a rule with one of each instruction type decodes properly. + * + * @throws IOException if the resource cannot be processed + */ + @Test + public void decodeInstructionsFlowTest() throws Exception { + FlowRule rule = getRule("instructions-flow.json"); + + checkCommonData(rule); + + rule.treatment().allInstructions() + .stream() + .forEach(instruction -> + { + String subType; + if (instruction.type() == Instruction.Type.L0MODIFICATION) { + subType = ((L0ModificationInstruction) instruction) + .subtype().name(); + } else if (instruction.type() == Instruction.Type.L2MODIFICATION) { + subType = ((L2ModificationInstruction) instruction) + .subtype().name(); + } else if (instruction.type() == Instruction.Type.L3MODIFICATION) { + subType = ((L3ModificationInstruction) instruction) + .subtype().name(); + } else if (instruction.type() == Instruction.Type.L4MODIFICATION) { + subType = ((L4ModificationInstruction) instruction) + .subtype().name(); + } else { + subType = ""; + } + instructions.put( + instruction.type().name() + "/" + subType, instruction); + }); + + assertThat(rule.treatment().allInstructions().size(), is(24)); + + Instruction instruction; + + instruction = getInstruction(Instruction.Type.OUTPUT, ""); + assertThat(instruction.type(), is(Instruction.Type.OUTPUT)); + assertThat(((Instructions.OutputInstruction) instruction).port(), is(PortNumber.CONTROLLER)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.ETH_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModEtherInstruction) instruction).mac(), + is(MacAddress.valueOf("12:34:56:78:90:12"))); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.ETH_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModEtherInstruction) instruction).mac(), + is(MacAddress.valueOf("98:76:54:32:01:00"))); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.VLAN_ID.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModVlanIdInstruction) instruction).vlanId().toShort(), + is((short) 22)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.VLAN_PCP.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModVlanPcpInstruction) instruction).vlanPcp(), + is((byte) 1)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.MPLS_LABEL.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModMplsLabelInstruction) instruction) + .mplsLabel().toInt(), + is(MplsLabel.MAX_MPLS)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.MPLS_PUSH.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.PushHeaderInstructions) instruction) + .ethernetType().toShort(), + is(Ethernet.MPLS_UNICAST)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.MPLS_POP.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.PushHeaderInstructions) instruction) + .ethernetType().toShort(), + is(Ethernet.MPLS_UNICAST)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(instruction, instanceOf(L2ModificationInstruction.ModMplsTtlInstruction.class)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.VLAN_POP.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(instruction, instanceOf(L2ModificationInstruction.PopVlanInstruction.class)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.VLAN_PUSH.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(instruction, instanceOf(L2ModificationInstruction.PushHeaderInstructions.class)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.TUNNEL_ID.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModTunnelIdInstruction) instruction) + .tunnelId(), is(100L)); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV4_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(), + is(IpAddress.valueOf("1.2.3.4"))); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV4_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(), + is(IpAddress.valueOf("1.2.3.3"))); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV6_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(), + is(IpAddress.valueOf("1.2.3.2"))); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV6_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(), + is(IpAddress.valueOf("1.2.3.1"))); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV6_FLABEL.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPv6FlowLabelInstruction) instruction) + .flowLabel(), + is(8)); + + instruction = getInstruction(Instruction.Type.L0MODIFICATION, + L0ModificationInstruction.L0SubType.LAMBDA.name()); + assertThat(instruction.type(), is(Instruction.Type.L0MODIFICATION)); + assertThat(((L0ModificationInstruction.ModLambdaInstruction) instruction) + .lambda(), + is((short) 7)); + + instruction = getInstruction(Instruction.Type.L0MODIFICATION, + L0ModificationInstruction.L0SubType.OCH.name()); + assertThat(instruction.type(), is(Instruction.Type.L0MODIFICATION)); + L0ModificationInstruction.ModOchSignalInstruction och = + (L0ModificationInstruction.ModOchSignalInstruction) instruction; + assertThat(och.lambda().spacingMultiplier(), is(4)); + assertThat(och.lambda().slotGranularity(), is(8)); + assertThat(och.lambda().gridType(), is(GridType.DWDM)); + assertThat(och.lambda().channelSpacing(), is(ChannelSpacing.CHL_100GHZ)); + + instruction = getInstruction(Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.L4SubType.TCP_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L4MODIFICATION)); + assertThat(((L4ModificationInstruction.ModTransportPortInstruction) instruction) + .port().toInt(), is(40001)); + + instruction = getInstruction(Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.L4SubType.TCP_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L4MODIFICATION)); + assertThat(((L4ModificationInstruction.ModTransportPortInstruction) instruction) + .port().toInt(), is(40002)); + + instruction = getInstruction(Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.L4SubType.UDP_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L4MODIFICATION)); + assertThat(((L4ModificationInstruction.ModTransportPortInstruction) instruction) + .port().toInt(), is(40003)); + + instruction = getInstruction(Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.L4SubType.UDP_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L4MODIFICATION)); + assertThat(((L4ModificationInstruction.ModTransportPortInstruction) instruction) + .port().toInt(), is(40004)); + } + + SortedMap<String, Criterion> criteria = new TreeMap<>(); + + /** + * Looks up a criterion in the instruction map based on type and subtype. + * + * @param type type string + * @return criterion that matches + */ + private Criterion getCriterion(Criterion.Type type) { + Criterion criterion = criteria.get(type.name()); + assertThat(criterion.type(), is(type)); + return criterion; + } + + /** + * Checks that a rule with one of each kind of criterion decodes properly. + * + * @throws IOException if the resource cannot be processed + */ + @Test + public void codecCriteriaFlowTest() throws Exception { + FlowRule rule = getRule("criteria-flow.json"); + + checkCommonData(rule); + + assertThat(rule.selector().criteria().size(), is(33)); + + rule.selector().criteria() + .stream() + .forEach(criterion -> + criteria.put(criterion.type().name(), criterion)); + + Criterion criterion; + + criterion = getCriterion(Criterion.Type.ETH_TYPE); + assertThat(((EthTypeCriterion) criterion).ethType(), is(new EthType(2054))); + + criterion = getCriterion(Criterion.Type.ETH_DST); + assertThat(((EthCriterion) criterion).mac(), + is(MacAddress.valueOf("00:11:22:33:44:55"))); + + criterion = getCriterion(Criterion.Type.ETH_SRC); + assertThat(((EthCriterion) criterion).mac(), + is(MacAddress.valueOf("00:11:22:33:44:55"))); + + criterion = getCriterion(Criterion.Type.IN_PORT); + assertThat(((PortCriterion) criterion).port(), + is(PortNumber.portNumber(23))); + + criterion = getCriterion(Criterion.Type.IN_PHY_PORT); + assertThat(((PortCriterion) criterion).port(), + is(PortNumber.portNumber(44))); + + criterion = getCriterion(Criterion.Type.VLAN_VID); + assertThat(((VlanIdCriterion) criterion).vlanId(), + is(VlanId.vlanId((short) 777))); + + criterion = getCriterion(Criterion.Type.VLAN_PCP); + assertThat(((VlanPcpCriterion) criterion).priority(), + is(((byte) 3))); + + criterion = getCriterion(Criterion.Type.IP_DSCP); + assertThat(((IPDscpCriterion) criterion).ipDscp(), + is(((byte) 2))); + + criterion = getCriterion(Criterion.Type.IP_ECN); + assertThat(((IPEcnCriterion) criterion).ipEcn(), + is(((byte) 1))); + + criterion = getCriterion(Criterion.Type.IP_PROTO); + assertThat(((IPProtocolCriterion) criterion).protocol(), + is(((short) 4))); + + criterion = getCriterion(Criterion.Type.IPV4_SRC); + assertThat(((IPCriterion) criterion).ip(), + is((IpPrefix.valueOf("1.2.0.0/32")))); + + criterion = getCriterion(Criterion.Type.IPV4_DST); + assertThat(((IPCriterion) criterion).ip(), + is((IpPrefix.valueOf("2.2.0.0/32")))); + + criterion = getCriterion(Criterion.Type.IPV6_SRC); + assertThat(((IPCriterion) criterion).ip(), + is((IpPrefix.valueOf("3.2.0.0/32")))); + + criterion = getCriterion(Criterion.Type.IPV6_DST); + assertThat(((IPCriterion) criterion).ip(), + is((IpPrefix.valueOf("4.2.0.0/32")))); + + criterion = getCriterion(Criterion.Type.TCP_SRC); + assertThat(((TcpPortCriterion) criterion).tcpPort().toInt(), + is(80)); + + criterion = getCriterion(Criterion.Type.TCP_DST); + assertThat(((TcpPortCriterion) criterion).tcpPort().toInt(), + is(443)); + + criterion = getCriterion(Criterion.Type.UDP_SRC); + assertThat(((UdpPortCriterion) criterion).udpPort().toInt(), + is(180)); + + criterion = getCriterion(Criterion.Type.UDP_DST); + assertThat(((UdpPortCriterion) criterion).udpPort().toInt(), + is(1443)); + + criterion = getCriterion(Criterion.Type.SCTP_SRC); + assertThat(((SctpPortCriterion) criterion).sctpPort().toInt(), + is(280)); + + criterion = getCriterion(Criterion.Type.SCTP_DST); + assertThat(((SctpPortCriterion) criterion).sctpPort().toInt(), + is(2443)); + + criterion = getCriterion(Criterion.Type.ICMPV4_TYPE); + assertThat(((IcmpTypeCriterion) criterion).icmpType(), + is((short) 24)); + + criterion = getCriterion(Criterion.Type.ICMPV4_CODE); + assertThat(((IcmpCodeCriterion) criterion).icmpCode(), + is((short) 16)); + + criterion = getCriterion(Criterion.Type.ICMPV6_TYPE); + assertThat(((Icmpv6TypeCriterion) criterion).icmpv6Type(), + is((short) 14)); + + criterion = getCriterion(Criterion.Type.ICMPV6_CODE); + assertThat(((Icmpv6CodeCriterion) criterion).icmpv6Code(), + is((short) 6)); + + criterion = getCriterion(Criterion.Type.IPV6_FLABEL); + assertThat(((IPv6FlowLabelCriterion) criterion).flowLabel(), + is(8)); + + criterion = getCriterion(Criterion.Type.IPV6_ND_TARGET); + assertThat(((IPv6NDTargetAddressCriterion) criterion) + .targetAddress().toString(), + is("1111:2222:3333:4444:5555:6666:7777:8888")); + + criterion = getCriterion(Criterion.Type.IPV6_ND_SLL); + assertThat(((IPv6NDLinkLayerAddressCriterion) criterion).mac(), + is(MacAddress.valueOf("00:11:22:33:44:56"))); + + criterion = getCriterion(Criterion.Type.IPV6_ND_TLL); + assertThat(((IPv6NDLinkLayerAddressCriterion) criterion).mac(), + is(MacAddress.valueOf("00:11:22:33:44:57"))); + + criterion = getCriterion(Criterion.Type.MPLS_LABEL); + assertThat(((MplsCriterion) criterion).label(), + is(MplsLabel.mplsLabel(123))); + + criterion = getCriterion(Criterion.Type.IPV6_EXTHDR); + assertThat(((IPv6ExthdrFlagsCriterion) criterion).exthdrFlags(), + is(99)); + + criterion = getCriterion(Criterion.Type.OCH_SIGID); + assertThat(((IndexedLambdaCriterion) criterion).lambda(), + is(Lambda.indexedLambda(122))); + + criterion = getCriterion(Criterion.Type.TUNNEL_ID); + assertThat(((TunnelIdCriterion) criterion).tunnelId(), + is(100L)); + } + + /** + * Checks that a rule with a SigId criterion decodes properly. + * + * @throws IOException if the resource cannot be processed + */ + @Test + public void codecSigIdCriteriaFlowTest() throws Exception { + FlowRule rule = getRule("sigid-flow.json"); + + checkCommonData(rule); + + assertThat(rule.selector().criteria().size(), is(1)); + Criterion criterion = rule.selector().criteria().iterator().next(); + assertThat(criterion.type(), is(Criterion.Type.OCH_SIGID)); + Lambda lambda = ((OchSignalCriterion) criterion).lambda(); + assertThat(lambda, instanceOf(OchSignal.class)); + OchSignal ochSignal = (OchSignal) lambda; + assertThat(ochSignal.spacingMultiplier(), is(3)); + assertThat(ochSignal.slotGranularity(), is(4)); + assertThat(ochSignal.gridType(), is(GridType.CWDM)); + assertThat(ochSignal.channelSpacing(), is(ChannelSpacing.CHL_25GHZ)); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupBucketJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupBucketJsonMatcher.java new file mode 100644 index 00000000..b3056216 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupBucketJsonMatcher.java @@ -0,0 +1,87 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.group.GroupBucket; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for instructions. + */ +public final class GroupBucketJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { + + private final GroupBucket bucket; + + private GroupBucketJsonMatcher(GroupBucket bucket) { + this.bucket = bucket; + } + + /** + * Matches the contents of a group bucket. + * + * @param bucketJson JSON representation of bucket to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + @Override + public boolean matchesSafely(JsonNode bucketJson, Description description) { + + // check type + final String jsonType = bucketJson.get("type").textValue(); + if (!bucket.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final long jsonWeight = bucketJson.get("weight").longValue(); + if (bucket.weight() != jsonWeight) { + description.appendText("weight was " + jsonWeight); + return false; + } + + final long packetsJson = bucketJson.get("packets").asLong(); + if (bucket.packets() != packetsJson) { + description.appendText("packets was " + packetsJson); + return false; + } + + final long bytesJson = bucketJson.get("bytes").asLong(); + if (bucket.bytes() != bytesJson) { + description.appendText("bytes was " + packetsJson); + return false; + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(bucket.toString()); + } + + /** + * Factory to allocate an bucket matcher. + * + * @param bucket bucket object we are looking for + * @return matcher + */ + public static GroupBucketJsonMatcher matchesGroupBucket(GroupBucket bucket) { + return new GroupBucketJsonMatcher(bucket); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupCodecTest.java new file mode 100644 index 00000000..409f8eb3 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupCodecTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.junit.Test; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.group.DefaultGroup; +import org.onosproject.net.group.DefaultGroupBucket; +import org.onosproject.net.group.GroupBucket; +import org.onosproject.net.group.GroupBuckets; +import org.onosproject.net.group.GroupDescription; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableList; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.onosproject.codec.impl.GroupJsonMatcher.matchesGroup; + +/** + * Group codec unit tests. + */ + +public class GroupCodecTest { + + @Test + public void codecTest() { + GroupBucket bucket1 = DefaultGroupBucket + .createSelectGroupBucket(DefaultTrafficTreatment.emptyTreatment()); + GroupBucket bucket2 = DefaultGroupBucket + .createIndirectGroupBucket(DefaultTrafficTreatment.emptyTreatment()); + GroupBuckets buckets = new GroupBuckets(ImmutableList.of(bucket1, bucket2)); + + + DefaultGroup group = new DefaultGroup( + new DefaultGroupId(1), + NetTestTools.did("d1"), + GroupDescription.Type.INDIRECT, + buckets); + + MockCodecContext context = new MockCodecContext(); + GroupCodec codec = new GroupCodec(); + ObjectNode groupJson = codec.encode(group, context); + + assertThat(groupJson, matchesGroup(group)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupJsonMatcher.java new file mode 100644 index 00000000..0e62c305 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupJsonMatcher.java @@ -0,0 +1,120 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.GroupBucket; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for groups. + */ + +public final class GroupJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { + + private final Group group; + + private GroupJsonMatcher(Group group) { + this.group = group; + } + + @Override + public boolean matchesSafely(JsonNode jsonGroup, Description description) { + // check id + String jsonGroupId = jsonGroup.get("id").asText(); + String groupId = group.id().toString(); + if (!jsonGroupId.equals(groupId)) { + description.appendText("group id was " + jsonGroupId); + return false; + } + + // check state + String jsonState = jsonGroup.get("state").asText(); + String state = group.state().toString(); + if (!jsonState.equals(state)) { + description.appendText("state was " + jsonState); + return false; + } + + // check life + long jsonLife = jsonGroup.get("life").asLong(); + long life = group.life(); + if (life != jsonLife) { + description.appendText("life was " + jsonLife); + return false; + } + + // check bytes + long jsonBytes = jsonGroup.get("bytes").asLong(); + long bytes = group.bytes(); + if (bytes != jsonBytes) { + description.appendText("bytes was " + jsonBytes); + return false; + } + + // check packets + long jsonPackets = jsonGroup.get("packets").asLong(); + long packets = group.packets(); + if (packets != jsonPackets) { + description.appendText("packets was " + jsonPackets); + return false; + } + + // check size of bucket array + JsonNode jsonBuckets = jsonGroup.get("buckets"); + if (jsonBuckets.size() != group.buckets().buckets().size()) { + description.appendText("buckets size was " + jsonBuckets.size()); + return false; + } + + // Check buckets + for (GroupBucket bucket : group.buckets().buckets()) { + boolean bucketFound = false; + for (int bucketIndex = 0; bucketIndex < jsonBuckets.size(); bucketIndex++) { + GroupBucketJsonMatcher bucketMatcher = + GroupBucketJsonMatcher.matchesGroupBucket(bucket); + if (bucketMatcher.matches(jsonBuckets.get(bucketIndex))) { + bucketFound = true; + break; + } + } + if (!bucketFound) { + description.appendText("bucket not found " + bucket.toString()); + return false; + } + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(group.toString()); + } + + /** + * Factory to allocate a group matcher. + * + * @param group group object we are looking for + * @return matcher + */ + public static GroupJsonMatcher matchesGroup(Group group) { + return new GroupJsonMatcher(group); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ImmutableCodecsTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ImmutableCodecsTest.java new file mode 100644 index 00000000..2081fa58 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ImmutableCodecsTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.junit.Test; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; + +/** + * Tests to assure that the codec classes follow the contract of having + * no local context. + */ +public class ImmutableCodecsTest { + + /** + * Checks that the codec classes adhere to the contract that there cannot + * be any local context in a codec. + */ + @Test + public void checkImmutability() { + assertThatClassIsImmutableBaseClass(AnnotatedCodec.class); + assertThatClassIsImmutable(AnnotationsCodec.class); + assertThatClassIsImmutable(ApplicationCodec.class); + assertThatClassIsImmutable(ConnectivityIntentCodec.class); + assertThatClassIsImmutable(ConnectPointCodec.class); + assertThatClassIsImmutable(ConstraintCodec.class); + assertThatClassIsImmutable(EncodeConstraintCodecHelper.class); + assertThatClassIsImmutable(DecodeConstraintCodecHelper.class); + assertThatClassIsImmutable(CriterionCodec.class); + assertThatClassIsImmutable(EncodeCriterionCodecHelper.class); + assertThatClassIsImmutable(DecodeCriterionCodecHelper.class); + assertThatClassIsImmutable(DeviceCodec.class); + assertThatClassIsImmutable(EthernetCodec.class); + assertThatClassIsImmutable(FlowEntryCodec.class); + assertThatClassIsImmutable(HostCodec.class); + assertThatClassIsImmutable(HostLocationCodec.class); + assertThatClassIsImmutable(HostToHostIntentCodec.class); + assertThatClassIsImmutable(InstructionCodec.class); + assertThatClassIsImmutable(EncodeInstructionCodecHelper.class); + assertThatClassIsImmutable(DecodeInstructionCodecHelper.class); + assertThatClassIsImmutable(IntentCodec.class); + assertThatClassIsImmutable(LinkCodec.class); + assertThatClassIsImmutable(PathCodec.class); + assertThatClassIsImmutable(PointToPointIntentCodec.class); + assertThatClassIsImmutable(PortCodec.class); + assertThatClassIsImmutable(TopologyClusterCodec.class); + assertThatClassIsImmutable(TopologyCodec.class); + assertThatClassIsImmutable(TrafficSelectorCodec.class); + assertThatClassIsImmutable(TrafficTreatmentCodec.class); + assertThatClassIsImmutable(FlowRuleCodec.class); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java new file mode 100644 index 00000000..bafbc0f1 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java @@ -0,0 +1,247 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.VlanId; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.IndexedLambda; +import org.onosproject.net.Lambda; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.net.flow.instructions.L0ModificationInstruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.InstructionJsonMatcher.matchesInstruction; + +/** + * Unit tests for Instruction codec. + */ +public class InstructionCodecTest { + CodecContext context; + JsonCodec<Instruction> instructionCodec; + + /** + * Sets up for each test. Creates a context and fetches the instruction + * codec. + */ + @Before + public void setUp() { + context = new MockCodecContext(); + instructionCodec = context.codec(Instruction.class); + assertThat(instructionCodec, notNullValue()); + } + + /** + * Tests the encoding of push header instructions. + */ + @Test + public void pushHeaderInstructionsTest() { + final L2ModificationInstruction.PushHeaderInstructions instruction = + (L2ModificationInstruction.PushHeaderInstructions) Instructions.pushMpls(); + final ObjectNode instructionJson = instructionCodec.encode(instruction, context); + + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of drop instructions. + */ + @Test + public void dropInstructionTest() { + final Instructions.DropInstruction instruction = + Instructions.createDrop(); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of output instructions. + */ + @Test + public void outputInstructionTest() { + final Instructions.OutputInstruction instruction = + Instructions.createOutput(PortNumber.portNumber(22)); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod lambda instructions. + */ + @Test + public void modLambdaInstructionTest() { + final L0ModificationInstruction.ModLambdaInstruction instruction = + (L0ModificationInstruction.ModLambdaInstruction) + Instructions.modL0Lambda(new IndexedLambda(55)); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod OCh signal instructions. + */ + @Test + public void modOchSignalInstructionTest() { + L0ModificationInstruction.ModOchSignalInstruction instruction = + (L0ModificationInstruction.ModOchSignalInstruction) + Instructions.modL0Lambda(Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8)); + ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod ether instructions. + */ + @Test + public void modEtherInstructionTest() { + final L2ModificationInstruction.ModEtherInstruction instruction = + (L2ModificationInstruction.ModEtherInstruction) + Instructions.modL2Src(MacAddress.valueOf("11:22:33:44:55:66")); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod vlan id instructions. + */ + @Test + public void modVlanIdInstructionTest() { + final L2ModificationInstruction.ModVlanIdInstruction instruction = + (L2ModificationInstruction.ModVlanIdInstruction) + Instructions.modVlanId(VlanId.vlanId((short) 12)); + + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod vlan pcp instructions. + */ + @Test + public void modVlanPcpInstructionTest() { + final L2ModificationInstruction.ModVlanPcpInstruction instruction = + (L2ModificationInstruction.ModVlanPcpInstruction) + Instructions.modVlanPcp((byte) 9); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv4 src instructions. + */ + @Test + public void modIPSrcInstructionTest() { + final Ip4Address ip = Ip4Address.valueOf("1.2.3.4"); + final L3ModificationInstruction.ModIPInstruction instruction = + (L3ModificationInstruction.ModIPInstruction) + Instructions.modL3Src(ip); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv4 dst instructions. + */ + @Test + public void modIPDstInstructionTest() { + final Ip4Address ip = Ip4Address.valueOf("1.2.3.4"); + final L3ModificationInstruction.ModIPInstruction instruction = + (L3ModificationInstruction.ModIPInstruction) + Instructions.modL3Dst(ip); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv6 src instructions. + */ + @Test + public void modIPv6SrcInstructionTest() { + final Ip6Address ip = Ip6Address.valueOf("1111::2222"); + final L3ModificationInstruction.ModIPInstruction instruction = + (L3ModificationInstruction.ModIPInstruction) + Instructions.modL3IPv6Src(ip); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv6 dst instructions. + */ + @Test + public void modIPv6DstInstructionTest() { + final Ip6Address ip = Ip6Address.valueOf("1111::2222"); + final L3ModificationInstruction.ModIPInstruction instruction = + (L3ModificationInstruction.ModIPInstruction) + Instructions.modL3IPv6Dst(ip); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv6 flow label instructions. + */ + @Test + public void modIPv6FlowLabelInstructionTest() { + final int flowLabel = 0xfffff; + final L3ModificationInstruction.ModIPv6FlowLabelInstruction instruction = + (L3ModificationInstruction.ModIPv6FlowLabelInstruction) + Instructions.modL3IPv6FlowLabel(flowLabel); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod MPLS label instructions. + */ + @Test + public void modMplsLabelInstructionTest() { + final L2ModificationInstruction.ModMplsLabelInstruction instruction = + (L2ModificationInstruction.ModMplsLabelInstruction) + Instructions.modMplsLabel(MplsLabel.mplsLabel(99)); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java new file mode 100644 index 00000000..72081e6c --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java @@ -0,0 +1,438 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.flow.instructions.Instruction; + +import com.fasterxml.jackson.databind.JsonNode; + +import static org.onosproject.net.flow.instructions.Instructions.*; +import static org.onosproject.net.flow.instructions.L0ModificationInstruction.*; +import static org.onosproject.net.flow.instructions.L2ModificationInstruction.*; +import static org.onosproject.net.flow.instructions.L3ModificationInstruction.*; + +/** + * Hamcrest matcher for instructions. + */ +public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { + + private final Instruction instruction; + + private InstructionJsonMatcher(Instruction instructionValue) { + instruction = instructionValue; + } + + /** + * Matches the contents of a push header instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchPushHeaderInstruction(JsonNode instructionJson, + Description description) { + PushHeaderInstructions instructionToMatch = + (PushHeaderInstructions) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final JsonNode ethJson = instructionJson.get("ethernetType"); + if (ethJson == null) { + description.appendText("ethernetType was not null"); + return false; + } + + if (instructionToMatch.ethernetType().toShort() != ethJson.asInt()) { + description.appendText("ethernetType was " + ethJson); + return false; + } + + return true; + } + + /** + * Matches the contents of an output instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchOutputInstruction(JsonNode instructionJson, + Description description) { + OutputInstruction instructionToMatch = (OutputInstruction) instruction; + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final long jsonPort = instructionJson.get("port").asLong(); + if (instructionToMatch.port().toLong() != jsonPort) { + description.appendText("port was " + jsonPort); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod lambda instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModLambdaInstruction(JsonNode instructionJson, + Description description) { + ModLambdaInstruction instructionToMatch = + (ModLambdaInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final long jsonLambda = instructionJson.get("lambda").shortValue(); + if (instructionToMatch.lambda() != jsonLambda) { + description.appendText("lambda was " + jsonLambda); + return false; + } + + return true; + } + + /** + * Matches teh contents of a mod OCh singal instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents matches, false otherwise + */ + private boolean matchModOchSingalInstruction(JsonNode instructionJson, + Description description) { + ModOchSignalInstruction instructionToMatch = + (ModOchSignalInstruction) instruction; + + String jsonSubType = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubType)) { + description.appendText("subtype was " + jsonSubType); + return false; + } + + String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + String jsonGridType = instructionJson.get("gridType").textValue(); + if (!instructionToMatch.lambda().gridType().name().equals(jsonGridType)) { + description.appendText("gridType was " + jsonGridType); + return false; + } + + String jsonChannelSpacing = instructionJson.get("channelSpacing").textValue(); + if (!instructionToMatch.lambda().channelSpacing().name().equals(jsonChannelSpacing)) { + description.appendText("channelSpacing was " + jsonChannelSpacing); + return false; + } + + int jsonSpacingMultiplier = instructionJson.get("spacingMultiplier").intValue(); + if (instructionToMatch.lambda().spacingMultiplier() != jsonSpacingMultiplier) { + description.appendText("spacingMultiplier was " + jsonSpacingMultiplier); + return false; + } + + int jsonSlotGranularity = instructionJson.get("slotGranularity").intValue(); + if (instructionToMatch.lambda().slotGranularity() != jsonSlotGranularity) { + description.appendText("slotGranularity was " + jsonSlotGranularity); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod Ethernet instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModEtherInstruction(JsonNode instructionJson, + Description description) { + ModEtherInstruction instructionToMatch = + (ModEtherInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final String jsonMac = instructionJson.get("mac").textValue(); + final String mac = instructionToMatch.mac().toString(); + if (!mac.equals(jsonMac)) { + description.appendText("mac was " + jsonMac); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod vlan id instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModVlanIdInstruction(JsonNode instructionJson, + Description description) { + ModVlanIdInstruction instructionToMatch = + (ModVlanIdInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final short jsonVlanId = instructionJson.get("vlanId").shortValue(); + final short vlanId = instructionToMatch.vlanId().toShort(); + if (jsonVlanId != vlanId) { + description.appendText("vlan id was " + jsonVlanId); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod vlan pcp instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModVlanPcpInstruction(JsonNode instructionJson, + Description description) { + ModVlanPcpInstruction instructionToMatch = + (ModVlanPcpInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final short jsonVlanPcp = instructionJson.get("vlanPcp").shortValue(); + final short vlanId = instructionToMatch.vlanPcp(); + if (jsonVlanPcp != vlanId) { + description.appendText("vlan pcp was " + jsonVlanPcp); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod ip instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModIpInstruction(JsonNode instructionJson, + Description description) { + ModIPInstruction instructionToMatch = + (ModIPInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final String jsonIp = instructionJson.get("ip").textValue(); + final String ip = instructionToMatch.ip().toString(); + if (!ip.equals(jsonIp)) { + description.appendText("ip was " + jsonIp); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod IPv6 Flow Label instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModIPv6FlowLabelInstruction(JsonNode instructionJson, + Description description) { + ModIPv6FlowLabelInstruction instructionToMatch = + (ModIPv6FlowLabelInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final int jsonFlowLabel = instructionJson.get("flowLabel").intValue(); + final int flowLabel = instructionToMatch.flowLabel(); + if (flowLabel != jsonFlowLabel) { + description.appendText("IPv6 flow label was " + jsonFlowLabel); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod MPLS label instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModMplsLabelInstruction(JsonNode instructionJson, + Description description) { + ModMplsLabelInstruction instructionToMatch = + (ModMplsLabelInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final int jsonLabel = instructionJson.get("label").intValue(); + final int label = instructionToMatch.mplsLabel().toInt(); + if (label != jsonLabel) { + description.appendText("MPLS label was " + jsonLabel); + return false; + } + + return true; + } + + @Override + public boolean matchesSafely(JsonNode jsonInstruction, Description description) { + + // check type + final JsonNode jsonTypeNode = jsonInstruction.get("type"); + final String jsonType = jsonTypeNode.textValue(); + final String type = instruction.type().name(); + if (!jsonType.equals(type)) { + description.appendText("type was " + type); + return false; + } + + if (instruction instanceof PushHeaderInstructions) { + return matchPushHeaderInstruction(jsonInstruction, description); + } else if (instruction instanceof DropInstruction) { + return true; + } else if (instruction instanceof OutputInstruction) { + return matchOutputInstruction(jsonInstruction, description); + } else if (instruction instanceof ModLambdaInstruction) { + return matchModLambdaInstruction(jsonInstruction, description); + } else if (instruction instanceof ModOchSignalInstruction) { + return matchModOchSingalInstruction(jsonInstruction, description); + } else if (instruction instanceof ModEtherInstruction) { + return matchModEtherInstruction(jsonInstruction, description); + } else if (instruction instanceof ModVlanIdInstruction) { + return matchModVlanIdInstruction(jsonInstruction, description); + } else if (instruction instanceof ModVlanPcpInstruction) { + return matchModVlanPcpInstruction(jsonInstruction, description); + } else if (instruction instanceof ModIPInstruction) { + return matchModIpInstruction(jsonInstruction, description); + } else if (instruction instanceof ModIPv6FlowLabelInstruction) { + return matchModIPv6FlowLabelInstruction(jsonInstruction, + description); + } else if (instruction instanceof ModMplsLabelInstruction) { + return matchModMplsLabelInstruction(jsonInstruction, description); + } + + return false; + } + + @Override + public void describeTo(Description description) { + description.appendText(instruction.toString()); + } + + /** + * Factory to allocate an instruction matcher. + * + * @param instruction instruction object we are looking for + * @return matcher + */ + public static InstructionJsonMatcher matchesInstruction(Instruction instruction) { + return new InstructionJsonMatcher(instruction); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java new file mode 100644 index 00000000..7cbce4d1 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java @@ -0,0 +1,288 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.time.Duration; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.util.Bandwidth; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.GridType; +import org.onosproject.net.HostId; +import org.onosproject.net.IndexedLambda; +import org.onosproject.net.Lambda; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criteria; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.intent.AbstractIntentTest; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.IntentServiceAdapter; +import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.intent.constraint.AnnotationConstraint; +import org.onosproject.net.intent.constraint.AsymmetricPathConstraint; +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.intent.constraint.LatencyConstraint; +import org.onosproject.net.intent.constraint.ObstacleConstraint; +import org.onosproject.net.intent.constraint.WaypointConstraint; +import org.onosproject.net.resource.link.BandwidthResource; +import org.onosproject.net.resource.link.LambdaResource; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableList; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.IntentJsonMatcher.matchesIntent; +import static org.onosproject.net.NetTestTools.did; +import static org.onosproject.net.NetTestTools.hid; +import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; + +/** + * Unit tests for the host to host intent class codec. + */ +public class IntentCodecTest extends AbstractIntentTest { + + private final HostId id1 = hid("12:34:56:78:91:ab/1"); + private final HostId id2 = hid("12:34:56:78:92:ab/1"); + private final ApplicationId appId = new DefaultApplicationId(3, "test"); + final TrafficSelector emptySelector = + DefaultTrafficSelector.emptySelector(); + final TrafficTreatment emptyTreatment = + DefaultTrafficTreatment.emptyTreatment(); + private final MockCodecContext context = new MockCodecContext(); + final CoreService mockCoreService = createMock(CoreService.class); + + @Before + public void setUpIntentService() { + final IntentService mockIntentService = new IntentServiceAdapter(); + context.registerService(IntentService.class, mockIntentService); + context.registerService(CoreService.class, mockCoreService); + expect(mockCoreService.getAppId(appId.name())) + .andReturn(appId); + replay(mockCoreService); + } + + /** + * Tests the encoding of a host to host intent. + */ + @Test + public void hostToHostIntent() { + final HostToHostIntent intent = + HostToHostIntent.builder() + .appId(appId) + .one(id1) + .two(id2) + .build(); + + final JsonCodec<HostToHostIntent> intentCodec = + context.codec(HostToHostIntent.class); + assertThat(intentCodec, notNullValue()); + + final ObjectNode intentJson = intentCodec.encode(intent, context); + assertThat(intentJson, matchesIntent(intent)); + } + + /** + * Tests the encoding of a point to point intent. + */ + @Test + public void pointToPointIntent() { + ConnectPoint ingress = NetTestTools.connectPoint("ingress", 1); + ConnectPoint egress = NetTestTools.connectPoint("egress", 2); + + final PointToPointIntent intent = + PointToPointIntent.builder() + .appId(appId) + .selector(emptySelector) + .treatment(emptyTreatment) + .ingressPoint(ingress) + .egressPoint(egress).build(); + + final JsonCodec<PointToPointIntent> intentCodec = + context.codec(PointToPointIntent.class); + assertThat(intentCodec, notNullValue()); + + final ObjectNode intentJson = intentCodec.encode(intent, context); + assertThat(intentJson, matchesIntent(intent)); + } + + /** + * Tests the encoding of an intent with treatment, selector and constraints + * specified. + */ + @Test + public void intentWithTreatmentSelectorAndConstraints() { + ConnectPoint ingress = NetTestTools.connectPoint("ingress", 1); + ConnectPoint egress = NetTestTools.connectPoint("egress", 2); + DeviceId did1 = did("device1"); + DeviceId did2 = did("device2"); + DeviceId did3 = did("device3"); + Lambda ochSignal = Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8); + final TrafficSelector selector = DefaultTrafficSelector.builder() + .matchIPProtocol((byte) 3) + .matchMplsLabel(MplsLabel.mplsLabel(4)) + .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID)) + .add(Criteria.matchLambda(ochSignal)) + .matchEthDst(MacAddress.BROADCAST) + .matchIPDst(IpPrefix.valueOf("1.2.3.4/24")) + .build(); + final TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .add(Instructions.modL0Lambda(new IndexedLambda(33))) + .setMpls(MplsLabel.mplsLabel(44)) + .setOutput(PortNumber.CONTROLLER) + .setEthDst(MacAddress.BROADCAST) + .build(); + + final List<Constraint> constraints = + ImmutableList.of( + new BandwidthConstraint(new BandwidthResource(Bandwidth.bps(1.0))), + new LambdaConstraint(LambdaResource.valueOf(3)), + new AnnotationConstraint("key", 33.0), + new AsymmetricPathConstraint(), + new LatencyConstraint(Duration.ofSeconds(2)), + new ObstacleConstraint(did1, did2), + new WaypointConstraint(did3)); + + final PointToPointIntent intent = + PointToPointIntent.builder() + .appId(appId) + .selector(selector) + .treatment(treatment) + .ingressPoint(ingress) + .egressPoint(egress) + .constraints(constraints) + .build(); + + + final JsonCodec<PointToPointIntent> intentCodec = + context.codec(PointToPointIntent.class); + assertThat(intentCodec, notNullValue()); + + final ObjectNode intentJson = intentCodec.encode(intent, context); + assertThat(intentJson, matchesIntent(intent)); + + } + + /** + * Reads in a rule from the given resource and decodes it. + * + * @param resourceName resource to use to read the JSON for the rule + * @return decoded flow rule + * @throws IOException if processing the resource fails + */ + private Intent getIntent(String resourceName, JsonCodec intentCodec) throws IOException { + InputStream jsonStream = FlowRuleCodecTest.class + .getResourceAsStream(resourceName); + JsonNode json = context.mapper().readTree(jsonStream); + assertThat(json, notNullValue()); + Intent intent = (Intent) intentCodec.decode((ObjectNode) json, context); + assertThat(intent, notNullValue()); + return intent; + } + + /** + * Tests the point to point intent JSON codec. + * + * @throws IOException if JSON processing fails + */ + @Test + public void decodePointToPointIntent() throws IOException { + JsonCodec<Intent> intentCodec = context.codec(Intent.class); + assertThat(intentCodec, notNullValue()); + + Intent intent = getIntent("PointToPointIntent.json", intentCodec); + assertThat(intent, notNullValue()); + assertThat(intent, instanceOf(PointToPointIntent.class)); + + PointToPointIntent pointIntent = (PointToPointIntent) intent; + assertThat(pointIntent.priority(), is(55)); + assertThat(pointIntent.ingressPoint().deviceId(), is(did("0000000000000001"))); + assertThat(pointIntent.ingressPoint().port(), is(PortNumber.portNumber(1))); + assertThat(pointIntent.egressPoint().deviceId(), is(did("0000000000000007"))); + assertThat(pointIntent.egressPoint().port(), is(PortNumber.portNumber(2))); + + assertThat(pointIntent.constraints(), hasSize(1)); + + assertThat(pointIntent.selector(), notNullValue()); + assertThat(pointIntent.selector().criteria(), hasSize(1)); + Criterion criterion1 = pointIntent.selector().criteria().iterator().next(); + assertThat(criterion1, instanceOf(EthCriterion.class)); + EthCriterion ethCriterion = (EthCriterion) criterion1; + assertThat(ethCriterion.mac().toString(), is("11:22:33:44:55:66")); + assertThat(ethCriterion.type().name(), is("ETH_DST")); + + assertThat(pointIntent.treatment(), notNullValue()); + assertThat(pointIntent.treatment().allInstructions(), hasSize(1)); + Instruction instruction1 = pointIntent.treatment().allInstructions().iterator().next(); + assertThat(instruction1, instanceOf(ModEtherInstruction.class)); + ModEtherInstruction ethInstruction = (ModEtherInstruction) instruction1; + assertThat(ethInstruction.mac().toString(), is("22:33:44:55:66:77")); + assertThat(ethInstruction.type().toString(), is("L2MODIFICATION")); + assertThat(ethInstruction.subtype().toString(), is("ETH_SRC")); + } + + /** + * Tests the host to host intent JSON codec. + * + * @throws IOException + */ + @Test + public void decodeHostToHostIntent() throws IOException { + JsonCodec<Intent> intentCodec = context.codec(Intent.class); + assertThat(intentCodec, notNullValue()); + + Intent intent = getIntent("HostToHostIntent.json", intentCodec); + assertThat(intent, notNullValue()); + assertThat(intent, instanceOf(HostToHostIntent.class)); + + HostToHostIntent hostIntent = (HostToHostIntent) intent; + assertThat(hostIntent.priority(), is(7)); + assertThat(hostIntent.constraints(), hasSize(1)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java new file mode 100644 index 00000000..e485a5fa --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java @@ -0,0 +1,512 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import java.util.List; +import java.util.Set; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.NetworkResource; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.intent.ConnectivityIntent; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.intent.constraint.AnnotationConstraint; +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.intent.constraint.LatencyConstraint; +import org.onosproject.net.intent.constraint.LinkTypeConstraint; +import org.onosproject.net.intent.constraint.ObstacleConstraint; +import org.onosproject.net.intent.constraint.WaypointConstraint; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher to check that an intent representation in JSON matches + * the actual intent. + */ +public final class IntentJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> { + + private final Intent intent; + + /** + * Constructor is private, use factory method. + * + * @param intentValue the intent object to compare against + */ + private IntentJsonMatcher(Intent intentValue) { + intent = intentValue; + } + + /** + * Matches the JSON representation of a host to host intent. + * + * @param jsonIntent JSON representation of the intent + * @param description Description object used for recording errors + * @return true if the JSON matches the intent, false otherwise + */ + private boolean matchHostToHostIntent(JsonNode jsonIntent, Description description) { + final HostToHostIntent hostToHostIntent = (HostToHostIntent) intent; + + // check host one + final String host1 = hostToHostIntent.one().toString(); + final String jsonHost1 = jsonIntent.get("one").asText(); + if (!host1.equals(jsonHost1)) { + description.appendText("host one was " + jsonHost1); + return false; + } + + // check host 2 + final String host2 = hostToHostIntent.two().toString(); + final String jsonHost2 = jsonIntent.get("two").asText(); + if (!host2.equals(jsonHost2)) { + description.appendText("host two was " + jsonHost2); + return false; + } + return true; + } + + /** + * Matches the JSON representation of a point to point intent. + * + * @param jsonIntent JSON representation of the intent + * @param description Description object used for recording errors + * @return true if the JSON matches the intent, false otherwise + */ + private boolean matchPointToPointIntent(JsonNode jsonIntent, Description description) { + final PointToPointIntent pointToPointIntent = (PointToPointIntent) intent; + + // check ingress connection + final ConnectPoint ingress = pointToPointIntent.ingressPoint(); + final ConnectPointJsonMatcher ingressMatcher = + ConnectPointJsonMatcher.matchesConnectPoint(ingress); + final JsonNode jsonIngress = jsonIntent.get("ingressPoint"); + final boolean ingressMatches = + ingressMatcher.matchesSafely(jsonIngress, description); + + if (!ingressMatches) { + description.appendText("ingress was " + jsonIngress); + return false; + } + + // check egress connection + final ConnectPoint egress = pointToPointIntent.egressPoint(); + final ConnectPointJsonMatcher egressMatcher = + ConnectPointJsonMatcher.matchesConnectPoint(egress); + final JsonNode jsonEgress = jsonIntent.get("egressPoint"); + final boolean egressMatches = + egressMatcher.matchesSafely(jsonEgress, description); + + if (!egressMatches) { + description.appendText("egress was " + jsonEgress); + return false; + } + + return true; + } + + + /** + * Matches a bandwidth constraint against a JSON representation of the + * constraint. + * + * @param bandwidthConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchBandwidthConstraint(BandwidthConstraint bandwidthConstraint, + JsonNode constraintJson) { + final JsonNode bandwidthJson = constraintJson.get("bandwidth"); + return bandwidthJson != null + && constraintJson.get("bandwidth").asDouble() + == bandwidthConstraint.bandwidth().toDouble(); + } + + /** + * Matches a lamdba constraint against a JSON representation of the + * constraint. + * + * @param lambdaConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchLambdaConstraint(LambdaConstraint lambdaConstraint, + JsonNode constraintJson) { + final JsonNode lambdaJson = constraintJson.get("lambda"); + return lambdaJson != null + && constraintJson.get("lambda").asInt() + == lambdaConstraint.lambda().toInt(); + } + + /** + * Matches a link type constraint against a JSON representation of the + * constraint. + * + * @param linkTypeConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchLinkTypeConstraint(LinkTypeConstraint linkTypeConstraint, + JsonNode constraintJson) { + final JsonNode inclusiveJson = constraintJson.get("inclusive"); + final JsonNode typesJson = constraintJson.get("types"); + + if (typesJson.size() != linkTypeConstraint.types().size()) { + return false; + } + + int foundType = 0; + for (Link.Type type : linkTypeConstraint.types()) { + for (int jsonIndex = 0; jsonIndex < typesJson.size(); jsonIndex++) { + if (type.name().equals(typesJson.get(jsonIndex).asText())) { + foundType++; + break; + } + } + } + return (inclusiveJson != null && + inclusiveJson.asBoolean() == linkTypeConstraint.isInclusive()) && + foundType == typesJson.size(); + } + + /** + * Matches an annotation constraint against a JSON representation of the + * constraint. + * + * @param annotationConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchAnnotationConstraint(AnnotationConstraint annotationConstraint, + JsonNode constraintJson) { + final JsonNode keyJson = constraintJson.get("key"); + final JsonNode thresholdJson = constraintJson.get("threshold"); + return (keyJson != null + && keyJson.asText().equals(annotationConstraint.key())) && + (thresholdJson != null + && thresholdJson.asDouble() == annotationConstraint.threshold()); + } + + /** + * Matches a latency constraint against a JSON representation of the + * constraint. + * + * @param latencyConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchLatencyConstraint(LatencyConstraint latencyConstraint, + JsonNode constraintJson) { + final JsonNode latencyJson = constraintJson.get("latencyMillis"); + return (latencyJson != null + && latencyJson.asInt() == latencyConstraint.latency().toMillis()); + } + + /** + * Matches an obstacle constraint against a JSON representation of the + * constraint. + * + * @param obstacleConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchObstacleConstraint(ObstacleConstraint obstacleConstraint, + JsonNode constraintJson) { + final JsonNode obstaclesJson = constraintJson.get("obstacles"); + + if (obstaclesJson.size() != obstacleConstraint.obstacles().size()) { + return false; + } + + for (int obstaclesIndex = 0; obstaclesIndex < obstaclesJson.size(); + obstaclesIndex++) { + boolean obstacleFound = false; + final String obstacleJson = obstaclesJson.get(obstaclesIndex) + .asText(); + for (DeviceId obstacle : obstacleConstraint.obstacles()) { + if (obstacle.toString().equals(obstacleJson)) { + obstacleFound = true; + } + } + if (!obstacleFound) { + return false; + } + } + return true; + } + + /** + * Matches a waypoint constraint against a JSON representation of the + * constraint. + * + * @param waypointConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchWaypointConstraint(WaypointConstraint waypointConstraint, + JsonNode constraintJson) { + final JsonNode waypointsJson = constraintJson.get("waypoints"); + + if (waypointsJson.size() != waypointConstraint.waypoints().size()) { + return false; + } + + for (int waypointsIndex = 0; waypointsIndex < waypointsJson.size(); + waypointsIndex++) { + boolean waypointFound = false; + final String waypointJson = waypointsJson.get(waypointsIndex) + .asText(); + for (DeviceId waypoint : waypointConstraint.waypoints()) { + if (waypoint.toString().equals(waypointJson)) { + waypointFound = true; + } + } + if (!waypointFound) { + return false; + } + } + return true; + } + + + /** + * Matches a constraint against a JSON representation of the + * constraint. + * + * @param constraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchConstraint(Constraint constraint, JsonNode constraintJson) { + final JsonNode typeJson = constraintJson.get("type"); + if (!typeJson.asText().equals(constraint.getClass().getSimpleName())) { + return false; + } + if (constraint instanceof BandwidthConstraint) { + return matchBandwidthConstraint((BandwidthConstraint) constraint, + constraintJson); + } else if (constraint instanceof LambdaConstraint) { + return matchLambdaConstraint((LambdaConstraint) constraint, + constraintJson); + } else if (constraint instanceof LinkTypeConstraint) { + return matchLinkTypeConstraint((LinkTypeConstraint) constraint, + constraintJson); + } else if (constraint instanceof AnnotationConstraint) { + return matchAnnotationConstraint((AnnotationConstraint) constraint, + constraintJson); + } else if (constraint instanceof LatencyConstraint) { + return matchLatencyConstraint((LatencyConstraint) constraint, + constraintJson); + } else if (constraint instanceof ObstacleConstraint) { + return matchObstacleConstraint((ObstacleConstraint) constraint, + constraintJson); + } else if (constraint instanceof WaypointConstraint) { + return matchWaypointConstraint((WaypointConstraint) constraint, + constraintJson); + } + return true; + } + + /** + * Matches the JSON representation of a connectivity intent. Calls the + * matcher for the connectivity intent subtype. + * + * @param jsonIntent JSON representation of the intent + * @param description Description object used for recording errors + * @return true if the JSON matches the intent, false otherwise + */ + private boolean matchConnectivityIntent(JsonNode jsonIntent, Description description) { + final ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent; + + // check selector + final JsonNode jsonSelector = jsonIntent.get("selector"); + final TrafficSelector selector = connectivityIntent.selector(); + final Set<Criterion> criteria = selector.criteria(); + final JsonNode jsonCriteria = jsonSelector.get("criteria"); + if (jsonCriteria.size() != criteria.size()) { + description.appendText("size of criteria array is " + + Integer.toString(jsonCriteria.size())); + return false; + } + + for (Criterion criterion : criteria) { + boolean criterionFound = false; + for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) { + final CriterionJsonMatcher criterionMatcher = + CriterionJsonMatcher.matchesCriterion(criterion); + if (criterionMatcher.matches(jsonCriteria.get(criterionIndex))) { + criterionFound = true; + break; + } + } + if (!criterionFound) { + description.appendText("criterion not found " + criterion.toString()); + return false; + } + } + + // check treatment + final JsonNode jsonTreatment = jsonIntent.get("treatment"); + final TrafficTreatment treatment = connectivityIntent.treatment(); + final List<Instruction> instructions = treatment.immediate(); + final JsonNode jsonInstructions = jsonTreatment.get("instructions"); + if (jsonInstructions.size() != instructions.size()) { + description.appendText("size of instructions array is " + + Integer.toString(jsonInstructions.size())); + return false; + } + + for (Instruction instruction : instructions) { + boolean instructionFound = false; + for (int instructionIndex = 0; instructionIndex < jsonInstructions.size(); instructionIndex++) { + final InstructionJsonMatcher instructionMatcher = + InstructionJsonMatcher.matchesInstruction(instruction); + if (instructionMatcher.matches(jsonInstructions.get(instructionIndex))) { + instructionFound = true; + break; + } + } + if (!instructionFound) { + description.appendText("instruction not found " + instruction.toString()); + return false; + } + } + + // Check constraints + final JsonNode jsonConstraints = jsonIntent.get("constraints"); + if (connectivityIntent.constraints() != null) { + if (connectivityIntent.constraints().size() != jsonConstraints.size()) { + description.appendText("constraints array size was " + + Integer.toString(jsonConstraints.size())); + return false; + } + for (final Constraint constraint : connectivityIntent.constraints()) { + boolean constraintFound = false; + for (int constraintIndex = 0; constraintIndex < jsonConstraints.size(); + constraintIndex++) { + final JsonNode value = jsonConstraints.get(constraintIndex); + if (matchConstraint(constraint, value)) { + constraintFound = true; + } + } + if (!constraintFound) { + final String constraintString = constraint.toString(); + description.appendText("constraint missing " + constraintString); + return false; + } + } + } else if (jsonConstraints.size() != 0) { + description.appendText("constraint array not empty"); + return false; + } + + if (connectivityIntent instanceof HostToHostIntent) { + return matchHostToHostIntent(jsonIntent, description); + } else if (connectivityIntent instanceof PointToPointIntent) { + return matchPointToPointIntent(jsonIntent, description); + } else { + description.appendText("class of connectivity intent is unknown"); + return false; + } + } + + @Override + public boolean matchesSafely(JsonNode jsonIntent, Description description) { + // check id + final String jsonId = jsonIntent.get("id").asText(); + final String id = intent.id().toString(); + if (!jsonId.equals(id)) { + description.appendText("id was " + jsonId); + return false; + } + + // check application id + final JsonNode jsonAppIdNode = jsonIntent.get("appId"); + + final String jsonAppId = jsonAppIdNode.asText(); + final String appId = intent.appId().name(); + if (!jsonAppId.equals(appId)) { + description.appendText("appId was " + jsonAppId); + return false; + } + + // check intent type + final String jsonType = jsonIntent.get("type").asText(); + final String type = intent.getClass().getSimpleName(); + if (!jsonType.equals(type)) { + description.appendText("type was " + jsonType); + return false; + } + + // check resources array + final JsonNode jsonResources = jsonIntent.get("resources"); + if (intent.resources() != null) { + if (intent.resources().size() != jsonResources.size()) { + description.appendText("resources array size was " + + Integer.toString(jsonResources.size())); + return false; + } + for (final NetworkResource resource : intent.resources()) { + boolean resourceFound = false; + final String resourceString = resource.toString(); + for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) { + final JsonNode value = jsonResources.get(resourceIndex); + if (value.asText().equals(resourceString)) { + resourceFound = true; + } + } + if (!resourceFound) { + description.appendText("resource missing " + resourceString); + return false; + } + } + } else if (jsonResources.size() != 0) { + description.appendText("resources array empty"); + return false; + } + + if (intent instanceof ConnectivityIntent) { + return matchConnectivityIntent(jsonIntent, description); + } else { + description.appendText("class of intent is unknown"); + return false; + } + } + + @Override + public void describeTo(Description description) { + description.appendText(intent.toString()); + } + + /** + * Factory to allocate an intent matcher. + * + * @param intent intent object we are looking for + * @return matcher + */ + public static IntentJsonMatcher matchesIntent(Intent intent) { + return new IntentJsonMatcher(intent); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java new file mode 100644 index 00000000..67c2f47f --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java @@ -0,0 +1,83 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.codec.impl; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DeviceId.deviceId; + +import org.onlab.packet.ChassisId; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.provider.ProviderId; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * JsonCodec test utilities. + */ +public abstract class JsonCodecUtils { + + /** + * Checks if given Object can be encoded to JSON and back. + * + * @param context CodecContext + * @param codec JsonCodec + * @param pojoIn Java Object to encode. + * Object is expected to have #equals implemented. + */ + public static <T> void assertJsonEncodable(final CodecContext context, + final JsonCodec<T> codec, + final T pojoIn) { + final ObjectNode json = codec.encode(pojoIn, context); + + assertThat(json, is(notNullValue())); + + final T pojoOut = codec.decode(json, context); + assertThat(pojoOut, is(notNullValue())); + + assertEquals(pojoIn, pojoOut); + } + + static final ProviderId PID = new ProviderId("of", "foo"); + static final ProviderId PIDA = new ProviderId("of", "bar", true); + static final DeviceId DID1 = deviceId("of:foo"); + static final DeviceId DID2 = deviceId("of:bar"); + static final String MFR = "whitebox"; + static final String HW = "1.1.x"; + static final String SW1 = "3.8.1"; + static final String SW2 = "3.9.5"; + static final String SN = "43311-12345"; + static final ChassisId CID = new ChassisId(); + static final PortNumber P1 = PortNumber.portNumber(1); + static final PortNumber P2 = PortNumber.portNumber(2); + static final PortNumber P3 = PortNumber.portNumber(3); + static final SparseAnnotations A1 = DefaultAnnotations.builder() + .set("A1", "a1") + .set("B1", "b1") + .build(); + static final ConnectPoint CP1 = new ConnectPoint(DID1, P1); + static final ConnectPoint CP2 = new ConnectPoint(DID2, P2); + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java new file mode 100644 index 00000000..c44b0eb1 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.codec.impl; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.JsonCodecUtils.assertJsonEncodable; + +import org.junit.Test; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.Link; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.device.DeviceServiceAdapter; + +/** + * Unit test for LinkCodec. + */ +public class LinkCodecTest { + + private final Link link = new DefaultLink(JsonCodecUtils.PID, + JsonCodecUtils.CP1, + JsonCodecUtils.CP2, + Link.Type.DIRECT, + Link.State.ACTIVE, + false, + JsonCodecUtils.A1); + + @Test + public void linkCodecTest() { + final MockCodecContext context = new MockCodecContext(); + context.registerService(DeviceService.class, new DeviceServiceAdapter()); + final JsonCodec<Link> codec = context.codec(Link.class); + assertThat(codec, is(notNullValue())); + final Link pojoIn = link; + + assertJsonEncodable(context, codec, pojoIn); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LoadCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LoadCodecTest.java new file mode 100644 index 00000000..4cb2916e --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LoadCodecTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import org.junit.Test; +import org.onosproject.net.statistic.DefaultLoad; +import org.onosproject.net.statistic.Load; + +import com.fasterxml.jackson.databind.JsonNode; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.is; + +/** + * Unit tests for Load codec. + */ +public class LoadCodecTest { + + /** + * Tests encoding of a Load object. + */ + @Test + public void testLoadEncode() { + final long startTime = System.currentTimeMillis(); + final Load load = new DefaultLoad(20, 10, 1); + final JsonNode node = new LoadCodec() + .encode(load, new MockCodecContext()); + assertThat(node.get("valid").asBoolean(), is(true)); + assertThat(node.get("latest").asLong(), is(20L)); + assertThat(node.get("rate").asLong(), is(10L)); + assertThat(node.get("time").asLong(), greaterThanOrEqualTo(startTime)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java new file mode 100644 index 00000000..6a9b6708 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.codec.impl; + +import java.util.HashMap; +import java.util.Map; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Mock codec context for use in codec unit tests. + */ +public class MockCodecContext implements CodecContext { + + private final ObjectMapper mapper = new ObjectMapper(); + private final CodecManager manager = new CodecManager(); + private final Map<Class<? extends Object>, Object> services = new HashMap<>(); + + /** + * Constructs a new mock codec context. + */ + public MockCodecContext() { + manager.activate(); + } + + @Override + public ObjectMapper mapper() { + return mapper; + } + + @Override + @SuppressWarnings("unchecked") + public <T> JsonCodec<T> codec(Class<T> entityClass) { + return manager.getCodec(entityClass); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T getService(Class<T> serviceClass) { + return (T) services.get(serviceClass); + } + + // for registering mock services + public <T> void registerService(Class<T> serviceClass, T impl) { + services.put(serviceClass, impl); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java new file mode 100644 index 00000000..f3f7d920 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.codec.impl; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.JsonCodecUtils.assertJsonEncodable; + +import org.junit.Test; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.DefaultPort; +import org.onosproject.net.Device; +import org.onosproject.net.Port; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.device.DeviceServiceAdapter; + +/** + * Unit test for PortCodec. + */ +public class PortCodecTest { + + + + private final Device device = new DefaultDevice(JsonCodecUtils.PID, + JsonCodecUtils.DID1, + Device.Type.SWITCH, + JsonCodecUtils.MFR, + JsonCodecUtils.HW, + JsonCodecUtils.SW1, + JsonCodecUtils.SN, + JsonCodecUtils.CID, + JsonCodecUtils.A1); + + private final Port port = new DefaultPort(device, + JsonCodecUtils.P1, + true, + JsonCodecUtils.A1); + + @Test + public void portCodecTest() { + final MockCodecContext context = new MockCodecContext(); + context.registerService(DeviceService.class, new DeviceServiceAdapter()); + final JsonCodec<Port> codec = context.codec(Port.class); + assertThat(codec, is(notNullValue())); + final Port pojoIn = port; + + assertJsonEncodable(context, codec, pojoIn); + } + +} |