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 }