Fix REST server side exception if array of devices is given

Fixes ONOS-6637

Change-Id: I7ec201e58f9e90a026fcdc1912b04e7398d8c2de
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java
index 77dd4ea..b453923 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java
@@ -70,6 +70,10 @@
                 + "' not found";
     }
 
+    private String subjectClassInvalidErrorString(String subjectClassKey) {
+        return "Config for '" + subjectClassKey + "' is invalid";
+    }
+
     private String subjectClassNotValidErrorString(String subjectClassKey) {
         return "subjectClassKey '" + subjectClassKey + "' not found";
     }
@@ -207,8 +211,10 @@
         List<String> errorMsgs = new ArrayList<String>();
         root.fieldNames()
                 .forEachRemaining(sk -> {
-                    if (service.getSubjectFactory(sk) == null)  {
+                    if (service.getSubjectFactory(sk) == null) {
                         errorMsgs.add(subjectClassNotValidErrorString(sk));
+                    } else if (!root.path(sk).isObject()) {
+                        errorMsgs.add(subjectClassInvalidErrorString(sk));
                     } else {
                         errorMsgs.addAll(consumeJson(service, (ObjectNode) root.path(sk),
                                 service.getSubjectFactory(sk)));
diff --git a/web/api/src/test/java/org/onosproject/rest/resources/NetworkConfigWebResourceTest.java b/web/api/src/test/java/org/onosproject/rest/resources/NetworkConfigWebResourceTest.java
index c14ba8c..41f3df7 100644
--- a/web/api/src/test/java/org/onosproject/rest/resources/NetworkConfigWebResourceTest.java
+++ b/web/api/src/test/java/org/onosproject/rest/resources/NetworkConfigWebResourceTest.java
@@ -15,12 +15,18 @@
  */
 package org.onosproject.rest.resources;
 
-import com.eclipsesource.json.Json;
-import com.eclipsesource.json.JsonObject;
-import com.eclipsesource.json.JsonValue;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.ImmutableSet;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.jetty.http.HttpStatus;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -35,11 +41,12 @@
 import org.onosproject.net.config.NetworkConfigServiceAdapter;
 import org.onosproject.net.config.SubjectFactory;
 
-import javax.ws.rs.NotFoundException;
-import javax.ws.rs.client.WebTarget;
-import java.net.HttpURLConnection;
-import java.util.HashSet;
-import java.util.Set;
+import com.eclipsesource.json.Json;
+import com.eclipsesource.json.JsonObject;
+import com.eclipsesource.json.JsonValue;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableSet;
 
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.replay;
@@ -55,7 +62,7 @@
  */
 public class NetworkConfigWebResourceTest extends ResourceTest {
 
-    MockNetworkConfigService mockNetworkConfigService;
+    private MockNetworkConfigService mockNetworkConfigService;
 
     public class MockDeviceConfig extends Config<Device> {
 
@@ -204,7 +211,7 @@
      * Sets up test config data.
      */
     @SuppressWarnings("unchecked")
-    public void setUpConfigData() {
+    private void setUpConfigData() {
         mockNetworkConfigService.devicesSubjects.add("device1");
         mockNetworkConfigService.devicesConfigs.add(new MockDeviceConfig("v1", "v2"));
     }
@@ -348,5 +355,49 @@
         checkBasicAttributes(result);
     }
 
-    // TODO: Add test for DELETE and POST
+    /**
+     * Tests network configuration with POST and illegal JSON.
+     */
+    @Test
+    public void testBadPost() {
+        String json = "this is invalid!";
+        WebTarget wt = target();
+
+        Response response = wt.path("network/configuration")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(json));
+        Assert.assertThat(response.getStatus(), is(HttpURLConnection.HTTP_BAD_REQUEST));
+    }
+
+    /**
+     * Tests creating a network config with POST.
+     */
+    @Test
+    public void testPost() {
+        InputStream jsonStream = IntentsResourceTest.class
+                .getResourceAsStream("post-config.json");
+        WebTarget wt = target();
+
+        Response response = wt.path("network/configuration")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        Assert.assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
+    }
+
+    /**
+     * Tests creating a network config with POST of valid but incorrect JSON.
+     */
+    @Test
+    public void testBadSyntaxPost() {
+        InputStream jsonStream = IntentsResourceTest.class
+                .getResourceAsStream("post-config-bad-syntax.json");
+        WebTarget wt = target();
+
+        Response response = wt.path("network/configuration")
+                .request(MediaType.APPLICATION_JSON_TYPE)
+                .post(Entity.json(jsonStream));
+        Assert.assertThat(response.getStatus(), is(HttpStatus.MULTI_STATUS_207));
+    }
+
+    // TODO: Add test for DELETE
 }
diff --git a/web/api/src/test/resources/org/onosproject/rest/resources/post-config-bad-syntax.json b/web/api/src/test/resources/org/onosproject/rest/resources/post-config-bad-syntax.json
new file mode 100644
index 0000000..70e0e9d
--- /dev/null
+++ b/web/api/src/test/resources/org/onosproject/rest/resources/post-config-bad-syntax.json
@@ -0,0 +1,10 @@
+{
+  "devices": [
+    { "alias": "s1", "uri": "of:0000000000000001", "annotations":
+    { "driver": "ovs-corsa" }
+    },
+    { "alias": "s2", "uri": "of:0000000000000002", "annotations":
+    { "driver": "ovs-corsa" }
+    }
+  ]
+}
diff --git a/web/api/src/test/resources/org/onosproject/rest/resources/post-config.json b/web/api/src/test/resources/org/onosproject/rest/resources/post-config.json
new file mode 100644
index 0000000..5353a7d
--- /dev/null
+++ b/web/api/src/test/resources/org/onosproject/rest/resources/post-config.json
@@ -0,0 +1 @@
+{"devices":{},"links":{}}