| /* |
| * 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.onlab.util.HexString; |
| import org.onosproject.net.OduSignalId; |
| import org.onosproject.net.flow.instructions.Instruction; |
| import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction; |
| import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; |
| import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction; |
| import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction; |
| import org.onosproject.net.flow.instructions.L1ModificationInstruction.ModOduSignalIdInstruction; |
| import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; |
| import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction; |
| import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; |
| import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction; |
| import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions; |
| import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; |
| import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction; |
| |
| import com.fasterxml.jackson.databind.JsonNode; |
| |
| /** |
| * 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) { |
| final String jsonType = instructionJson.get("type").textValue(); |
| OutputInstruction instructionToMatch = (OutputInstruction) instruction; |
| if (!instructionToMatch.type().name().equals(jsonType)) { |
| description.appendText("type was " + jsonType); |
| return false; |
| } |
| |
| if (instructionJson.get("port").isLong() || |
| instructionJson.get("port").isInt()) { |
| final long jsonPort = instructionJson.get("port").asLong(); |
| if (instructionToMatch.port().toLong() != (jsonPort)) { |
| description.appendText("port was " + jsonPort); |
| return false; |
| } |
| } else if (instructionJson.get("port").isTextual()) { |
| final String jsonPort = instructionJson.get("port").textValue(); |
| if (!instructionToMatch.port().toString().equals(jsonPort)) { |
| description.appendText("port was " + jsonPort); |
| return false; |
| } |
| } else { |
| final String jsonPort = instructionJson.get("port").toString(); |
| description.appendText("Unmathcing types "); |
| description.appendText("instructionToMatch " + instructionToMatch.port().toString()); |
| description.appendText("jsonPort " + jsonPort); |
| } |
| |
| 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 the 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 ODU singal Id instruction. |
| * |
| * @param instructionJson JSON instruction to match |
| * @param description Description object used for recording errors |
| * @return true if contents matches, false otherwise |
| */ |
| private boolean matchModOduSingalIdInstruction(JsonNode instructionJson, |
| Description description) { |
| ModOduSignalIdInstruction instructionToMatch = |
| (ModOduSignalIdInstruction) 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; |
| } |
| final JsonNode jsonOduSignal = instructionJson.get("oduSignalId"); |
| int jsonTpn = jsonOduSignal.get("tributaryPortNumber").intValue(); |
| int jsonTsLen = jsonOduSignal.get("tributarySlotLength").intValue(); |
| byte[] tributaryBitMap = HexString.fromHexString(jsonOduSignal.get("tributarySlotBitmap").asText()); |
| OduSignalId jsonOduSignalId = OduSignalId.oduSignalId(jsonTpn, jsonTsLen, tributaryBitMap); |
| if (!instructionToMatch.oduSignalId().equals(jsonOduSignalId)) { |
| description.appendText("oduSignalId was " + instructionToMatch); |
| 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.label().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 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); |
| } else if (instruction instanceof ModOduSignalIdInstruction) { |
| return matchModOduSingalIdInstruction(jsonInstruction, description); |
| } else if (instruction instanceof NoActionInstruction) { |
| return true; |
| } |
| |
| 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); |
| } |
| } |