Jian Li
Committed by Gerrit Code Review

[ONOS-2225] Add codecs with unit test for FlowObjective REST API

* Add codec for FilteringObjective
* Add codec for ForwardingObjective
* Add codec for NextObjective

Change-Id: I715aa7f1969697468692459052fd27cc65ca2363
......@@ -43,6 +43,9 @@ import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.intent.ConnectivityIntent;
......@@ -109,6 +112,9 @@ public class CodecManager implements CodecService {
registerCodec(TableStatisticsEntry.class, new TableStatisticsEntryCodec());
registerCodec(PortStatistics.class, new PortStatisticsCodec());
registerCodec(Metric.class, new MetricCodec());
registerCodec(FilteringObjective.class, new FilteringObjectiveCodec());
registerCodec(ForwardingObjective.class, new ForwardingObjectiveCodec());
registerCodec(NextObjective.class, new NextObjectiveCodec());
log.info("Started");
}
......
/*
* Copyright 2016 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.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flowobjective.DefaultFilteringObjective;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.slf4j.Logger;
import java.util.stream.IntStream;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.nullIsIllegal;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Filtering Objective Codec.
*/
public class FilteringObjectiveCodec extends JsonCodec<FilteringObjective> {
private final Logger log = getLogger(getClass());
// JSON field names
private static final String ID = "id";
private static final String TYPE = "type";
private static final String KEY = "key";
private static final String META = "meta";
private static final String OPERATION = "operation";
private static final String CONDITIONS = "conditions";
// messages to be printed out
private static final String MISSING_MEMBER_MESSAGE =
" member is required in FilteringObjective";
private static final String NOT_NULL_MESSAGE =
"FilteringObjective cannot be null";
private static final String INVALID_TYPE_MESSAGE =
"The requested type {} is not defined in FilteringObjective.";
private static final String INVALID_OP_MESSAGE =
"The requested operation {} is not defined for FilteringObjective.";
public static final String REST_APP_ID = "org.onosproject.rest";
@Override
public ObjectNode encode(FilteringObjective filteringObjective, CodecContext context) {
checkNotNull(filteringObjective, NOT_NULL_MESSAGE);
final JsonCodec<Criterion> criterionCodec = context.codec(Criterion.class);
final JsonCodec<TrafficTreatment> trafficTreatmentCodec = context.codec(TrafficTreatment.class);
// encode common properties
ObjectiveCodecHelper och = new ObjectiveCodecHelper();
ObjectNode result = och.encode(filteringObjective, context);
// encode id
result.put(ID, filteringObjective.id());
// encode type
result.put(TYPE, filteringObjective.type().toString());
// encode key
if (filteringObjective.key() != null) {
ObjectNode criterionNode = criterionCodec.encode(filteringObjective.key(), context);
result.set(KEY, criterionNode);
}
// encode meta
if (filteringObjective.meta() != null) {
ObjectNode trafficTreatmentNode = trafficTreatmentCodec.encode(filteringObjective.meta(), context);
result.set(META, trafficTreatmentNode);
}
// encode conditions
ArrayNode conditions = context.mapper().createArrayNode();
filteringObjective.conditions().forEach(c -> {
ObjectNode criterionJson = criterionCodec.encode(c, context);
conditions.add(criterionJson);
});
result.set(CONDITIONS, conditions);
return result;
}
@Override
public FilteringObjective decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
CoreService coreService = context.getService(CoreService.class);
final JsonCodec<Criterion> criterionCodec = context.codec(Criterion.class);
final JsonCodec<TrafficTreatment> trafficTreatmentCodec = context.codec(TrafficTreatment.class);
ObjectiveCodecHelper och = new ObjectiveCodecHelper();
DefaultFilteringObjective.Builder baseBuilder = DefaultFilteringObjective.builder();
final DefaultFilteringObjective.Builder builder =
(DefaultFilteringObjective.Builder) och.decode(json, baseBuilder, context);
// application id
ApplicationId appId = coreService.registerApplication(REST_APP_ID);
builder.fromApp(appId);
// decode type
String typeStr = nullIsIllegal(json.get(TYPE), TYPE + MISSING_MEMBER_MESSAGE).asText();
switch (typeStr) {
case "PERMIT":
builder.permit();
break;
case "DENY":
builder.deny();
break;
default:
log.warn(INVALID_TYPE_MESSAGE, typeStr);
return null;
}
// decode key
JsonNode keyJson = json.get(KEY);
if (keyJson != null) {
Criterion key = criterionCodec.decode((ObjectNode) keyJson, context);
builder.withKey(key);
}
// decode conditions
JsonNode conditionsJson = json.get(CONDITIONS);
checkNotNull(conditionsJson);
if (conditionsJson != null) {
IntStream.range(0, conditionsJson.size()).forEach(i -> {
ObjectNode conditionJson = get(conditionsJson, i);
builder.addCondition(criterionCodec.decode(conditionJson, context));
});
}
// decode meta
JsonNode metaJson = json.get(META);
if (metaJson != null) {
TrafficTreatment trafficTreatment = trafficTreatmentCodec.decode((ObjectNode) metaJson, context);
builder.withMeta(trafficTreatment);
}
// decode operation
String opStr = nullIsIllegal(json.get(OPERATION), OPERATION + MISSING_MEMBER_MESSAGE).asText();
FilteringObjective filteringObjective;
switch (opStr) {
case "ADD":
filteringObjective = builder.add();
break;
case "REMOVE":
filteringObjective = builder.remove();
break;
default:
log.warn(INVALID_OP_MESSAGE, opStr);
return null;
}
return filteringObjective;
}
}
/*
* Copyright 2016 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 org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.slf4j.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.nullIsIllegal;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Forwarding Objective Codec.
*/
public class ForwardingObjectiveCodec extends JsonCodec<ForwardingObjective> {
private final Logger log = getLogger(getClass());
// JSON field names
private static final String ID = "id";
private static final String SELECTOR = "selector";
private static final String FLAG = "flag";
private static final String OPERATION = "operation";
private static final String NEXT_ID = "nextId";
private static final String TREATMENT = "treatment";
// messages to be printed out
private static final String MISSING_MEMBER_MESSAGE =
" member is required in ForwardingObjective";
private static final String NOT_NULL_MESSAGE =
"ForwardingObjective cannot be null";
private static final String INVALID_FLAG_MESSAGE =
"The requested flag {} is not defined in ForwardingObjective.";
private static final String INVALID_OP_MESSAGE =
"The requested operation {} is not defined for FilteringObjective.";
public static final String REST_APP_ID = "org.onosproject.rest";
@Override
public ObjectNode encode(ForwardingObjective forwardingObjective, CodecContext context) {
checkNotNull(forwardingObjective, NOT_NULL_MESSAGE);
final JsonCodec<TrafficTreatment> trafficTreatmentCodec = context.codec(TrafficTreatment.class);
final JsonCodec<TrafficSelector> trafficSelectorCodec = context.codec(TrafficSelector.class);
// encode common properties
ObjectiveCodecHelper och = new ObjectiveCodecHelper();
ObjectNode result = och.encode(forwardingObjective, context);
// encode id
result.put(ID, forwardingObjective.id());
// encode flag
result.put(FLAG, forwardingObjective.flag().toString());
// encode op
result.put(OPERATION, forwardingObjective.op().toString());
// encode selector
ObjectNode trafficSelectorNode =
trafficSelectorCodec.encode(forwardingObjective.selector(), context);
result.set(SELECTOR, trafficSelectorNode);
// encode nextId
if (forwardingObjective.nextId() != null) {
result.put(NEXT_ID, forwardingObjective.nextId());
}
// encode treatment
if (forwardingObjective.treatment() != null) {
ObjectNode trafficTreatmentNode =
trafficTreatmentCodec.encode(forwardingObjective.treatment(), context);
result.set(TREATMENT, trafficTreatmentNode);
}
return result;
}
@Override
public ForwardingObjective decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
CoreService coreService = context.getService(CoreService.class);
final JsonCodec<TrafficTreatment> trafficTreatmentCodec = context.codec(TrafficTreatment.class);
final JsonCodec<TrafficSelector> trafficSelectorCodec = context.codec(TrafficSelector.class);
ObjectiveCodecHelper och = new ObjectiveCodecHelper();
DefaultForwardingObjective.Builder baseBuilder = DefaultForwardingObjective.builder();
final DefaultForwardingObjective.Builder builder =
(DefaultForwardingObjective.Builder) och.decode(json, baseBuilder, context);
// application id
ApplicationId appId = coreService.registerApplication(REST_APP_ID);
builder.fromApp(appId);
// decode flag
String flagStr = nullIsIllegal(json.get(FLAG), FLAG + MISSING_MEMBER_MESSAGE).asText();
switch (flagStr) {
case "SPECIFIC":
builder.withFlag(ForwardingObjective.Flag.SPECIFIC);
break;
case "VERSATILE":
builder.withFlag(ForwardingObjective.Flag.VERSATILE);
break;
default:
log.warn(INVALID_FLAG_MESSAGE, flagStr);
return null;
}
// decode selector
JsonNode selectorJson = json.get(SELECTOR);
if (selectorJson != null) {
TrafficSelector trafficSelector = trafficSelectorCodec.decode((ObjectNode) selectorJson, context);
builder.withSelector(trafficSelector);
}
// decode treatment
JsonNode treatmentJson = json.get(TREATMENT);
if (treatmentJson != null) {
TrafficTreatment trafficTreatment = trafficTreatmentCodec.decode((ObjectNode) treatmentJson, context);
builder.withTreatment(trafficTreatment);
}
// decode nextId
JsonNode nextIdJson = json.get(NEXT_ID);
if (nextIdJson != null) {
builder.nextStep(nextIdJson.asInt());
}
// decode operation
String opStr = nullIsIllegal(json.get(OPERATION), OPERATION + MISSING_MEMBER_MESSAGE).asText();
ForwardingObjective forwardingObjective;
switch (opStr) {
case "ADD":
forwardingObjective = builder.add();
break;
case "REMOVE":
forwardingObjective = builder.remove();
break;
default:
log.warn(INVALID_OP_MESSAGE, opStr);
return null;
}
return forwardingObjective;
}
}
/*
* Copyright 2016 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.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flowobjective.DefaultNextObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.slf4j.Logger;
import java.util.stream.IntStream;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.nullIsIllegal;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Next Objective Codec.
*/
public class NextObjectiveCodec extends JsonCodec<NextObjective> {
private final Logger log = getLogger(getClass());
// JSON field names
private static final String ID = "id";
private static final String TYPE = "type";
private static final String OPERATION = "operation";
private static final String TREATMENTS = "treatments";
private static final String META = "meta";
// messages to be printed out
private static final String MISSING_MEMBER_MESSAGE =
" member is required in NextObjective";
private static final String NOT_NULL_MESSAGE =
"NextObjective cannot be null";
private static final String INVALID_TYPE_MESSAGE =
"The requested flag {} is not defined in NextObjective.";
private static final String INVALID_OP_MESSAGE =
"The requested operation {} is not defined for NextObjective.";
public static final String REST_APP_ID = "org.onosproject.rest";
@Override
public ObjectNode encode(NextObjective nextObjective, CodecContext context) {
checkNotNull(nextObjective, NOT_NULL_MESSAGE);
final JsonCodec<TrafficTreatment> trafficTreatmentCodec = context.codec(TrafficTreatment.class);
final JsonCodec<TrafficSelector> trafficSelectorCodec = context.codec(TrafficSelector.class);
// encode common properties
ObjectiveCodecHelper och = new ObjectiveCodecHelper();
ObjectNode result = och.encode(nextObjective, context);
// encode id
result.put(ID, nextObjective.id());
// encode type
result.put(TYPE, nextObjective.type().toString());
// encode operation
result.put(OPERATION, nextObjective.op().toString());
// encode treatments
ArrayNode treatments = context.mapper().createArrayNode();
nextObjective.next().forEach(t -> {
ObjectNode treatmentJson = trafficTreatmentCodec.encode(t, context);
treatments.add(treatmentJson);
});
result.set(TREATMENTS, treatments);
// encode meta
if (nextObjective.meta() != null) {
ObjectNode trafficSelectorNode = trafficSelectorCodec.encode(nextObjective.meta(), context);
result.set(META, trafficSelectorNode);
}
return result;
}
@Override
public NextObjective decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
CoreService coreService = context.getService(CoreService.class);
final JsonCodec<TrafficSelector> trafficSelectorCodec = context.codec(TrafficSelector.class);
final JsonCodec<TrafficTreatment> trafficTreatmentCodec = context.codec(TrafficTreatment.class);
ObjectiveCodecHelper och = new ObjectiveCodecHelper();
DefaultNextObjective.Builder baseBuilder = DefaultNextObjective.builder();
final DefaultNextObjective.Builder builder =
(DefaultNextObjective.Builder) och.decode(json, baseBuilder, context);
// decode id
JsonNode idJson = json.get(ID);
checkNotNull(idJson);
builder.withId(idJson.asInt());
// decode application id
ApplicationId appId = coreService.registerApplication(REST_APP_ID);
builder.fromApp(appId);
// decode type
String typeStr = nullIsIllegal(json.get(TYPE), TYPE + MISSING_MEMBER_MESSAGE).asText();
switch (typeStr) {
case "HASHED":
builder.withType(NextObjective.Type.HASHED);
break;
case "BROADCAST":
builder.withType(NextObjective.Type.BROADCAST);
break;
case "FAILOVER":
builder.withType(NextObjective.Type.FAILOVER);
break;
case "SIMPLE":
builder.withType(NextObjective.Type.SIMPLE);
break;
default:
log.warn(INVALID_TYPE_MESSAGE, typeStr);
return null;
}
// decode treatments
JsonNode treatmentsJson = json.get(TREATMENTS);
checkNotNull(treatmentsJson);
if (treatmentsJson != null) {
IntStream.range(0, treatmentsJson.size()).forEach(i -> {
ObjectNode treatmentJson = get(treatmentsJson, i);
builder.addTreatment(trafficTreatmentCodec.decode(treatmentJson, context));
});
}
// decode meta
JsonNode metaJson = json.get(META);
if (metaJson != null) {
TrafficSelector trafficSelector = trafficSelectorCodec.decode((ObjectNode) metaJson, context);
builder.withMeta(trafficSelector);
}
// decode operation
String opStr = nullIsIllegal(json.get(OPERATION), OPERATION + MISSING_MEMBER_MESSAGE).asText();
NextObjective nextObjective;
switch (opStr) {
case "ADD":
nextObjective = builder.add();
break;
case "REMOVE":
nextObjective = builder.remove();
break;
default:
log.warn(INVALID_OP_MESSAGE, opStr);
return null;
}
return nextObjective;
}
}
/*
* Copyright 2016 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.node.ObjectNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.net.flowobjective.Objective;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Objective Codec Helper.
*/
public class ObjectiveCodecHelper {
// JSON field names
private static final String ID = "id";
private static final String APP_ID = "appId";
private static final String OPERATION = "operation";
private static final String PERMANENT = "isPermanent";
private static final String PRIORITY = "priority";
private static final String TIMEOUT = "timeout";
public static final String REST_APP_ID = "org.onosproject.rest";
public ObjectNode encode(Objective objective, CodecContext context) {
checkNotNull(objective, "Objective cannot be null");
ObjectNode result = context.mapper().createObjectNode()
.put(ID, objective.id())
.put(OPERATION, objective.op().toString())
.put(PERMANENT, String.valueOf(objective.permanent()))
.put(PRIORITY, objective.priority())
.put(TIMEOUT, objective.timeout());
if (objective.appId() != null) {
result.put(APP_ID, objective.appId().toString());
}
return result;
}
public Objective.Builder decode(ObjectNode json, Objective.Builder builder, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
// permanent
boolean permanent = false;
if (json.get(PERMANENT) != null) {
permanent = json.get(PERMANENT).asBoolean();
}
// timeout
int timeoutInt = 0;
if (json.get(TIMEOUT) != null) {
timeoutInt = json.get(TIMEOUT).asInt();
}
// priority
int priorityInt = 0;
if (json.get(PRIORITY) != null) {
priorityInt = json.get(PRIORITY).asInt();
}
if (permanent) {
builder.makePermanent()
.makeTemporary(timeoutInt)
.withPriority(priorityInt);
} else {
builder.makeTemporary(timeoutInt)
.withPriority(priorityInt);
}
return builder;
}
}
/*
* Copyright 2016 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 org.junit.Before;
import org.junit.Test;
import org.onlab.packet.VlanId;
import org.onosproject.codec.JsonCodec;
import org.onosproject.core.CoreService;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flowobjective.DefaultFilteringObjective;
import org.onosproject.net.flowobjective.FilteringObjective;
import java.io.IOException;
import java.io.InputStream;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.onosproject.codec.impl.FilteringObjectiveJsonMatcher.matchesFilteringObjective;
import static org.onosproject.net.NetTestTools.APP_ID;
/**
* Unit tests for FilteringObjective Codec.
*/
public class FilteringObjectiveCodecTest {
MockCodecContext context;
JsonCodec<FilteringObjective> filteringObjectiveCodec;
final CoreService mockCoreService = createMock(CoreService.class);
/**
* Sets up for each test.
* Creates a context and fetches the FilteringObjective codec.
*/
@Before
public void setUp() {
context = new MockCodecContext();
filteringObjectiveCodec = context.codec(FilteringObjective.class);
assertThat(filteringObjectiveCodec, notNullValue());
expect(mockCoreService.registerApplication(FilteringObjectiveCodec.REST_APP_ID))
.andReturn(APP_ID).anyTimes();
replay(mockCoreService);
context.registerService(CoreService.class, mockCoreService);
}
/**
* Tests encoding of a FilteringObjective object.
*/
@Test
public void testFilteringObjectiveEncode() {
Criterion condition1 = Criteria.matchVlanId(VlanId.ANY);
Criterion condition2 = Criteria.matchEthType((short) 0x8844);
FilteringObjective filteringObj = DefaultFilteringObjective.builder()
.makePermanent()
.permit()
.fromApp(APP_ID)
.withPriority(60)
.addCondition(condition1)
.addCondition(condition2)
.add();
// TODO: need to add test case for TrafficTreatment (META in filteringObj)
ObjectNode filteringObjJson = filteringObjectiveCodec.encode(filteringObj, context);
assertThat(filteringObjJson, matchesFilteringObjective(filteringObj));
}
/**
* Test decoding of a FilteringObjective object.
*/
@Test
public void testFilteringObjectiveDecode() throws IOException {
FilteringObjective filteringObjective = getFilteringObjective("FilteringObjective.json");
assertThat(filteringObjective.type(), is(FilteringObjective.Type.PERMIT));
assertThat(filteringObjective.priority(), is(60));
assertThat(filteringObjective.timeout(), is(1));
assertThat(filteringObjective.op(), is(FilteringObjective.Operation.ADD));
assertThat(filteringObjective.permanent(), is(false));
}
/**
* Reads in a filteringObjective from the given resource and decodes it.
*
* @param resourceName resource to use to read the JSON for the rule
* @return decoded filteringObjective
* @throws IOException if processing the resource fails
*/
private FilteringObjective getFilteringObjective(String resourceName) throws IOException {
InputStream jsonStream = FilteringObjectiveCodecTest.class.getResourceAsStream(resourceName);
JsonNode json = context.mapper().readTree(jsonStream);
assertThat(json, notNullValue());
FilteringObjective filteringObjective = filteringObjectiveCodec.decode((ObjectNode) json, context);
assertThat(filteringObjective, notNullValue());
return filteringObjective;
}
}
/*
* Copyright 2016 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 org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flowobjective.FilteringObjective;
/**
* Hamcrest matcher for filteringObjective.
*/
public final class FilteringObjectiveJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
final FilteringObjective filteringObj;
private FilteringObjectiveJsonMatcher(FilteringObjective filteringObjective) {
this.filteringObj = filteringObjective;
}
@Override
protected boolean matchesSafely(JsonNode jsonFilteringObj, Description description) {
ObjectiveJsonMatcher.matchesObjective(filteringObj).matchesSafely(jsonFilteringObj);
// check id
int jsonId = jsonFilteringObj.get("id").asInt();
int id = filteringObj.id();
if (jsonId != id) {
description.appendText("id was " + jsonId);
return false;
}
// check type
String jsonType = jsonFilteringObj.get("type").asText();
String type = filteringObj.type().toString();
if (!jsonType.equals(type)) {
description.appendText("type was " + jsonType);
return false;
}
// check size of condition array
JsonNode jsonConditions = jsonFilteringObj.get("conditions");
if (jsonConditions.size() != filteringObj.conditions().size()) {
description.appendText("conditions size was " + jsonConditions.size());
return false;
}
// check conditions
for (Criterion c : filteringObj.conditions()) {
boolean conditionFound = false;
for (int cIndex = 0; cIndex < jsonConditions.size(); cIndex++) {
CriterionJsonMatcher criterionMatcher = CriterionJsonMatcher.matchesCriterion(c);
if (criterionMatcher.matches(jsonConditions.get(cIndex))) {
conditionFound = true;
break;
}
}
if (!conditionFound) {
description.appendText("condition not found " + c.toString());
return false;
}
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(filteringObj.toString());
}
/**
* Factory to allocate a filteringObjective matcher.
*
* @param filteringObj filteringObjective object we are looking for
* @return matcher
*/
public static FilteringObjectiveJsonMatcher matchesFilteringObjective(FilteringObjective filteringObj) {
return new FilteringObjectiveJsonMatcher(filteringObj);
}
}
/*
* Copyright 2016 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 org.junit.Before;
import org.junit.Test;
import org.onlab.packet.VlanId;
import org.onosproject.codec.JsonCodec;
import org.onosproject.core.CoreService;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import java.io.IOException;
import java.io.InputStream;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.onosproject.codec.impl.ForwardingObjectiveJsonMatcher.matchesForwardingObjective;
import static org.onosproject.net.NetTestTools.APP_ID;
/**
* Unit tests for ForwardingObjective Codec.
*/
public class ForwardingObjectiveCodecTest {
MockCodecContext context;
JsonCodec<ForwardingObjective> forwardingObjectiveCodec;
final CoreService mockCoreService = createMock(CoreService.class);
/**
* Sets up for each test.
* Creates a context and fetches the ForwardingObjective codec.
*/
@Before
public void setUp() {
context = new MockCodecContext();
forwardingObjectiveCodec = context.codec(ForwardingObjective.class);
assertThat(forwardingObjectiveCodec, notNullValue());
expect(mockCoreService.registerApplication(ForwardingObjectiveCodec.REST_APP_ID))
.andReturn(APP_ID).anyTimes();
replay(mockCoreService);
context.registerService(CoreService.class, mockCoreService);
}
/**
* Tests encoding of a ForwardingObjective object.
*/
@Test
public void testForwardingObjectiveEncode() {
Criterion criterion1 = Criteria.matchVlanId(VlanId.ANY);
Criterion criterion2 = Criteria.matchEthType((short) 0x8844);
TrafficSelector selector = DefaultTrafficSelector.builder()
.add(criterion1)
.add(criterion2)
.build();
ForwardingObjective forwardingObj = DefaultForwardingObjective.builder()
.makePermanent()
.fromApp(APP_ID)
.withPriority(60)
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.nextStep(1)
.withSelector(selector)
.add();
ObjectNode forwardingObjJson = forwardingObjectiveCodec.encode(forwardingObj, context);
assertThat(forwardingObjJson, matchesForwardingObjective(forwardingObj));
}
/**
* Test decoding of a ForwardingObjective object.
*/
@Test
public void testForwardingObjectiveDecode() throws IOException {
ForwardingObjective forwardingObjective = getForwardingObjective("ForwardingObjective.json");
assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
assertThat(forwardingObjective.priority(), is(60));
assertThat(forwardingObjective.timeout(), is(1));
assertThat(forwardingObjective.op(), is(ForwardingObjective.Operation.ADD));
assertThat(forwardingObjective.permanent(), is(false));
}
/**
* Reads in a forwardingObjectiveJsonCodec from the given resource and decodes it.
*
* @param resourceName resource to use to read the JSON for the rule
* @return decoded forwardingObjectiveJsonCodec
* @throws IOException if processing the resource fails
*/
private ForwardingObjective getForwardingObjective(String resourceName) throws IOException {
InputStream jsonStream = ForwardingObjectiveCodecTest.class.getResourceAsStream(resourceName);
JsonNode json = context.mapper().readTree(jsonStream);
assertThat(json, notNullValue());
ForwardingObjective forwardingObjective = forwardingObjectiveCodec.decode((ObjectNode) json, context);
assertThat(forwardingObjective, notNullValue());
return forwardingObjective;
}
}
/*
* Copyright 2016 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 org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.onosproject.net.flowobjective.ForwardingObjective;
/**
* Hamcrest matcher for forwardingObjective.
*/
public final class ForwardingObjectiveJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
final ForwardingObjective forwardingObjective;
private ForwardingObjectiveJsonMatcher(ForwardingObjective forwardingObjective) {
this.forwardingObjective = forwardingObjective;
}
@Override
protected boolean matchesSafely(JsonNode jsonForwardingObj, Description description) {
ObjectiveJsonMatcher.matchesObjective(forwardingObjective).matchesSafely(jsonForwardingObj);
// check id
int jsonId = jsonForwardingObj.get("id").asInt();
int id = forwardingObjective.id();
if (jsonId != id) {
description.appendText("id was " + jsonId);
return false;
}
// check nextId
int jsonNextId = jsonForwardingObj.get("nextId").asInt();
int nextId = forwardingObjective.nextId();
if (jsonNextId != nextId) {
description.appendText("nextId was " + jsonNextId);
return false;
}
// check flag
String jsonFlag = jsonForwardingObj.get("flag").asText();
String flag = forwardingObjective.flag().toString();
if (!jsonFlag.equals(flag)) {
description.appendText("flag was " + jsonFlag);
return false;
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(forwardingObjective.toString());
}
/**
* Factory to allocate a forwardingObjective matcher.
*
* @param forwardingObjective forwardingObjective object we are looking for
* @return matcher
*/
public static ForwardingObjectiveJsonMatcher matchesForwardingObjective(ForwardingObjective forwardingObjective) {
return new ForwardingObjectiveJsonMatcher(forwardingObjective);
}
}
/*
* Copyright 2016 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 org.junit.Before;
import org.junit.Test;
import org.onosproject.codec.JsonCodec;
import org.onosproject.core.CoreService;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flowobjective.DefaultNextObjective;
import org.onosproject.net.flowobjective.NextObjective;
import java.io.IOException;
import java.io.InputStream;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.onosproject.codec.impl.NextObjectiveJsonMatcher.matchesNextObjective;
import static org.onosproject.net.NetTestTools.APP_ID;
/**
* Unit tests for NextObjective Codec.
*/
public class NextObjectiveCodecTest {
MockCodecContext context;
JsonCodec<NextObjective> nextObjectiveCodec;
final CoreService mockCoreService = createMock(CoreService.class);
/**
* Sets up for each test.
* Creates a context and fetches the NextObjective codec.
*/
@Before
public void setUp() {
context = new MockCodecContext();
nextObjectiveCodec = context.codec(NextObjective.class);
assertThat(nextObjectiveCodec, notNullValue());
expect(mockCoreService.registerApplication(NextObjectiveCodec.REST_APP_ID))
.andReturn(APP_ID).anyTimes();
replay(mockCoreService);
context.registerService(CoreService.class, mockCoreService);
}
/**
* Tests encoding of a NextObjective object.
*/
@Test
public void testNextObjectiveEncode() {
TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
NextObjective nextObj = DefaultNextObjective.builder()
.makePermanent()
.withType(NextObjective.Type.HASHED)
.fromApp(APP_ID)
.withPriority(60)
.withId(5)
.addTreatment(treatment)
.add();
ObjectNode nextObjJson = nextObjectiveCodec.encode(nextObj, context);
assertThat(nextObjJson, matchesNextObjective(nextObj));
}
/**
* Test decoding of a NextObjective object.
*/
@Test
public void testNextObjectiveDecode() throws IOException {
NextObjective nextObjective = getNextObjective("NextObjective.json");
assertThat(nextObjective.type(), is(NextObjective.Type.FAILOVER));
assertThat(nextObjective.op(), is(NextObjective.Operation.ADD));
}
/**
* Reads in a nextObjective from the given resource and decodes it.
*
* @param resourceName resource to use to read the JSON for the rule
* @return decoded nextObjective
* @throws IOException if processing the resource fails
*/
private NextObjective getNextObjective(String resourceName) throws IOException {
InputStream jsonStream = NextObjectiveCodecTest.class.getResourceAsStream(resourceName);
JsonNode json = context.mapper().readTree(jsonStream);
assertThat(json, notNullValue());
NextObjective nextObjective = nextObjectiveCodec.decode((ObjectNode) json, context);
assertThat(nextObjective, notNullValue());
return nextObjective;
}
}
/*
* Copyright 2016 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 org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.onosproject.net.flowobjective.NextObjective;
/**
* Hamcrest matcher for nextObjective.
*/
public final class NextObjectiveJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
final NextObjective nextObjective;
private NextObjectiveJsonMatcher(NextObjective nextObjective) {
this.nextObjective = nextObjective;
}
@Override
protected boolean matchesSafely(JsonNode jsonNextObj, Description description) {
ObjectiveJsonMatcher.matchesObjective(nextObjective).matchesSafely(jsonNextObj);
// check id
int jsonId = jsonNextObj.get("id").asInt();
int id = nextObjective.id();
if (jsonId != id) {
description.appendText("id was " + jsonId);
return false;
}
// check type
String jsonType = jsonNextObj.get("type").asText();
String type = nextObjective.type().toString();
if (!jsonType.equals(type)) {
description.appendText("type was " + jsonType);
return false;
}
// check size of treatment array
JsonNode jsonTreatments = jsonNextObj.get("treatments");
if (jsonTreatments.size() != nextObjective.next().size()) {
description.appendText("treatments size was " + jsonTreatments.size());
return false;
}
// TODO: need to check the content of treatment collection
// TODO: need to check the content of selector instance
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(nextObjective.toString());
}
/**
* Factory to allocate a nextObjective matcher.
*
* @param nextObjective nextObjective object we are looking for
* @return matcher
*/
public static NextObjectiveJsonMatcher matchesNextObjective(NextObjective nextObjective) {
return new NextObjectiveJsonMatcher(nextObjective);
}
}
/*
* Copyright 2016 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 org.onosproject.net.flowobjective.Objective;
/**
* Hamcrest matcher for instructions.
*/
public final class ObjectiveJsonMatcher {
final Objective objective;
private ObjectiveJsonMatcher(Objective objective) {
this.objective = objective;
}
protected boolean matchesSafely(JsonNode jsonObjective) {
// check operation
String jsonOp = jsonObjective.get("operation").asText();
String op = objective.op().toString();
if (!jsonOp.equals(op)) {
return false;
}
// check permanent
boolean jsonPermanent = jsonObjective.get("isPermanent").asBoolean();
boolean permanent = objective.permanent();
if (jsonPermanent != permanent) {
return false;
}
// check priority
int jsonPriority = jsonObjective.get("priority").asInt();
int priority = objective.priority();
if (jsonPriority != priority) {
return false;
}
// check timeout
int jsonTimeout = jsonObjective.get("timeout").asInt();
int timeout = objective.timeout();
if (jsonTimeout != timeout) {
return false;
}
return true;
}
/**
* Factory to allocate a ObjectiveJsonMatcher.
*
* @param objective objective object we are looking for
* @return matcher
*/
public static ObjectiveJsonMatcher matchesObjective(Objective objective) {
return new ObjectiveJsonMatcher(objective);
}
}
{
"priority": 60,
"isPermanent": "false",
"timeout": 1,
"type": "PERMIT",
"operation": "ADD",
"conditions": [
{
"type": "IN_PORT",
"port": 23
}
],
"meta": {
"instructions": [
{
"type": "OUTPUT",
"port": -3
},
{
"type": "DROP"
}
],
"deferred": []
}
}
\ No newline at end of file
{
"priority": 60,
"isPermanent": "false",
"timeout": 1,
"flag": "SPECIFIC",
"operation": "ADD",
"selector": {
"criteria": [
{
"type": "ETH_TYPE",
"ethType": "0x806"
}
]
},
"treatment":
{
"instructions":
[
{"type":"OUTPUT","port":-3},
{"type":"DROP"}
],
"deferred":[]
}
}
\ No newline at end of file
{
"id": 1,
"type": "FAILOVER",
"operation": "ADD",
"treatments": [
{
"instructions": [
{
"type": "OUTPUT",
"port": -3
},
{
"type": "DROP"
}
],
"deferred": []
}
],
"meta": {
"criteria": [
{
"type": "IN_PORT",
"port": 23
}
]
}
}
\ No newline at end of file