Merge "Fix ResourceUtilsTest junit"
diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/HttpClient.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/HttpClient.java
index 2fe46fb..ebed1d7 100644
--- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/HttpClient.java
+++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/HttpClient.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,14 +21,16 @@
 package org.onap.policy.common.endpoints.http.client;
 
 import java.util.Map;
-
+import java.util.concurrent.Future;
 import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.InvocationCallback;
 import javax.ws.rs.core.Response;
 
 import org.onap.policy.common.capabilities.Startable;
 
 /**
- * Http Client interface.
+ * Http Client interface. Supports both synchronous and asynchronous operations.
+ *
  */
 public interface HttpClient extends Startable {
 
@@ -48,6 +50,24 @@
     Response get();
 
     /**
+     * Asynchronous GET request.
+     *
+     * @param callback callback to be invoked, asynchronously, when the request completes
+     * @param path context uri path.
+     *
+     * @return future that can be used to cancel the request or await the response
+     */
+    Future<Response> get(InvocationCallback<Response> callback, String path);
+
+    /**
+     * Asynchronous GET request.
+     *
+     * @param callback callback to be invoked, asynchronously, when the request completes
+     * @return future that can be used to cancel the request or await the response
+     */
+    Future<Response> get(InvocationCallback<Response> callback);
+
+    /**
      * PUT request.
      *
      * @param path context uri path
@@ -59,6 +79,19 @@
     Response put(String path, Entity<?> entity, Map<String, Object> headers);
 
     /**
+     * Asynchronous PUT request.
+     *
+     * @param callback callback to be invoked, asynchronously, when the request completes
+     * @param path context uri path
+     * @param entity body
+     * @param headers headers
+     *
+     * @return future that can be used to cancel the request or await the response
+     */
+    Future<Response> put(InvocationCallback<Response> callback, String path, Entity<?> entity,
+                    Map<String, Object> headers);
+
+    /**
      * POST request.
      *
      * @param path context uri path
@@ -70,6 +103,19 @@
     Response post(String path, Entity<?> entity, Map<String, Object> headers);
 
     /**
+     * Asynchronous POST request.
+     *
+     * @param callback callback to be invoked, asynchronously, when the request completes
+     * @param path context uri path
+     * @param entity body
+     * @param headers headers
+     *
+     * @return future that can be used to cancel the request or await the response
+     */
+    Future<Response> post(InvocationCallback<Response> callback, String path, Entity<?> entity,
+                    Map<String, Object> headers);
+
+    /**
      * DELETE request.
      *
      * @param path context uri path
@@ -80,6 +126,17 @@
     Response delete(String path, Map<String, Object> headers);
 
     /**
+     * Asynchronous DELETE request.
+     *
+     * @param callback callback to be invoked, asynchronously, when the request completes
+     * @param path context uri path
+     * @param headers headers
+     *
+     * @return future that can be used to cancel the request or await the response
+     */
+    Future<Response> delete(InvocationCallback<Response> callback, String path, Map<String, Object> headers);
+
+    /**
      * Retrieve the body from the HTTP transaction.
      *
      * @param response response.
diff --git a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/internal/JerseyClient.java b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/internal/JerseyClient.java
index 8a71771..1a822ff 100644
--- a/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/internal/JerseyClient.java
+++ b/policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/client/internal/JerseyClient.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved.
  * Modifications Copyright (C) 2018 Samsung Electronics Co., Ltd.
  * Modifications Copyright (C) 2019 Nordix Foundation.
  * ================================================================================
@@ -28,11 +28,13 @@
 import java.security.SecureRandom;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.concurrent.Future;
 import javax.net.ssl.SSLContext;
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.ClientBuilder;
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.Invocation.Builder;
+import javax.ws.rs.client.InvocationCallback;
 import javax.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
 import org.glassfish.jersey.client.ClientProperties;
@@ -169,21 +171,52 @@
     }
 
     @Override
+    public Future<Response> get(InvocationCallback<Response> callback, String path) {
+        if (!StringUtils.isBlank(path)) {
+            return this.client.target(this.baseUrl).path(path).request().async().get(callback);
+        } else {
+            return this.client.target(this.baseUrl).request().async().get(callback);
+        }
+    }
+
+    @Override
+    public Future<Response> get(InvocationCallback<Response> callback) {
+        return this.client.target(this.baseUrl).request().async().get(callback);
+    }
+
+    @Override
     public Response put(String path, Entity<?> entity, Map<String, Object> headers) {
         return getBuilder(path, headers).put(entity);
     }
 
     @Override
+    public Future<Response> put(InvocationCallback<Response> callback, String path, Entity<?> entity,
+                    Map<String, Object> headers) {
+        return getBuilder(path, headers).async().put(entity, callback);
+    }
+
+    @Override
     public Response post(String path, Entity<?> entity, Map<String, Object> headers) {
         return getBuilder(path, headers).post(entity);
     }
 
     @Override
+    public Future<Response> post(InvocationCallback<Response> callback, String path, Entity<?> entity,
+                    Map<String, Object> headers) {
+        return getBuilder(path, headers).async().post(entity, callback);
+    }
+
+    @Override
     public Response delete(String path, Map<String, Object> headers) {
         return getBuilder(path, headers).delete();
     }
 
     @Override
+    public Future<Response> delete(InvocationCallback<Response> callback, String path, Map<String, Object> headers) {
+        return getBuilder(path, headers).async().delete(callback);
+    }
+
+    @Override
     public boolean start() {
         return alive;
     }
diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpClientTest.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpClientTest.java
index 2aaf136..d3f94cd 100644
--- a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpClientTest.java
+++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpClientTest.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved.
  * Modifications Copyright (C) 2018 Samsung Electronics Co., Ltd.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,15 +23,21 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.InvocationCallback;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import lombok.Getter;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -194,6 +200,28 @@
     }
 
     @Test
+    public void testHttpGetNoAuthClientAsync() throws Exception {
+        final HttpClient client = getNoAuthHttpClient(TEST_HTTP_NO_AUTH_CLIENT, false,
+            6666);
+        MyCallback callback = new MyCallback();
+        final Response response = client.get(callback, HELLO).get();
+
+        verifyCallback("testHttpGetNoAuthClientAsync", callback, response);
+
+        final String body = HttpClient.getBody(response, String.class);
+
+        assertEquals(200, response.getStatus());
+        assertEquals(HELLO, body);
+    }
+
+    private void verifyCallback(String testName, MyCallback callback, final Response response)
+                    throws InterruptedException {
+        assertTrue(testName, callback.await());
+        assertNull(testName, callback.getThrowable());
+        assertSame(testName, response, callback.getResponse());
+    }
+
+    @Test
     public void testHttpPutNoAuthClient() throws Exception {
         final HttpClient client = getNoAuthHttpClient(TEST_HTTP_NO_AUTH_CLIENT, false, 6666);
 
@@ -206,6 +234,22 @@
     }
 
     @Test
+    public void testHttpPutNoAuthClientAsync() throws Exception {
+        final HttpClient client = getNoAuthHttpClient(TEST_HTTP_NO_AUTH_CLIENT, false, 6666);
+
+        Entity<MyEntity> entity = Entity.entity(new MyEntity(MY_VALUE), MediaType.APPLICATION_JSON);
+        MyCallback callback = new MyCallback();
+        final Response response = client.put(callback, HELLO, entity, Collections.emptyMap()).get();
+
+        verifyCallback("testHttpPutNoAuthClientAsync", callback, response);
+
+        final String body = HttpClient.getBody(response, String.class);
+
+        assertEquals(200, response.getStatus());
+        assertEquals(PUT_HELLO, body);
+    }
+
+    @Test
     public void testHttpPostNoAuthClient() throws Exception {
         final HttpClient client = getNoAuthHttpClient(TEST_HTTP_NO_AUTH_CLIENT, false,
             6666);
@@ -219,6 +263,23 @@
     }
 
     @Test
+    public void testHttpPostNoAuthClientAsync() throws Exception {
+        final HttpClient client = getNoAuthHttpClient(TEST_HTTP_NO_AUTH_CLIENT, false,
+            6666);
+
+        Entity<MyEntity> entity = Entity.entity(new MyEntity(MY_VALUE), MediaType.APPLICATION_JSON);
+        MyCallback callback = new MyCallback();
+        final Response response = client.post(callback, HELLO, entity, Collections.emptyMap()).get();
+
+        verifyCallback("testHttpPostNoAuthClientAsync", callback, response);
+
+        final String body = HttpClient.getBody(response, String.class);
+
+        assertEquals(200, response.getStatus());
+        assertEquals("POST:hello:{myParameter=myValue}", body);
+    }
+
+    @Test
     public void testHttpDeletetNoAuthClient() throws Exception {
         final HttpClient client = getNoAuthHttpClient(TEST_HTTP_NO_AUTH_CLIENT, false,
             6666);
@@ -231,6 +292,41 @@
     }
 
     @Test
+    public void testHttpDeletetNoAuthClientAsync() throws Exception {
+        final HttpClient client = getNoAuthHttpClient(TEST_HTTP_NO_AUTH_CLIENT, false,
+            6666);
+
+        MyCallback callback = new MyCallback();
+        final Response response = client.delete(callback, HELLO, Collections.emptyMap()).get();
+
+        verifyCallback("testHttpDeletetNoAuthClientAsync", callback, response);
+
+        final String body = HttpClient.getBody(response, String.class);
+
+        assertEquals(200, response.getStatus());
+        assertEquals("DELETE:hello", body);
+    }
+
+    /**
+     * Perform one asynchronous test with auth client; don't need to test every method.
+     * @throws Exception if an error occurs
+     */
+    @Test
+    public void testHttpAsyncAuthClient() throws Exception {
+        final HttpClient client = getAuthHttpClient();
+
+        MyCallback callback = new MyCallback();
+        final Response response = client.get(callback, HELLO).get();
+
+        verifyCallback("testHttpAsyncAuthClient", callback, response);
+
+        final String body = HttpClient.getBody(response, String.class);
+
+        assertEquals(200, response.getStatus());
+        assertEquals(HELLO, body);
+    }
+
+    @Test
     public void testHttpGetAuthClient() throws Exception {
         final HttpClient client = getAuthHttpClient();
 
@@ -382,16 +478,33 @@
             server.waitedStart(10000);
         }
 
+        Response response;
         final HttpClient clientPap = HttpClientFactoryInstance.getClientFactory().get("PAP");
-        final Response response = clientPap.get();
+        response = clientPap.get();
         assertEquals(200, response.getStatus());
 
         final HttpClient clientPdp = HttpClientFactoryInstance.getClientFactory().get("PDP");
-        final Response response2 = clientPdp.get("test");
-        assertEquals(500, response2.getStatus());
+        response = clientPdp.get("test");
+        assertEquals(500, response.getStatus());
 
         assertFalse(MyJacksonProvider.hasWrittenSome());
         assertFalse(MyGsonProvider.hasWrittenSome());
+
+        // try with empty path
+        response = clientPap.get("");
+        assertEquals(200, response.getStatus());
+
+        // try it asynchronously, too
+        MyCallback callback = new MyCallback();
+        response = clientPap.get(callback).get();
+        verifyCallback("testHttpAuthClientProps", callback, response);
+        assertEquals(200, response.getStatus());
+
+        // try it asynchronously, with empty path
+        callback = new MyCallback();
+        response = clientPap.get(callback, "").get();
+        verifyCallback("testHttpAuthClientProps - empty path", callback, response);
+        assertEquals(200, response.getStatus());
     }
 
     @Test
@@ -497,4 +610,29 @@
 
     }
 
+    class MyCallback implements InvocationCallback<Response> {
+        @Getter
+        private Response response;
+
+        @Getter
+        private Throwable throwable;
+
+        private CountDownLatch latch = new CountDownLatch(1);
+
+        @Override
+        public void completed(Response response) {
+            this.response = response;
+            latch.countDown();
+        }
+
+        @Override
+        public void failed(Throwable throwable) {
+            this.throwable = throwable;
+            latch.countDown();
+        }
+
+        public boolean await() throws InterruptedException {
+            return latch.await(5, TimeUnit.SECONDS);
+        }
+    }
 }
diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java
index bb51f2b..ec0e5e4 100644
--- a/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java
+++ b/utils/src/main/java/org/onap/policy/common/utils/coder/Coder.java
@@ -1,8 +1,8 @@
 /*
  * ============LICENSE_START=======================================================
- * ONAP PAP
+ * ONAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,6 +41,16 @@
     String encode(Object object) throws CoderException;
 
     /**
+     * Encodes an object into json, optionally making it "pretty".
+     *
+     * @param object object to be encoded
+     * @param pretty {@code true} if it should be encoded as "pretty" json, {@code false} otherwise
+     * @return a json string representing the object
+     * @throws CoderException if an error occurs
+     */
+    String encode(Object object, boolean pretty) throws CoderException;
+
+    /**
      * Encodes an object into json, writing to the given target.
      *
      * @param target target to which to write the encoded json
diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java
index 6d0cbc9..13973f1 100644
--- a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java
+++ b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardCoder.java
@@ -54,9 +54,21 @@
      * Gson object used to encode and decode messages.
      */
     @Getter(AccessLevel.PROTECTED)
-    private static final Gson GSON = GsonMessageBodyHandler.configBuilder(
-                    new GsonBuilder().registerTypeAdapter(StandardCoderObject.class, new StandardTypeAdapter()))
-                    .create();
+    private static final Gson GSON;
+
+    /**
+     * Gson object used to encode messages in "pretty" format.
+     */
+    @Getter(AccessLevel.PROTECTED)
+    private static final Gson GSON_PRETTY;
+
+    static {
+        GsonBuilder builder = GsonMessageBodyHandler.configBuilder(
+                        new GsonBuilder().registerTypeAdapter(StandardCoderObject.class, new StandardTypeAdapter()));
+
+        GSON = builder.create();
+        GSON_PRETTY = builder.setPrettyPrinting().create();
+    }
 
     /**
      * Constructs the object.
@@ -67,8 +79,18 @@
 
     @Override
     public String encode(Object object) throws CoderException {
+        return encode(object, false);
+    }
+
+    @Override
+    public String encode(Object object, boolean pretty) throws CoderException {
         try {
-            return toJson(object);
+            if (pretty) {
+                return toPrettyJson(object);
+
+            } else {
+                return toJson(object);
+            }
 
         } catch (RuntimeException e) {
             throw new CoderException(e);
@@ -151,6 +173,16 @@
         }
     }
 
+    /**
+     * Encodes the object as "pretty" json.
+     *
+     * @param object object to be encoded
+     * @return the encoded object
+     */
+    protected String toPrettyJson(Object object) {
+        return GSON_PRETTY.toJson(object);
+    }
+
     @Override
     public StandardCoderObject toStandard(Object object) throws CoderException {
         try {
diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardValCoder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardValCoder.java
index 378254b..6e08e72 100644
--- a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardValCoder.java
+++ b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardValCoder.java
@@ -62,10 +62,21 @@
     }
 
     @Override
+    protected String toPrettyJson(Object object) {
+        /*
+         * The validator strips off the "pretty" stuff (i.e., spaces), thus we have to validate
+         * and generate the pretty JSON in separate steps.
+         */
+        getGSON().toJson(object, object.getClass(), validatorApi.createJsonWriter(validator, new StringWriter()));
+
+        return super.toPrettyJson(object);
+    }
+
+    @Override
     protected String toJson(@NonNull Object object) {
         StringWriter output = new StringWriter();
         toJson(output, object);
-        return String.valueOf(output);
+        return output.toString();
     }
 
     @Override
diff --git a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardYamlCoder.java b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardYamlCoder.java
index 36f15b9..1bcf6ac 100644
--- a/utils/src/main/java/org/onap/policy/common/utils/coder/StandardYamlCoder.java
+++ b/utils/src/main/java/org/onap/policy/common/utils/coder/StandardYamlCoder.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,6 +38,12 @@
     }
 
     @Override
+    protected String toPrettyJson(Object object) {
+        // YAML is already "pretty"
+        return toJson(object);
+    }
+
+    @Override
     protected String toJson(Object object) {
         return translator.toYaml(object);
     }
diff --git a/utils/src/test/java/org/onap/policy/common/utils/coder/StandardCoderTest.java b/utils/src/test/java/org/onap/policy/common/utils/coder/StandardCoderTest.java
index 43a17de..d5cde55 100644
--- a/utils/src/test/java/org/onap/policy/common/utils/coder/StandardCoderTest.java
+++ b/utils/src/test/java/org/onap/policy/common/utils/coder/StandardCoderTest.java
@@ -77,6 +77,32 @@
     }
 
     @Test
+    public void testEncodeObjectBoolean() throws Exception {
+        final List<Integer> arr = Arrays.asList(1100, 1110);
+
+        /*
+         * As plain json.
+         */
+        assertEquals("[1100,1110]", coder.encode(arr, false));
+
+        // test exception case
+        coder = spy(new StandardCoder());
+        when(coder.toJson(arr)).thenThrow(jpe);
+        assertThatThrownBy(() -> coder.encode(arr, false)).isInstanceOf(CoderException.class).hasCause(jpe);
+
+
+        /*
+         * As pretty json.
+         */
+        assertEquals("[\n  1100,\n  1110\n]", coder.encode(arr, true));
+
+        // test exception case
+        coder = spy(new StandardCoder());
+        when(coder.toPrettyJson(arr)).thenThrow(jpe);
+        assertThatThrownBy(() -> coder.encode(arr, true)).isInstanceOf(CoderException.class).hasCause(jpe);
+    }
+
+    @Test
     public void testEncodeWriterObject() throws Exception {
         List<Integer> arr = Arrays.asList(1200, 1210);
         StringWriter wtr = new StringWriter();
diff --git a/utils/src/test/java/org/onap/policy/common/utils/coder/StandardValCoderTest.java b/utils/src/test/java/org/onap/policy/common/utils/coder/StandardValCoderTest.java
index 38106f5..2fcdb0d 100644
--- a/utils/src/test/java/org/onap/policy/common/utils/coder/StandardValCoderTest.java
+++ b/utils/src/test/java/org/onap/policy/common/utils/coder/StandardValCoderTest.java
@@ -20,8 +20,10 @@
 
 package org.onap.policy.common.utils.coder;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -119,6 +121,26 @@
         StringWriter writer = new StringWriter();
         valCoder.encode(writer, valOuter);
         assertEquals(valOuterJson, writer.toString());
+
+        // test exception case with an empty object
+        assertThatThrownBy(() -> valCoder.encode(new ValOuter())).isInstanceOf(CoderException.class);
+    }
+
+    @Test
+    public void testPretty() throws CoderException {
+        StandardValCoder valCoder = new StandardValCoder(jsonSchema, "test-schema");
+        ValOuter valOuter = valCoder.decode(validJson, ValOuter.class);
+
+        String valOuterJson = valCoder.encode(valOuter);
+        assertEquals(valOuterJson, valCoder.encode(valOuter, false));
+        String prettyValOuterJson = valCoder.encode(valOuter, true);
+        assertNotEquals(valOuterJson, prettyValOuterJson);
+
+        assertEquals(valOuter, valCoder.decode(prettyValOuterJson, ValOuter.class));
+
+        // test exception cases with an empty object
+        assertThatThrownBy(() -> valCoder.encode(new ValOuter(), false)).isInstanceOf(CoderException.class);
+        assertThatThrownBy(() -> valCoder.encode(new ValOuter(), true)).isInstanceOf(CoderException.class);
     }
 
     @Test
diff --git a/utils/src/test/java/org/onap/policy/common/utils/coder/StandardYamlCoderTest.java b/utils/src/test/java/org/onap/policy/common/utils/coder/StandardYamlCoderTest.java
index e38c5c9..c770cd3 100644
--- a/utils/src/test/java/org/onap/policy/common/utils/coder/StandardYamlCoderTest.java
+++ b/utils/src/test/java/org/onap/policy/common/utils/coder/StandardYamlCoderTest.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,8 +20,11 @@
 
 package org.onap.policy.common.utils.coder;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 import java.io.File;
 import java.io.StringWriter;
@@ -45,6 +48,25 @@
     }
 
     @Test
+    public void testToPrettyJson() throws CoderException {
+        String expected = coder.encode(cont);
+        assertEquals(expected, coder.encode(cont, false));
+
+        String yaml = coder.encode(cont, true);
+        assertEquals(expected, yaml);
+
+        Container cont2 = coder.decode(yaml, Container.class);
+        assertEquals(cont, cont2);
+
+        // test exception cases
+        IllegalArgumentException expex = new IllegalArgumentException("expected exception");
+        coder = spy(new StandardYamlCoder());
+        when(coder.toJson(cont)).thenThrow(expex);
+        assertThatThrownBy(() -> coder.encode(cont, false)).isInstanceOf(CoderException.class).hasCause(expex);
+        assertThatThrownBy(() -> coder.encode(cont, true)).isInstanceOf(CoderException.class).hasCause(expex);
+    }
+
+    @Test
     public void testToJsonObject() throws CoderException {
         String yaml = coder.encode(cont);