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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 import org.opensolaris.os.dtrace.*; 28 import java.util.*; 29 import java.io.*; 30 import java.beans.*; 31 import java.lang.reflect.*; 32 33 /** 34 * Regression test for serialization and XML encoding/decoding. Tests 35 * every Serializable class in the Java DTrace API by creating a dummy 36 * instance, writing it to a file, then reading it back in and comparing 37 * the string values of the object before and after, as well as 38 * verifying object equality before and after if the class overrides the 39 * equals() method. 40 */ 41 public class TestBean { 42 public static final String[] TESTS = new String[] { 43 "ExitRecord", 44 "AggregationRecord", 45 "Aggregation", 46 "Tuple", 47 "ScalarRecord", 48 "KernelStackRecord", 49 "LogDistribution", 50 "LinearDistribution", 51 "LogLinearDistribution", 52 "Option", 53 "ProcessState", 54 "ProbeDescription", 55 "PrintaRecord", 56 "PrintfRecord", 57 "ProbeData", 58 "Aggregate", 59 "UserStackRecord", 60 "AvgValue", 61 "CountValue", 62 "SumValue", 63 "MinValue", 64 "MaxValue", 65 "Error", 66 "Drop", 67 "InterfaceAttributes", 68 "ProgramInfo", 69 "ProbeInfo", 70 "Probe", 71 "Flow", 72 "KernelSymbolRecord", 73 "UserSymbolRecord", 74 "UserSymbolRecord$Value", 75 "Program", 76 "Program$File", 77 "StddevValue" 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 LogLinearDistribution 267 getLogLinearDistribution() 268 { 269 Distribution.Bucket bucket; 270 long next, step; 271 long low = 0; 272 long high = 6; 273 long factor = 2; 274 long nsteps = 2; 275 int value = 1; 276 int order; 277 278 List < Distribution.Bucket > buckets = 279 new ArrayList < Distribution.Bucket > (); 280 281 for (order = 0; order < low; order++) 282 value *= factor; 283 284 bucket = new Distribution.Bucket(Long.MIN_VALUE, (value - 1), 0); 285 buckets.add(bucket); 286 287 next = value * factor; 288 step = (next > nsteps) ? (next / nsteps) : 1; 289 290 while (order <= high) { 291 bucket = new Distribution.Bucket(value, value + step - 1, 5); 292 buckets.add(bucket); 293 294 if ((value += step) != next) 295 continue; 296 297 next = value * factor; 298 step = (next > nsteps) ? (next / nsteps) : 1; 299 order++; 300 } 301 302 bucket = new Distribution.Bucket(value, Long.MAX_VALUE, 0); 303 buckets.add(bucket); 304 305 LogLinearDistribution d = new LogLinearDistribution(factor, low, high, 306 nsteps, 0, buckets); 307 return d; 308 } 309 310 public static Option 311 getOption() 312 { 313 Option option = new Option("aggrate", "1s"); 314 return option; 315 } 316 317 public static ProcessState 318 getProcessState() 319 { 320 ProcessState p = new ProcessState(123456, "UNDEAD", 321 3, "SIGSTOP", 322 -2, "Process stopped on dime"); 323 return p; 324 } 325 326 public static ProbeDescription 327 getProbeDescription() 328 { 329 ProbeDescription d = new ProbeDescription(256, "syscall", null, 330 "malloc", "entry"); 331 return d; 332 } 333 334 public static PrintaRecord 335 getPrintaRecord() 336 { 337 List < Aggregation > aggregations = new ArrayList < Aggregation > (); 338 Aggregation a = getAggregation(); 339 aggregations.add(a); 340 aggregations.add(a); 341 Map < Tuple, String > formattedOutput = 342 new HashMap < Tuple, String > (); 343 for (Tuple t : a.asMap().keySet()) { 344 formattedOutput.put(t, "cat"); 345 } 346 List < Tuple > tuples = new ArrayList < Tuple > (); 347 for (Tuple t : a.asMap().keySet()) { 348 tuples.add(t); 349 } 350 Collections.sort(tuples); 351 PrintaRecord r = new PrintaRecord(1234567890L, 352 aggregations, formattedOutput, tuples, 353 "Yes, this is the formatted printa() output"); 354 return r; 355 } 356 357 public static PrintfRecord 358 getPrintfRecord() 359 { 360 List < ValueRecord > list = new ArrayList < ValueRecord > (); 361 ValueRecord v1 = getScalarRecord(); 362 ValueRecord v2 = new ScalarRecord(new Integer(7), 4); 363 list.add(v1); 364 list.add(v2); 365 PrintfRecord r = new PrintfRecord(list, 366 "long formatted string"); 367 return r; 368 } 369 370 public static ProbeData 371 getProbeData() 372 { 373 List < Record > list = new ArrayList < Record > (); 374 list.add(getPrintaRecord()); 375 list.add(getPrintfRecord()); 376 list.add(getScalarRecord()); 377 list.add(getUserSymbolRecord()); 378 list.add(getUserStackRecord()); 379 list.add(getExitRecord()); 380 ProbeData d = new ProbeData(7, 1, getProbeDescription(), 381 getFlow(), list); 382 return d; 383 } 384 385 public static Aggregate 386 getAggregate() 387 { 388 List < Aggregation > list = new ArrayList < Aggregation > (); 389 list.add(getAggregation()); 390 391 List < AggregationRecord > reclist = 392 new ArrayList < AggregationRecord > (); 393 AggregationRecord r; 394 ValueRecord v1 = new ScalarRecord("cat", 256); 395 ValueRecord v2 = new ScalarRecord("dog", 256); 396 ValueRecord v3 = new ScalarRecord("mouse", 256); 397 ValueRecord v4 = new ScalarRecord("mouse", 256); 398 ValueRecord v5 = new ScalarRecord(new Byte((byte) 'C'), 1); 399 ValueRecord v6 = new ScalarRecord(new Short((short) 7), 2); 400 Tuple tuple = new Tuple(v1, v2, v3, v4, v5, v6); 401 AggregationValue value = getCountValue(); 402 r = new AggregationRecord(tuple, value); 403 reclist.add(r); 404 list.add(new Aggregation("times", 1, reclist)); 405 406 Aggregate a = new Aggregate(1234567890L, list); 407 return a; 408 } 409 410 public static UserStackRecord 411 getUserStackRecord() 412 { 413 StackFrame[] frames = new StackFrame[] { 414 new StackFrame("User Stack Frame 1"), 415 new StackFrame("User Stack Frame 2"), 416 new StackFrame("User Stack Frame 3") 417 }; 418 UserStackRecord r = new UserStackRecord(123456, frames, 419 new byte[] { (byte)0, (byte)1, (byte)2 }); 420 return r; 421 } 422 423 public static AvgValue 424 getAvgValue() 425 { 426 AvgValue v = new AvgValue(5, 20, 4); 427 return v; 428 } 429 430 public static CountValue 431 getCountValue() 432 { 433 CountValue v = new CountValue(9); 434 return v; 435 } 436 437 public static MinValue 438 getMinValue() 439 { 440 MinValue v = new MinValue(101); 441 return v; 442 } 443 444 public static MaxValue 445 getMaxValue() 446 { 447 MaxValue v = new MaxValue(101); 448 return v; 449 } 450 451 public static SumValue 452 getSumValue() 453 { 454 SumValue v = new SumValue(25); 455 return v; 456 } 457 458 public static org.opensolaris.os.dtrace.Error 459 getError() 460 { 461 ProbeDescription probe = getProbeDescription(); 462 org.opensolaris.os.dtrace.Error e = 463 new org.opensolaris.os.dtrace.Error(probe, 8, 3, 464 1, 20, "DTRACEFLT_BADALIGN", -1, "error on enabled probe ID 8 " + 465 "(ID " + probe.getID() + ": " + probe + "): Bad alignment " + 466 "(0x33ef) in action #1 at DIF offset 20"); 467 return e; 468 } 469 470 public static Drop 471 getDrop() 472 { 473 Drop drop = new Drop(2, "SPECBUSY", 72, 1041, 474 "Guess we dropped stuff all over the place."); 475 return drop; 476 } 477 478 public static InterfaceAttributes 479 getInterfaceAttributes() 480 { 481 InterfaceAttributes a = new InterfaceAttributes( 482 InterfaceAttributes.Stability.UNSTABLE, 483 InterfaceAttributes.Stability.EVOLVING, 484 InterfaceAttributes.DependencyClass.ISA); 485 return a; 486 } 487 488 public static ProgramInfo 489 getProgramInfo() 490 { 491 ProgramInfo info = new ProgramInfo(getInterfaceAttributes(), 492 getInterfaceAttributes(), 256); 493 return info; 494 } 495 496 public static ProbeInfo 497 getProbeInfo() 498 { 499 ProbeInfo info = new ProbeInfo(getInterfaceAttributes(), 500 getInterfaceAttributes()); 501 return info; 502 } 503 504 public static Probe 505 getProbe() 506 { 507 Probe p = new Probe(getProbeDescription(), getProbeInfo()); 508 return p; 509 } 510 511 public static Flow 512 getFlow() 513 { 514 Flow f = new Flow(Flow.Kind.RETURN.name(), 3); 515 return f; 516 } 517 518 public static KernelSymbolRecord 519 getKernelSymbolRecord() 520 { 521 KernelSymbolRecord r = new KernelSymbolRecord("mod`func+0x4", -1L); 522 return r; 523 } 524 525 public static UserSymbolRecord 526 getUserSymbolRecord() 527 { 528 UserSymbolRecord r = new UserSymbolRecord(7, "mod`func+0x4", -1L); 529 return r; 530 } 531 532 public static UserSymbolRecord.Value 533 getUserSymbolRecord$Value() 534 { 535 UserSymbolRecord.Value v = new UserSymbolRecord.Value(7, -1L); 536 return v; 537 } 538 539 public static Program 540 getProgram() 541 { 542 final String PROGRAM = "syscall:::entry { @[execname] = count(); }"; 543 Consumer consumer = new LocalConsumer(); 544 Program p; 545 try { 546 consumer.open(); 547 p = consumer.compile(PROGRAM); 548 consumer.close(); 549 } catch (DTraceException e) { 550 e.printStackTrace(); 551 p = null; 552 } 553 return p; 554 } 555 556 public static Program.File 557 getProgram$File() 558 { 559 final String PROGRAM = "syscall:::entry { @[execname] = count(); }"; 560 Consumer consumer = new LocalConsumer(); 561 Program p; 562 try { 563 OutputStream out = new FileOutputStream(file); 564 out.write(PROGRAM.getBytes(), 0, PROGRAM.length()); 565 out.flush(); 566 out.close(); 567 consumer.open(); 568 p = consumer.compile(file); 569 consumer.close(); 570 } catch (Exception e) { 571 e.printStackTrace(); 572 p = null; 573 } 574 return Program.File.class.cast(p); 575 } 576 577 public static StddevValue 578 getStddevValue() 579 { 580 StddevValue v = new StddevValue(37, 114, 5, Integer.toString(9544)); 581 return v; 582 } 583 584 @SuppressWarnings("unchecked") 585 static String 586 getString(Object o) 587 { 588 String s; 589 if (o instanceof ScalarRecord) { 590 o = ((ScalarRecord)o).getValue(); 591 } 592 593 if (o instanceof byte[]) { 594 s = Arrays.toString((byte[])o); 595 } else if (o instanceof Object[]) { 596 s = Arrays.toString((Object[])o); 597 } else { 598 Class c = o.getClass(); 599 try { 600 Method m = c.getDeclaredMethod("toLogString"); 601 s = (String)m.invoke(o); 602 } catch (Exception e) { 603 s = o.toString(); 604 } 605 } 606 return s; 607 } 608 609 static void 610 checkEquality(Object obj, Object newobj) 611 { 612 // If the class overrides equals(), make sure the re-created 613 // object still equals the original object 614 try { 615 Method eq = obj.getClass().getDeclaredMethod("equals", 616 Object.class); 617 Boolean ret = (Boolean) eq.invoke(obj, newobj); 618 if (ret != true) { 619 System.err.println("serialization failed: " + 620 obj.getClass().getName()); 621 exit(1); 622 } 623 } catch (Exception e) { 624 // Does not override equals(), although a super-class might. 625 // A better test would check for any superclass other than 626 // Object.class. 627 } 628 } 629 630 static void 631 performSerializationTest(File file, String classname) 632 throws IOException, ClassNotFoundException 633 { 634 String methodName = "get" + classname; 635 Object obj = null; 636 Object newobj = null; 637 try { 638 Method method = TestBean.class.getDeclaredMethod(methodName); 639 obj = method.invoke(null); 640 } catch (Exception e) { 641 e.printStackTrace(); 642 exit(1); 643 } 644 645 System.out.println(classname + ":"); 646 String serialized = getString(obj); 647 System.out.println(" serialized: " + serialized); 648 FileOutputStream fos = new FileOutputStream(file); 649 ObjectOutputStream out = new ObjectOutputStream(fos); 650 out.writeObject(obj); 651 out.close(); 652 FileInputStream fis = new FileInputStream(file); 653 ObjectInputStream in = new ObjectInputStream(fis); 654 newobj = in.readObject(); 655 in.close(); 656 String deserialized = getString(newobj); 657 System.out.println(" deserialized: " + deserialized); 658 659 if (!serialized.equals(deserialized)) { 660 System.err.println("serialization failed: " + classname); 661 exit(1); 662 } 663 checkEquality(obj, newobj); 664 } 665 666 static void 667 performBeanTest(File file, String classname) 668 { 669 String methodName = "get" + classname; 670 Object obj = null; 671 Object newobj = null; 672 try { 673 Method method = TestBean.class.getDeclaredMethod(methodName); 674 obj = method.invoke(null); 675 } catch (Exception e) { 676 e.printStackTrace(); 677 exit(1); 678 } 679 680 Class c = obj.getClass(); 681 if (c.getConstructors().length == 0) { 682 return; 683 } 684 685 System.out.println(classname + ":"); 686 XMLEncoder encoder = getXMLEncoder(file); 687 String encoded = getString(obj); 688 System.out.println(" encoded: " + encoded); 689 encoder.writeObject(obj); 690 encoder.close(); 691 XMLDecoder decoder = getXMLDecoder(file); 692 newobj = decoder.readObject(); 693 String decoded = getString(newobj); 694 System.out.println(" decoded: " + decoded); 695 decoder.close(); 696 697 if (!encoded.equals(decoded)) { 698 System.err.println("bean persistence failed: " + classname); 699 exit(1); 700 } 701 checkEquality(obj, newobj); 702 } 703 704 public static void 705 main(String[] args) 706 { 707 if ((args.length != 1) && (args.length != 2)) { 708 System.err.println("usage: java TestBean < filename > " + 709 "[ < classname > ]"); 710 exit(1); 711 } 712 713 String filename = args[0]; 714 String classname = null; 715 if (args.length >= 2) { 716 classname = args[1]; 717 } 718 719 file = new File(filename); 720 try { 721 if (!file.canRead()) { 722 try { 723 file.createNewFile(); 724 } catch (Exception e) { 725 System.err.println("failed to create " + filename); 726 exit(1); 727 } 728 } 729 } catch (SecurityException e) { 730 System.err.println("failed to open " + filename); 731 exit(1); 732 } 733 734 String[] tests = (classname == null ? TESTS: 735 new String[] { classname }); 736 try { 737 for (int i = 0; i < tests.length; ++i) { 738 performSerializationTest(file, tests[i]); 739 performBeanTest(file, tests[i]); 740 } 741 } catch (IOException e) { 742 e.printStackTrace(); 743 exit(1); 744 } catch (ClassNotFoundException e) { 745 e.printStackTrace(); 746 exit(1); 747 } 748 } 749 } 750