Jian Li
Committed by Ray Milkey

Add unit test for TrafficTreatment REST API

Change-Id: I19834b9edbb87e66ca6fb4ce4f6601f685ba116e
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import com.google.common.collect.ImmutableSet;
21 +import org.apache.commons.lang3.StringUtils;
22 +import org.hamcrest.Description;
23 +import org.hamcrest.TypeSafeDiagnosingMatcher;
24 +import org.junit.Before;
25 +import org.junit.Test;
26 +import org.onlab.packet.MacAddress;
27 +import org.onosproject.codec.JsonCodec;
28 +import org.onosproject.net.PortNumber;
29 +import org.onosproject.net.flow.DefaultTrafficTreatment;
30 +import org.onosproject.net.flow.TrafficTreatment;
31 +import org.onosproject.net.flow.instructions.Instruction;
32 +import org.onosproject.net.flow.instructions.Instructions;
33 +import org.onosproject.net.meter.MeterId;
34 +
35 +import java.io.IOException;
36 +import java.io.InputStream;
37 +import java.util.List;
38 +
39 +import static org.hamcrest.MatcherAssert.assertThat;
40 +import static org.hamcrest.Matchers.is;
41 +import static org.hamcrest.Matchers.notNullValue;
42 +
43 +/**
44 + * Unit tests for traffic treatment codec.
45 + */
46 +public class TrafficTreatmentCodecTest {
47 +
48 + private MockCodecContext context;
49 + private JsonCodec<TrafficTreatment> trafficTreatmentCodec;
50 +
51 + @Before
52 + public void setUp() {
53 + context = new MockCodecContext();
54 + trafficTreatmentCodec = context.codec(TrafficTreatment.class);
55 + assertThat(trafficTreatmentCodec, notNullValue());
56 + }
57 +
58 + /**
59 + * Tests encoding of a traffic treatment object.
60 + */
61 + @Test
62 + public void testTrafficTreatmentEncode() {
63 +
64 + Instruction output = Instructions.createOutput(PortNumber.portNumber(0));
65 + Instruction modL2Src = Instructions.modL2Src(MacAddress.valueOf("11:22:33:44:55:66"));
66 + Instruction modL2Dst = Instructions.modL2Dst(MacAddress.valueOf("44:55:66:77:88:99"));
67 + MeterId meterId = MeterId.meterId(0);
68 + Instruction meter = Instructions.meterTraffic(meterId);
69 + Instruction transition = Instructions.transition(1);
70 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
71 + TrafficTreatment treatment = tBuilder
72 + .add(output)
73 + .add(modL2Src)
74 + .add(modL2Dst)
75 + .add(meter)
76 + .add(transition)
77 + .build();
78 +
79 + ObjectNode treatmentJson = trafficTreatmentCodec.encode(treatment, context);
80 + assertThat(treatmentJson, TrafficTreatmentJsonMatcher.matchesTrafficTreatment(treatment));
81 + }
82 +
83 + /**
84 + * Tests decoding of a traffic treatment JSON object.
85 + */
86 + @Test
87 + public void testTrafficTreatmentDecode() throws IOException {
88 + TrafficTreatment treatment = getTreatment("TrafficTreatment.json");
89 +
90 + List<Instruction> insts = treatment.immediate();
91 + assertThat(insts.size(), is(2));
92 +
93 + ImmutableSet<String> types = ImmutableSet.of("OUTPUT", "L2MODIFICATION");
94 + assertThat(types.contains(insts.get(0).type().name()), is(true));
95 + assertThat(types.contains(insts.get(1).type().name()), is(true));
96 + }
97 +
98 + private static final class TrafficTreatmentJsonMatcher
99 + extends TypeSafeDiagnosingMatcher<JsonNode> {
100 +
101 + private final TrafficTreatment trafficTreatment;
102 +
103 + private TrafficTreatmentJsonMatcher(TrafficTreatment trafficTreatment) {
104 + this.trafficTreatment = trafficTreatment;
105 + }
106 +
107 + /**
108 + * Filtered out the meter and table transition instructions.
109 + *
110 + * @param node JSON node
111 + * @return filtered JSON node
112 + */
113 + private int filteredSize(JsonNode node) {
114 + int counter = 0;
115 + for (int idx = 0; idx < node.size(); idx++) {
116 + String type = node.get(idx).get("type").asText();
117 + if (!type.equals("METER") && !type.equals("TABLE")) {
118 + counter++;
119 + }
120 + }
121 + return counter;
122 + }
123 +
124 + private JsonNode getInstNode(JsonNode node, String name) {
125 + for (int idx = 0; idx < node.size(); idx++) {
126 + String type = node.get(idx).get("type").asText();
127 + if (type.equals(name)) {
128 + return node.get(idx);
129 + }
130 + }
131 + return null;
132 + }
133 +
134 + @Override
135 + protected boolean matchesSafely(JsonNode jsonNode, Description description) {
136 +
137 + // check instructions
138 + final JsonNode jsonInstructions = jsonNode.get("instructions");
139 +
140 + if (trafficTreatment.immediate().size() != filteredSize(jsonInstructions)) {
141 + description.appendText("instructions array size of " +
142 + Integer.toString(trafficTreatment.immediate().size()));
143 + return false;
144 + }
145 +
146 + for (final Instruction instruction : trafficTreatment.immediate()) {
147 + boolean instructionFound = false;
148 + for (int instructionIndex = 0; instructionIndex < jsonInstructions.size();
149 + instructionIndex++) {
150 + final String jsonType =
151 + jsonInstructions.get(instructionIndex).get("type").asText();
152 + final String instructionType = instruction.type().name();
153 + if (jsonType.equals(instructionType)) {
154 + instructionFound = true;
155 + }
156 + }
157 + if (!instructionFound) {
158 + description.appendText("instruction " + instruction.toString());
159 + return false;
160 + }
161 + }
162 +
163 + // check metered
164 + JsonNode meterNode = getInstNode(jsonInstructions, "METER");
165 + String jsonMeterId = meterNode != null ? meterNode.get("meterId").asText() : null;
166 + String meterId = trafficTreatment.metered().meterId().toString();
167 + if (!StringUtils.equals(jsonMeterId, meterId)) {
168 + description.appendText("meter id was " + jsonMeterId);
169 + return false;
170 + }
171 +
172 + // check table transition
173 + JsonNode tableNode = getInstNode(jsonInstructions, "TABLE");
174 + String jsonTableId = tableNode != null ? tableNode.get("tableId").asText() : null;
175 + String tableId = trafficTreatment.tableTransition().tableId().toString();
176 + if (!StringUtils.equals(jsonTableId, tableId)) {
177 + description.appendText("table id was " + jsonMeterId);
178 + return false;
179 + }
180 +
181 + // TODO: check deferred
182 +
183 + return true;
184 + }
185 +
186 + @Override
187 + public void describeTo(Description description) {
188 + description.appendText(trafficTreatment.toString());
189 + }
190 +
191 + /**
192 + * Factory to allocate a traffic treatment.
193 + *
194 + * @param trafficTreatment traffic treatment object we are looking for
195 + * @return matcher
196 + */
197 + static TrafficTreatmentJsonMatcher matchesTrafficTreatment(TrafficTreatment trafficTreatment) {
198 + return new TrafficTreatmentJsonMatcher(trafficTreatment);
199 + }
200 + }
201 +
202 + /**
203 + * Reads in a traffic treatment from the given resource and decodes it.
204 + *
205 + * @param resourceName resource to use to read the JSON for the rule
206 + * @return decoded trafficTreatment
207 + * @throws IOException if processing the resource fails
208 + */
209 + private TrafficTreatment getTreatment(String resourceName) throws IOException {
210 + InputStream jsonStream = TrafficTreatmentCodecTest.class.getResourceAsStream(resourceName);
211 + JsonNode json = context.mapper().readTree(jsonStream);
212 + assertThat(json, notNullValue());
213 + TrafficTreatment treatment = trafficTreatmentCodec.decode((ObjectNode) json, context);
214 + assertThat(treatment, notNullValue());
215 + return treatment;
216 + }
217 +}
1 +{
2 + "instructions": [
3 + {
4 + "type": "OUTPUT",
5 + "port": -3
6 + },
7 + {
8 + "type": "L2MODIFICATION",
9 + "subtype": "ETH_SRC",
10 + "mac": "00:00:00:00:00:00"
11 + },
12 + {
13 + "type": "METER",
14 + "meterId": "0"
15 + },
16 + {
17 + "type": "TABLE",
18 + "tableId": "1"
19 + }
20 + ]
21 +}
...\ No newline at end of file ...\ No newline at end of file