/* * Copyright 2015-present 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.Objects; import org.hamcrest.Description; import org.hamcrest.TypeSafeDiagnosingMatcher; import org.onlab.util.HexString; import org.onosproject.net.OchSignal; import org.onosproject.net.OduSignalId; 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.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.OduSignalIdCriterion; import org.onosproject.net.flow.criteria.OduSignalTypeCriterion; 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 com.fasterxml.jackson.databind.JsonNode; import com.google.common.base.Joiner; /** * 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() & 0xffff; final int jsonEthType = Integer.decode(jsonCriterion.get("ethType").textValue()) & 0xffff; 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; } /** * Matches an ODU signal ID criterion object. * * @param criterion criterion to match * @return true if the JSON matches the criterion, false otherwise. */ private boolean matchCriterion(OduSignalIdCriterion criterion) { final OduSignalId oduSignal = criterion.oduSignalId(); final JsonNode jsonOduSignal = jsonCriterion.get(CriterionCodec.ODU_SIGNAL_ID); int jsonTpn = jsonOduSignal.get(CriterionCodec.TRIBUTARY_PORT_NUMBER).intValue(); int jsonTsLen = jsonOduSignal.get(CriterionCodec.TRIBUTARY_SLOT_LEN).intValue(); byte[] jsonTributaryBitMap = HexString.fromHexString( jsonOduSignal.get(CriterionCodec.TRIBUTARY_SLOT_BITMAP).asText()); OduSignalId jsonOduSignalId = OduSignalId.oduSignalId(jsonTpn, jsonTsLen, jsonTributaryBitMap); if (!oduSignal.equals(jsonOduSignalId)) { description.appendText("oduSignalId was " + criterion); return false; } return true; } /** * Matches an ODU signal Type criterion object. * * @param criterion criterion to match * @return true if the JSON matches the criterion, false otherwise. */ private boolean matchCriterion(OduSignalTypeCriterion criterion) { final String signalType = criterion.signalType().name(); final String jsonOduSignalType = jsonCriterion.get("oduSignalType").textValue(); if (!signalType.equals(jsonOduSignalType)) { description.appendText("signalType was " + signalType); 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); case ODU_SIGID: return matchCriterion((OduSignalIdCriterion) criterion); case ODU_SIGTYPE: return matchCriterion((OduSignalTypeCriterion) 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()); } }