Initial import of CFM and SOAM api 1.10
Change-Id: Icf5cc2d5fb34b75460e80e8cced0d70265bcd33b
Minor changes to get CFM and SOAM patch work on 1.10
Change-Id: Ibd90fdeaf143f4cfdc98f7e6eb28bfa55f471e4b
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/CfmCodecContext.java b/apps/cfm/src/test/java/org/onosproject/cfm/CfmCodecContext.java
new file mode 100644
index 0000000..0f1de5e
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/CfmCodecContext.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.CodecService;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.codec.impl.CodecManager;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Mock codec context for use in codec unit tests.
+ */
+public class CfmCodecContext implements CodecContext {
+
+ private final ObjectMapper mapper = new ObjectMapper();
+ private final CodecManager codecManager = new CodecManager();
+ private final CfmWebComponent manager = new CfmWebComponent();
+
+ /**
+ * Constructs a new mock codec context.
+ */
+ public CfmCodecContext() {
+ codecManager.activate();
+ manager.codecService = codecManager;
+ manager.activate();
+ }
+
+ @Override
+ public ObjectMapper mapper() {
+ return mapper;
+ }
+
+ @Override
+ public <T> T getService(Class<T> serviceClass) {
+ return null;
+ }
+
+ @Override
+ public <T> JsonCodec<T> codec(Class<T> entityClass) {
+ return codecManager.getCodec(entityClass);
+ }
+
+ /**
+ * Get the codec manager.
+ *
+ * @return instance of codec manager
+ */
+ public CodecService codecManager() {
+ return codecManager;
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/impl/CfmResourceTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/impl/CfmResourceTest.java
new file mode 100644
index 0000000..bcbaa9a
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/impl/CfmResourceTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.impl;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.onosproject.rest.resources.ResourceTest;
+
+/**
+ * Base class for CFM REST API tests. Performs common configuration operations.
+ */
+public class CfmResourceTest extends ResourceTest {
+
+ /**
+ * Creates a new web-resource test.
+ */
+ public CfmResourceTest() {
+ super(ResourceConfig.forApplicationClass(CfmWebApplication.class));
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/impl/MaWebResourceTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/impl/MaWebResourceTest.java
new file mode 100644
index 0000000..6378ea9
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/impl/MaWebResourceTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.packet.VlanId;
+import org.onlab.rest.BaseResource;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.codec.CodecService;
+import org.onosproject.incubator.net.l2monitoring.cfm.Component;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultComponent;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Optional;
+
+import static junit.framework.TestCase.fail;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class MaWebResourceTest extends CfmResourceTest {
+ private final CfmMdService mdService = createMock(CfmMdService.class);
+
+ private static final MdId MDNAME1 = MdIdCharStr.asMdId("md-1");
+ private static final MaIdShort MANAME1 = MaIdCharStr.asMaId("ma-1-1");
+
+ private MaintenanceAssociation ma1;
+
+ @Before
+ public void setUpTest() throws CfmConfigException {
+ CfmCodecContext context = new CfmCodecContext();
+ ServiceDirectory testDirectory = new TestServiceDirectory()
+ .add(CfmMdService.class, mdService)
+ .add(CodecService.class, context.codecManager());
+ BaseResource.setServiceDirectory(testDirectory);
+
+ ma1 = DefaultMaintenanceAssociation
+ .builder(MANAME1, MDNAME1.getNameLength())
+ .addToRemoteMepIdList(MepId.valueOf((short) 101))
+ .addToRemoteMepIdList(MepId.valueOf((short) 102))
+ .ccmInterval(MaintenanceAssociation.CcmInterval.INTERVAL_3MS)
+ .maNumericId((short) 1)
+ .addToComponentList(
+ DefaultComponent.builder(1)
+ .tagType(Component.TagType.VLAN_STAG)
+ .mhfCreationType(Component.MhfCreationType.NONE)
+ .idPermission(Component.IdPermissionType.MANAGE)
+ .addToVidList(VlanId.vlanId((short) 1010))
+ .build())
+ .build();
+ }
+
+ @Test
+ public void testGetMa() {
+
+ expect(mdService.getMaintenanceAssociation(MDNAME1, MANAME1))
+ .andReturn(Optional.ofNullable(ma1)).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName()
+ + "/ma/" + MANAME1.maName()).request().get(String.class);
+
+ assertThat(response, is("{\"ma\":" +
+ "{\"maName\":\"ma-1-1\"," +
+ "\"maNameType\":\"CHARACTERSTRING\"," +
+ "\"maNumericId\":1," +
+ "\"ccm-interval\":\"INTERVAL_3MS\"," +
+ "\"component-list\":[{\"component\":" +
+ "{\"component-id\":1," +
+ "\"vid-list\":[{\"vid\":\"1010\"}]," +
+ "\"mhf-creation-type\":\"NONE\"," +
+ "\"id-permission\":\"MANAGE\"," +
+ "\"tag-type\":\"VLAN_STAG\"}}]," +
+ "\"rmep-list\":" +
+ "[{\"rmep\":101}," +
+ "{\"rmep\":102}]}}"));
+ }
+
+ @Test
+ public void testGetMaEmpty() throws IOException {
+ MaIdShort maId2 = MaIdCharStr.asMaId("ma-2");
+ expect(mdService
+ .getMaintenanceAssociation(MDNAME1, maId2))
+ .andReturn(Optional.empty()).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ try {
+ final String response = wt.path("md/" + MDNAME1.mdName()
+ + "/ma/" + maId2.maName()).request().get(String.class);
+ fail("Expected InternalServerErrorException, as MA is unknown");
+ } catch (InternalServerErrorException e) {
+ ByteArrayInputStream is = (ByteArrayInputStream) e.getResponse().getEntity();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ String line = null;
+ StringBuffer sb = new StringBuffer();
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ }
+
+ assertThat(sb.toString(), is("{ \"failure\":" +
+ "\"java.lang.IllegalArgumentException: MA ma-2 not Found\" }"));
+ }
+ }
+
+ @Test
+ public void testDeleteMa() throws CfmConfigException {
+
+ expect(mdService.deleteMaintenanceAssociation(MDNAME1, MANAME1))
+ .andReturn(true).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName()
+ + "/ma/" + MANAME1.maName()).request().delete();
+
+ assertEquals(200, response.getStatus());
+ }
+
+ @Test
+ public void testDeleteMaEmpty() throws CfmConfigException {
+ MaIdShort maId2 = MaIdCharStr.asMaId("ma-2");
+
+ expect(mdService.deleteMaintenanceAssociation(MDNAME1, maId2))
+ .andReturn(false).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName()
+ + "/ma/" + maId2.maName()).request().delete();
+
+ assertEquals(304, response.getStatus());
+ }
+
+ @Test
+ public void testCreateMa() throws CfmConfigException {
+ MaintenanceDomain md1 = DefaultMaintenanceDomain
+ .builder(MDNAME1).mdLevel(MaintenanceDomain.MdLevel.LEVEL2).build();
+
+ expect(mdService.getMaintenanceDomain(MDNAME1))
+ .andReturn(Optional.ofNullable(md1)).anyTimes();
+ expect(mdService.createMaintenanceAssociation(MDNAME1, ma1))
+ .andReturn(false).anyTimes();
+ replay(mdService);
+
+ ObjectMapper mapper = new ObjectMapper();
+ CfmCodecContext context = new CfmCodecContext();
+ ObjectNode node = mapper.createObjectNode();
+ node.set("ma", context.codec(MaintenanceAssociation.class)
+ .encode(ma1, context));
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName()
+ + "/ma").request().post(Entity.json(node.toString()));
+
+ assertEquals(201, response.getStatus());
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/impl/MdWebResourceTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/impl/MdWebResourceTest.java
new file mode 100644
index 0000000..f4c9b5a
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/impl/MdWebResourceTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.rest.BaseResource;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.codec.CodecService;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static junit.framework.TestCase.fail;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class MdWebResourceTest extends CfmResourceTest {
+ private final CfmMdService mdService = createMock(CfmMdService.class);
+
+ private static final MdId MDNAME1 = MdIdCharStr.asMdId("md-1");
+ private static final MdId MDNAME2 = MdIdCharStr.asMdId("md-2");
+
+ private List<MaintenanceDomain> mdList;
+
+ @Before
+ public void setUpTest() throws CfmConfigException {
+ CfmCodecContext context = new CfmCodecContext();
+ ServiceDirectory testDirectory = new TestServiceDirectory()
+ .add(CfmMdService.class, mdService)
+ .add(CodecService.class, context.codecManager());
+ BaseResource.setServiceDirectory(testDirectory);
+
+ mdList = new ArrayList<>();
+
+ mdList.add(DefaultMaintenanceDomain.builder(MDNAME1)
+ .mdLevel(MaintenanceDomain.MdLevel.LEVEL1).build());
+ mdList.add(DefaultMaintenanceDomain.builder(MDNAME2)
+ .mdLevel(MaintenanceDomain.MdLevel.LEVEL2).build());
+ }
+
+ @Test
+ public void testGetMds() {
+ expect(mdService.getAllMaintenanceDomain()).andReturn(mdList).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md").request().get(String.class);
+
+ assertThat(response, is("{\"mds\":[[" +
+ "{\"mdName\":\"md-1\",\"mdNameType\":\"CHARACTERSTRING\"," +
+ "\"mdLevel\":\"LEVEL1\",\"maList\":[]}," +
+ "{\"mdName\":\"md-2\",\"mdNameType\":\"CHARACTERSTRING\"," +
+ "\"mdLevel\":\"LEVEL2\",\"maList\":[]}]]}"));
+ }
+
+ @Test
+ public void testGetMdsEmpty() {
+ expect(mdService.getAllMaintenanceDomain())
+ .andReturn(new ArrayList<>()).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md").request().get(String.class);
+
+ assertThat(response, is("{\"mds\":[[]]}"));
+ }
+
+ @Test
+ public void testGetMd() {
+ expect(mdService.getMaintenanceDomain(MDNAME1))
+ .andReturn(Optional.ofNullable(mdList.get(0))).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1).request().get(String.class);
+
+ assertThat(response, is("{\"md\":" +
+ "{\"mdName\":\"md-1\",\"mdNameType\":\"CHARACTERSTRING\"," +
+ "\"mdLevel\":\"LEVEL1\",\"maList\":[]}}"));
+ }
+
+ @Test
+ public void testGetMdEmpty() throws IOException {
+ final MdId mdName3 = MdIdCharStr.asMdId("md-3");
+ expect(mdService.getMaintenanceDomain(mdName3))
+ .andReturn(Optional.empty()).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ try {
+ final String response = wt.path("md/" + mdName3).request().get(String.class);
+ fail("Expected InternalServerErrorException, as MD is unknown");
+ } catch (InternalServerErrorException e) {
+ ByteArrayInputStream is = (ByteArrayInputStream) e.getResponse().getEntity();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ String line = null;
+ StringBuffer sb = new StringBuffer();
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ }
+
+ assertThat(sb.toString(), is("{ \"failure\":" +
+ "\"java.lang.IllegalArgumentException: MD md-3 not Found\" }"));
+ }
+ }
+
+ @Test
+ public void testDeleteMd() throws CfmConfigException {
+ expect(mdService.deleteMaintenanceDomain(MDNAME1))
+ .andReturn(true).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1).request().delete();
+
+ assertEquals(200, response.getStatus());
+ }
+
+ @Test
+ public void testDeleteMdNotPresent() throws CfmConfigException {
+ expect(mdService.deleteMaintenanceDomain(MDNAME1))
+ .andReturn(false).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1).request().delete();
+
+ assertEquals(304, response.getStatus());
+ }
+
+ @Test
+ public void testCreateMd() throws CfmConfigException {
+ MaintenanceDomain md3 = DefaultMaintenanceDomain
+ .builder(MdIdCharStr.asMdId("md-3"))
+ .mdLevel(MaintenanceDomain.MdLevel.LEVEL3)
+ .mdNumericId((short) 3)
+ .build();
+
+ expect(mdService.createMaintenanceDomain(mdList.get(1)))
+ .andReturn(false).anyTimes();
+ replay(mdService);
+
+ ObjectMapper mapper = new ObjectMapper();
+ CfmCodecContext context = new CfmCodecContext();
+ ObjectNode node = mapper.createObjectNode();
+ node.set("md", context.codec(MaintenanceDomain.class)
+ .encode(mdList.get(1), context));
+
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md")
+ .request().post(Entity.json(node.toString()));
+
+ assertEquals(201, response.getStatus());
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/impl/MepWebResourceTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/impl/MepWebResourceTest.java
new file mode 100644
index 0000000..4dd83db
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/impl/MepWebResourceTest.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.packet.VlanId;
+import org.onlab.rest.BaseResource;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.codec.CodecService;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMep;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepLbCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Optional;
+
+import static junit.framework.TestCase.fail;
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class MepWebResourceTest extends CfmResourceTest {
+ private final CfmMepService mepService = createMock(CfmMepService.class);
+ private final CfmMdService mdService = createMock(CfmMdService.class);
+
+ private static final MdId MDNAME1 = MdIdCharStr.asMdId("md-1");
+ private static final MaIdShort MANAME1 = MaIdCharStr.asMaId("ma-1-1");
+ private static final MepId MEPID1 = MepId.valueOf((short) 1);
+
+ private MepEntry mepEntry1 = null;
+
+ @Before
+ public void setUpTest() throws CfmConfigException {
+ CfmCodecContext context = new CfmCodecContext();
+ ServiceDirectory testDirectory = new TestServiceDirectory()
+ .add(CfmMepService.class, mepService)
+ .add(CfmMdService.class, mdService)
+ .add(CodecService.class, context.codecManager());
+ BaseResource.setServiceDirectory(testDirectory);
+
+ mepEntry1 = DefaultMepEntry.builder(
+ MEPID1,
+ DeviceId.deviceId("netconf:1.2.3.4:830"),
+ PortNumber.portNumber(1),
+ Mep.MepDirection.UP_MEP, MDNAME1, MANAME1)
+ .buildEntry();
+
+ }
+
+ @Test
+ public void testGetAllMepsForMaEmpty() throws CfmConfigException {
+
+ expect(mepService.getAllMeps(MDNAME1, MANAME1)).andReturn(null).anyTimes();
+ replay(mepService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep").request().get(String.class);
+ assertThat(response, is("{\"meps\":[[]]}"));
+ }
+
+ @Test
+ public void testGetAllMepsForMa1Mep() throws CfmConfigException {
+ Collection<MepEntry> meps = new ArrayList<>();
+ meps.add(mepEntry1);
+
+ expect(mepService.getAllMeps(MDNAME1, MANAME1)).andReturn(meps).anyTimes();
+ replay(mepService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep").request().get(String.class);
+
+ assertThat(response, is("{\"meps\":" +
+ "[[{" +
+ "\"mepId\":" + MEPID1.value() + "," +
+ "\"deviceId\":\"netconf:1.2.3.4:830\"," +
+ "\"port\":1," +
+ "\"direction\":\"UP_MEP\"," +
+ "\"mdName\":\"" + MDNAME1.mdName() + "\"," +
+ "\"maName\":\"" + MANAME1.maName() + "\"," +
+ "\"administrative-state\":false," +
+ "\"cci-enabled\":false," +
+ "\"remoteMeps\":[]}]]}"));
+ }
+
+ @Test
+ public void testGetMepValid() throws CfmConfigException {
+
+ expect(mepService.getMep(MDNAME1, MANAME1, MepId.valueOf((short) 1)))
+ .andReturn(mepEntry1).anyTimes();
+ replay(mepService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value()).request().get(String.class);
+
+ assertThat(response, is("{\"mep\":" +
+ "{" +
+ "\"mepId\":" + MEPID1.value() + "," +
+ "\"deviceId\":\"netconf:1.2.3.4:830\"," +
+ "\"port\":1," +
+ "\"direction\":\"UP_MEP\"," +
+ "\"mdName\":\"" + MDNAME1.mdName() + "\"," +
+ "\"maName\":\"" + MANAME1.maName() + "\"," +
+ "\"administrative-state\":false," +
+ "\"cci-enabled\":false," +
+ "\"remoteMeps\":[]}}"));
+ }
+
+ @Test
+ public void testGetMepNotFound() throws CfmConfigException, IOException {
+
+ expect(mepService.getMep(MDNAME1, MANAME1, MepId.valueOf((short) 2)))
+ .andReturn(null).anyTimes();
+ replay(mepService);
+
+ final WebTarget wt = target();
+
+ try {
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + 2).request().get(String.class);
+ fail("Expected exception to be thrown");
+ } catch (InternalServerErrorException e) {
+ ByteArrayInputStream is = (ByteArrayInputStream) e.getResponse().getEntity();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ String line = null;
+ StringBuffer sb = new StringBuffer();
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ }
+ assertEquals("{ \"failure\":\"MEP md-1/ma-1-1/2 not found\" }", sb.toString());
+ }
+ }
+
+ @Test
+ public void testDeleteMepValid() throws CfmConfigException {
+
+ expect(mepService.deleteMep(MDNAME1, MANAME1, MepId.valueOf((short) 1)))
+ .andReturn(true).anyTimes();
+ replay(mepService);
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value()).request().delete();
+
+ assertEquals("Expecting 200", 200, response.getStatus());
+ }
+
+ @Test
+ public void testDeleteMepNotFound() throws CfmConfigException {
+
+ expect(mepService.deleteMep(MDNAME1, MANAME1, MepId.valueOf((short) 2)))
+ .andReturn(false).anyTimes();
+ replay(mepService);
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/2").request().delete();
+
+ assertEquals("Expecting 304", 304, response.getStatus());
+ }
+
+ @Test
+ public void testCreateMep() throws CfmConfigException, IOException {
+ MepId mepId2 = MepId.valueOf((short) 2);
+ Mep mep2 = DefaultMep.builder(
+ mepId2,
+ DeviceId.deviceId("netconf:2.2.3.4:830"),
+ PortNumber.portNumber(2),
+ Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).build();
+
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation
+ .builder(MANAME1, MDNAME1.getNameLength()).build();
+
+ expect(mdService.getMaintenanceAssociation(MDNAME1, MANAME1))
+ .andReturn(Optional.ofNullable(ma1)).anyTimes();
+ replay(mdService);
+ expect(mepService.createMep(MDNAME1, MANAME1, mep2))
+ .andReturn(true).anyTimes();
+ replay(mepService);
+
+ ObjectMapper mapper = new ObjectMapper();
+ CfmCodecContext context = new CfmCodecContext();
+ ObjectNode node = mapper.createObjectNode();
+ node.set("mep", context.codec(Mep.class).encode(mep2, context));
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep")
+ .request()
+ .post(Entity.json(node.toString()));
+
+ assertEquals("Expecting 201", 201, response.getStatus());
+ }
+
+ @Test
+ public void testCreateMepAlreadyExists() throws CfmConfigException, IOException {
+ MepId mepId3 = MepId.valueOf((short) 3);
+ Mep mep3 = DefaultMep.builder(
+ mepId3,
+ DeviceId.deviceId("netconf:3.2.3.4:830"),
+ PortNumber.portNumber(3),
+ Mep.MepDirection.UP_MEP, MDNAME1, MANAME1)
+ .cciEnabled(true)
+ .ccmLtmPriority(Mep.Priority.PRIO3)
+ .administrativeState(false)
+ .primaryVid(VlanId.vlanId((short) 3))
+ .defectAbsentTime(Duration.ofMinutes(2))
+ .defectPresentTime(Duration.ofMinutes(3))
+ .fngAddress(Mep.FngAddress.notSpecified())
+ .lowestFaultPriorityDefect(Mep.LowestFaultDefect.ALL_DEFECTS)
+ .build();
+
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation
+ .builder(MANAME1, MDNAME1.getNameLength()).build();
+
+ expect(mdService.getMaintenanceAssociation(MDNAME1, MANAME1))
+ .andReturn(Optional.ofNullable(ma1)).anyTimes();
+ replay(mdService);
+ expect(mepService.createMep(MDNAME1, MANAME1, mep3))
+ .andReturn(false).anyTimes();
+ replay(mepService);
+
+ ObjectMapper mapper = new ObjectMapper();
+ CfmCodecContext context = new CfmCodecContext();
+ ObjectNode node = mapper.createObjectNode();
+ node.set("mep", context.codec(Mep.class).encode(mep3, context));
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep")
+ .request()
+ .post(Entity.json(node.toString()));
+
+ assertEquals("Expecting 304", 304, response.getStatus());
+ }
+
+ @Test
+ public void testTransmitLoopback() throws CfmConfigException {
+ MepLbCreate mepLbCreate1 = DefaultMepLbCreate
+ .builder(MEPID1)
+ .numberMessages(20)
+ .dataTlvHex("AA:BB:CC:DD")
+ .vlanDropEligible(true)
+ .build();
+
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation
+ .builder(MANAME1, MDNAME1.getNameLength()).build();
+ MaintenanceDomain md1 = DefaultMaintenanceDomain.builder(MDNAME1)
+ .addToMaList(ma1).build();
+ expect(mdService.getMaintenanceDomain(MDNAME1))
+ .andReturn(Optional.ofNullable(md1)).anyTimes();
+ expect(mdService.getMaintenanceAssociation(MDNAME1, MANAME1))
+ .andReturn(Optional.ofNullable(ma1)).anyTimes();
+ replay(mdService);
+
+ ObjectMapper mapper = new ObjectMapper();
+ CfmCodecContext context = new CfmCodecContext();
+ ObjectNode node = mapper.createObjectNode();
+ node.set("loopback", context.codec(MepLbCreate.class).encode(mepLbCreate1, context));
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/transmit-loopback")
+ .request()
+ .put(Entity.json(node.toString()));
+
+ assertEquals("Expecting 202", 202, response.getStatus());
+ }
+
+ @Test
+ public void testAbortLoopback() throws CfmConfigException {
+
+ MepLbCreate mepLbCreate1 = DefaultMepLbCreate.builder(MEPID1).build();
+
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation
+ .builder(MANAME1, MDNAME1.getNameLength()).build();
+ MaintenanceDomain md1 = DefaultMaintenanceDomain.builder(MDNAME1)
+ .addToMaList(ma1).build();
+ expect(mdService.getMaintenanceDomain(MDNAME1))
+ .andReturn(Optional.ofNullable(md1)).anyTimes();
+ expect(mdService.getMaintenanceAssociation(MDNAME1, MANAME1))
+ .andReturn(Optional.ofNullable(ma1)).anyTimes();
+ replay(mdService);
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/abort-loopback")
+ .request()
+ .put(Entity.json(""));
+
+ assertEquals("Expecting 202", 202, response.getStatus());
+
+ }
+
+ @Test
+ public void testTransmitLinktrace() throws CfmConfigException {
+ MepLtCreate mepLtCreate1 = DefaultMepLtCreate
+ .builder(MEPID1)
+ .defaultTtl((short) 20)
+ .transmitLtmFlags(BitSet.valueOf(new byte[]{1}))
+ .build();
+
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation
+ .builder(MANAME1, MDNAME1.getNameLength()).build();
+ MaintenanceDomain md1 = DefaultMaintenanceDomain.builder(MDNAME1)
+ .addToMaList(ma1).build();
+ expect(mdService.getMaintenanceDomain(MDNAME1))
+ .andReturn(Optional.ofNullable(md1)).anyTimes();
+ expect(mdService.getMaintenanceAssociation(MDNAME1, MANAME1))
+ .andReturn(Optional.ofNullable(ma1)).anyTimes();
+ replay(mdService);
+
+ ObjectMapper mapper = new ObjectMapper();
+ CfmCodecContext context = new CfmCodecContext();
+ ObjectNode node = mapper.createObjectNode();
+ node.set("linktrace", context.codec(MepLtCreate.class).encode(mepLtCreate1, context));
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/transmit-linktrace")
+ .request()
+ .put(Entity.json(node.toString()));
+
+ assertEquals("Expecting 202", 202, response.getStatus());
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/web/MaintenanceAssociationCodecTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/web/MaintenanceAssociationCodecTest.java
new file mode 100644
index 0000000..9712c7d
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/web/MaintenanceAssociationCodecTest.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaId2Octet;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdIccY1731;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdPrimaryVid;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdRfc2685VpnId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test that the MaintenanceAssociationCodec can successfully parse Json in to a MaintenanceAssociation.
+ */
+public class MaintenanceAssociationCodecTest {
+ private static final MaIdShort MAID1_CHAR = MaIdCharStr.asMaId("ma-1");
+ private static final MaIdShort MAID2_VID = MaIdPrimaryVid.asMaId(1234);
+ private static final MaIdShort MAID3_OCTET = MaId2Octet.asMaId(12467);
+ private static final MaIdShort MAID4_RFC = MaIdRfc2685VpnId.asMaIdHex("aa:bb:cc:dd:ee:ff:99");
+ private static final MaIdShort MAID5_Y1731 = MaIdIccY1731.asMaId("abc", "defghij");
+
+
+ private ObjectMapper mapper;
+ private CfmCodecContext context;
+
+ @Before
+ public void setUp() throws Exception, CfmConfigException {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ }
+
+ @Test
+ public void testDecodeMa1() throws IOException {
+ String mdString = "{\"ma\": { \"maName\": \"ma-1\"," +
+ "\"maNameType\": \"CHARACTERSTRING\"," +
+ "\"component-list\": [], " +
+ "\"rmep-list\": [], " +
+ "\"maNumericId\": 1}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceAssociation maDecode1 = ((MaintenanceAssociationCodec) context
+ .codec(MaintenanceAssociation.class))
+ .decode((ObjectNode) cfg, context, 10);
+ assertEquals(MAID1_CHAR, maDecode1.maId());
+ assertEquals(1, maDecode1.maNumericId());
+ }
+
+ @Test
+ public void testDecodeMa1NoTypeGiven() throws IOException {
+ String mdString = "{\"ma\": { \"maName\": \"ma-1\"," +
+ "\"component-list\": [], " +
+ "\"rmep-list\": [], " +
+ "\"maNumericId\": 1}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceAssociation maDecode1 = ((MaintenanceAssociationCodec) context
+ .codec(MaintenanceAssociation.class))
+ .decode((ObjectNode) cfg, context, 10);
+ assertEquals(MAID1_CHAR, maDecode1.maId());
+ assertEquals(1, maDecode1.maNumericId());
+ }
+
+ @Test
+ public void testDecodeMa2() throws IOException {
+ String mdString = "{\"ma\": { \"maName\": 1234," +
+ "\"maNameType\": \"PRIMARYVID\"," +
+ "\"component-list\": [], " +
+ "\"rmep-list\": [], " +
+ "\"maNumericId\": 2}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceAssociation maDecode2 = ((MaintenanceAssociationCodec) context
+ .codec(MaintenanceAssociation.class))
+ .decode((ObjectNode) cfg, context, 10);
+ assertEquals(MAID2_VID, maDecode2.maId());
+ }
+
+ @Test
+ public void testDecodeMa3() throws IOException {
+ String mdString = "{\"ma\": { \"maName\": 12467," +
+ "\"maNameType\": \"TWOOCTET\"," +
+ "\"component-list\": [], " +
+ "\"rmep-list\": [], " +
+ "\"maNumericId\": 3}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceAssociation maDecode3 = ((MaintenanceAssociationCodec) context
+ .codec(MaintenanceAssociation.class))
+ .decode((ObjectNode) cfg, context, 10);
+ assertEquals(MAID3_OCTET, maDecode3.maId());
+ }
+
+ @Test
+ public void testDecodeMa4() throws IOException {
+ String mdString = "{\"ma\": { \"maName\": \"aa:bb:cc:dd:ee:ff:99\"," +
+ "\"maNameType\": \"RFC2685VPNID\"," +
+ "\"component-list\": [], " +
+ "\"rmep-list\": [], " +
+ "\"maNumericId\": 4}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceAssociation maDecode4 = ((MaintenanceAssociationCodec) context
+ .codec(MaintenanceAssociation.class))
+ .decode((ObjectNode) cfg, context, 10);
+ assertEquals(MAID4_RFC, maDecode4.maId());
+ }
+
+ @Test
+ public void testDecodeMa5() throws IOException {
+ String mdString = "{\"ma\": { \"maName\": \"abc:defghij\"," +
+ "\"maNameType\": \"ICCY1731\"," +
+ "\"component-list\": [], " +
+ "\"rmep-list\": [], " +
+ "\"maNumericId\": 5}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceAssociation maDecode5 = ((MaintenanceAssociationCodec) context
+ .codec(MaintenanceAssociation.class))
+ .decode((ObjectNode) cfg, context, 10);
+ assertEquals(MAID5_Y1731, maDecode5.maId());
+ }
+
+ @Test
+ public void testEncodeMa1() throws CfmConfigException {
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation.builder(MAID1_CHAR, 10)
+ .maNumericId((short) 1)
+ .build();
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("ma", context.codec(MaintenanceAssociation.class).encode(ma1, context));
+
+ assertEquals("{\"ma\":{" +
+ "\"maName\":\"ma-1\"," +
+ "\"maNameType\":\"CHARACTERSTRING\"," +
+ "\"maNumericId\":1," +
+ "\"component-list\":[]," +
+ "\"rmep-list\":[]}}", node.toString());
+ }
+
+ @Test
+ public void testEncodeMa2() throws CfmConfigException {
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation.builder(MAID2_VID, 10)
+ .maNumericId((short) 2)
+ .build();
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("ma", context.codec(MaintenanceAssociation.class).encode(ma1, context));
+
+ assertEquals("{\"ma\":{" +
+ "\"maName\":\"1234\"," +
+ "\"maNameType\":\"PRIMARYVID\"," +
+ "\"maNumericId\":2," +
+ "\"component-list\":[]," +
+ "\"rmep-list\":[]}}", node.toString());
+ }
+
+ @Test
+ public void testEncodeMa3() throws CfmConfigException {
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation.builder(MAID3_OCTET, 10)
+ .maNumericId((short) 3)
+ .build();
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("ma", context.codec(MaintenanceAssociation.class).encode(ma1, context));
+
+ assertEquals("{\"ma\":{" +
+ "\"maName\":\"12467\"," +
+ "\"maNameType\":\"TWOOCTET\"," +
+ "\"maNumericId\":3," +
+ "\"component-list\":[]," +
+ "\"rmep-list\":[]}}", node.toString());
+ }
+
+ @Test
+ public void testEncodeMa4() throws CfmConfigException {
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation.builder(MAID4_RFC, 10)
+ .maNumericId((short) 4)
+ .build();
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("ma", context.codec(MaintenanceAssociation.class).encode(ma1, context));
+
+ assertEquals("{\"ma\":{" +
+ "\"maName\":\"aa:bb:cc:dd:ee:ff:99\"," +
+ "\"maNameType\":\"RFC2685VPNID\"," +
+ "\"maNumericId\":4," +
+ "\"component-list\":[]," +
+ "\"rmep-list\":[]}}", node.toString());
+ }
+
+ @Test
+ public void testEncodeMa5() throws CfmConfigException {
+ MaintenanceAssociation ma1 = DefaultMaintenanceAssociation.builder(MAID5_Y1731, 10)
+ .maNumericId((short) 5)
+ .build();
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("ma", context.codec(MaintenanceAssociation.class).encode(ma1, context));
+
+ assertEquals("{\"ma\":{" +
+ "\"maName\":\"abc:defghij\"," +
+ "\"maNameType\":\"ICCY1731\"," +
+ "\"maNumericId\":5," +
+ "\"component-list\":[]," +
+ "\"rmep-list\":[]}}", node.toString());
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/web/MaintenanceDomainCodecTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/web/MaintenanceDomainCodecTest.java
new file mode 100644
index 0000000..b1fff52
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/web/MaintenanceDomainCodecTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.net.InternetDomainName;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test that the MaintenanceDomainCodec can successfully parse Json in to a MaintenanceDomain.
+ */
+public class MaintenanceDomainCodecTest {
+ private static final MdId MDID1_CHAR = MdIdCharStr.asMdId("test-1");
+ private static final MdId MDID2_DOMAIN = MdIdDomainName.asMdId(
+ InternetDomainName.from("test.opennetworking.org"));
+ private static final MdId MDID3_MACUINT =
+ MdIdMacUint.asMdId(MacAddress.valueOf("aa:bb:cc:dd:ee:ff"), 181);
+ private static final MdId MDID4_NONE = MdIdNone.asMdId();
+
+ private ObjectMapper mapper;
+ private CfmCodecContext context;
+
+ @Before
+ public void setUp() throws Exception, CfmConfigException {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ }
+
+ @Test
+ public void testDecodeMd1() throws IOException {
+ String mdString = "{\"md\": { \"mdName\": \"test-1\"," +
+ "\"mdNameType\": \"CHARACTERSTRING\"," +
+ "\"mdLevel\": \"LEVEL1\", \"mdNumericId\": 1}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceDomain mdDecode1 = context
+ .codec(MaintenanceDomain.class).decode((ObjectNode) cfg, context);
+ assertEquals(MDID1_CHAR, mdDecode1.mdId());
+ assertEquals(MaintenanceDomain.MdLevel.LEVEL1, mdDecode1.mdLevel());
+ assertEquals(1, mdDecode1.mdNumericId());
+ }
+
+ @Test
+ public void testDecodeMd1NoTypeGiven() throws IOException {
+ String mdString = "{\"md\": { \"mdName\": \"test-1\"," +
+ "\"mdLevel\": \"LEVEL1\", \"mdNumericId\": 1}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceDomain mdDecode1 = context
+ .codec(MaintenanceDomain.class).decode((ObjectNode) cfg, context);
+ assertEquals(MDID1_CHAR, mdDecode1.mdId());
+ assertEquals(MaintenanceDomain.MdLevel.LEVEL1, mdDecode1.mdLevel());
+ assertEquals(1, mdDecode1.mdNumericId());
+ }
+
+
+ @Test
+ public void testDecodeMd2() throws IOException {
+ String mdString = "{\"md\": { \"mdName\": \"test.opennetworking.org\"," +
+ "\"mdNameType\": \"DOMAINNAME\"}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceDomain mdDecode1 = context
+ .codec(MaintenanceDomain.class).decode((ObjectNode) cfg, context);
+ assertEquals(MDID2_DOMAIN, mdDecode1.mdId());
+ assertEquals(MaintenanceDomain.MdLevel.LEVEL0, mdDecode1.mdLevel());
+ assertEquals(0, mdDecode1.mdNumericId());
+ }
+
+ @Test
+ public void testDecodeMd3() throws IOException {
+ String mdString = "{\"md\": { \"mdName\": \"aa:bb:cc:dd:ee:ff:181\"," +
+ "\"mdNameType\": \"MACANDUINT\"}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceDomain mdDecode1 = context
+ .codec(MaintenanceDomain.class).decode((ObjectNode) cfg, context);
+ assertEquals(MDID3_MACUINT, mdDecode1.mdId());
+ }
+
+ @Test
+ public void testDecodeMd4() throws IOException {
+ String mdString = "{\"md\": { \"mdName\": \"\"," +
+ "\"mdNameType\": \"NONE\"}}";
+
+ InputStream input = new ByteArrayInputStream(
+ mdString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceDomain mdDecode1 = context
+ .codec(MaintenanceDomain.class).decode((ObjectNode) cfg, context);
+ assertEquals(MDID4_NONE, mdDecode1.mdId());
+ }
+
+ @Test
+ public void testEncodeMd1() throws CfmConfigException {
+ MaintenanceDomain md1 = DefaultMaintenanceDomain.builder(MDID1_CHAR)
+ .mdLevel(MaintenanceDomain.MdLevel.LEVEL1)
+ .mdNumericId((short) 1)
+ .build();
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("md", context.codec(MaintenanceDomain.class).encode(md1, context));
+
+ assertEquals("{\"md\":{" +
+ "\"mdName\":\"test-1\"," +
+ "\"mdNameType\":\"CHARACTERSTRING\"," +
+ "\"mdLevel\":\"LEVEL1\"," +
+ "\"mdNumericId\":1," +
+ "\"maList\":[]}}", node.toString());
+ }
+
+ @Test
+ public void testEncodeMd2() throws CfmConfigException {
+ MaintenanceDomain md2 = DefaultMaintenanceDomain.builder(MDID2_DOMAIN)
+ .mdLevel(MaintenanceDomain.MdLevel.LEVEL2).build();
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("md", context.codec(MaintenanceDomain.class).encode(md2, context));
+
+ assertEquals("{\"md\":{" +
+ "\"mdName\":\"test.opennetworking.org\"," +
+ "\"mdNameType\":\"DOMAINNAME\"," +
+ "\"mdLevel\":\"LEVEL2\"," +
+ "\"maList\":[]}}", node.toString());
+ }
+
+ @Test
+ public void testEncodeMd3() throws CfmConfigException {
+ MaintenanceDomain md3 = DefaultMaintenanceDomain.builder(MDID3_MACUINT)
+ .mdLevel(MaintenanceDomain.MdLevel.LEVEL3).build();
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("md", context.codec(MaintenanceDomain.class).encode(md3, context));
+
+ assertEquals("{\"md\":{" +
+ "\"mdName\":\"AA:BB:CC:DD:EE:FF:181\"," +
+ "\"mdNameType\":\"MACANDUINT\"," +
+ "\"mdLevel\":\"LEVEL3\"," +
+ "\"maList\":[]}}", node.toString());
+ }
+
+ @Test
+ public void testEncodeMd4() throws CfmConfigException {
+ MaintenanceDomain md4 = DefaultMaintenanceDomain.builder(MDID4_NONE)
+ .mdLevel(MaintenanceDomain.MdLevel.LEVEL4).build();
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("md", context.codec(MaintenanceDomain.class).encode(md4, context));
+
+ assertEquals("{\"md\":{" +
+ "\"mdName\":\"\"," +
+ "\"mdNameType\":\"NONE\"," +
+ "\"mdLevel\":\"LEVEL4\"," +
+ "\"maList\":[]}}", node.toString());
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/web/MepEntryCodecTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/web/MepEntryCodecTest.java
new file mode 100644
index 0000000..ea07b8e
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/web/MepEntryCodecTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.web;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.MepDirection;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.Priority;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry.MepEntryBuilder;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Test that the MepEntryCodec can successfully parse Json in to a Mep.
+ */
+public class MepEntryCodecTest {
+ ObjectMapper mapper;
+ CfmCodecContext context;
+ MepEntry mepEntry1;
+
+ @Before
+ public void setUp() throws Exception, CfmConfigException {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ MepEntryBuilder builder = DefaultMepEntry.builder(
+ MepId.valueOf((short) 22),
+ DeviceId.deviceId("netconf:1234:830"),
+ PortNumber.portNumber(2),
+ MepDirection.UP_MEP,
+ MdIdCharStr.asMdId("md-1"),
+ MaIdCharStr.asMaId("ma-1-1"))
+ .macAddress(MacAddress.valueOf("aa:bb:cc:dd:ee:ff"));
+ builder = (MepEntryBuilder) builder
+ .administrativeState(true)
+ .cciEnabled(true)
+ .ccmLtmPriority(Priority.PRIO1);
+ mepEntry1 = builder.buildEntry();
+
+ }
+
+ @Test
+ public void testEncodeMepEntryCodecContext() {
+ ObjectNode node = mapper.createObjectNode();
+ node.set("mep", context.codec(MepEntry.class).encode(mepEntry1, context));
+
+ assertEquals(22, node.get("mep").get("mepId").asInt());
+ assertEquals("aa:bb:cc:dd:ee:ff".toUpperCase(),
+ node.get("mep").get("macAddress").asText());
+ assertTrue(node.get("mep").get("administrative-state").asBoolean());
+ assertTrue(node.get("mep").get("cci-enabled").asBoolean());
+ assertEquals(Priority.PRIO1.ordinal(),
+ node.get("mep").get("ccm-ltm-priority").asInt());
+ }
+
+ @Test
+ public void testEncodeIterableOfMepEntryCodecContext() throws CfmConfigException {
+ MepEntry mepEntry2 = DefaultMepEntry.builder(
+ MepId.valueOf((short) 33),
+ DeviceId.deviceId("netconf:4321:830"),
+ PortNumber.portNumber(1),
+ MepDirection.DOWN_MEP,
+ MdIdCharStr.asMdId("md-2"),
+ MaIdCharStr.asMaId("ma-2-2"))
+ .buildEntry();
+
+ ArrayList<MepEntry> meps = new ArrayList<>();
+ meps.add(mepEntry1);
+ meps.add(mepEntry2);
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("mep", context.codec(MepEntry.class)
+ .encode(meps, context));
+
+ Iterator<JsonNode> an = node.get("mep").elements();
+ while (an.hasNext()) {
+ JsonNode jn = an.next();
+ assertEquals("md-", jn.get("mdName").asText().substring(0, 3));
+ }
+ }
+
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/web/MepLbCreateCodecTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/web/MepLbCreateCodecTest.java
new file mode 100644
index 0000000..e2c853a
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/web/MepLbCreateCodecTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.web;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class MepLbCreateCodecTest {
+ ObjectMapper mapper;
+ CfmCodecContext context;
+
+ @Before
+ public void setUp() throws Exception {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ }
+
+ @Test
+ public void testDecodeMepLbCreateMepId() throws JsonProcessingException, IOException {
+ String loopbackString = "{\"loopback\": { \"remoteMepId\": 20," +
+ "\"numberMessages\": 10, \"vlanDropEligible\": true," +
+ "\"vlanPriority\": 6, \"dataTlvHex\": \"0A:BB:CC\" }}";
+
+ InputStream input = new ByteArrayInputStream(
+ loopbackString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MepLbCreate mepLbCreate = context
+ .codec(MepLbCreate.class).decode((ObjectNode) cfg, context);
+
+ assertNull(mepLbCreate.remoteMepAddress());
+ assertEquals(20, mepLbCreate.remoteMepId().id().shortValue());
+ assertEquals(10, mepLbCreate.numberMessages().intValue());
+ assertEquals(6, mepLbCreate.vlanPriority().ordinal());
+ assertEquals(true, mepLbCreate.vlanDropEligible());
+ assertEquals("0A:BB:CC".toLowerCase(), mepLbCreate.dataTlvHex());
+ }
+
+ @Test
+ public void testDecodeMepLbCreateMepMac() throws JsonProcessingException, IOException {
+ String loopbackString = "{\"loopback\": { " +
+ "\"remoteMepMac\": \"AA:BB:CC:DD:EE:FF\" }}";
+ InputStream input = new ByteArrayInputStream(
+ loopbackString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MepLbCreate mepLbCreate = context
+ .codec(MepLbCreate.class).decode((ObjectNode) cfg, context);
+
+ assertNull(mepLbCreate.remoteMepId());
+ assertEquals("AA:BB:CC:DD:EE:FF", mepLbCreate.remoteMepAddress().toString());
+ assertNull(mepLbCreate.dataTlvHex());
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/web/MepLbEntryCodecTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/web/MepLbEntryCodecTest.java
new file mode 100644
index 0000000..844e4a2
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/web/MepLbEntryCodecTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.web;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepLbEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbEntry;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class MepLbEntryCodecTest {
+ ObjectMapper mapper;
+ CfmCodecContext context;
+
+ @Before
+ public void setUp() throws Exception {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ }
+
+ @Test
+ public void testEncodeMepLbEntryCodecContext() {
+ MepLbEntry mepLbEntry1 = DefaultMepLbEntry.builder()
+ .countLbrMacMisMatch(987654321L)
+ .countLbrReceived(987654322L)
+ .countLbrTransmitted(987654323L)
+ .countLbrValidInOrder(987654324L)
+ .countLbrValidOutOfOrder(987654325L)
+ .nextLbmIdentifier(987654326L)
+ .build();
+
+ assertEquals(987654321L, mepLbEntry1.countLbrMacMisMatch());
+ assertEquals(987654322L, mepLbEntry1.countLbrReceived());
+ assertEquals(987654323L, mepLbEntry1.countLbrTransmitted());
+ assertEquals(987654324L, mepLbEntry1.countLbrValidInOrder());
+ assertEquals(987654325L, mepLbEntry1.countLbrValidOutOfOrder());
+ assertEquals(987654326L, mepLbEntry1.nextLbmIdentifier());
+ }
+
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/web/MepLtCreateCodecTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/web/MepLtCreateCodecTest.java
new file mode 100644
index 0000000..3e0ec46
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/web/MepLtCreateCodecTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.web;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.BitSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class MepLtCreateCodecTest {
+ ObjectMapper mapper;
+ CfmCodecContext context;
+
+ @Before
+ public void setUp() throws Exception {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ }
+
+ @Test
+ public void testDecodeMepLtCreateMepId() throws JsonProcessingException, IOException {
+ String linktraceString = "{\"linktrace\": { " +
+ "\"remoteMepId\": 20," +
+ "\"defaultTtl\": 21," +
+ "\"transmitLtmFlags\": \"use-fdb-only\"}}";
+
+ InputStream input = new ByteArrayInputStream(
+ linktraceString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ MepLtCreate mepLtCreate = context
+ .codec(MepLtCreate.class).decode((ObjectNode) cfg, context);
+
+ assertNull(mepLtCreate.remoteMepAddress());
+ assertEquals(20, mepLtCreate.remoteMepId().id().shortValue());
+ assertEquals(21, mepLtCreate.defaultTtl().intValue());
+ assertEquals(BitSet.valueOf(new byte[]{1}), mepLtCreate.transmitLtmFlags());
+ }
+
+ @Test
+ public void testDecodeMepLtCreateInvalidTransmitLtmFlags()
+ throws JsonProcessingException, IOException {
+ String linktraceString = "{\"linktrace\": { " +
+ "\"remoteMepId\": 20," +
+ "\"transmitLtmFlags\": \"1\"}}";
+
+ InputStream input = new ByteArrayInputStream(
+ linktraceString.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ try {
+ context.codec(MepLtCreate.class).decode((ObjectNode) cfg, context);
+ } catch (IllegalArgumentException e) {
+ assertEquals("Expecting value 'use-fdb-only' or '' " +
+ "for transmitLtmFlags", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testEncodeMepLtCreate() {
+ MepId mepId1 = MepId.valueOf((short) 1);
+ MepLtCreate mepLtCreate1 = DefaultMepLtCreate
+ .builder(mepId1)
+ .defaultTtl((short) 20)
+ .transmitLtmFlags(BitSet.valueOf(new byte[]{1}))
+ .build();
+
+ ObjectMapper mapper = new ObjectMapper();
+ CfmCodecContext context = new CfmCodecContext();
+ ObjectNode node = mapper.createObjectNode();
+ node.set("linktrace", context.codec(MepLtCreate.class).encode(mepLtCreate1, context));
+
+ assertEquals("{\"linktrace\":{" +
+ "\"remoteMepId\":1," +
+ "\"defaultTtl\":20," +
+ "\"transmitLtmFlags\":\"use-fdb-only\"}}", node.toString());
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/cfm/web/RemoteMepEntryCodecTest.java b/apps/cfm/src/test/java/org/onosproject/cfm/web/RemoteMepEntryCodecTest.java
new file mode 100644
index 0000000..7ad77ac
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/cfm/web/RemoteMepEntryCodecTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.cfm.web;
+
+import static org.junit.Assert.assertEquals;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MacAddress;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultRemoteMepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.RemoteMepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.RemoteMepEntry.InterfaceStatusTlvType;
+import org.onosproject.incubator.net.l2monitoring.cfm.RemoteMepEntry.PortStatusTlvType;
+import org.onosproject.incubator.net.l2monitoring.cfm.RemoteMepEntry.RemoteMepState;
+import org.onosproject.incubator.net.l2monitoring.cfm.SenderIdTlv.SenderIdTlvType;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class RemoteMepEntryCodecTest {
+ ObjectMapper mapper;
+ CfmCodecContext context;
+ RemoteMepEntry remoteMep1;
+
+ @Before
+ public void setUp() throws Exception, CfmConfigException {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ remoteMep1 = DefaultRemoteMepEntry
+ .builder(MepId.valueOf((short) 10), RemoteMepState.RMEP_OK)
+ .failedOrOkTime(Duration.ofMillis(546546546L))
+ .interfaceStatusTlvType(InterfaceStatusTlvType.IS_LOWERLAYERDOWN)
+ .macAddress(MacAddress.IPV4_MULTICAST)
+ .portStatusTlvType(PortStatusTlvType.PS_NO_STATUS_TLV)
+ .rdi(true)
+ .senderIdTlvType(SenderIdTlvType.SI_NETWORK_ADDRESS)
+ .build();
+ }
+
+ @Test
+ public void testEncodeRemoteMepEntryCodecContext() {
+ ObjectNode node = mapper.createObjectNode();
+ node.set("remoteMep", context.codec(RemoteMepEntry.class)
+ .encode(remoteMep1, context));
+
+ assertEquals(10, node.get("remoteMep").get("remoteMepId").asInt());
+ }
+
+ @Test
+ public void testEncodeIterableOfRemoteMepEntryCodecContext()
+ throws CfmConfigException {
+ RemoteMepEntry remoteMep2 = DefaultRemoteMepEntry
+ .builder(MepId.valueOf((short) 20), RemoteMepState.RMEP_IDLE)
+ .build();
+
+ ArrayList<RemoteMepEntry> remoteMeps = new ArrayList<>();
+ remoteMeps.add(remoteMep1);
+ remoteMeps.add(remoteMep2);
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("remoteMep", context.codec(RemoteMepEntry.class)
+ .encode(remoteMeps, context));
+
+ Iterator<JsonNode> an = node.get("remoteMep").elements();
+ while (an.hasNext()) {
+ JsonNode jn = an.next();
+ assertEquals("RMEP_", jn.get("remoteMepState").asText().substring(0, 5));
+ }
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/soam/impl/DmWebResourceTest.java b/apps/cfm/src/test/java/org/onosproject/soam/impl/DmWebResourceTest.java
new file mode 100644
index 0000000..702bc09
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/soam/impl/DmWebResourceTest.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.soam.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.rest.BaseResource;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.cfm.impl.CfmResourceTest;
+import org.onosproject.codec.CodecService;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamConfigException;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamId;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamService;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DefaultDelayMeasurementEntry;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DefaultDelayMeasurementStatCurrent;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementEntry;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementStatCurrent;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+import static junit.framework.TestCase.fail;
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class DmWebResourceTest extends CfmResourceTest {
+ private final CfmMepService mepService = createMock(CfmMepService.class);
+ private final SoamService soamService = createMock(SoamService.class);
+
+ private static final MdId MDNAME1 = MdIdCharStr.asMdId("md-1");
+ private static final MaIdShort MANAME1 = MaIdCharStr.asMaId("ma-1-1");
+ private static final MepId MEPID1 = MepId.valueOf((short) 1);
+ private static final SoamId DM1 = SoamId.valueOf(1);
+ private static final SoamId DM2 = SoamId.valueOf(2);
+
+ private DelayMeasurementEntry dm1;
+ private DelayMeasurementEntry dm2;
+
+ private final Instant now = Instant.now();
+
+ @Before
+ public void setUpTest() throws CfmConfigException, SoamConfigException {
+ CfmCodecContext context = new CfmCodecContext();
+ ServiceDirectory testDirectory = new TestServiceDirectory()
+ .add(CfmMepService.class, mepService)
+ .add(SoamService.class, soamService)
+ .add(CodecService.class, context.codecManager());
+ BaseResource.setServiceDirectory(testDirectory);
+
+ DelayMeasurementStatCurrent.DmStatCurrentBuilder dmCurrBuilder1 =
+ (DelayMeasurementStatCurrent.DmStatCurrentBuilder)
+ DefaultDelayMeasurementStatCurrent
+ .builder(Duration.ofMinutes(1), false)
+ .startTime(now)
+ .frameDelayBackwardAvg(Duration.ofMillis(10))
+ .frameDelayForwardAvg(Duration.ofMillis(11))
+ .frameDelayRangeBackwardAvg(Duration.ofMillis(12));
+
+ dm1 = DefaultDelayMeasurementEntry.builder(DM1,
+ DelayMeasurementCreate.DmType.DMDMM,
+ DelayMeasurementCreate.Version.Y17312008,
+ MepId.valueOf((short) 2),
+ Mep.Priority.PRIO1)
+ .sessionStatus(DelayMeasurementEntry.SessionStatus.ACTIVE)
+ .frameDelayTwoWay(Duration.ofMillis(40))
+ .frameDelayBackward(Duration.ofMillis(30))
+ .frameDelayForward(Duration.ofMillis(10))
+ .interFrameDelayVariationTwoWay(Duration.ofMillis(8))
+ .interFrameDelayVariationBackward(Duration.ofMillis(3))
+ .interFrameDelayVariationForward(Duration.ofMillis(5))
+ .currentResult((DelayMeasurementStatCurrent) dmCurrBuilder1.build())
+ .build();
+
+ dm2 = DefaultDelayMeasurementEntry.builder(DM2,
+ DelayMeasurementCreate.DmType.DMDMM,
+ DelayMeasurementCreate.Version.Y17312011,
+ MepId.valueOf((short) 2),
+ Mep.Priority.PRIO2)
+ .build();
+ }
+
+ @Test
+ public void testGetAllDmsForMep() throws CfmConfigException, SoamConfigException {
+
+ List<DelayMeasurementEntry> dmList = new ArrayList<>();
+ dmList.add(dm1);
+ dmList.add(dm2);
+
+ expect(soamService.getAllDms(MDNAME1, MANAME1, MEPID1)).andReturn(dmList).anyTimes();
+ replay(soamService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/dm")
+ .request().get(String.class);
+
+ assertThat(response, is("{\"dms\":[[" +
+ "{" +
+ "\"dmId\":\"1\"," +
+ "\"sessionStatus\":\"ACTIVE\"," +
+ "\"frameDelayTwoWay\":\"PT0.04S\"," +
+ "\"frameDelayForward\":\"PT0.01S\"," +
+ "\"frameDelayBackward\":\"PT0.03S\"," +
+ "\"interFrameDelayVariationTwoWay\":\"PT0.008S\"," +
+ "\"interFrameDelayVariationForward\":\"PT0.005S\"," +
+ "\"interFrameDelayVariationBackward\":\"PT0.003S\"," +
+ "\"dmCfgType\":\"DMDMM\"," +
+ "\"version\":\"Y17312008\"," +
+ "\"remoteMepId\":2," +
+ "\"priority\":\"PRIO1\"," +
+ "\"measurementsEnabled\":[]," +
+ "\"current\":{" +
+ "\"startTime\":\"" + now + "\"," +
+ "\"elapsedTime\":\"PT1M\"," +
+ "\"suspectStatus\":\"false\"," +
+ "\"frameDelayForwardAvg\":\"PT0.011S\"," +
+ "\"frameDelayBackwardAvg\":\"PT0.01S\"," +
+ "\"frameDelayRangeBackwardAvg\":\"PT0.012S\"" +
+ "}," +
+ "\"historic\":[]" +
+ "},{" +
+ "\"dmId\":\"2\"," +
+ "\"dmCfgType\":\"DMDMM\"," +
+ "\"version\":\"Y17312011\"," +
+ "\"remoteMepId\":2," +
+ "\"priority\":\"PRIO2\"," +
+ "\"measurementsEnabled\":[]," +
+ "\"historic\":[]}]]" +
+ "}"));
+ }
+
+ @Test
+ public void testGetAllDmsForMepEmpty() throws CfmConfigException, SoamConfigException {
+
+ List<DelayMeasurementEntry> dmListEmpty = new ArrayList<>();
+
+ expect(soamService.getAllDms(MDNAME1, MANAME1, MEPID1)).andReturn(dmListEmpty).anyTimes();
+ replay(soamService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/dm")
+ .request().get(String.class);
+
+ assertThat(response, is("{\"dms\":[[]]}"));
+ }
+
+ @Test
+ public void testGetDm() throws CfmConfigException, SoamConfigException {
+
+ expect(soamService.getDm(MDNAME1, MANAME1, MEPID1, DM1)).andReturn(dm1).anyTimes();
+ replay(soamService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/dm/" + DM1.value())
+ .request().get(String.class);
+
+ assertThat(response, is("{\"dm\":" +
+ "{" +
+ "\"dmId\":\"1\"," +
+ "\"sessionStatus\":\"ACTIVE\"," +
+ "\"frameDelayTwoWay\":\"PT0.04S\"," +
+ "\"frameDelayForward\":\"PT0.01S\"," +
+ "\"frameDelayBackward\":\"PT0.03S\"," +
+ "\"interFrameDelayVariationTwoWay\":\"PT0.008S\"," +
+ "\"interFrameDelayVariationForward\":\"PT0.005S\"," +
+ "\"interFrameDelayVariationBackward\":\"PT0.003S\"," +
+ "\"dmCfgType\":\"DMDMM\"," +
+ "\"version\":\"Y17312008\"," +
+ "\"remoteMepId\":2," +
+ "\"priority\":\"PRIO1\"," +
+ "\"measurementsEnabled\":[]," +
+ "\"current\":{" +
+ "\"startTime\":\"" + now + "\"," +
+ "\"elapsedTime\":\"PT1M\"," +
+ "\"suspectStatus\":\"false\"," +
+ "\"frameDelayForwardAvg\":\"PT0.011S\"," +
+ "\"frameDelayBackwardAvg\":\"PT0.01S\"," +
+ "\"frameDelayRangeBackwardAvg\":\"PT0.012S\"" +
+ "}," +
+ "\"historic\":[]" +
+ "}}"));
+ }
+
+ @Test
+ public void testGetDmInvalid() throws CfmConfigException, SoamConfigException, IOException {
+
+ SoamId dm3 = SoamId.valueOf(3);
+
+ expect(soamService.getDm(MDNAME1, MANAME1, MEPID1, dm3)).andReturn(null).anyTimes();
+ replay(soamService);
+
+ final WebTarget wt = target();
+ try {
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/dm/" + dm3.value())
+ .request().get(String.class);
+ fail("Expecting excpetion");
+ } catch (InternalServerErrorException e) {
+ ByteArrayInputStream is = (ByteArrayInputStream) e.getResponse().getEntity();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ String line = null;
+ StringBuffer sb = new StringBuffer();
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ }
+ assertEquals("{ \"failure\":\"DM md-1/ma-1-1/1/3 not found\" }", sb.toString());
+ }
+ }
+
+ @Test
+ public void testAbortDm() {
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/dm/" + DM1.value())
+ .request().delete();
+
+ assertEquals(200, response.getStatus());
+ }
+
+ @Test
+ public void testCreateDm() throws CfmConfigException, SoamConfigException {
+ MepEntry mep1 = DefaultMepEntry.builder(MEPID1, DeviceId.deviceId("netconf:1.2.3.4:830"),
+ PortNumber.portNumber(1), Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).buildEntry();
+
+ expect(mepService.getMep(MDNAME1, MANAME1, MEPID1)).andReturn(mep1).anyTimes();
+ replay(mepService);
+
+ ObjectMapper mapper = new ObjectMapper();
+ CfmCodecContext context = new CfmCodecContext();
+ ObjectNode node = mapper.createObjectNode();
+ node.set("dm", context.codec(DelayMeasurementCreate.class).encode(dm1, context));
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/dm")
+ .request().post(Entity.json(node.toString()));
+
+ assertEquals(201, response.getStatus());
+ }
+
+ @Test
+ public void testClearDmHistory() {
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/dm/" + DM1.value() +
+ "/clear-history")
+ .request().put(Entity.json(""));
+
+ assertEquals(200, response.getStatus());
+ }
+
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/soam/impl/LmWebResourceTest.java b/apps/cfm/src/test/java/org/onosproject/soam/impl/LmWebResourceTest.java
new file mode 100644
index 0000000..9dd70e6
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/soam/impl/LmWebResourceTest.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.soam.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.rest.BaseResource;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.cfm.impl.CfmResourceTest;
+import org.onosproject.codec.CodecService;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.onosproject.incubator.net.l2monitoring.soam.MilliPct;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamConfigException;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamId;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamService;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.DefaultLmEntry;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementCreate;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementEntry;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class LmWebResourceTest extends CfmResourceTest {
+ private final CfmMepService mepService = createMock(CfmMepService.class);
+ private final SoamService soamService = createMock(SoamService.class);
+
+ private static final MdId MDNAME1 = MdIdCharStr.asMdId("md-1");
+ private static final MaIdShort MANAME1 = MaIdCharStr.asMaId("ma-1-1");
+ private static final MepId MEPID1 = MepId.valueOf((short) 1);
+ private static final SoamId LMID1 = SoamId.valueOf(1);
+ private static final SoamId LMID2 = SoamId.valueOf(2);
+
+ private LossMeasurementEntry lm1;
+ private LossMeasurementEntry lm2;
+
+ private final Instant now = Instant.now();
+
+ @Before
+ public void setUpTest() throws CfmConfigException, SoamConfigException {
+ CfmCodecContext context = new CfmCodecContext();
+ ServiceDirectory testDirectory = new TestServiceDirectory()
+ .add(CfmMepService.class, mepService)
+ .add(SoamService.class, soamService)
+ .add(CodecService.class, context.codecManager());
+ BaseResource.setServiceDirectory(testDirectory);
+
+ lm1 = DefaultLmEntry.builder(
+ DelayMeasurementCreate.Version.Y17312008,
+ MepId.valueOf((short) 10),
+ Mep.Priority.PRIO1,
+ LossMeasurementCreate.LmType.LMLMM,
+ LMID1)
+ .build();
+ lm2 = DefaultLmEntry.builder(
+ DelayMeasurementCreate.Version.Y17312011,
+ MepId.valueOf((short) 10),
+ Mep.Priority.PRIO2,
+ LossMeasurementCreate.LmType.LMLMM,
+ LMID2)
+ .measuredAvailabilityBackwardStatus(LossMeasurementEntry.AvailabilityType.AVAILABLE)
+ .measuredAvailabilityForwardStatus(LossMeasurementEntry.AvailabilityType.UNKNOWN)
+ .measuredBackwardFlr(MilliPct.ofPercent(49.9f))
+ .measuredForwardFlr(MilliPct.ofRatio(0.51f))
+ .measuredBackwardLastTransitionTime(now)
+ .measuredForwardLastTransitionTime(now)
+ .build();
+
+ }
+
+ @Test
+ public void testGetAllLmsForMep() throws CfmConfigException, SoamConfigException {
+ List<LossMeasurementEntry> lmList = new ArrayList<>();
+ lmList.add(lm1);
+ lmList.add(lm2);
+
+ expect(soamService.getAllLms(MDNAME1, MANAME1, MEPID1)).andReturn(lmList).anyTimes();
+ replay(soamService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/lm")
+ .request().get(String.class);
+
+ assertThat(response, is("{\"lms\":[[" +
+ "{" +
+ "\"lmId\":\"1\"," +
+ "\"lmCfgType\":\"LMLMM\"," +
+ "\"version\":\"Y17312008\"," +
+ "\"remoteMepId\":10," +
+ "\"priority\":\"PRIO1\"," +
+ "\"countersEnabled\":[]," +
+ "\"measurementHistories\":[]," +
+ "\"availabilityHistories\":[]" +
+ "},{" +
+ "\"lmId\":\"2\"," +
+ "\"measuredForwardFlr\":51.0," +
+ "\"measuredBackwardFlr\":49.9," +
+ "\"measuredAvailabilityForwardStatus\":\"UNKNOWN\"," +
+ "\"measuredAvailabilityBackwardStatus\":\"AVAILABLE\"," +
+ "\"measuredForwardLastTransitionTime\":\"" + now + "\"," +
+ "\"measuredBackwardLastTransitionTime\":\"" + now + "\"," +
+ "\"lmCfgType\":\"LMLMM\"," +
+ "\"version\":\"Y17312011\"," +
+ "\"remoteMepId\":10," +
+ "\"priority\":\"PRIO2\"," +
+ "\"countersEnabled\":[]," +
+ "\"measurementHistories\":[]," +
+ "\"availabilityHistories\":[]" +
+ "}]]}"));
+ }
+
+ @Test
+ public void testGetAllLmsForMepEmpty() throws CfmConfigException, SoamConfigException {
+ List<LossMeasurementEntry> lmList = new ArrayList<>();
+
+ expect(soamService.getAllLms(MDNAME1, MANAME1, MEPID1)).andReturn(lmList).anyTimes();
+ replay(soamService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/lm")
+ .request().get(String.class);
+
+ assertThat(response, is("{\"lms\":[[]]}"));
+ }
+
+ @Test
+ public void testGetLm() throws CfmConfigException, SoamConfigException {
+
+ expect(soamService.getLm(MDNAME1, MANAME1, MEPID1, LMID1)).andReturn(lm1).anyTimes();
+ replay(soamService);
+
+ final WebTarget wt = target();
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/lm/" + LMID1.value())
+ .request().get(String.class);
+
+ assertThat(response, is("{\"lm\":" +
+ "{" +
+ "\"lmId\":\"1\"," +
+ "\"lmCfgType\":\"LMLMM\"," +
+ "\"version\":\"Y17312008\"," +
+ "\"remoteMepId\":10," +
+ "\"priority\":\"PRIO1\"," +
+ "\"countersEnabled\":[]," +
+ "\"measurementHistories\":[]," +
+ "\"availabilityHistories\":[]" +
+ "}}"));
+ }
+
+ @Test
+ public void testGetLmEmpty() throws CfmConfigException, SoamConfigException, IOException {
+ SoamId lmId3 = SoamId.valueOf(3);
+ expect(soamService.getLm(MDNAME1, MANAME1, MEPID1, lmId3))
+ .andReturn(null).anyTimes();
+ replay(soamService);
+
+ final WebTarget wt = target();
+ try {
+ final String response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/lm/" + lmId3.value())
+ .request().get(String.class);
+ } catch (InternalServerErrorException e) {
+ ByteArrayInputStream is = (ByteArrayInputStream) e.getResponse().getEntity();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ String line = null;
+ StringBuffer sb = new StringBuffer();
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ }
+ assertEquals("{ \"failure\":\"LM md-1/ma-1-1/1/3 not found\" }",
+ sb.toString());
+ }
+ }
+
+ @Test
+ public void testAbortLm() {
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/lm/" + LMID1.value())
+ .request().delete();
+ assertEquals(200, response.getStatus());
+ }
+
+ @Test
+ public void testCreateLm() throws CfmConfigException, SoamConfigException {
+ MepEntry mep1 = DefaultMepEntry.builder(MEPID1, DeviceId.deviceId("netconf:1.2.3.4:830"),
+ PortNumber.portNumber(1), Mep.MepDirection.UP_MEP, MDNAME1, MANAME1).buildEntry();
+
+ expect(mepService.getMep(MDNAME1, MANAME1, MEPID1)).andReturn(mep1).anyTimes();
+ replay(mepService);
+
+ ObjectMapper mapper = new ObjectMapper();
+ CfmCodecContext context = new CfmCodecContext();
+ ObjectNode node = mapper.createObjectNode();
+ node.set("lm", context.codec(LossMeasurementCreate.class).encode(lm1, context));
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/lm")
+ .request().post(Entity.json(node.toString()));
+ assertEquals(201, response.getStatus());
+ }
+
+ @Test
+ public void testClearLmHistory() {
+
+ final WebTarget wt = target();
+ final Response response = wt.path("md/" + MDNAME1.mdName() + "/ma/" +
+ MANAME1.maName() + "/mep/" + MEPID1.value() + "/lm/" + LMID1.value() +
+ "/clear-history")
+ .request().put(Entity.json(""));
+
+ assertEquals(200, response.getStatus());
+ }
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/soam/web/DmCreateCodecTest.java b/apps/cfm/src/test/java/org/onosproject/soam/web/DmCreateCodecTest.java
new file mode 100644
index 0000000..2f31310
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/soam/web/DmCreateCodecTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.soam.web;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.Priority;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamConfigException;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DefaultDelayMeasurementCreate;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate.DmCreateBuilder;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate.DmType;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate.MeasurementOption;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate.Version;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class DmCreateCodecTest {
+ ObjectMapper mapper;
+ CfmCodecContext context;
+
+ @Before
+ public void setUp() throws Exception {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ }
+
+ @Test
+ public void testDecodeObjectNodeCodecContext1()
+ throws JsonProcessingException, IOException {
+ String moStr = "{\"dm\": {}}";
+
+ InputStream input = new ByteArrayInputStream(
+ moStr.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+
+ try {
+ context.codec(DelayMeasurementCreate.class)
+ .decode((ObjectNode) cfg, context);
+ fail("Expecting an exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals("remoteMepId is required", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testDecodeObjectNodeCodecContext2()
+ throws JsonProcessingException, IOException {
+ String moStr = "{\"dm\": {" +
+ "\"version\":\"Y17312008\"," +
+ "\"dmType\":\"DMDMM\"," +
+ "\"remoteMepId\":12," +
+ "\"priority\":\"PRIO6\"," +
+ "\"measurementsEnabled\" :" +
+ "[\"FRAME_DELAY_RANGE_BACKWARD_AVERAGE\", " +
+ "\"INTER_FRAME_DELAY_VARIATION_FORWARD_AVERAGE\"]" +
+ "}}";
+
+ InputStream input = new ByteArrayInputStream(
+ moStr.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+
+ DelayMeasurementCreate dmCreate = context
+ .codec(DelayMeasurementCreate.class)
+ .decode((ObjectNode) cfg, context);
+
+ assertEquals(Version.Y17312008, dmCreate.version());
+ assertEquals(DmType.DMDMM, dmCreate.dmCfgType());
+ assertEquals(12, dmCreate.remoteMepId().id().shortValue());
+ }
+
+ @Test
+ public void testEncodeDelayMeasurementCreateCodecContext()
+ throws SoamConfigException {
+ DmCreateBuilder builder = DefaultDelayMeasurementCreate
+ .builder(DmType.DM1DMRX, Version.Y17312011,
+ MepId.valueOf((short) 16), Priority.PRIO5);
+ builder.addToMeasurementsEnabled(
+ MeasurementOption.FRAME_DELAY_BACKWARD_MAX);
+ builder.addToMeasurementsEnabled(
+ MeasurementOption.FRAME_DELAY_TWO_WAY_MAX);
+ builder.addToMeasurementsEnabled(
+ MeasurementOption.INTER_FRAME_DELAY_VARIATION_BACKWARD_BINS);
+ builder = (DmCreateBuilder) builder.messagePeriod(Duration.ofMillis(100));
+ builder = (DmCreateBuilder) builder.frameSize((short) 1200);
+
+ ObjectNode node = mapper.createObjectNode();
+ node.set("dm", context.codec(DelayMeasurementCreate.class)
+ .encode(builder.build(), context));
+
+ assertEquals(DmType.DM1DMRX.name(), node.get("dm").get("dmCfgType").asText());
+ assertEquals(Version.Y17312011.name(), node.get("dm").get("version").asText());
+ assertEquals(16, node.get("dm").get("remoteMepId").asInt());
+ assertEquals(Priority.PRIO5.name(), node.get("dm").get("priority").asText());
+ assertEquals(100, node.get("dm").get("messagePeriodMs").asInt());
+ assertEquals(1200, node.get("dm").get("frameSize").asInt());
+
+ assertEquals(3, ((ArrayNode) node.get("dm").get("measurementsEnabled")).size());
+ }
+
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/soam/web/DmEntryCodecTest.java b/apps/cfm/src/test/java/org/onosproject/soam/web/DmEntryCodecTest.java
new file mode 100644
index 0000000..028fad8
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/soam/web/DmEntryCodecTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.soam.web;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.Priority;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamConfigException;
+import org.onosproject.incubator.net.l2monitoring.soam.SoamId;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DefaultDelayMeasurementEntry;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate.DmType;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate.MeasurementOption;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate.Version;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementEntry;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementEntry.DmEntryBuilder;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementEntry.SessionStatus;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class DmEntryCodecTest {
+ ObjectMapper mapper;
+ CfmCodecContext context;
+ DelayMeasurementEntry dmEntry1;
+
+ @Before
+ public void setUp() throws Exception, SoamConfigException {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ DmEntryBuilder builder = DefaultDelayMeasurementEntry
+ .builder(SoamId.valueOf(12), DmType.DM1DMTX,
+ Version.Y17312008, MepId.valueOf((short) 10), Priority.PRIO4);
+ builder = builder.sessionStatus(SessionStatus.NOT_ACTIVE);
+ builder = builder.frameDelayTwoWay(Duration.ofNanos(101 * 1000));
+ builder = builder.frameDelayForward(Duration.ofNanos(102 * 1000));
+ builder = builder.frameDelayBackward(Duration.ofNanos(103 * 1000));
+ builder = builder.interFrameDelayVariationTwoWay(Duration.ofNanos(104 * 1000));
+ builder = builder.interFrameDelayVariationForward(Duration.ofNanos(105 * 1000));
+ builder = builder.interFrameDelayVariationBackward(Duration.ofNanos(106 * 1000));
+ builder.addToMeasurementsEnabled(MeasurementOption.FRAME_DELAY_BACKWARD_MAX);
+ builder.addToMeasurementsEnabled(MeasurementOption.FRAME_DELAY_TWO_WAY_MAX);
+ builder.addToMeasurementsEnabled(MeasurementOption.INTER_FRAME_DELAY_VARIATION_BACKWARD_BINS);
+
+ dmEntry1 = builder.build();
+ }
+
+ @Test
+ public void testEncodeDelayMeasurementEntryCodecContext()
+ throws JsonProcessingException, IOException {
+ ObjectNode node = mapper.createObjectNode();
+ node.set("dm", context.codec(DelayMeasurementEntry.class)
+ .encode(dmEntry1, context));
+
+ assertEquals(12, node.get("dm").get("dmId").asInt());
+ assertEquals(DmType.DM1DMTX.name(), node.get("dm").get("dmCfgType").asText());
+ assertEquals(Version.Y17312008.name(), node.get("dm").get("version").asText());
+ assertEquals(10, node.get("dm").get("remoteMepId").asInt());
+ assertEquals(3, ((ArrayNode) node.get("dm").get("measurementsEnabled")).size());
+
+ assertEquals(SessionStatus.NOT_ACTIVE.name(),
+ node.get("dm").get("sessionStatus").asText());
+ assertEquals("PT0.000101S",
+ node.get("dm").get("frameDelayTwoWay").asText());
+ assertEquals("PT0.000102S",
+ node.get("dm").get("frameDelayForward").asText());
+ assertEquals("PT0.000103S",
+ node.get("dm").get("frameDelayBackward").asText());
+ assertEquals("PT0.000104S",
+ node.get("dm").get("interFrameDelayVariationTwoWay").asText());
+ assertEquals("PT0.000105S",
+ node.get("dm").get("interFrameDelayVariationForward").asText());
+ assertEquals("PT0.000106S",
+ node.get("dm").get("interFrameDelayVariationBackward").asText());
+
+ }
+
+ @Test
+ public void testEncodeIterableOfDelayMeasurementEntryCodecContext()
+ throws SoamConfigException {
+ DmEntryBuilder builder2 = DefaultDelayMeasurementEntry
+ .builder(SoamId.valueOf(14), DmType.DM1DMRX,
+ Version.Y17312011, MepId.valueOf((short) 16), Priority.PRIO5);
+ builder2.addToMeasurementsEnabled(MeasurementOption.FRAME_DELAY_BACKWARD_MIN);
+ builder2.addToMeasurementsEnabled(MeasurementOption.FRAME_DELAY_TWO_WAY_MIN);
+ builder2.addToMeasurementsEnabled(MeasurementOption.INTER_FRAME_DELAY_VARIATION_BACKWARD_MIN);
+
+ Collection<DelayMeasurementEntry> dmEntries = new ArrayList<>();
+ dmEntries.add(dmEntry1);
+ dmEntries.add(builder2.build());
+ ObjectNode node = mapper.createObjectNode();
+ node.set("dm", context.codec(DelayMeasurementEntry.class)
+ .encode(dmEntries, context));
+
+ assertEquals(2, ((ArrayNode) node.get("dm")).size());
+ }
+
+}
diff --git a/apps/cfm/src/test/java/org/onosproject/soam/web/DmMeasurementOptionCodecTest.java b/apps/cfm/src/test/java/org/onosproject/soam/web/DmMeasurementOptionCodecTest.java
new file mode 100644
index 0000000..4986d5a
--- /dev/null
+++ b/apps/cfm/src/test/java/org/onosproject/soam/web/DmMeasurementOptionCodecTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.soam.web;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfm.CfmCodecContext;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate.MeasurementOption;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+public class DmMeasurementOptionCodecTest {
+ ObjectMapper mapper;
+ CfmCodecContext context;
+
+ @Before
+ public void setUp() throws Exception {
+ mapper = new ObjectMapper();
+ context = new CfmCodecContext();
+ }
+
+ @Test
+ public void testEncodeIterableOfMeasurementOptionCodecContext() {
+ List<MeasurementOption> moList = new ArrayList<>();
+ moList.add(MeasurementOption.FRAME_DELAY_BACKWARD_MAX);
+ moList.add(MeasurementOption.FRAME_DELAY_FORWARD_BINS);
+
+ ArrayNode an =
+ context.codec(MeasurementOption.class).encode(moList, context);
+
+ assertEquals(MeasurementOption.FRAME_DELAY_BACKWARD_MAX.toString(),
+ an.get(0).asText());
+ assertEquals(MeasurementOption.FRAME_DELAY_FORWARD_BINS.toString(),
+ an.get(1).asText());
+ }
+
+ @Test
+ public void testDecodeArrayNodeCodecContext()
+ throws JsonProcessingException, IOException {
+ String moStr = "{\"measurementsEnabled\": " +
+ "[\"FRAME_DELAY_RANGE_BACKWARD_AVERAGE\", " +
+ "\"INTER_FRAME_DELAY_VARIATION_FORWARD_AVERAGE\"]}";
+ InputStream input = new ByteArrayInputStream(
+ moStr.getBytes(StandardCharsets.UTF_8));
+ JsonNode cfg = mapper.readTree(input);
+ Iterable<MeasurementOption> moIter = context
+ .codec(MeasurementOption.class)
+ .decode((ArrayNode) cfg.get("measurementsEnabled"), context);
+
+ Iterator<MeasurementOption> source = moIter.iterator();
+ List<MeasurementOption> moList = new ArrayList<>();
+ source.forEachRemaining(moList::add);
+
+ assertEquals(MeasurementOption.FRAME_DELAY_RANGE_BACKWARD_AVERAGE.toString(),
+ moList.get(0).name());
+ assertEquals(MeasurementOption.INTER_FRAME_DELAY_VARIATION_FORWARD_AVERAGE.toString(),
+ moList.get(1).name());
+ }
+
+}
diff --git a/apps/cfm/src/test/resources/examples/CreateDM_Mep10.json b/apps/cfm/src/test/resources/examples/CreateDM_Mep10.json
new file mode 100644
index 0000000..4b8a962
--- /dev/null
+++ b/apps/cfm/src/test/resources/examples/CreateDM_Mep10.json
@@ -0,0 +1,18 @@
+{
+ "dm": {
+ "remoteMepId":20,
+ "dmCfgType": "DMDMM",
+ "version": "Y17312008",
+ "priority": "PRIO1",
+ "messagePeriodMs": 100,
+ "startTime": {
+ "immediate":true
+ },
+ "stopTime": {
+ "none":true
+ },
+ "frameSize": 1500,
+ "measurementIntervalMins": 1,
+ "measurementsEnabled": ["FRAME_DELAY_TWO_WAY_BINS","FRAME_DELAY_TWO_WAY_AVERAGE"]
+ }
+}
\ No newline at end of file
diff --git a/apps/cfm/src/test/resources/examples/CreateMa1InDomainA.json b/apps/cfm/src/test/resources/examples/CreateMa1InDomainA.json
new file mode 100644
index 0000000..0790aee
--- /dev/null
+++ b/apps/cfm/src/test/resources/examples/CreateMa1InDomainA.json
@@ -0,0 +1,23 @@
+{
+ "ma": {
+ "maName": "ma-vlan-1",
+ "maNameType": "CHARACTERSTRING",
+ "maNumericId": 1,
+ "ccm-interval": "INTERVAL_1S",
+ "component-list": [
+ { "component": {
+ "component-id":"1",
+ "tag-type": "VLAN_STAG",
+ "vid-list": [
+ {"vid":1}
+ ]
+ }
+ }
+ ],
+ "rmep-list": [
+ { "rmep":10 },
+ { "rmep":20 },
+ { "rmep":30 }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/apps/cfm/src/test/resources/examples/CreateMa2InDomainA.json b/apps/cfm/src/test/resources/examples/CreateMa2InDomainA.json
new file mode 100644
index 0000000..67afdba
--- /dev/null
+++ b/apps/cfm/src/test/resources/examples/CreateMa2InDomainA.json
@@ -0,0 +1,22 @@
+{
+ "ma": {
+ "maName": "ma-vlan-2",
+ "maNameType": "CHARACTERSTRING",
+ "maNumericId": 2,
+ "ccm-interval": "INTERVAL_1S",
+ "component-list": [
+ { "component": {
+ "component-id":"1",
+ "tag-type": "VLAN_STAG",
+ "vid-list": [
+ {"vid":2}
+ ]
+ }
+ }
+ ],
+ "rmep-list": [
+ { "rmep":10 },
+ { "rmep":20 }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/apps/cfm/src/test/resources/examples/CreateMdDomainA.json b/apps/cfm/src/test/resources/examples/CreateMdDomainA.json
new file mode 100644
index 0000000..2dbb761
--- /dev/null
+++ b/apps/cfm/src/test/resources/examples/CreateMdDomainA.json
@@ -0,0 +1,7 @@
+{"md": {
+ "mdName": "DomainA",
+ "mdNameType": "CHARACTERSTRING",
+ "mdLevel": "LEVEL3",
+ "mdNumeridId": 1
+}
+}
\ No newline at end of file
diff --git a/apps/cfm/src/test/resources/examples/CreateMep10.json b/apps/cfm/src/test/resources/examples/CreateMep10.json
new file mode 100644
index 0000000..3b393c2
--- /dev/null
+++ b/apps/cfm/src/test/resources/examples/CreateMep10.json
@@ -0,0 +1,14 @@
+{
+ "mep": {
+ "mepId": 10,
+ "deviceId": "netconf:192.168.56.10:830",
+ "port": 0,
+ "direction": "DOWN_MEP",
+ "mdName": "DomainA",
+ "maName": "ma-vlan-1",
+ "primary-vid": 1,
+ "administrative-state": true,
+ "ccm-ltm-priority": 4,
+ "cci-enabled" :true
+ }
+}
\ No newline at end of file
diff --git a/apps/cfm/src/test/resources/examples/README.md b/apps/cfm/src/test/resources/examples/README.md
new file mode 100644
index 0000000..3557cff
--- /dev/null
+++ b/apps/cfm/src/test/resources/examples/README.md
@@ -0,0 +1,12 @@
+Run:
+
+* curl --user onos:rocks -d @CreateMdDomainA.json http://localhost:8181/onos/cfm/md --header "Content-Type:application/json"
+* curl --user onos:rocks -d @CreateMa1InDomainA.json http://localhost:8181/onos/cfm/md/DomainA/ma --header "Content-Type:application/json"
+* curl --user onos:rocks -d @CreateMa2InDomainA.json http://localhost:8181/onos/cfm/md/DomainA/ma --header "Content-Type:application/json"
+* curl --user onos:rocks http://localhost:8181/onos/cfm/md
+
+Create a Device that supports CFM Programmable, say at netconf:192.168.56.10:830
+* curl --user onos:rocks -d @CreateMep10.json http://localhost:8181/onos/cfm/md/DomainA/ma/ma-vlan-1/mep --header "Content-Type:application/json"
+
+Now call the RPC to create a Delay Measurement on that device
+* curl --user onos:rocks -X PUT -d @CreateDM_Mep10.json http://localhost:8181/onos/cfm/md/DomainA/ma/ma-vlan-1/mep/10/dm --header "Content-Type:application/json"