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
exit(int status)83     exit(int status)
84     {
85 	System.out.flush();
86 	System.err.flush();
87 	System.exit(status);
88     }
89 
90     public static XMLEncoder
getXMLEncoder(File file)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
getXMLDecoder(File file)106     getXMLDecoder(File file)
107     {
108         return getXMLDecoder(file, null);
109     }
110 
111     public static XMLDecoder
getXMLDecoder(File file, ExceptionListener exceptionListener)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
getExitRecord()127     getExitRecord()
128     {
129 	ExitRecord r = new ExitRecord(1);
130 	return r;
131     }
132 
133     public static AggregationRecord
getAggregationRecord()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
getAggregation()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
getTuple()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
getScalarRecord()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
getKernelStackRecord()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
getLogDistribution()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
getLinearDistribution()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
getLogLinearDistribution()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
getOption()311     getOption()
312     {
313 	Option option = new Option("aggrate", "1s");
314 	return option;
315     }
316 
317     public static ProcessState
getProcessState()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
getProbeDescription()327     getProbeDescription()
328     {
329 	ProbeDescription d = new ProbeDescription(256, "syscall", null,
330 	    "malloc", "entry");
331 	return d;
332     }
333 
334     public static PrintaRecord
getPrintaRecord()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
getPrintfRecord()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
getProbeData()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
getAggregate()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
getUserStackRecord()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
getAvgValue()424     getAvgValue()
425     {
426 	AvgValue v = new AvgValue(5, 20, 4);
427 	return v;
428     }
429 
430     public static CountValue
getCountValue()431     getCountValue()
432     {
433 	CountValue v = new CountValue(9);
434 	return v;
435     }
436 
437     public static MinValue
getMinValue()438     getMinValue()
439     {
440 	MinValue v = new MinValue(101);
441 	return v;
442     }
443 
444     public static MaxValue
getMaxValue()445     getMaxValue()
446     {
447 	MaxValue v = new MaxValue(101);
448 	return v;
449     }
450 
451     public static SumValue
getSumValue()452     getSumValue()
453     {
454 	SumValue v = new SumValue(25);
455 	return v;
456     }
457 
458     public static org.opensolaris.os.dtrace.Error
getError()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
getDrop()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
getInterfaceAttributes()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
getProgramInfo()489     getProgramInfo()
490     {
491 	ProgramInfo info = new ProgramInfo(getInterfaceAttributes(),
492 		getInterfaceAttributes(), 256);
493 	return info;
494     }
495 
496     public static ProbeInfo
getProbeInfo()497     getProbeInfo()
498     {
499 	ProbeInfo info = new ProbeInfo(getInterfaceAttributes(),
500 		getInterfaceAttributes());
501 	return info;
502     }
503 
504     public static Probe
getProbe()505     getProbe()
506     {
507 	Probe p = new Probe(getProbeDescription(), getProbeInfo());
508 	return p;
509     }
510 
511     public static Flow
getFlow()512     getFlow()
513     {
514 	Flow f = new Flow(Flow.Kind.RETURN.name(), 3);
515 	return f;
516     }
517 
518     public static KernelSymbolRecord
getKernelSymbolRecord()519     getKernelSymbolRecord()
520     {
521 	KernelSymbolRecord r = new KernelSymbolRecord("mod`func+0x4", -1L);
522 	return r;
523     }
524 
525     public static UserSymbolRecord
getUserSymbolRecord()526     getUserSymbolRecord()
527     {
528 	UserSymbolRecord r = new UserSymbolRecord(7, "mod`func+0x4", -1L);
529 	return r;
530     }
531 
532     public static UserSymbolRecord.Value
getUserSymbolRecord$Value()533     getUserSymbolRecord$Value()
534     {
535 	UserSymbolRecord.Value v = new UserSymbolRecord.Value(7, -1L);
536 	return v;
537     }
538 
539     public static Program
getProgram()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
getProgram$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
getStddevValue()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
getString(Object o)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
checkEquality(Object obj, Object newobj)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
performSerializationTest(File file, String classname)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
performBeanTest(File file, String classname)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
main(String[] args)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