Jian Li
Committed by Ray Milkey

Add unit test for TrafficTreatment REST API

Change-Id: I19834b9edbb87e66ca6fb4ce4f6601f685ba116e
/*
* 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;
}
}
{
"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