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