Add unit test for TrafficTreatment REST API
Change-Id: I19834b9edbb87e66ca6fb4ce4f6601f685ba116e
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/TrafficTreatmentCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/TrafficTreatmentCodecTest.java
new file mode 100644
index 0000000..f23e846
--- /dev/null
+++ b/core/common/src/test/java/org/onosproject/codec/impl/TrafficTreatmentCodecTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2016-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 com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.apache.commons.lang3.StringUtils;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MacAddress;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.meter.MeterId;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
+/**
+ * Unit tests for traffic treatment codec.
+ */
+public class TrafficTreatmentCodecTest {
+
+ private MockCodecContext context;
+ private JsonCodec<TrafficTreatment> trafficTreatmentCodec;
+
+ @Before
+ public void setUp() {
+ context = new MockCodecContext();
+ trafficTreatmentCodec = context.codec(TrafficTreatment.class);
+ assertThat(trafficTreatmentCodec, notNullValue());
+ }
+
+ /**
+ * Tests encoding of a traffic treatment object.
+ */
+ @Test
+ public void testTrafficTreatmentEncode() {
+
+ Instruction output = Instructions.createOutput(PortNumber.portNumber(0));
+ Instruction modL2Src = Instructions.modL2Src(MacAddress.valueOf("11:22:33:44:55:66"));
+ Instruction modL2Dst = Instructions.modL2Dst(MacAddress.valueOf("44:55:66:77:88:99"));
+ MeterId meterId = MeterId.meterId(0);
+ Instruction meter = Instructions.meterTraffic(meterId);
+ Instruction transition = Instructions.transition(1);
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ TrafficTreatment treatment = tBuilder
+ .add(output)
+ .add(modL2Src)
+ .add(modL2Dst)
+ .add(meter)
+ .add(transition)
+ .build();
+
+ ObjectNode treatmentJson = trafficTreatmentCodec.encode(treatment, context);
+ assertThat(treatmentJson, TrafficTreatmentJsonMatcher.matchesTrafficTreatment(treatment));
+ }
+
+ /**
+ * Tests decoding of a traffic treatment JSON object.
+ */
+ @Test
+ public void testTrafficTreatmentDecode() throws IOException {
+ TrafficTreatment treatment = getTreatment("TrafficTreatment.json");
+
+ List<Instruction> insts = treatment.immediate();
+ assertThat(insts.size(), is(2));
+
+ ImmutableSet<String> types = ImmutableSet.of("OUTPUT", "L2MODIFICATION");
+ assertThat(types.contains(insts.get(0).type().name()), is(true));
+ assertThat(types.contains(insts.get(1).type().name()), is(true));
+ }
+
+ private static final class TrafficTreatmentJsonMatcher
+ extends TypeSafeDiagnosingMatcher<JsonNode> {
+
+ private final TrafficTreatment trafficTreatment;
+
+ private TrafficTreatmentJsonMatcher(TrafficTreatment trafficTreatment) {
+ this.trafficTreatment = trafficTreatment;
+ }
+
+ /**
+ * Filtered out the meter and table transition instructions.
+ *
+ * @param node JSON node
+ * @return filtered JSON node
+ */
+ private int filteredSize(JsonNode node) {
+ int counter = 0;
+ for (int idx = 0; idx < node.size(); idx++) {
+ String type = node.get(idx).get("type").asText();
+ if (!type.equals("METER") && !type.equals("TABLE")) {
+ counter++;
+ }
+ }
+ return counter;
+ }
+
+ private JsonNode getInstNode(JsonNode node, String name) {
+ for (int idx = 0; idx < node.size(); idx++) {
+ String type = node.get(idx).get("type").asText();
+ if (type.equals(name)) {
+ return node.get(idx);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean matchesSafely(JsonNode jsonNode, Description description) {
+
+ // check instructions
+ final JsonNode jsonInstructions = jsonNode.get("instructions");
+
+ if (trafficTreatment.immediate().size() != filteredSize(jsonInstructions)) {
+ description.appendText("instructions array size of " +
+ Integer.toString(trafficTreatment.immediate().size()));
+ return false;
+ }
+
+ for (final Instruction instruction : trafficTreatment.immediate()) {
+ boolean instructionFound = false;
+ for (int instructionIndex = 0; instructionIndex < jsonInstructions.size();
+ instructionIndex++) {
+ final String jsonType =
+ jsonInstructions.get(instructionIndex).get("type").asText();
+ final String instructionType = instruction.type().name();
+ if (jsonType.equals(instructionType)) {
+ instructionFound = true;
+ }
+ }
+ if (!instructionFound) {
+ description.appendText("instruction " + instruction.toString());
+ return false;
+ }
+ }
+
+ // check metered
+ JsonNode meterNode = getInstNode(jsonInstructions, "METER");
+ String jsonMeterId = meterNode != null ? meterNode.get("meterId").asText() : null;
+ String meterId = trafficTreatment.metered().meterId().toString();
+ if (!StringUtils.equals(jsonMeterId, meterId)) {
+ description.appendText("meter id was " + jsonMeterId);
+ return false;
+ }
+
+ // check table transition
+ JsonNode tableNode = getInstNode(jsonInstructions, "TABLE");
+ String jsonTableId = tableNode != null ? tableNode.get("tableId").asText() : null;
+ String tableId = trafficTreatment.tableTransition().tableId().toString();
+ if (!StringUtils.equals(jsonTableId, tableId)) {
+ description.appendText("table id was " + jsonMeterId);
+ return false;
+ }
+
+ // TODO: check deferred
+
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(trafficTreatment.toString());
+ }
+
+ /**
+ * Factory to allocate a traffic treatment.
+ *
+ * @param trafficTreatment traffic treatment object we are looking for
+ * @return matcher
+ */
+ static TrafficTreatmentJsonMatcher matchesTrafficTreatment(TrafficTreatment trafficTreatment) {
+ return new TrafficTreatmentJsonMatcher(trafficTreatment);
+ }
+ }
+
+ /**
+ * Reads in a traffic treatment from the given resource and decodes it.
+ *
+ * @param resourceName resource to use to read the JSON for the rule
+ * @return decoded trafficTreatment
+ * @throws IOException if processing the resource fails
+ */
+ private TrafficTreatment getTreatment(String resourceName) throws IOException {
+ InputStream jsonStream = TrafficTreatmentCodecTest.class.getResourceAsStream(resourceName);
+ JsonNode json = context.mapper().readTree(jsonStream);
+ assertThat(json, notNullValue());
+ TrafficTreatment treatment = trafficTreatmentCodec.decode((ObjectNode) json, context);
+ assertThat(treatment, notNullValue());
+ return treatment;
+ }
+}
diff --git a/core/common/src/test/resources/org/onosproject/codec/impl/TrafficTreatment.json b/core/common/src/test/resources/org/onosproject/codec/impl/TrafficTreatment.json
new file mode 100644
index 0000000..c185905
--- /dev/null
+++ b/core/common/src/test/resources/org/onosproject/codec/impl/TrafficTreatment.json
@@ -0,0 +1,21 @@
+{
+ "instructions": [
+ {
+ "type": "OUTPUT",
+ "port": -3
+ },
+ {
+ "type": "L2MODIFICATION",
+ "subtype": "ETH_SRC",
+ "mac": "00:00:00:00:00:00"
+ },
+ {
+ "type": "METER",
+ "meterId": "0"
+ },
+ {
+ "type": "TABLE",
+ "tableId": "1"
+ }
+ ]
+}
\ No newline at end of file