|
1 /* |
|
2 * Copyright (c) 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.api.consumer; |
|
27 |
|
28 import java.io.IOException; |
|
29 import java.time.Duration; |
|
30 import java.time.Instant; |
|
31 import java.util.Arrays; |
|
32 import java.util.HashSet; |
|
33 import java.util.List; |
|
34 import java.util.Set; |
|
35 import java.util.function.Function; |
|
36 |
|
37 import jdk.jfr.Event; |
|
38 import jdk.jfr.Recording; |
|
39 import jdk.jfr.StackTrace; |
|
40 import jdk.jfr.Timespan; |
|
41 import jdk.jfr.Timestamp; |
|
42 import jdk.jfr.Unsigned; |
|
43 import jdk.jfr.consumer.RecordedClass; |
|
44 import jdk.jfr.consumer.RecordedEvent; |
|
45 import jdk.jfr.consumer.RecordedObject; |
|
46 import jdk.jfr.consumer.RecordedThread; |
|
47 import jdk.test.lib.Asserts; |
|
48 import jdk.test.lib.jfr.Events; |
|
49 |
|
50 /* |
|
51 * @test |
|
52 * @summary Verifies the methods of the RecordedObject |
|
53 * @key jfr |
|
54 * @library /test/lib |
|
55 * @run main/othervm jdk.jfr.api.consumer.TestRecordedObject |
|
56 */ |
|
57 public class TestRecordedObject { |
|
58 |
|
59 private final static boolean BOOLEAN_VALUE = true; |
|
60 private final static byte VALUE = 47; |
|
61 private final static String STRING_VALUE = "47"; |
|
62 private final static Class<?> CLASS_VALUE = String.class; |
|
63 private final static Thread THREAD_VALUE = Thread.currentThread(); |
|
64 private final static Instant INSTANT_VALUE = Instant.now(); |
|
65 private final static Duration DURATION_VALUE = Duration.ofSeconds(47); |
|
66 |
|
67 @StackTrace(false) |
|
68 static final class EventWithValues extends Event { |
|
69 boolean booleanField = BOOLEAN_VALUE; |
|
70 byte byteField = VALUE; |
|
71 char charField = VALUE; |
|
72 short shortField = VALUE; |
|
73 int intField = VALUE; |
|
74 long longField = VALUE; |
|
75 float floatField = VALUE; |
|
76 double doubleField = VALUE; |
|
77 String stringField = STRING_VALUE; |
|
78 Class<?> classField = CLASS_VALUE; |
|
79 Thread threadField = THREAD_VALUE; |
|
80 @Timespan(Timespan.NANOSECONDS) |
|
81 long durationField = DURATION_VALUE.toNanos(); |
|
82 @Timestamp(Timestamp.MILLISECONDS_SINCE_EPOCH) |
|
83 long instantField = INSTANT_VALUE.toEpochMilli(); |
|
84 Thread nullField = null; |
|
85 Class<?> nullField2 = null; |
|
86 |
|
87 @Timespan(Timespan.MICROSECONDS) |
|
88 long durationMicros = DURATION_VALUE.toNanos() / 1000; |
|
89 |
|
90 @Timespan(Timespan.MILLISECONDS) |
|
91 long durationMillis = DURATION_VALUE.toMillis(); |
|
92 |
|
93 @Timespan(Timespan.SECONDS) |
|
94 long durationSeconds = DURATION_VALUE.toSeconds(); |
|
95 |
|
96 @Timestamp(Timestamp.MILLISECONDS_SINCE_EPOCH) |
|
97 long instantMillis = 1000; |
|
98 |
|
99 @Timestamp(Timespan.TICKS) |
|
100 long instantTicks = 0; |
|
101 |
|
102 @Unsigned |
|
103 byte unsignedByte = Byte.MIN_VALUE; |
|
104 @Unsigned |
|
105 char unsignedChar = 'q'; |
|
106 @Unsigned |
|
107 short unsignedShort = Short.MIN_VALUE; |
|
108 @Unsigned |
|
109 int unsignedInt = Integer.MIN_VALUE; |
|
110 @Unsigned |
|
111 long unsignedLong = Long.MIN_VALUE; // unsigned should be ignored |
|
112 @Unsigned |
|
113 float unsignedFloat = Float.MIN_VALUE; // unsigned should be ignored |
|
114 @Unsigned |
|
115 double unsignedDouble = Double.MIN_VALUE; // unsigned should be ignored |
|
116 |
|
117 } |
|
118 |
|
119 private final static Set<String> ALL = createAll(); |
|
120 |
|
121 public static void main(String[] args) throws Throwable { |
|
122 |
|
123 RecordedObject event = makeRecordedObject(); |
|
124 |
|
125 // Primitives |
|
126 testGetBoolean(event); |
|
127 testGetByte(event); |
|
128 testGetChar(event); |
|
129 testGetShort(event); |
|
130 testGetInt(event); |
|
131 testGetLong(event); |
|
132 testGetDouble(event); |
|
133 testGetFloat(event); |
|
134 |
|
135 // // Complex types |
|
136 testGetString(event); |
|
137 testGetInstant(event); |
|
138 testGetDuration(event); |
|
139 testGetThread(event); |
|
140 testGetClass(event); |
|
141 |
|
142 // Misc. |
|
143 testNestedNames(event); |
|
144 testTimeUnits(event); |
|
145 testUnsigned(event); |
|
146 } |
|
147 |
|
148 private static void testUnsigned(RecordedObject event) { |
|
149 // Unsigned byte value |
|
150 Asserts.assertEquals(event.getByte("unsignedByte"), Byte.MIN_VALUE); |
|
151 Asserts.assertEquals(event.getInt("unsignedByte"), Byte.toUnsignedInt(Byte.MIN_VALUE)); |
|
152 Asserts.assertEquals(event.getLong("unsignedByte"), Byte.toUnsignedLong(Byte.MIN_VALUE)); |
|
153 Asserts.assertEquals(event.getShort("unsignedByte"), (short)Byte.toUnsignedInt(Byte.MIN_VALUE)); |
|
154 |
|
155 // Unsigned char, nothing should happen, it is unsigned |
|
156 Asserts.assertEquals(event.getChar("unsignedChar"), 'q'); |
|
157 Asserts.assertEquals(event.getInt("unsignedChar"), (int)'q'); |
|
158 Asserts.assertEquals(event.getLong("unsignedChar"), (long)'q'); |
|
159 |
|
160 // Unsigned short |
|
161 Asserts.assertEquals(event.getShort("unsignedShort"), Short.MIN_VALUE); |
|
162 Asserts.assertEquals(event.getInt("unsignedShort"), Short.toUnsignedInt(Short.MIN_VALUE)); |
|
163 Asserts.assertEquals(event.getLong("unsignedShort"), Short.toUnsignedLong(Short.MIN_VALUE)); |
|
164 |
|
165 // Unsigned int |
|
166 Asserts.assertEquals(event.getInt("unsignedInt"), Integer.MIN_VALUE); |
|
167 Asserts.assertEquals(event.getLong("unsignedInt"), Integer.toUnsignedLong(Integer.MIN_VALUE)); |
|
168 |
|
169 // Unsigned long, nothing should happen |
|
170 Asserts.assertEquals(event.getLong("unsignedLong"), Long.MIN_VALUE); |
|
171 |
|
172 // Unsigned float, nothing should happen |
|
173 Asserts.assertEquals(event.getFloat("unsignedFloat"), Float.MIN_VALUE); |
|
174 |
|
175 // Unsigned double, nothing should happen |
|
176 Asserts.assertEquals(event.getDouble("unsignedDouble"), Double.MIN_VALUE); |
|
177 } |
|
178 |
|
179 private static void testTimeUnits(RecordedObject event) { |
|
180 Asserts.assertEquals(event.getDuration("durationMicros"), DURATION_VALUE); |
|
181 Asserts.assertEquals(event.getDuration("durationMillis"), DURATION_VALUE); |
|
182 Asserts.assertEquals(event.getDuration("durationSeconds"), DURATION_VALUE); |
|
183 Asserts.assertEquals(event.getInstant("instantMillis").toEpochMilli(), 1000L); |
|
184 if (!event.getInstant("instantTicks").isBefore(INSTANT_VALUE)) { |
|
185 throw new AssertionError("Expected start time of JVM to before call to Instant.now()"); |
|
186 } |
|
187 } |
|
188 |
|
189 private static void testNestedNames(RecordedObject event) { |
|
190 RecordedThread t = event.getValue("threadField"); |
|
191 |
|
192 // Nested with getValue |
|
193 try { |
|
194 event.getValue("nullField.javaName"); |
|
195 throw new AssertionError("Expected NullPointerException"); |
|
196 } catch (NullPointerException npe) { |
|
197 // OK, expected; |
|
198 } |
|
199 try { |
|
200 event.getValue("nullField.does.not.exist"); |
|
201 throw new AssertionError("Expected IllegalArgumentException"); |
|
202 } catch (IllegalArgumentException iae) { |
|
203 // OK, expected; |
|
204 } |
|
205 |
|
206 // Nested getLong |
|
207 try { |
|
208 event.getLong("nullField.javaName"); |
|
209 throw new AssertionError("Expected NullPointerException"); |
|
210 } catch (NullPointerException npe) { |
|
211 // OK, expected; |
|
212 } |
|
213 try { |
|
214 event.getLong("nullField.does.not.exist"); |
|
215 throw new AssertionError("Expected IllegalArgumentException"); |
|
216 } catch (IllegalArgumentException npe) { |
|
217 // OK, expected; |
|
218 } |
|
219 if (t.getOSThreadId() != event.getLong("threadField.osThreadId")) { |
|
220 throw new AssertionError("Incorrect result from nested long value"); |
|
221 } |
|
222 |
|
223 // Nested getString |
|
224 try { |
|
225 event.getString("nullField.osThreadId"); |
|
226 throw new AssertionError("Expected IllegalArgumentException"); |
|
227 } catch (IllegalArgumentException npe) { |
|
228 // OK, expected; |
|
229 } |
|
230 try { |
|
231 event.getLong("nullField.does.not.exist"); |
|
232 throw new AssertionError("Expected IllegalArgumentException"); |
|
233 } catch (IllegalArgumentException npe) { |
|
234 // OK, expected; |
|
235 } |
|
236 if (!t.getJavaName().equals(event.getString("threadField.javaName"))) { |
|
237 throw new AssertionError("Incorrect result from nested long value"); |
|
238 } |
|
239 |
|
240 // Nested getClass |
|
241 try { |
|
242 event.getClass("nullField.osThreadId"); |
|
243 throw new AssertionError("Expected IllegalArgumentException"); |
|
244 } catch (IllegalArgumentException npe) { |
|
245 // OK, expected; |
|
246 } |
|
247 try { |
|
248 event.getClass("nullField.does.not.exist"); |
|
249 throw new AssertionError("Expected IllegalArgumentException"); |
|
250 } catch (IllegalArgumentException npe) { |
|
251 // OK, expected; |
|
252 } |
|
253 |
|
254 // Nested getThread |
|
255 try { |
|
256 event.getThread("nullField2.name"); |
|
257 throw new AssertionError("Expected IllegalArgumentException"); |
|
258 } catch (IllegalArgumentException npe) { |
|
259 // OK, expected; |
|
260 } |
|
261 try { |
|
262 event.getThread("nullField2.does.not.exist"); |
|
263 throw new AssertionError("Expected IllegalArgumentException"); |
|
264 } catch (IllegalArgumentException npe) { |
|
265 // OK, expected; |
|
266 } |
|
267 } |
|
268 |
|
269 private static void testGetBoolean(RecordedObject e) { |
|
270 assertGetter(x -> e.getBoolean(x), BOOLEAN_VALUE, "boolean"); |
|
271 } |
|
272 |
|
273 private static void testGetByte(RecordedObject e) { |
|
274 assertGetter(x -> e.getByte(x), (byte) VALUE, "byte"); |
|
275 } |
|
276 |
|
277 private static void testGetChar(RecordedObject e) { |
|
278 assertGetter(x -> e.getChar(x), (char) VALUE, "char"); |
|
279 } |
|
280 |
|
281 private static void testGetShort(RecordedObject e) { |
|
282 assertGetter(x -> e.getShort(x), (short) VALUE, "byte", "short"); |
|
283 } |
|
284 |
|
285 private static void testGetInt(RecordedObject e) { |
|
286 assertGetter(x -> e.getInt(x), (int) VALUE, "byte", "char", "short", "int"); |
|
287 } |
|
288 |
|
289 private static void testGetLong(RecordedObject e) { |
|
290 assertGetter(x -> e.getLong(x), (long) VALUE, "byte", "char", "short", "int", "long"); |
|
291 } |
|
292 |
|
293 private static void testGetFloat(RecordedObject e) { |
|
294 assertGetter(x -> e.getFloat(x), (float) VALUE, "byte", "char", "short", "int", "long", "float"); |
|
295 } |
|
296 |
|
297 private static void testGetDouble(RecordedObject e) { |
|
298 assertGetter(x -> e.getDouble(x), (double) VALUE, "byte", "char", "short", "int", "long", "float", "double"); |
|
299 } |
|
300 |
|
301 private static void testGetString(RecordedObject e) { |
|
302 assertGetter(x -> e.getString(x), STRING_VALUE, "string"); |
|
303 } |
|
304 |
|
305 private static void testGetInstant(RecordedObject e) { |
|
306 assertGetter(x -> e.getInstant(x), Instant.ofEpochMilli(INSTANT_VALUE.toEpochMilli()), "instant"); |
|
307 } |
|
308 |
|
309 private static void testGetDuration(RecordedObject e) { |
|
310 assertGetter(x -> e.getDuration(x), DURATION_VALUE, "duration"); |
|
311 } |
|
312 |
|
313 private static void testGetThread(RecordedObject e) { |
|
314 RecordedThread thread = e.getValue("threadField"); |
|
315 if (!thread.getJavaName().equals(THREAD_VALUE.getName())) { |
|
316 throw new AssertionError("Expected thread to have name " + THREAD_VALUE.getName()); |
|
317 } |
|
318 assertGetter(x -> { |
|
319 // OK to access nullField if it is correct type |
|
320 // Chose a second null field with class type |
|
321 if ("nullField".equals(x)) { |
|
322 return e.getThread("nullField2"); |
|
323 } else { |
|
324 return e.getThread(x); |
|
325 } |
|
326 |
|
327 }, thread, "thread"); |
|
328 } |
|
329 |
|
330 private static void testGetClass(RecordedObject e) { |
|
331 RecordedClass clazz = e.getValue("classField"); |
|
332 if (!clazz.getName().equals(CLASS_VALUE.getName())) { |
|
333 throw new AssertionError("Expected class to have name " + CLASS_VALUE.getName()); |
|
334 } |
|
335 assertGetter(x -> e.getClass(x), clazz, "class"); |
|
336 } |
|
337 |
|
338 private static <T> void assertGetter(Function<String, T> f, T expectedValue, String... validTypes) { |
|
339 Set<String> valids = new HashSet<String>(Arrays.asList(validTypes)); |
|
340 Set<String> invalids = new HashSet<String>(ALL); |
|
341 invalids.removeAll(valids); |
|
342 for (String valid : valids) { |
|
343 T result = f.apply(valid + "Field"); |
|
344 if (!expectedValue.equals(result)) { |
|
345 throw new AssertionError("Incorrect return value " + result + ". Expected " + expectedValue); |
|
346 } |
|
347 } |
|
348 for (String invalid : invalids) { |
|
349 try { |
|
350 f.apply(invalid + "Field"); |
|
351 } catch (IllegalArgumentException iae) { |
|
352 // OK, as expected |
|
353 } catch (Exception e) { |
|
354 throw new AssertionError("Unexpected exception for invalid field " + invalid + ". " + e.getClass().getName() + " : " + e.getMessage(), e); |
|
355 } |
|
356 } |
|
357 String[] illegals = { "missingField", "nullField.javaName.does.not.exist", "nullField" }; |
|
358 for (String illegal : illegals) { |
|
359 try { |
|
360 f.apply(illegal); |
|
361 throw new AssertionError("Expected IllegalArgumentException when accessing " + illegal); |
|
362 } catch (IllegalArgumentException iae) { |
|
363 // OK, as expected |
|
364 } catch (Exception e) { |
|
365 throw new AssertionError("Expected IllegalArgumentException. Got " + e.getClass().getName() + " : " + e.getMessage(), e); |
|
366 } |
|
367 } |
|
368 try { |
|
369 f.apply(null); |
|
370 throw new AssertionError("Expected NullpointerException exception when passing in null value"); |
|
371 } catch (NullPointerException iae) { |
|
372 // OK, as expected |
|
373 } catch (Exception e) { |
|
374 throw new AssertionError("Expected NullpointerException. Got " + e.getClass().getName() + " : " + e.getMessage(), e); |
|
375 } |
|
376 } |
|
377 |
|
378 private static RecordedObject makeRecordedObject() throws IOException { |
|
379 Recording r = new Recording(); |
|
380 r.start(); |
|
381 EventWithValues t = new EventWithValues(); |
|
382 t.commit(); |
|
383 r.stop(); |
|
384 List<RecordedEvent> events = Events.fromRecording(r); |
|
385 Events.hasEvents(events); |
|
386 return events.get(0); |
|
387 } |
|
388 |
|
389 private static Set<String> createAll() { |
|
390 Set<String> set = new HashSet<>(); |
|
391 set.add("boolean"); |
|
392 set.add("byte"); |
|
393 set.add("char"); |
|
394 set.add("short"); |
|
395 set.add("int"); |
|
396 set.add("long"); |
|
397 set.add("float"); |
|
398 set.add("double"); |
|
399 set.add("string"); |
|
400 set.add("class"); |
|
401 set.add("thread"); |
|
402 set.add("instant"); |
|
403 set.add("duration"); |
|
404 return set; |
|
405 } |
|
406 } |