changeset 2439:cea7c676ac26

Don't HTML escape Byteman metric's data. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-August/020720.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Mon, 29 Aug 2016 17:30:33 +0200
parents 2896940c9722
children 4516a694428a
files vm-byteman/agent/src/main/java/com/redhat/thermostat/vm/byteman/agent/internal/BytemanMetricsReceiver.java vm-byteman/agent/src/test/java/com/redhat/thermostat/vm/byteman/agent/internal/BytemanMetricsReceiverTest.java vm-byteman/common/src/test/java/com/redhat/thermostat/vm/byteman/common/internal/BytemanMetricTypeAdapterTest.java
diffstat 3 files changed, 79 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/vm-byteman/agent/src/main/java/com/redhat/thermostat/vm/byteman/agent/internal/BytemanMetricsReceiver.java	Thu Aug 25 19:08:52 2016 +0200
+++ b/vm-byteman/agent/src/main/java/com/redhat/thermostat/vm/byteman/agent/internal/BytemanMetricsReceiver.java	Mon Aug 29 17:30:33 2016 +0200
@@ -57,10 +57,16 @@
     private static final Logger logger = LoggingUtils.getLogger(BytemanMetricsReceiver.class);
     private final VmBytemanDAO dao;
     private final VmSocketIdentifier socketId;
+    private final Gson gson;
     
     BytemanMetricsReceiver(VmBytemanDAO dao, VmSocketIdentifier socketId) {
         this.dao = dao;
         this.socketId = socketId;
+        this.gson = new GsonBuilder()
+                .registerTypeAdapterFactory(new BytemanMetricTypeAdapterFactory())
+                .serializeNulls()
+                .disableHtmlEscaping()
+                .create();
     }
 
     @Override
@@ -76,10 +82,6 @@
     }
 
     private List<BytemanMetric> convertFromJson(String data) {
-        Gson gson = new GsonBuilder()
-                .registerTypeAdapterFactory(new BytemanMetricTypeAdapterFactory())
-                .serializeNulls()
-                .create();
         BytemanMetric[] metrics = gson.fromJson(data, BytemanMetric[].class);
         List<BytemanMetric> listOfMetrics = new ArrayList<>();
         for (BytemanMetric m: metrics) {
--- a/vm-byteman/agent/src/test/java/com/redhat/thermostat/vm/byteman/agent/internal/BytemanMetricsReceiverTest.java	Thu Aug 25 19:08:52 2016 +0200
+++ b/vm-byteman/agent/src/test/java/com/redhat/thermostat/vm/byteman/agent/internal/BytemanMetricsReceiverTest.java	Mon Aug 29 17:30:33 2016 +0200
@@ -83,4 +83,42 @@
         assertEquals("Expected 7 keys, including one with null value", 7, payloadAsMap.keySet().size());
     }
     
+    /*
+     * There was an issue where the metric data json became HTML escaped:
+     * 
+     * before JSON convert: 'count = foo'
+     * after JSON convert:  'count \u003d foo'
+     * 
+     * This test is supposed to catch that data won't get HTML escaped.
+     */
+    @Test
+    public void canSendDataToStorageUtf8() {
+        VmBytemanDAO dao = mock(VmBytemanDAO.class);
+        String jsonMetric = 
+                "[ {\n" +
+                        "    \"marker\": \"marker\",\n" +
+                        "    \"timestamp\":\"30\",\n" +
+                        "    \"data\": {\n" +
+                        "        \"key\": \"value = foo\"\n" +
+                        "    }\n" +
+                        "} ]";
+        ByteBuffer data = Charset.forName("UTF-8").encode(jsonMetric);
+        IPCMessage message = mock(IPCMessage.class);
+        when(message.get()).thenReturn(data);
+        ArgumentCaptor<BytemanMetric> metricsCaptor = ArgumentCaptor.forClass(BytemanMetric.class);
+        
+        
+        BytemanMetricsReceiver receiver = new BytemanMetricsReceiver(dao, mock(VmSocketIdentifier.class));
+        receiver.messageReceived(message);
+        
+        verify(dao, times(1)).addMetric(metricsCaptor.capture());
+        
+        List<BytemanMetric> metrics = metricsCaptor.getAllValues();
+        BytemanMetric metric = metrics.get(0);
+        // make sure HTML chars are not escaped
+        assertEquals("{\"key\":\"value = foo\"}", metric.getData());
+        Map<String, Object> dataVals = metric.getDataAsMap();
+        assertEquals("value = foo", dataVals.get("key"));
+    }
+    
 }
--- a/vm-byteman/common/src/test/java/com/redhat/thermostat/vm/byteman/common/internal/BytemanMetricTypeAdapterTest.java	Thu Aug 25 19:08:52 2016 +0200
+++ b/vm-byteman/common/src/test/java/com/redhat/thermostat/vm/byteman/common/internal/BytemanMetricTypeAdapterTest.java	Mon Aug 29 17:30:33 2016 +0200
@@ -43,6 +43,7 @@
 
 import java.util.Map;
 
+import org.junit.Before;
 import org.junit.Test;
 
 import com.google.gson.Gson;
@@ -54,14 +55,21 @@
 public class BytemanMetricTypeAdapterTest {
     
     private static final double DELTA = 0.001;
+    
+    private Gson gson;
+    
+    @Before
+    public void setup() {
+        gson = new GsonBuilder()
+                .registerTypeAdapterFactory(new BytemanMetricTypeAdapterFactory())
+                .disableHtmlEscaping()
+                .serializeNulls()
+                .create();
+    }
 
     @Test
     public void canDeserializeArrayOfMetrics() {
         String json = JsonHelper.buildJsonArray(10);
-        Gson gson = new GsonBuilder()
-                .registerTypeAdapterFactory(new BytemanMetricTypeAdapterFactory())
-                .serializeNulls()
-                .create();
         BytemanMetric[] metrics = gson.fromJson(json, BytemanMetric[].class);
         assertEquals(10, metrics.length);
         for (int i = 0; i < 10; i++) {
@@ -87,5 +95,28 @@
             assertEquals(10_000_000_001L, longVal);
         }
     }
+    
+    /*
+     * This is a test which makes sure that html characters don't get
+     * escaped. We were seeing instances where the following happened which this
+     * test is trying to catch:
+     * 
+     * before JSON deserialization: {"key": "value = 'foo', 'bar', 'baz'"}
+     * after JSON deserialization: {"key"; "value \u003d \u0027foo\u0027, \u0027bar\u0027, \u0027baz\u0027"}
+     */
+    @Test
+    public void canDeserializeMetricWithSpecialChar() {
+        String json = "{\n" +
+                "    \"marker\": \"marker\",\n" +
+                "    \"timestamp\":\"30\",\n" +
+                "    \"data\": {\n" +
+                "        \"key\": \"value = 'foo', 'bar', 'baz'\"\n" +
+                "    }\n" +
+                "}";
+        BytemanMetric metric = gson.fromJson(json, BytemanMetric.class);
+        assertEquals("{\"key\":\"value = 'foo', 'bar', 'baz'\"}", metric.getData());
+        Map<String, Object> dataAsMap = metric.getDataAsMap();
+        assertEquals("value = 'foo', 'bar', 'baz'", dataAsMap.get("key"));
+    }
 
 }