1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * ident "%Z%%M% %I% %E% SMI" 27 */ 28 29 import org.opensolaris.os.dtrace.*; 30 import java.util.*; 31 import java.io.*; 32 import java.beans.*; 33 import java.lang.reflect.*; 34 35 /** 36 * Regression test for serialization and XML encoding/decoding. Tests 37 * every Serializable class in the Java DTrace API by creating a dummy 38 * instance, writing it to a file, then reading it back in and comparing 39 * the string values of the object before and after, as well as 40 * verifying object equality before and after if the class overrides the 41 * equals() method. 42 */ 43 public class TestBean { 44 public static final String[] TESTS = new String[] { 45 "ExitRecord", 46 "AggregationRecord", 47 "Aggregation", 48 "Tuple", 49 "ScalarRecord", 50 "KernelStackRecord", 51 "LogDistribution", 52 "LinearDistribution", 53 "Option", 54 "ProcessState", 55 "ProbeDescription", 56 "PrintaRecord", 57 "PrintfRecord", 58 "ProbeData", 59 "Aggregate", 60 "UserStackRecord", 61 "AvgValue", 62 "CountValue", 63 "SumValue", 64 "MinValue", 65 "MaxValue", 66 "Error", 67 "Drop", 68 "InterfaceAttributes", 69 "ProgramInfo", 70 "ProbeInfo", 71 "Probe", 72 "Flow", 73 "KernelSymbolRecord", 74 "UserSymbolRecord", 75 "UserSymbolRecord$Value", 76 "Program", 77 "Program$File" 78 }; 79 80 static File file; 81 82 static void 83 exit(int status) 84 { 85 System.out.flush(); 86 System.err.flush(); 87 System.exit(status); 88 } 89 90 public static XMLEncoder 91 getXMLEncoder(File file) 92 { 93 XMLEncoder encoder = null; 94 try { 95 OutputStream out = new BufferedOutputStream 96 (new FileOutputStream(file)); 97 encoder = new XMLEncoder(out); 98 } catch (Exception e) { 99 e.printStackTrace(); 100 exit(1); 101 } 102 return encoder; 103 } 104 105 public static XMLDecoder 106 getXMLDecoder(File file) 107 { 108 return getXMLDecoder(file, null); 109 } 110 111 public static XMLDecoder 112 getXMLDecoder(File file, ExceptionListener exceptionListener) 113 { 114 XMLDecoder decoder = null; 115 try { 116 InputStream in = new BufferedInputStream 117 (new FileInputStream(file)); 118 decoder = new XMLDecoder(in, null, exceptionListener); 119 } catch (Exception e) { 120 e.printStackTrace(); 121 exit(1); 122 } 123 return decoder; 124 } 125 126 public static ExitRecord 127 getExitRecord() 128 { 129 ExitRecord r = new ExitRecord(1); 130 return r; 131 } 132 133 public static AggregationRecord 134 getAggregationRecord() 135 { 136 Tuple tuple = getTuple(); 137 AggregationValue value = new CountValue(7); 138 AggregationRecord r = new AggregationRecord(tuple, value); 139 return r; 140 } 141 142 public static Aggregation 143 getAggregation() 144 { 145 List < AggregationRecord > list = 146 new ArrayList < AggregationRecord > (); 147 AggregationRecord r; 148 r = getAggregationRecord(); 149 list.add(r); 150 151 ValueRecord v1 = new ScalarRecord(new byte[] {(byte)1, (byte)2, 152 (byte)3}, 3); 153 ValueRecord v2 = new ScalarRecord("shebang!", 256); 154 Tuple tuple = new Tuple(v1, v2); 155 AggregationValue value = getLinearDistribution(); 156 r = new AggregationRecord(tuple, value); 157 list.add(r); 158 159 Aggregation a = new Aggregation("counts", 2, list); 160 return a; 161 } 162 163 public static Tuple 164 getTuple() 165 { 166 ValueRecord r1 = new ScalarRecord("cat", 256); 167 ValueRecord r2 = new ScalarRecord(new Integer(9), 2); 168 ValueRecord r3 = new KernelStackRecord( 169 new StackFrame[] { 170 new StackFrame("has"), 171 new StackFrame("nine"), 172 new StackFrame("lives")}, 173 new byte[] { (byte)0, (byte)1, (byte)2 }); 174 ValueRecord r4 = new ScalarRecord(new byte[] {(byte)1, (byte)2, 175 (byte)3}, 3); 176 177 Tuple tuple = new Tuple(r1, r2, r3, r4); 178 return tuple; 179 } 180 181 public static ScalarRecord 182 getScalarRecord() 183 { 184 Object v = new byte[] {(byte)1, (byte)2, (byte)3}; 185 ScalarRecord r = new ScalarRecord(v, 3); 186 return r; 187 } 188 189 public static KernelStackRecord 190 getKernelStackRecord() 191 { 192 StackFrame[] stackFrames = new StackFrame[] { 193 new StackFrame("Frame 1"), 194 new StackFrame("Frame 2"), 195 new StackFrame("Frame 3") 196 }; 197 KernelStackRecord r = new KernelStackRecord(stackFrames, 198 new byte[] { (byte)0, (byte)1, (byte)2 }); 199 return r; 200 } 201 202 public static LogDistribution 203 getLogDistribution() 204 { 205 List < Distribution.Bucket > buckets = 206 new ArrayList < Distribution.Bucket > (); 207 Distribution.Bucket bucket; 208 int n = 0; 209 long base = 0; 210 long i; 211 long sign; 212 long nextSign; 213 long power; 214 long nextPower; 215 long lowerBound; 216 long upperBound; 217 for (i = -62; i <= 62; ++i) { 218 if (i == 0) { 219 bucket = new Distribution.Bucket(-1, -1, n++); 220 buckets.add(bucket); 221 bucket = new Distribution.Bucket(0, 0, n++); 222 buckets.add(bucket); 223 bucket = new Distribution.Bucket(1, 1, n++); 224 buckets.add(bucket); 225 continue; 226 } 227 sign = ((i < 0) ? -1L : 1L); 228 power = (sign * i); 229 nextSign = (((i + 1) < 0) ? -1L : 1L); 230 nextPower = (nextSign * (i + 1)); 231 lowerBound = sign * ((long) Math.pow(2L, power)); 232 upperBound = (nextPower == 0 ? -2L : 233 (nextSign * ((long) Math.pow(2L, nextPower))) - 1); 234 if ((upperBound > 0) && ((upperBound * 2L) < 0)) { 235 upperBound = Long.MAX_VALUE; 236 } 237 bucket = new Distribution.Bucket(lowerBound, upperBound, n++); 238 buckets.add(bucket); 239 } 240 LogDistribution d = new LogDistribution(buckets); 241 return d; 242 } 243 244 public static LinearDistribution 245 getLinearDistribution() 246 { 247 List < Distribution.Bucket > buckets = 248 new ArrayList < Distribution.Bucket > (); 249 Distribution.Bucket bucket; 250 int n = 10; // number of buckets 251 int base = 1; 252 int step = 10; 253 bucket = new Distribution.Bucket(Long.MIN_VALUE, (base - 1), 0); 254 buckets.add(bucket); 255 for (int i = base; i < (n * step); i += step) { 256 bucket = new Distribution.Bucket(i, (i + (step - 1)), 257 ((i - 1) / step)); 258 buckets.add(bucket); 259 } 260 bucket = new Distribution.Bucket((n * step) + 1, Long.MAX_VALUE, 0); 261 buckets.add(bucket); 262 LinearDistribution d = new LinearDistribution(base, step, buckets); 263 return d; 264 } 265 266 public static Option 267 getOption() 268 { 269 Option option = new Option("aggrate", "1s"); 270 return option; 271 } 272 273 public static ProcessState 274 getProcessState() 275 { 276 ProcessState p = new ProcessState(123456, "UNDEAD", 277 3, "SIGSTOP", 278 -2, "Process stopped on dime"); 279 return p; 280 } 281 282 public static ProbeDescription 283 getProbeDescription() 284 { 285 ProbeDescription d = new ProbeDescription(256, "syscall", null, 286 "malloc", "entry"); 287 return d; 288 } 289 290 public static PrintaRecord 291 getPrintaRecord() 292 { 293 List < Aggregation > aggregations = new ArrayList < Aggregation > (); 294 Aggregation a = getAggregation(); 295 aggregations.add(a); 296 aggregations.add(a); 297 Map < Tuple, String > formattedOutput = 298 new HashMap < Tuple, String > (); 299 for (Tuple t : a.asMap().keySet()) { 300 formattedOutput.put(t, "cat"); 301 } 302 List < Tuple > tuples = new ArrayList < Tuple > (); 303 for (Tuple t : a.asMap().keySet()) { 304 tuples.add(t); 305 } 306 Collections.sort(tuples); 307 PrintaRecord r = new PrintaRecord(1234567890L, 308 aggregations, formattedOutput, tuples, 309 "Yes, this is the formatted printa() output"); 310 return r; 311 } 312 313 public static PrintfRecord 314 getPrintfRecord() 315 { 316 List < ValueRecord > list = new ArrayList < ValueRecord > (); 317 ValueRecord v1 = getScalarRecord(); 318 ValueRecord v2 = new ScalarRecord(new Integer(7), 4); 319 list.add(v1); 320 list.add(v2); 321 PrintfRecord r = new PrintfRecord(list, 322 "long formatted string"); 323 return r; 324 } 325 326 public static ProbeData 327 getProbeData() 328 { 329 List < Record > list = new ArrayList < Record > (); 330 list.add(getPrintaRecord()); 331 list.add(getPrintfRecord()); 332 list.add(getScalarRecord()); 333 ProbeData d = new ProbeData(7, 1, getProbeDescription(), 334 getFlow(), list); 335 return d; 336 } 337 338 public static Aggregate 339 getAggregate() 340 { 341 List < Aggregation > list = new ArrayList < Aggregation > (); 342 list.add(getAggregation()); 343 344 List < AggregationRecord > reclist = 345 new ArrayList < AggregationRecord > (); 346 AggregationRecord r; 347 ValueRecord v1 = new ScalarRecord("cat", 256); 348 ValueRecord v2 = new ScalarRecord("dog", 256); 349 ValueRecord v3 = new ScalarRecord("mouse", 256); 350 ValueRecord v4 = new ScalarRecord("mouse", 256); 351 ValueRecord v5 = new ScalarRecord(new Byte((byte) 'C'), 1); 352 ValueRecord v6 = new ScalarRecord(new Short((short) 7), 2); 353 Tuple tuple = new Tuple(v1, v2, v3, v4, v5, v6); 354 AggregationValue value = getCountValue(); 355 r = new AggregationRecord(tuple, value); 356 reclist.add(r); 357 list.add(new Aggregation("times", 1, reclist)); 358 359 Aggregate a = new Aggregate(1234567890L, list); 360 return a; 361 } 362 363 public static UserStackRecord 364 getUserStackRecord() 365 { 366 StackFrame[] frames = new StackFrame[] { 367 new StackFrame("User Stack Frame 1"), 368 new StackFrame("User Stack Frame 2"), 369 new StackFrame("User Stack Frame 3") 370 }; 371 UserStackRecord r = new UserStackRecord(123456, frames, 372 new byte[] { (byte)0, (byte)1, (byte)2 }); 373 return r; 374 } 375 376 public static AvgValue 377 getAvgValue() 378 { 379 AvgValue v = new AvgValue(5, 20, 4); 380 return v; 381 } 382 383 public static CountValue 384 getCountValue() 385 { 386 CountValue v = new CountValue(9); 387 return v; 388 } 389 390 public static MinValue 391 getMinValue() 392 { 393 MinValue v = new MinValue(101); 394 return v; 395 } 396 397 public static MaxValue 398 getMaxValue() 399 { 400 MaxValue v = new MaxValue(101); 401 return v; 402 } 403 404 public static SumValue 405 getSumValue() 406 { 407 SumValue v = new SumValue(25); 408 return v; 409 } 410 411 public static org.opensolaris.os.dtrace.Error 412 getError() 413 { 414 ProbeDescription probe = getProbeDescription(); 415 org.opensolaris.os.dtrace.Error e = 416 new org.opensolaris.os.dtrace.Error(probe, 8, 3, 417 1, 20, "DTRACEFLT_BADALIGN", -1, "error on enabled probe ID 8 " + 418 "(ID " + probe.getID() + ": " + probe + "): Bad alignment " + 419 "(0x33ef) in action #1 at DIF offset 20"); 420 return e; 421 } 422 423 public static Drop 424 getDrop() 425 { 426 Drop drop = new Drop(2, "SPECBUSY", 72, 1041, 427 "Guess we dropped stuff all over the place."); 428 return drop; 429 } 430 431 public static InterfaceAttributes 432 getInterfaceAttributes() 433 { 434 InterfaceAttributes a = new InterfaceAttributes( 435 InterfaceAttributes.Stability.UNSTABLE, 436 InterfaceAttributes.Stability.EVOLVING, 437 InterfaceAttributes.DependencyClass.ISA); 438 return a; 439 } 440 441 public static ProgramInfo 442 getProgramInfo() 443 { 444 ProgramInfo info = new ProgramInfo(getInterfaceAttributes(), 445 getInterfaceAttributes(), 256); 446 return info; 447 } 448 449 public static ProbeInfo 450 getProbeInfo() 451 { 452 ProbeInfo info = new ProbeInfo(getInterfaceAttributes(), 453 getInterfaceAttributes()); 454 return info; 455 } 456 457 public static Probe 458 getProbe() 459 { 460 Probe p = new Probe(getProbeDescription(), getProbeInfo()); 461 return p; 462 } 463 464 public static Flow 465 getFlow() 466 { 467 Flow f = new Flow(Flow.Kind.RETURN.name(), 3); 468 return f; 469 } 470 471 public static KernelSymbolRecord 472 getKernelSymbolRecord() 473 { 474 KernelSymbolRecord r = new KernelSymbolRecord("mod`func+0x4", -1L); 475 return r; 476 } 477 478 public static UserSymbolRecord 479 getUserSymbolRecord() 480 { 481 UserSymbolRecord r = new UserSymbolRecord(7, "mod`func+0x4", -1L); 482 return r; 483 } 484 485 public static UserSymbolRecord.Value 486 getUserSymbolRecord$Value() 487 { 488 UserSymbolRecord.Value v = new UserSymbolRecord.Value(7, -1L); 489 return v; 490 } 491 492 public static Program 493 getProgram() 494 { 495 final String PROGRAM = "syscall:::entry { @[execname] = count(); }"; 496 Consumer consumer = new LocalConsumer(); 497 Program p; 498 try { 499 consumer.open(); 500 p = consumer.compile(PROGRAM); 501 consumer.close(); 502 } catch (DTraceException e) { 503 e.printStackTrace(); 504 p = null; 505 } 506 return p; 507 } 508 509 public static Program.File 510 getProgram$File() 511 { 512 final String PROGRAM = "syscall:::entry { @[execname] = count(); }"; 513 Consumer consumer = new LocalConsumer(); 514 Program p; 515 try { 516 OutputStream out = new FileOutputStream(file); 517 out.write(PROGRAM.getBytes(), 0, PROGRAM.length()); 518 out.flush(); 519 out.close(); 520 consumer.open(); 521 p = consumer.compile(file); 522 consumer.close(); 523 } catch (Exception e) { 524 e.printStackTrace(); 525 p = null; 526 } 527 return Program.File.class.cast(p); 528 } 529 530 static String 531 getString(Object o) 532 { 533 String s; 534 if (o instanceof ScalarRecord) { 535 o = ((ScalarRecord)o).getValue(); 536 } 537 538 if (o instanceof byte[]) { 539 s = Arrays.toString((byte[])o); 540 } else if (o instanceof Object[]) { 541 s = Arrays.toString((Object[])o); 542 } else { 543 Class c = o.getClass(); 544 try { 545 Method m = c.getDeclaredMethod("toLogString"); 546 s = (String)m.invoke(o); 547 } catch (Exception e) { 548 s = o.toString(); 549 } 550 } 551 return s; 552 } 553 554 static void 555 checkEquality(Object obj, Object newobj) 556 { 557 // If the class overrides equals(), make sure the re-created 558 // object still equals the original object 559 try { 560 Method eq = obj.getClass().getDeclaredMethod("equals", 561 Object.class); 562 Boolean ret = (Boolean) eq.invoke(obj, newobj); 563 if (ret != true) { 564 System.err.println("serialization failed: " + 565 obj.getClass().getName()); 566 exit(1); 567 } 568 } catch (Exception e) { 569 // Does not override equals(), although a super-class might. 570 // A better test would check for any superclass other than 571 // Object.class. 572 } 573 } 574 575 static void 576 performSerializationTest(File file, String classname) 577 throws IOException, ClassNotFoundException 578 { 579 String methodName = "get" + classname; 580 Object obj = null; 581 Object newobj = null; 582 try { 583 Method method = TestBean.class.getDeclaredMethod(methodName); 584 obj = method.invoke(null); 585 } catch (Exception e) { 586 e.printStackTrace(); 587 exit(1); 588 } 589 590 System.out.println(classname + ":"); 591 String serialized = getString(obj); 592 System.out.println(" serialized: " + serialized); 593 FileOutputStream fos = new FileOutputStream(file); 594 ObjectOutputStream out = new ObjectOutputStream(fos); 595 out.writeObject(obj); 596 FileInputStream fis = new FileInputStream(file); 597 ObjectInputStream in = new ObjectInputStream(fis); 598 newobj = in.readObject(); 599 String deserialized = getString(newobj); 600 System.out.println(" deserialized: " + deserialized); 601 602 if (!serialized.equals(deserialized)) { 603 System.err.println("serialization failed: " + classname); 604 exit(1); 605 } 606 checkEquality(obj, newobj); 607 } 608 609 static void 610 performBeanTest(File file, String classname) 611 { 612 String methodName = "get" + classname; 613 Object obj = null; 614 Object newobj = null; 615 try { 616 Method method = TestBean.class.getDeclaredMethod(methodName); 617 obj = method.invoke(null); 618 } catch (Exception e) { 619 e.printStackTrace(); 620 exit(1); 621 } 622 623 Class c = obj.getClass(); 624 if (c.getConstructors().length == 0) { 625 return; 626 } 627 628 System.out.println(classname + ":"); 629 XMLEncoder encoder = getXMLEncoder(file); 630 String encoded = getString(obj); 631 System.out.println(" encoded: " + encoded); 632 encoder.writeObject(obj); 633 encoder.close(); 634 XMLDecoder decoder = getXMLDecoder(file); 635 newobj = decoder.readObject(); 636 String decoded = getString(newobj); 637 System.out.println(" decoded: " + decoded); 638 decoder.close(); 639 640 if (!encoded.equals(decoded)) { 641 System.err.println("bean persistence failed: " + classname); 642 exit(1); 643 } 644 checkEquality(obj, newobj); 645 } 646 647 public static void 648 main(String[] args) 649 { 650 if ((args.length != 1) && (args.length != 2)) { 651 System.err.println("usage: java TestBean < filename > " + 652 "[ < classname > ]"); 653 exit(1); 654 } 655 656 String filename = args[0]; 657 String classname = null; 658 if (args.length >= 2) { 659 classname = args[1]; 660 } 661 662 file = new File(filename); 663 try { 664 if (!file.canRead()) { 665 try { 666 file.createNewFile(); 667 } catch (Exception e) { 668 System.err.println("failed to create " + filename); 669 exit(1); 670 } 671 } 672 } catch (SecurityException e) { 673 System.err.println("failed to open " + filename); 674 exit(1); 675 } 676 677 String[] tests = (classname == null ? TESTS: 678 new String[] { classname }); 679 try { 680 for (int i = 0; i < tests.length; ++i) { 681 performSerializationTest(file, tests[i]); 682 performBeanTest(file, tests[i]); 683 } 684 } catch (IOException e) { 685 e.printStackTrace(); 686 exit(1); 687 } catch (ClassNotFoundException e) { 688 e.printStackTrace(); 689 exit(1); 690 } 691 } 692 } 693