blob: 6848cd5e4851d5e9622163dbb49ae8d068f4a034 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005 Sun Microsystems, Inc. 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 * @test
26 * @bug 6204469
27 * @summary Test that Open MBean attributes and parameters check constraints
28 * @author Eamonn McManus
29 * @run clean ConstraintTest
30 * @run build ConstraintTest
31 * @run main ConstraintTest
32 */
33
34import java.util.*;
35import javax.management.*;
36import javax.management.openmbean.*;
37
38public class ConstraintTest {
39 private static String failure;
40
41 public static void main(String[] args) throws Exception {
42 for (Object[][] test : tests) {
43 if (test.length != 4) {
44 throw new Exception("Test element has wrong length: " +
45 Arrays.deepToString(test));
46 }
47
48 if (test[0].length != 4) {
49 throw new Exception("Test constraints should have size 4: " +
50 Arrays.deepToString(test[0]));
51 }
52 Object defaultValue = test[0][0];
53 Comparable<?> minValue = (Comparable<?>) test[0][1];
54 Comparable<?> maxValue = (Comparable<?>) test[0][2];
55 Object[] legalValues = (Object[]) test[0][3];
56 System.out.println("test: defaultValue=" + defaultValue +
57 "; minValue=" + minValue +
58 "; maxValue=" + maxValue +
59 "; legalValues=" +
60 Arrays.deepToString(legalValues));
61
62 if (test[1].length != 1) {
63 throw new Exception("OpenType list should have size 1: " +
64 Arrays.deepToString(test[1]));
65 }
66 OpenType<?> openType = (OpenType<?>) test[1][0];
67
68 Object[] valid = test[2];
69 Object[] invalid = test[3];
70
71 System.out.println("...valid=" + Arrays.deepToString(valid));
72 System.out.println("...invalid=" + Arrays.deepToString(invalid));
73
74 test(openType, defaultValue, minValue, maxValue, legalValues,
75 valid, invalid);
76 }
77
78 if (failure == null)
79 System.out.println("Test passed");
80 else
81 throw new Exception("TEST FAILED: " + failure);
82 }
83
84 private static <T> void test(OpenType<T> openType, Object defaultValue,
85 Comparable<?> minValue,
86 Comparable<?> maxValue, Object[] legalValues,
87 Object[] valid, Object[] invalid)
88 throws Exception {
89 /* This hack is needed to avoid grief from the parameter checking
90 in the OpenMBean*InfoSupport constructors. Since they are defined
91 to check that the defaultValue etc are of the same type as the
92 OpenType<T>, there is no way to pass a defaultValue etc when
93 the type is OpenType<?>. So either you have to write plain
94 OpenType, and get unchecked warnings for every constructor
95 invocation, or you do this, and get the unchecked warnings just
96 here. */
97 test1(openType, (T) defaultValue, (Comparable<T>) minValue,
98 (Comparable<T>) maxValue, (T[]) legalValues, valid, invalid);
99 }
100
101 private static <T> void test1(OpenType<T> openType, T defaultValue,
102 Comparable<T> minValue,
103 Comparable<T> maxValue, T[] legalValues,
104 Object[] valid, Object[] invalid)
105 throws Exception {
106
107 if (legalValues != null && (minValue != null || maxValue != null))
108 throw new Exception("Test case has both legals and min/max");
109
110 if (defaultValue == null && minValue == null && maxValue == null &&
111 legalValues == null) {
112 test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
113 true, true, false),
114 valid, invalid);
115 test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
116 true, true, false, nullD),
117 valid, invalid);
118 test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
119 true, true, false, emptyD),
120 valid, invalid);
121 test(new OpenMBeanParameterInfoSupport("name", "descr", openType),
122 valid, invalid);
123 test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
124 nullD),
125 valid, invalid);
126 test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
127 emptyD),
128 valid, invalid);
129 }
130
131 if (minValue == null && maxValue == null && legalValues == null) {
132 Descriptor d = descriptor("defaultValue", defaultValue);
133 test(new OpenMBeanAttributeInfoSupport("blah", "descr", openType,
134 true, true, false, d),
135 valid, invalid);
136 test(new OpenMBeanAttributeInfoSupport("blah", "descr",
137 openType, true, true,
138 false, defaultValue),
139 valid, invalid);
140 test(new OpenMBeanParameterInfoSupport("blah", "descr", openType,
141 d),
142 valid, invalid);
143 test(new OpenMBeanParameterInfoSupport("blah", "descr", openType,
144 defaultValue),
145 valid, invalid);
146 }
147
148 if (legalValues == null) {
149 Descriptor d = descriptor("defaultValue", defaultValue,
150 "minValue", minValue,
151 "maxValue", maxValue);
152 test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
153 true, true, false, d),
154 valid, invalid);
155 test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
156 true, true, false,
157 defaultValue,
158 minValue, maxValue),
159 valid, invalid);
160 test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
161 d),
162 valid, invalid);
163 test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
164 defaultValue,
165 minValue, maxValue),
166 valid, invalid);
167 }
168
169 if (minValue == null && maxValue == null) {
170 // Legal values in descriptor can be either an array or a set
171 Descriptor d1 = descriptor("defaultValue", defaultValue,
172 "legalValues", legalValues);
173 Descriptor d2;
174 if (legalValues == null)
175 d2 = d1;
176 else {
177 d2 = descriptor("defaultValue", defaultValue,
178 "legalValues", arraySet(legalValues));
179 }
180 test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
181 true, true, false, d1),
182 valid, invalid);
183 test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
184 true, true, false, d2),
185 valid, invalid);
186 test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
187 true, true, false,
188 defaultValue, legalValues),
189 valid, invalid);
190 test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
191 d1),
192 valid, invalid);
193 test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
194 d2),
195 valid, invalid);
196 test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
197 defaultValue, legalValues),
198 valid, invalid);
199 }
200 }
201
202 /* Test one of the objects. Note that OpenMBeanAttributeInfo
203 extends OpenMBeanParameterInfo, so OpenMBeanAttributeInfoSupport
204 is-an OpenMBeanParameterInfo. */
205 private static void test(OpenMBeanParameterInfo info,
206 Object[] valid, Object[] invalid) {
207 test1(info, valid, invalid);
208
209 // Check that the constraints can be specified as strings
210 // rather than objects
211 if (info.getOpenType() instanceof SimpleType<?>) {
212 Descriptor d = ((DescriptorRead) info).getDescriptor();
213 String[] names = d.getFieldNames();
214 Object[] values = d.getFieldValues(names);
215 for (int i = 0; i < values.length; i++) {
216 if (values[i] == null)
217 continue;
218 if (names[i].equals("legalValues")) {
219 Collection<?> legals;
220 if (values[i] instanceof Collection<?>)
221 legals = (Collection<?>) values[i];
222 else
223 legals = Arrays.asList((Object[]) values[i]);
224 List<String> strings = new ArrayList<String>();
225 for (Object legal : legals)
226 strings.add(legal.toString());
227 values[i] = strings.toArray(new String[0]);
228 } else if (!(values[i] instanceof OpenType<?>))
229 values[i] = values[i].toString();
230 }
231 d = new ImmutableDescriptor(names, values);
232 OpenType<?> ot = info.getOpenType();
233 if (info instanceof OpenMBeanAttributeInfo) {
234 OpenMBeanAttributeInfo ai = (OpenMBeanAttributeInfo) info;
235 info = new OpenMBeanAttributeInfoSupport(info.getName(),
236 info.getDescription(),
237 info.getOpenType(),
238 ai.isReadable(),
239 ai.isWritable(),
240 ai.isIs(),
241 d);
242 } else {
243 info = new OpenMBeanParameterInfoSupport(info.getName(),
244 info.getDescription(),
245 info.getOpenType(),
246 d);
247 }
248 test1(info, valid, invalid);
249 }
250 }
251
252 private static void test1(OpenMBeanParameterInfo info,
253 Object[] valid, Object[] invalid) {
254
255 for (Object x : valid) {
256 if (!info.isValue(x)) {
257 fail("Object should be valid but is not: " + x + " for: " +
258 info);
259 }
260 }
261
262 for (Object x : invalid) {
263 if (info.isValue(x)) {
264 fail("Object should not be valid but is: " + x + " for: " +
265 info);
266 }
267 }
268
269 /* If you specify e.g. minValue in a descriptor, then we arrange
270 for getMinValue() to return the same value, and if you specify
271 a minValue as a constructor parameter then we arrange for the
272 descriptor to have a minValue entry. Check that these values
273 do in fact match. */
274
275 Descriptor d = ((DescriptorRead) info).getDescriptor();
276
277 checkSameValue("defaultValue", info.getDefaultValue(),
278 d.getFieldValue("defaultValue"));
279 checkSameValue("minValue", info.getMinValue(),
280 d.getFieldValue("minValue"));
281 checkSameValue("maxValue", info.getMaxValue(),
282 d.getFieldValue("maxValue"));
283 checkSameValues("legalValues", info.getLegalValues(),
284 d.getFieldValue("legalValues"));
285 }
286
287 private static void checkSameValue(String what, Object getterValue,
288 Object descriptorValue) {
289 if (getterValue == null) {
290 if (descriptorValue != null) {
291 fail("Getter returned null but descriptor has entry for " +
292 what + ": " + descriptorValue);
293 }
294 } else if (descriptorValue == null) {
295 fail("Getter returned value but descriptor has no entry for " +
296 what + ": " + getterValue);
297 } else if (!getterValue.equals(descriptorValue) &&
298 !getterValue.toString().equals(descriptorValue)) {
299 fail("For " + what + " getter returned " + getterValue +
300 " but descriptor entry is " + descriptorValue);
301 }
302 }
303
304 private static void checkSameValues(String what, Set<?> getterValues,
305 Object descriptorValues) {
306 if (getterValues == null) {
307 if (descriptorValues != null) {
308 fail("Getter returned null but descriptor has entry for " +
309 what + ": " + descriptorValues);
310 }
311 } else if (descriptorValues == null) {
312 fail("Getter returned value but descriptor has no entry for " +
313 what + ": " + getterValues);
314 } else {
315 Set<?> descriptorValueSet;
316 if (descriptorValues instanceof Set<?>)
317 descriptorValueSet = (Set<?>) descriptorValues;
318 else
319 descriptorValueSet = arraySet((Object[]) descriptorValues);
320 boolean same = true;
321 if (getterValues.size() != descriptorValueSet.size())
322 same = false;
323 else {
324 for (Object x : getterValues) {
325 if (!descriptorValueSet.contains(x)
326 && !descriptorValueSet.contains(x.toString())) {
327 same = false;
328 break;
329 }
330 }
331 }
332 if (!same) {
333 fail("For " + what + " getter returned " + getterValues +
334 " but descriptor entry is " + descriptorValueSet);
335 }
336 }
337 }
338
339 private static void fail(String why) {
340 System.out.println("FAILED: " + why);
341 failure = why;
342 }
343
344 private static Descriptor descriptor(Object... entries) {
345 if (entries.length % 2 != 0)
346 throw new RuntimeException("Odd length descriptor entries");
347 String[] names = new String[entries.length / 2];
348 Object[] values = new Object[entries.length / 2];
349 for (int i = 0; i < entries.length; i += 2) {
350 names[i / 2] = (String) entries[i];
351 values[i / 2] = entries[i + 1];
352 }
353 return new ImmutableDescriptor(names, values);
354 }
355
356 private static <T> Set<T> arraySet(T[] array) {
357 return new HashSet<T>(Arrays.asList(array));
358 }
359
360 private static final OpenType<?>
361 ostring = SimpleType.STRING,
362 oint = SimpleType.INTEGER,
363 obool = SimpleType.BOOLEAN,
364 olong = SimpleType.LONG,
365 obyte = SimpleType.BYTE,
366 ofloat = SimpleType.FLOAT,
367 odouble = SimpleType.DOUBLE,
368 ostringarray, ostringarray2;
369 private static final CompositeType ocomposite;
370 private static final CompositeData compositeData, compositeData2;
371 static {
372 try {
373 ostringarray = new ArrayType<String[]>(1, ostring);
374 ostringarray2 = new ArrayType<String[][]>(2, ostring);
375 ocomposite =
376 new CompositeType("name", "descr",
377 new String[] {"s", "i"},
378 new String[] {"sdesc", "idesc"},
379 new OpenType[] {ostring, oint});
380 compositeData =
381 new CompositeDataSupport(ocomposite,
382 new String[] {"s", "i"},
383 new Object[] {"foo", 23});
384 compositeData2 =
385 new CompositeDataSupport(ocomposite,
386 new String[] {"s", "i"},
387 new Object[] {"bar", -23});
388 } catch (OpenDataException e) { // damn checked exceptions...
389 throw new IllegalArgumentException(e.toString(), e);
390 }
391 }
392
393 private static final Descriptor
394 nullD = null,
395 emptyD = ImmutableDescriptor.EMPTY_DESCRIPTOR;
396
397 /* The elements of this array are grouped as follows. Each
398 element contains four Object[]s. The first one is a set of
399 four values: default value, min value, max value, legal values
400 (an Object[]), some of which can be null. These will be used
401 to derive the OpenMBean*Info values to be tested. The second
402 is an array with one element that is the OpenType that will be
403 given to the constructors of the OpenMBean*Infos. The third
404 element is a set of values that should be valid according to
405 the constraints in the OpenMBean*Info. The fourth is a set of
406 values that should be invalid according to those
407 constraints. */
408 private static final Object[][][] tests = {
409
410 // Test cases when there are no constraints
411 // Validity checking is limited to type of object
412
413 {{null, null, null, null},
414 {oint},
415 {-1, 0, 1, Integer.MAX_VALUE, Integer.MIN_VALUE},
416 {null, "noddy", 1.3, false, 3L, Long.MAX_VALUE, emptyD,
417 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
418
419 {{null, null, null, null},
420 {obool},
421 {true, false},
422 {null, "noddy", 1.3, 3, 3L, Long.MAX_VALUE, emptyD,
423 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
424
425 {{null, null, null, null},
426 {ostring},
427 {"", "yes!"},
428 {null, 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
429 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
430
431 {{null, null, null, null},
432 {obyte},
433 {Byte.MIN_VALUE, Byte.MAX_VALUE, (byte) 0},
434 {null, "noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
435 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
436
437 {{null, null, null, null},
438 {ostringarray},
439 {new String[0], new String[] {"hello", "world"}},
440 {null, "noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
441 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
442
443 {{null, null, null, null},
444 {ostringarray2},
445 {new String[0][0], new String[][] {{"hello", "world"},
446 {"goodbye", "cruel", "world"}}},
447 {null, "noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
448 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
449
450 {{null, null, null, null},
451 {ocomposite},
452 {compositeData, compositeData2},
453 {null, "noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
454 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
455
456 // Test cases where there is a default value, so null is allowed
457
458 {{23, null, null, null},
459 {oint},
460 {null, -1, 0, 1, Integer.MAX_VALUE, Integer.MIN_VALUE},
461 {"noddy", 1.3, false, 3L, Long.MAX_VALUE, emptyD,
462 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
463
464 {{true, null, null, null},
465 {obool},
466 {null, true, false},
467 {"noddy", 1.3, 3, 3L, Long.MAX_VALUE, emptyD,
468 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
469
470 {{"foo", null, null, null},
471 {ostring},
472 {null, "", "yes!"},
473 {1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
474 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
475
476 {{(byte) 23, null, null, null},
477 {obyte},
478 {null, Byte.MIN_VALUE, Byte.MAX_VALUE, (byte) 0},
479 {"noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
480 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
481
482 {{compositeData, null, null, null},
483 {ocomposite},
484 {null, compositeData, compositeData2},
485 {"noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
486 new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
487
488 // Test cases where there is a min and/or max, with or without default
489
490 {{23, 0, 50, null},
491 {oint},
492 {null, 0, 25, 50},
493 {"noddy", -1, 51, Integer.MIN_VALUE, Integer.MAX_VALUE, 25L}},
494
495 {{null, 0, 50, null},
496 {oint},
497 {0, 25, 50},
498 {null, "noddy", -1, 51, Integer.MIN_VALUE, Integer.MAX_VALUE, 25L}},
499
500 {{null, 0, null, null},
501 {oint},
502 {0, 25, 50, Integer.MAX_VALUE},
503 {null, "noddy", -1, Integer.MIN_VALUE, 25L}},
504
505 {{null, null, 50, null},
506 {oint},
507 {Integer.MIN_VALUE, -1, 0, 25, 50},
508 {null, "noddy", 51, Integer.MAX_VALUE, 25L}},
509
510 {{"go", "a", "z~", null},
511 {ostring},
512 {null, "a", "z~", "zzzz", "z!"},
513 {"A", "~", "", -1}},
514
515 // Test cases where there is a set of legal values
516
517 {{23, null, null, new Integer[] {2, 3, 5, 7, 11, 13, 17, 23}},
518 {oint},
519 {null, 2, 11, 23},
520 {"noddy", -1, 1, 51, Integer.MIN_VALUE, Integer.MAX_VALUE, 25L}},
521
522 {{null, null, null, new CompositeData[] {compositeData}},
523 {ocomposite},
524 {compositeData},
525 {null, compositeData2, "noddy"}},
526
527 {{null, null, null, new Long[0]},
528 {olong},
529 {}, // constraint is impossible to satisfy!
530 {null, 23L, "x", 23}},
531 };
532}