Improve unit test coverage for basic config classes

Change-Id: I8a9d6d51fcad89d8d215253fafdbecb12f1c81df
diff --git a/core/api/src/test/java/org/onosproject/net/config/basics/AllowedEntityConfigTest.java b/core/api/src/test/java/org/onosproject/net/config/basics/AllowedEntityConfigTest.java
new file mode 100644
index 0000000..a0bc219
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/config/basics/AllowedEntityConfigTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018-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.net.config.basics;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import org.junit.Test;
+import org.onosproject.net.config.ConfigApplyDelegate;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+public class AllowedEntityConfigTest {
+
+    class TestConfig extends AllowedEntityConfig<String> {
+        TestConfig() {
+        }
+    }
+
+    @Test
+    public void basicTest() {
+        ConfigApplyDelegate delegate = configApply -> { };
+        ObjectMapper mapper = new ObjectMapper();
+
+        TestConfig allowed = new TestConfig();
+        TestConfig notAllowed = new TestConfig();
+
+        allowed.init("enabled", "KEY", JsonNodeFactory.instance.objectNode(), mapper, delegate);
+
+        notAllowed.init("disabled", "KEY", JsonNodeFactory.instance.objectNode(), mapper, delegate);
+        notAllowed.isAllowed(false);
+
+        assertThat(allowed.isAllowed(), is(true));
+        assertThat(notAllowed.isAllowed(), is(false));
+
+        notAllowed.isAllowed(true);
+        allowed.isAllowed(false);
+        assertThat(allowed.isAllowed(), is(false));
+        assertThat(notAllowed.isAllowed(), is(true));
+    }
+}
\ No newline at end of file
diff --git a/core/api/src/test/java/org/onosproject/net/config/basics/BandwidthCapacityTest.java b/core/api/src/test/java/org/onosproject/net/config/basics/BandwidthCapacityTest.java
new file mode 100644
index 0000000..146930b
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/config/basics/BandwidthCapacityTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018-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.net.config.basics;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import org.junit.Test;
+import org.onlab.util.Bandwidth;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.config.ConfigApplyDelegate;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+
+public class BandwidthCapacityTest {
+
+    @Test
+    public void testConstruction() {
+        BandwidthCapacity config = new BandwidthCapacity();
+        ConfigApplyDelegate delegate = configApply -> { };
+        ObjectMapper mapper = new ObjectMapper();
+        ConnectPoint cp = NetTestTools.connectPoint("cp1", 3);
+
+        config.init(cp, "KEY", JsonNodeFactory.instance.objectNode(), mapper, delegate);
+
+        double expectedBw = 1.0;
+        config.capacity(Bandwidth.mbps(expectedBw));
+        assertThat(config.isValid(), is(true));
+        assertThat(config.toString(), containsString("capacity"));
+
+    }
+
+}
\ No newline at end of file
diff --git a/core/api/src/test/java/org/onosproject/net/config/basics/BasicFeatureConfigTest.java b/core/api/src/test/java/org/onosproject/net/config/basics/BasicFeatureConfigTest.java
new file mode 100644
index 0000000..67ffdef
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/config/basics/BasicFeatureConfigTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018-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.net.config.basics;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import org.junit.Test;
+import org.onosproject.net.config.ConfigApplyDelegate;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+public class BasicFeatureConfigTest {
+
+    class TestConfig extends BasicFeatureConfig<String> {
+        TestConfig(boolean defaultValue) {
+            super(defaultValue);
+        }
+    }
+
+    @Test
+    public void basicTest() {
+        ConfigApplyDelegate delegate = configApply -> { };
+        ObjectMapper mapper = new ObjectMapper();
+
+        TestConfig enabled = new TestConfig(true);
+        TestConfig disabled = new TestConfig(false);
+
+        enabled.init("enabled", "KEY", JsonNodeFactory.instance.objectNode(), mapper, delegate);
+        disabled.init("disabled", "KEY", JsonNodeFactory.instance.objectNode(), mapper, delegate);
+
+        assertThat(enabled.enabled(), is(true));
+        assertThat(disabled.enabled(), is(false));
+
+        disabled.enabled(true);
+        enabled.enabled(false);
+        assertThat(enabled.enabled(), is(false));
+        assertThat(disabled.enabled(), is(true));
+    }
+}
\ No newline at end of file
diff --git a/core/api/src/test/java/org/onosproject/net/config/basics/BasicHostConfigTest.java b/core/api/src/test/java/org/onosproject/net/config/basics/BasicHostConfigTest.java
new file mode 100644
index 0000000..6721cc7
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/config/basics/BasicHostConfigTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018-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.net.config.basics;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.google.common.collect.ImmutableSet;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.config.ConfigApplyDelegate;
+
+import java.util.Set;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+
+public class BasicHostConfigTest {
+
+    /**
+     * Tests construction, setters and getters of a BasicLinkConfig object.
+     */
+    @Test
+    public void testConstruction() {
+        BasicHostConfig config = new BasicHostConfig();
+        ConfigApplyDelegate delegate = configApply -> { };
+        ObjectMapper mapper = new ObjectMapper();
+        HostId hostId = NetTestTools.hid("12:34:56:78:90:ab/1");
+        IpAddress ip1 = IpAddress.valueOf("1.1.1.1");
+        IpAddress ip2 = IpAddress.valueOf("1.1.1.2");
+        IpAddress ip3 = IpAddress.valueOf("1.1.1.3");
+        Set<IpAddress> ips = ImmutableSet.of(ip1, ip2, ip3);
+        HostLocation loc1 = new HostLocation(
+                NetTestTools.connectPoint("d1", 1), System.currentTimeMillis());
+        HostLocation loc2 = new HostLocation(
+                NetTestTools.connectPoint("d2", 2), System.currentTimeMillis());
+        Set<HostLocation> locs = ImmutableSet.of(loc1, loc2);
+
+        config.init(hostId, "KEY", JsonNodeFactory.instance.objectNode(), mapper, delegate);
+
+        config.setIps(ips)
+              .setLocations(locs);
+
+        assertThat(config.isValid(), is(true));
+        assertThat(config.name(), is("-"));
+        assertThat(config.ipAddresses(), hasSize(3));
+        assertThat(config.ipAddresses(), hasItems(ip1, ip2, ip3));
+        assertThat(config.locations(), hasSize(2));
+        assertThat(config.locations(), hasItems(loc1, loc2));
+    }
+
+}
\ No newline at end of file
diff --git a/core/api/src/test/java/org/onosproject/net/config/basics/BasicRegionConfigTest.java b/core/api/src/test/java/org/onosproject/net/config/basics/BasicRegionConfigTest.java
index 7d9b78c..22058fe 100644
--- a/core/api/src/test/java/org/onosproject/net/config/basics/BasicRegionConfigTest.java
+++ b/core/api/src/test/java/org/onosproject/net/config/basics/BasicRegionConfigTest.java
@@ -24,10 +24,15 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.config.InvalidFieldException;
 import org.onosproject.net.region.Region;
+import org.onosproject.ui.topo.LayoutLocation;
 
 import java.util.List;
 import java.util.Set;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -186,4 +191,37 @@
 
         cfg.isValid();
     }
+
+    @Test
+    public void testPeerLocMapping() {
+        String peer1 = "peer1";
+        String loc1 = LayoutLocation.Type.GRID.toString();
+        double loc1Y = 22.0;
+        double loc1X = 33.0;
+        String peer2 = "peer2";
+        String loc2 = LayoutLocation.Type.GEO.toString();
+        double loc2Y = 222.0;
+        double loc2X = 333.0;
+        loadRegion(R2);
+        cfg.addPeerLocMapping(peer1, loc1, loc1Y, loc1X);
+        cfg.addPeerLocMapping(peer2, loc2, loc2Y, loc2X);
+
+        List<LayoutLocation> locs = cfg.getMappings();
+
+        assertThat(locs, hasSize(2));
+
+        LayoutLocation createdLoc1 = locs.stream().filter(loc -> loc.id().equals(peer1)).findFirst().orElse(null);
+        LayoutLocation createdLoc2 = locs.stream().filter(loc -> loc.id().equals(peer2)).findFirst().orElse(null);
+
+        assertThat(createdLoc1, notNullValue());
+        assertThat(createdLoc2, notNullValue());
+
+        assertThat(createdLoc1.locType().toString(), is(loc1));
+        assertThat(createdLoc1.longOrX(), is(loc1X));
+        assertThat(createdLoc1.latOrY(), is(loc1Y));
+
+        assertThat(createdLoc2.locType().toString(), is(loc2));
+        assertThat(createdLoc2.longOrX(), is(loc2X));
+        assertThat(createdLoc2.latOrY(), is(loc2Y));
+    }
 }
diff --git a/incubator/api/src/test/java/org/onosproject/incubator/net/config/basics/McastConfigTest.java b/core/api/src/test/java/org/onosproject/net/config/basics/McastConfigTest.java
similarity index 94%
rename from incubator/api/src/test/java/org/onosproject/incubator/net/config/basics/McastConfigTest.java
rename to core/api/src/test/java/org/onosproject/net/config/basics/McastConfigTest.java
index 8fce669..03536cd 100644
--- a/incubator/api/src/test/java/org/onosproject/incubator/net/config/basics/McastConfigTest.java
+++ b/core/api/src/test/java/org/onosproject/net/config/basics/McastConfigTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.onosproject.incubator.net.config.basics;
+package org.onosproject.net.config.basics;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -27,12 +27,14 @@
 import org.onosproject.core.CoreService;
 import org.onosproject.net.config.Config;
 import org.onosproject.net.config.ConfigApplyDelegate;
-import org.onosproject.net.config.basics.McastConfig;
 
 import java.io.InputStream;
 
 import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Tests for class {@link McastConfig}.
diff --git a/core/api/src/test/java/org/onosproject/net/config/basics/SubjectFactoriesTest.java b/core/api/src/test/java/org/onosproject/net/config/basics/SubjectFactoriesTest.java
new file mode 100644
index 0000000..7a4dc1a
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/config/basics/SubjectFactoriesTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2018-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.net.config.basics;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.LinkKey;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.config.SubjectFactory;
+import org.onosproject.net.region.RegionId;
+import org.onosproject.ui.model.topo.UiTopoLayoutId;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
+public class SubjectFactoriesTest {
+
+    class TestCoreService extends CoreServiceAdapter {
+
+        @Override
+        public ApplicationId registerApplication(String key) {
+            return new TestApplicationId(key);
+        }
+
+    }
+
+    @Before
+    public void setUp() {
+        SubjectFactories.setCoreService(new TestCoreService());
+    }
+
+    @Test
+    public void testAppIdFactory() {
+        SubjectFactory<ApplicationId> appIdFactory = SubjectFactories.APP_SUBJECT_FACTORY;
+        assertThat(appIdFactory, notNullValue());
+
+        ApplicationId id = NetTestTools.APP_ID;
+        ApplicationId createdAppId = appIdFactory.createSubject(id.name());
+        assertThat(createdAppId.id(), equalTo(id.id()));
+        assertThat(appIdFactory.subjectKey(id), is(id.name()));
+    }
+
+    @Test
+    public void testDeviceIdFactory() {
+        SubjectFactory<DeviceId> deviceIdFactory = SubjectFactories.DEVICE_SUBJECT_FACTORY;
+        assertThat(deviceIdFactory, notNullValue());
+
+        String deviceName = "d1";
+        String ofDeviceName = "of:" + deviceName;
+        DeviceId id = NetTestTools.did(deviceName);
+
+        DeviceId createdDeviceId = deviceIdFactory.createSubject(ofDeviceName);
+        assertThat(createdDeviceId, equalTo(id));
+        assertThat(deviceIdFactory.subjectKey(id), is(ofDeviceName));
+    }
+
+    @Test
+    public void testConnectPointFactory() {
+        SubjectFactory<ConnectPoint> connectPointFactory = SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
+        assertThat(connectPointFactory, notNullValue());
+
+        String deviceName = "d1";
+        String ofDeviceName = "of:" + deviceName;
+        int devicePort = 2;
+        String cpString = ofDeviceName + "/" + Integer.toString(devicePort);
+        ConnectPoint cp = NetTestTools.connectPoint(deviceName, devicePort);
+
+        ConnectPoint createdConnectPoint = connectPointFactory.createSubject(cpString);
+        assertThat(createdConnectPoint, equalTo(cp));
+        assertThat(connectPointFactory.subjectKey(cp), is(cpString));
+    }
+
+    @Test
+    public void testHostFactory() {
+        SubjectFactory<HostId> hostFactory = SubjectFactories.HOST_SUBJECT_FACTORY;
+        assertThat(hostFactory, notNullValue());
+
+        String hostName = "11:11:11:11:11:11/3";
+        HostId hostId = NetTestTools.hid(hostName);
+
+        HostId createdHostId = hostFactory.createSubject(hostName);
+        assertThat(createdHostId, equalTo(hostId));
+        assertThat(hostFactory.subjectKey(hostId), is(hostId.toString()));
+    }
+
+    @Test
+    public void testLinkFactory() {
+        SubjectFactory<LinkKey> linkFactory = SubjectFactories.LINK_SUBJECT_FACTORY;
+        assertThat(linkFactory, notNullValue());
+
+        String deviceName1 = "d1";
+        String deviceName2 = "d2";
+        String ofDeviceName1 = "of:" + deviceName1;
+        String ofDeviceName2 = "of:" + deviceName2;
+        int devicePort1 = 2;
+        int devicePort2 = 3;
+        String cpString1 = ofDeviceName1 + "/" + Integer.toString(devicePort1);
+        String cpString2 = ofDeviceName2 + "/" + Integer.toString(devicePort2);
+        ConnectPoint cp1 = NetTestTools.connectPoint(deviceName1, devicePort1);
+        ConnectPoint cp2 = NetTestTools.connectPoint(deviceName2, devicePort2);
+        String linkString1 = cpString1 + '-' + cpString2;
+        LinkKey key1 = LinkKey.linkKey(cp1, cp2);
+
+        LinkKey createdLink1 = linkFactory.createSubject(linkString1);
+        assertThat(createdLink1.asId(), is(linkString1));
+        assertThat(linkFactory.subjectKey(key1), is(linkString1));
+    }
+
+    @Test
+    public void testRegionIdFactory() {
+        SubjectFactory<RegionId> regionIdFactory = SubjectFactories.REGION_SUBJECT_FACTORY;
+        assertThat(regionIdFactory, notNullValue());
+
+        String region1 = "region1";
+        RegionId id = RegionId.regionId(region1);
+
+        RegionId createdRegionId = regionIdFactory.createSubject(region1);
+        assertThat(createdRegionId.id(), equalTo(region1));
+        assertThat(regionIdFactory.subjectKey(id), is(region1));
+    }
+
+    @Test
+    public void testUITopoLayoutIdFactory() {
+        SubjectFactory<UiTopoLayoutId> uiTopoLayoutIdFactory = SubjectFactories.LAYOUT_SUBJECT_FACTORY;
+        assertThat(uiTopoLayoutIdFactory, notNullValue());
+
+        String layout1 = "layout1";
+        UiTopoLayoutId id = UiTopoLayoutId.layoutId(layout1);
+
+        UiTopoLayoutId createdLayouId = uiTopoLayoutIdFactory.createSubject(layout1);
+        assertThat(createdLayouId.id(), equalTo(layout1));
+        assertThat(uiTopoLayoutIdFactory.subjectKey(id), is(layout1));
+    }
+}
\ No newline at end of file
diff --git a/incubator/api/src/test/resources/mcast-config-invalid.json b/core/api/src/test/resources/mcast-config-invalid.json
similarity index 100%
rename from incubator/api/src/test/resources/mcast-config-invalid.json
rename to core/api/src/test/resources/mcast-config-invalid.json
diff --git a/incubator/api/src/test/resources/mcast-config.json b/core/api/src/test/resources/mcast-config.json
similarity index 100%
rename from incubator/api/src/test/resources/mcast-config.json
rename to core/api/src/test/resources/mcast-config.json
diff --git a/core/net/src/test/java/org/onosproject/net/config/basics/DeviceAnnotationConfigTest.java b/core/net/src/test/java/org/onosproject/net/config/basics/DeviceAnnotationConfigTest.java
index b95f26d..86b1b81 100644
--- a/core/net/src/test/java/org/onosproject/net/config/basics/DeviceAnnotationConfigTest.java
+++ b/core/net/src/test/java/org/onosproject/net/config/basics/DeviceAnnotationConfigTest.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.config.basics;
 
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
 import static org.junit.Assert.*;
 
 import java.io.IOException;
@@ -33,6 +34,7 @@
 import org.onosproject.codec.CodecService;
 import org.onosproject.codec.impl.CodecManager;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.NetTestTools;
 import org.onosproject.net.config.BaseConfig;
 import org.onosproject.net.config.ConfigApplyDelegate;
 
@@ -67,6 +69,9 @@
     private final String value = "bar";
     private final String key1 = "foo1";
     private final String value1 = "bar1";
+    private final String nullKey = "null";
+    private final String numberKey = "number";
+    private final String numberValue = "123";
 
 
     // TODO consolidate code-clone in ProtectionConfigTest, and define constants for field name
@@ -123,8 +128,11 @@
 
         assertThat(sut.subject(), is(deviceId));
         Map<String, String> annotations = sut.annotations();
-        assertThat(annotations.size(), is(1));
+        assertThat(annotations.size(), is(3));
         assertThat(annotations.get(key), is(value));
+        assertThat(annotations.get(nullKey), nullValue());
+        assertThat(annotations.get(numberKey), is(numberValue));
+        assertThat(sut.isValid(), is(true));
     }
 
     @Test
@@ -199,4 +207,12 @@
         assertThat(annotations.get(key1), is(value1));
     }
 
+    @Test
+    public void detachedTest() {
+        DeviceAnnotationConfig config = new DeviceAnnotationConfig(NetTestTools.did("d1"));
+
+        // The default annotations have no JSON and are invalid
+        assertThat(config.isValid(), is(false));
+    }
+
 }
diff --git a/core/net/src/test/java/org/onosproject/net/config/basics/PortAnnotationConfigTest.java b/core/net/src/test/java/org/onosproject/net/config/basics/PortAnnotationConfigTest.java
index df6ce7b..3bf8848 100644
--- a/core/net/src/test/java/org/onosproject/net/config/basics/PortAnnotationConfigTest.java
+++ b/core/net/src/test/java/org/onosproject/net/config/basics/PortAnnotationConfigTest.java
@@ -15,7 +15,9 @@
  */
 package org.onosproject.net.config.basics;
 
+import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
 import static org.junit.Assert.*;
 import static org.onosproject.net.ConnectPoint.deviceConnectPoint;
 
@@ -66,6 +68,9 @@
 
     private final String key = "foo";
     private final String value = "bar";
+    private final String nullKey = "null";
+    private final String numberKey = "number";
+    private final String numberValue = "123";
 
 
     // TODO consolidate code-clone in ProtectionConfigTest, and define constants for field name
@@ -122,8 +127,11 @@
 
         assertThat(sut.subject(), is(cp));
         Map<String, String> annotations = sut.annotations();
-        assertThat(annotations.size(), is(1));
+        assertThat(annotations.size(), is(3));
         assertThat(annotations.get(key), is(value));
+        assertThat(annotations.get(nullKey), nullValue());
+        assertThat(annotations.get(numberKey), is(numberValue));
+        assertThat(sut.isValid(), is(true));
     }
 
     @Test
@@ -145,6 +153,7 @@
         Map<String, String> annotations = sut.annotations();
         assertThat(annotations.size(), is(1));
         assertThat(annotations.get(key), is(value));
+        assertThat(sut.isValid(), is(true));
     }
 
     @Test
@@ -166,6 +175,23 @@
         Map<String, String> annotations = sut.annotations();
         assertThat(annotations.size(), is(1));
         assertThat(annotations.get(key), is(value));
+        assertThat(sut.isValid(), is(true));
+    }
+
+    @Test
+    public void removeTest() {
+        PortAnnotationConfig sut = new PortAnnotationConfig();
+        sut.init(cp, PortAnnotationConfig.CONFIG_KEY, node, mapper, noopDelegate);
+
+        sut.annotation(key);
+
+        assertThat(sut.subject(), is(cp));
+        Map<String, String> annotations = sut.annotations();
+        assertThat(annotations.values(), hasSize(2));
+        assertThat(annotations.get(key), nullValue());
+        assertThat(annotations.get(nullKey), nullValue());
+        assertThat(annotations.get(numberKey), is(numberValue));
+        assertThat(sut.isValid(), is(true));
     }
 
 }
diff --git a/core/net/src/test/resources/org/onosproject/net/config/basics/device_annotation_config.json b/core/net/src/test/resources/org/onosproject/net/config/basics/device_annotation_config.json
index b37e19b..236846c 100644
--- a/core/net/src/test/resources/org/onosproject/net/config/basics/device_annotation_config.json
+++ b/core/net/src/test/resources/org/onosproject/net/config/basics/device_annotation_config.json
@@ -3,7 +3,9 @@
     "of:0000000000000001" : {
       "annotations" : {
         "entries" : {
-          "foo" : "bar"
+          "foo" : "bar",
+          "empty" : null,
+          "number" : 123
         }
       }
     }
diff --git a/core/net/src/test/resources/org/onosproject/net/config/basics/port_annotation_config.json b/core/net/src/test/resources/org/onosproject/net/config/basics/port_annotation_config.json
index 8a88ed8..d9ae179 100644
--- a/core/net/src/test/resources/org/onosproject/net/config/basics/port_annotation_config.json
+++ b/core/net/src/test/resources/org/onosproject/net/config/basics/port_annotation_config.json
@@ -3,7 +3,9 @@
     "of:0000000000000001/2" : {
       "annotations" : {
         "entries" : {
-          "foo" : "bar"
+          "foo" : "bar",
+          "empty" : null,
+          "number" : 123
         }
       }
     }