blob: f23e846df94703f2fbf93a98c57cdee0a0ed7d7a [file] [log] [blame]
Jian Li96b47d92016-05-16 17:59:06 -07001/*
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 */
16package org.onosproject.codec.impl;
17
18import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ObjectNode;
20import com.google.common.collect.ImmutableSet;
21import org.apache.commons.lang3.StringUtils;
22import org.hamcrest.Description;
23import org.hamcrest.TypeSafeDiagnosingMatcher;
24import org.junit.Before;
25import org.junit.Test;
26import org.onlab.packet.MacAddress;
27import org.onosproject.codec.JsonCodec;
28import org.onosproject.net.PortNumber;
29import org.onosproject.net.flow.DefaultTrafficTreatment;
30import org.onosproject.net.flow.TrafficTreatment;
31import org.onosproject.net.flow.instructions.Instruction;
32import org.onosproject.net.flow.instructions.Instructions;
33import org.onosproject.net.meter.MeterId;
34
35import java.io.IOException;
36import java.io.InputStream;
37import java.util.List;
38
39import static org.hamcrest.MatcherAssert.assertThat;
40import static org.hamcrest.Matchers.is;
41import static org.hamcrest.Matchers.notNullValue;
42
43/**
44 * Unit tests for traffic treatment codec.
45 */
46public 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}