1 /* 2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.jfr.tool; 27 28 import java.nio.file.Path; 29 import java.time.OffsetDateTime; 30 import java.util.Collections; 31 import java.util.Iterator; 32 import java.util.List; 33 34 import javax.script.ScriptEngine; 35 import javax.script.ScriptEngineManager; 36 37 import jdk.jfr.Timespan; 38 import jdk.jfr.Timestamp; 39 import jdk.jfr.ValueDescriptor; 40 import jdk.jfr.consumer.RecordedEvent; 41 import jdk.jfr.consumer.RecordedObject; 42 import jdk.jfr.consumer.RecordingFile; 43 import jdk.nashorn.api.scripting.JSObject; 44 import jdk.test.lib.Asserts; 45 import jdk.test.lib.process.OutputAnalyzer; 46 47 /** 48 * @test 49 * @key jfr 50 * @summary Tests print --json 51 * 52 * @library /lib / 53 * @modules jdk.scripting.nashorn 54 * jdk.jfr 55 * 56 * @run main/othervm jdk.jfr.tool.TestPrintJSON 57 */ 58 public class TestPrintJSON { 59 60 public static void main(String... args) throws Throwable { 61 62 Path recordingFile = ExecuteHelper.createProfilingRecording().toAbsolutePath(); 63 64 OutputAnalyzer output = ExecuteHelper.jfr("print", "--json", "--stack-depth", "999", recordingFile.toString()); 65 String json = output.getStdout(); 66 67 // Parse JSON using Nashorn 68 String statement = "var jsonObject = " + json; 69 ScriptEngineManager factory = new ScriptEngineManager(); 70 ScriptEngine engine = factory.getEngineByName("nashorn"); 71 engine.eval(statement); 72 JSObject o = (JSObject) engine.get("jsonObject"); 73 JSObject recording = (JSObject) o.getMember("recording"); 74 JSObject jsonEvents = (JSObject) recording.getMember("events"); 75 76 List<RecordedEvent> events = RecordingFile.readAllEvents(recordingFile); 77 Collections.sort(events, (e1, e2) -> e1.getEndTime().compareTo(e2.getEndTime())); 78 // Verify events are equal 79 Iterator<RecordedEvent> it = events.iterator(); 80 81 for (Object jsonEvent : jsonEvents.values()) { 82 RecordedEvent recordedEvent = it.next(); 83 String typeName = recordedEvent.getEventType().getName(); 84 Asserts.assertEquals(typeName, ((JSObject) jsonEvent).getMember("type").toString()); 85 assertEquals(jsonEvent, recordedEvent); 86 } 87 Asserts.assertFalse(events.size() != jsonEvents.values().size(), "Incorrect number of events"); 88 } 89 90 private static void assertEquals(Object jsonObject, Object jfrObject) throws Exception { 91 // Check object 92 if (jfrObject instanceof RecordedObject) { 93 JSObject values = (JSObject) ((JSObject) jsonObject).getMember("values"); 94 RecordedObject recObject = (RecordedObject) jfrObject; 95 Asserts.assertEquals(values.values().size(), recObject.getFields().size()); 96 for (ValueDescriptor v : recObject.getFields()) { 97 String name = v.getName(); 98 Object jsonValue = values.getMember(name); 99 Object expectedValue = recObject.getValue(name); 100 if (v.getAnnotation(Timestamp.class) != null) { 101 // Make instant of OffsetDateTime 102 jsonValue = OffsetDateTime.parse("" + jsonValue).toInstant().toString(); 103 expectedValue = recObject.getInstant(name); 104 } 105 if (v.getAnnotation(Timespan.class) != null) { 106 expectedValue = recObject.getDuration(name); 107 } 108 assertEquals(jsonValue, expectedValue); 109 return; 110 } 111 } 112 // Check array 113 if (jfrObject != null && jfrObject.getClass().isArray()) { 114 Object[] jfrArray = (Object[]) jfrObject; 115 JSObject jsArray = (JSObject) jsonObject; 116 for (int i = 0; i < jfrArray.length; i++) { 117 assertEquals(jsArray.getSlot(i), jfrArray[i]); 118 } 119 return; 120 } 121 String jsonText = String.valueOf(jsonObject); 122 // Double.NaN / Double.Inifinity is not supported by JSON format, 123 // use null 124 if (jfrObject instanceof Double) { 125 double expected = ((Double) jfrObject); 126 if (Double.isInfinite(expected) || Double.isNaN(expected)) { 127 Asserts.assertEquals("null", jsonText); 128 return; 129 } 130 double value = Double.parseDouble(jsonText); 131 Asserts.assertEquals(expected, value); 132 return; 133 } 134 // Float.NaN / Float.Inifinity is not supported by JSON format, 135 // use null 136 if (jfrObject instanceof Float) { 137 float expected = ((Float) jfrObject); 138 if (Float.isInfinite(expected) || Float.isNaN(expected)) { 139 Asserts.assertEquals("null", jsonText); 140 return; 141 } 142 float value = Float.parseFloat(jsonText); 143 Asserts.assertEquals(expected, value); 144 return; 145 } 146 if (jfrObject instanceof Integer) { 147 Integer expected = ((Integer) jfrObject); 148 double value = Double.parseDouble(jsonText); 149 Asserts.assertEquals(expected.doubleValue(), value); 150 return; 151 } 152 if (jfrObject instanceof Long) { 153 Long expected = ((Long) jfrObject); 154 double value = Double.parseDouble(jsonText); 155 Asserts.assertEquals(expected.doubleValue(), value); 156 return; 157 } 158 159 String jfrText = String.valueOf(jfrObject); 160 Asserts.assertEquals(jfrText, jsonText, "Primitive values don't match. JSON = " + jsonText); 161 } 162 }