    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package javax.jdo;
    19
    20  import java.io.IOException;
    21  import java.io.InputStream;
    22  import java.net.URLClassLoader;
    23  import java.util.HashMap;
    24  import java.util.Map;
    25
    26  import javax.jdo.util.BatchTestRunner;
    27
    28  import junit.framework.TestSuite;
    29
    30  /**
    31   *
    32   * Tests class javax.jdo.JDOHelper for META-INF/jdoconfig.xml compliance.
    33   *
    34   */
    35  public class JDOHelperConfigTest extends AbstractJDOConfigTest implements
    36  	Constants {
    37
    38      public static void main(String args[]) {
    39  	BatchTestRunner.run(JDOHelperConfigTest.class);
    40      }
    41
    42      /**
    43       * {@inheritDoc}
    44       *
    45       * @return {@inheritDoc}
    46       */
    47      public static TestSuite suite() {
    48  	return new TestSuite(JDOHelperConfigTest.class);
    49      }
    50
    51      /**
    52       * Builds up a {@link java.util.Map Map} object that contains key parameter
    53       * values specific to a named test. All of the properties needed to run a
    54       * particular test are loaded into this object.
    55       *
    56       * @param testVariant
    57       *            the name of the test to include in the {@link java.util.Map
    58       *            Map} values.
    59       * @param listenerCount
    60       *            the number of life cycle listener class names to add to this
    61       *            map. The listener names will begin with the value stored in
    62       *            {@link javax.jdo.Constants.PROPERTY_INSTANCE_LIFECYCLE_LISTENER
    63       *            PROPERTY_INSTANCE_LIFECYCLE_LISTENER}.
    64       * @param vendorSpecificPropertyCount
    65       *            the number of properties named of the form
    66       *
    67       *            <pre>
    68       * &quot;property.&quot; + testVariant + &quot;.name&quot;
    69       * </pre>
    70       *
    71       *            that are added to the map.
    72       * @param excludeName
    73       *            if true the property specified by
    74       *            {@link javax.jdo.Constants.PROPERTY_NAME PROPERTY_NAME} is not
    75       *            added to the map.
    76       * @param excludePUName
    77       *            if true the property specified by
    78       *            {@link javax.jdo.Constants.PROPERTY_PERSISTENCE_UNIT_NAME
    79       *            PROPERTY_PERSISTENCE_UNIT_NAME} is not added to the map.
    80       * @return a new {@link java.util.Map Map} object populated with properties
    81       *         that can be used in this test suite.
    82       */
    83      protected Map prepareInitialExpectedMap(String testVariant,
    84  	    int listenerCount, int vendorSpecificPropertyCount,
    85  	    boolean excludeName, boolean excludePUName) {
    86  	Map<String, String> expected = new HashMap<String, String>();
    87
    88  	if (!excludeName) {
    89  	    expected.put(PROPERTY_NAME, PMF_ATTRIBUTE_NAME + "." + testVariant);
    90  	}
    91  	if (!excludePUName) {
    92  	    expected.put(PROPERTY_PERSISTENCE_UNIT_NAME,
    93  		    PMF_ATTRIBUTE_PERSISTENCE_UNIT_NAME + "." + testVariant);
    94  	}
    95
    96  	expected.put(PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS,
    97  		PMF_ATTRIBUTE_CLASS + "." + testVariant);
    98  	expected.put(PROPERTY_CONNECTION_DRIVER_NAME,
    99  		PMF_ATTRIBUTE_CONNECTION_DRIVER_NAME + "." + testVariant);
    100 	expected.put(PROPERTY_CONNECTION_FACTORY_NAME,
    101 		PMF_ATTRIBUTE_CONNECTION_FACTORY_NAME + "." + testVariant);
    102 	expected.put(PROPERTY_CONNECTION_FACTORY2_NAME,
    103 		PMF_ATTRIBUTE_CONNECTION_FACTORY2_NAME + "." + testVariant);
    104 	expected.put(PROPERTY_CONNECTION_PASSWORD,
    105 		PMF_ATTRIBUTE_CONNECTION_PASSWORD + "." + testVariant);
    106 	expected.put(PROPERTY_CONNECTION_URL, PMF_ATTRIBUTE_CONNECTION_URL
    107 		+ "." + testVariant);
    108 	expected.put(PROPERTY_CONNECTION_USER_NAME,
    109 		PMF_ATTRIBUTE_CONNECTION_USER_NAME + "." + testVariant);
    110 	expected.put(PROPERTY_IGNORE_CACHE, PMF_ATTRIBUTE_IGNORE_CACHE + "."
    111 		+ testVariant);
    112 	expected.put(PROPERTY_MAPPING, PMF_ATTRIBUTE_MAPPING + "."
    113 		+ testVariant);
    114 	expected.put(PROPERTY_MULTITHREADED, PMF_ATTRIBUTE_MULTITHREADED + "."
    115 		+ testVariant);
    116 	expected.put(PROPERTY_NONTRANSACTIONAL_READ,
    117 		PMF_ATTRIBUTE_NONTRANSACTIONAL_READ + "." + testVariant);
    118 	expected.put(PROPERTY_NONTRANSACTIONAL_WRITE,
    119 		PMF_ATTRIBUTE_NONTRANSACTIONAL_WRITE + "." + testVariant);
    120 	expected.put(PROPERTY_OPTIMISTIC, PMF_ATTRIBUTE_OPTIMISTIC + "."
    121 		+ testVariant);
    122 	expected.put(PROPERTY_RESTORE_VALUES, PMF_ATTRIBUTE_RESTORE_VALUES
    123 		+ "." + testVariant);
    124 	expected.put(PROPERTY_RETAIN_VALUES, PMF_ATTRIBUTE_RETAIN_VALUES + "."
    125 		+ testVariant);
    126 	expected.put(PROPERTY_DETACH_ALL_ON_COMMIT,
    127 		PMF_ATTRIBUTE_DETACH_ALL_ON_COMMIT + "." + testVariant);
    128 	expected.put(PROPERTY_SERVER_TIME_ZONE_ID,
    129 		PMF_ATTRIBUTE_SERVER_TIME_ZONE_ID + "." + testVariant);
    130
    131 	// listeners
    132 	for (int i = 0; i < listenerCount; i++) {
    133 	    expected.put(PROPERTY_PREFIX_INSTANCE_LIFECYCLE_LISTENER
    134 		    + "listener." + testVariant + ".listener" + i, "classes."
    135 		    + testVariant + ".classes" + i);
    136 	}
    137
    138 	// vendor-specific properties
    139 	for (int i = 0; i < vendorSpecificPropertyCount; i++) {
    140 	    expected.put("property." + testVariant + ".name" + i, "property."
    141 		    + testVariant + ".value" + i);
    142 	}
    143
    144 	return expected;
    145     }
    146
    147     /**
    148      * Performs a test specified by <tt>testVariantName</tt>, by building up a
    149      * property map and executing the test according to the property values.
    150      * With this version of <tt>doPositiveTest</tt> the property name (
    151      * {@link javax.jdo.Constants.PROPERTY_NAME PROPERTY_NAME}) and the
    152      * {@link javax.jdo.Constants.PERSISTENCE_UNIT_NAME PERSISTENCE_UNIT_NAME})
    153      * are included in the property map that is used to run the test.
    154      *
    155      * @param classpaths
    156      *            class paths to add to the class loader that runs the test that
    157      *            specify where <tt>jdoconfig.xml</tt> can be found.
    158      * @param testVariantName
    159      *            the name of the test.
    160      * @param listenerCount
    161      *            number of listeners utilized in the test.
    162      * @param vendorSpecificPropertyCount
    163      *            number of vendor properties used in the test.
    164      * @param checkEqualProperties
    165      *            if true the test's properties are tested.
    166      * @throws java.io.IOException
    167      *             if an {@java.io.IOException
    168      *             IOException} occurs during class loading or any part of the
    169      *             test.
    170      */
    171     protected void doPositiveTest(String[] classpaths, String testVariantName,
    172 	    int listenerCount, int vendorSpecificPropertyCount,
    173 	    boolean checkEqualProperties) throws IOException {
    174
    175 	doPositiveTest(classpaths, testVariantName, listenerCount,
    176 		vendorSpecificPropertyCount, checkEqualProperties, false, false);
    177     }
    178
    179     /**
    180      * Performs a test specified by <tt>testVariantName</tt>, by building up a
    181      * property map and executing the test according to the property values. An
    182      * assertion exeception is thrown if the test being run has a negative
    183      * (non-true) result. With this version of <tt>doPositiveTest</tt> the
    184      * property name ({@link javax.jdo.Constants.PROPERTY_NAME PROPERTY_NAME})
    185      * and the {@link javax.jdo.Constants.PERSISTENCE_UNIT_NAME
    186      * PERSISTENCE_UNIT_NAME}) are included in the property map that is used to
    187      * run the test.
    188      *
    189      * @param classpaths
    190      *            class paths to add to the class loader that runs the test that
    191      *            specify where <tt>jdoconfig.xml</tt> can be found.
    192      * @param testVariantName
    193      *            the name of the test.
    194      * @param listenerCount
    195      *            number of listeners utilized in the test.
    196      * @param vendorSpecificPropertyCount
    197      *            number of vendor properties used in the test.
    198      * @param checkEqualProperties
    199      *            if true the test's properties are tested.
    200      * @param excludeName
    201      *            if true the property specified by
    202      *            {@link javax.jdo.Constants.PROPERTY_NAME PROPERTY_NAME} is not
    203      *            added to the map.
    204      * @param excludePUName
    205      *            if true the property specified by
    206      *            {@link javax.jdo.Constants.PROPERTY_PERSISTENCE_UNIT_NAME
    207      *            PROPERTY_PERSISTENCE_UNIT_NAME} is not added to the map.
    208      * @throws java.io.IOException
    209      *             if an {@java.io.IOException
    210      *             IOException} occurs during class loading or any part of the
    211      *             test.
    212      */
    213     protected void doPositiveTest(String[] classpaths, String testVariantName,
    214 	    int listenerCount, int vendorSpecificPropertyCount,
    215 	    boolean checkEqualProperties, boolean excludeName,
    216 	    boolean excludePUName) throws IOException {
    217
    218 	URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    219 		.getClassLoader(), classpaths);
    220
    221 	Map expected = prepareInitialExpectedMap(testVariantName,
    222 		listenerCount, vendorSpecificPropertyCount, excludeName,
    223 		excludePUName);
    224
    225 	String name = testVariantName == null ? null : (String) expected
    226 		.get(PROPERTY_NAME);
    227
    228 	Map actual = JDOHelper.getPropertiesFromJdoconfig(name, loader);
    229
    230 	assertNotNull("No properties found", actual);
    231 	if (checkEqualProperties) {
    232 	    assertEqualProperties(expected, actual);
    233 	}
    234     }
    235
    236     public void testPositive00_PMF0_BasicPMFConfigUsingOnlyStandardAttributesAndListeners()
    237 	    throws IOException {
    238 	doPositiveTest(new String[] { JDOCONFIG_CLASSPATH_PREFIX
    239 		+ "/Positive00" }, "positive00.pmf0", 2, 0, true);
    240     }
    241
    242     public void testPositive00_PMF1_BasicPMFConfigUsingOnlyPropertyElementsWithStandardJavaxDotJDOProperties()
    243 	    throws IOException {
    244 	doPositiveTest(new String[] { JDOCONFIG_CLASSPATH_PREFIX
    245 		+ "/Positive00" }, "positive00.pmf1", 2, 0, true);
    246     }
    247
    248     public void testPositive00_PMF2_NestedPropertyElementsWithOnlyStandardAttributeNames()
    249 	    throws IOException {
    250 	doPositiveTest(new String[] { JDOCONFIG_CLASSPATH_PREFIX
    251 		+ "/Positive00" }, "positive00.pmf2", 2, 0, true);
    252     }
    253
    254     public void testPositive00_PMF3_StandardAttributesPlusNonstandardPropertiesInPropertyElements()
    255 	    throws IOException {
    256 	doPositiveTest(new String[] { JDOCONFIG_CLASSPATH_PREFIX
    257 		+ "/Positive00" }, "positive00.pmf3", 2, 2, true);
    258     }
    259
    260     public void testPositive00_PMF4_StandardAttributesPlusNonstandardAttributes()
    261 	    throws IOException {
    262 	doPositiveTest(new String[] { JDOCONFIG_CLASSPATH_PREFIX
    263 		+ "/Positive00" }, "positive00.pmf4", 0, 2, true);
    264     }
    265
    266     public void testPositive01_DuplicatePUsInDifferentConfigFilesButNotRequested()
    267 	    throws IOException {
    268
    269 	String[] classpaths = new String[] {
    270 		JDOCONFIG_CLASSPATH_PREFIX + "/Positive01/1a",
    271 		JDOCONFIG_CLASSPATH_PREFIX + "/Positive01/1b" };
    272 	URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    273 		.getClassLoader(), classpaths);
    274
    275 	Map actual = JDOHelper.getPropertiesFromJdoconfig(
    276 		ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, loader);
    277     }
    278
    279     public void testPositive02_GetAnonymousPMFWithNoProperties()
    280 	    throws IOException {
    281
    282 	URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    283 		.getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX + "/Positive02/");
    284
    285 	Map properties = JDOHelper.getPropertiesFromJdoconfig(
    286 		ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, loader);
    287 	assertNotNull("Anonymous PMF with no properties returned null",
    288 		properties);
    289 	assertTrue("Anonymous PMF with no properties had properties",
    290 		properties.size() == 0);
    291     }
    292
    293     public void testPositive03_PMF0_PMFClassNameViaServicesLookup()
    294 	    throws IOException {
    295
    296 	URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    297 		.getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX + "/Positive03/");
    298
    299 	String expected = "class.positive03.pmf0";
    300 	String actual = getPMFClassNameViaServiceLookup(loader);
    301
    302 	assertNotNull("No PMF name found via services lookup", actual);
    303 	assertEquals(expected, actual);
    304     }
    305
    306     public void testPositive04_PMF0_PMFClassNameViaServicesLookup()
    307 	    throws IOException {
    308
    309 	URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    310 		.getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX + "/Positive04/");
    311
    312 	String expected = "class.positive04.pmf0";
    313 	String actual = getPMFClassNameViaServiceLookup(loader);
    314
    315 	assertNotNull("No PMF name found via services lookup", actual);
    316 	assertEquals(expected, actual);
    317     }
    318
    319     public void testPositive05_PMF0_PMFClassNameViaServicesLookup()
    320 	    throws IOException {
    321
    322 	URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    323 		.getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX + "/Positive05/");
    324
    325 	String expected = "class.positive05.pmf0";
    326 	String actual = getPMFClassNameViaServiceLookup(loader);
    327
    328 	assertNotNull("No PMF name found via services lookup", actual);
    329 	assertEquals(expected, actual);
    330     }
    331
    332     public void testPositive06_PMF0_GetAnonymousPMFProperties()
    333 	    throws IOException {
    334
    335 	URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    336 		.getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX + "/Positive06/");
    337
    338 	Map expected = prepareInitialExpectedMap("positive06.pmf0", 2, 0, true,
    339 		true);
    340
    341 	Map actual = JDOHelper.getPropertiesFromJdoconfig(
    342 		ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, loader);
    343
    344 	assertNotNull("No properties found", actual);
    345 	assertEqualProperties(expected, actual);
    346     }
    347
    348     public void testPositive07_PMF0_GetAnonymousPMFPropertiesWithPUName()
    349 	    throws IOException {
    350
    351 	URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    352 		.getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX + "/Positive07/");
    353
    354 	Map expected = prepareInitialExpectedMap("positive07.pmf0", 2, 0, true,
    355 		false);
    356
    357 	Map actual = JDOHelper.getPropertiesFromJdoconfig(
    358 		ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME, loader);
    359
    360 	assertNotNull("No properties found", actual);
    361 	assertEqualProperties(expected, actual);
    362     }
    363
    364     public void testNegative00_EmptyJDOConfigXML() throws IOException {
    365 	try {
    366 	    URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    367 		    .getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    368 		    + "/Negative0/");
    369
    370 	    JDOHelper.getPersistenceManagerFactory(loader);
    371 	    fail("JDOHelper failed to throw JDOFatalUserException");
    372 	} catch (JDOFatalUserException x) {
    373 	    // sunny day
    374 	}
    375     }
    376
    377     public void testNegative01_NoPersistenceUnitsDefined() throws IOException {
    378 	try {
    379 	    URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    380 		    .getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    381 		    + "/Negative01/");
    382
    383 	    JDOHelper.getPersistenceManagerFactory(loader);
    384 	    fail("JDOHelper failed to throw JDOFatalUserException");
    385 	} catch (JDOFatalUserException x) {
    386 	    // joy, sweet joy
    387 	}
    388     }
    389
    390     public void testNegative02_DuplicateAnonymousPersistenceUnitsInSameConfig()
    391 	    throws IOException {
    392 	try {
    393 	    URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    394 		    .getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    395 		    + "/Negative02/");
    396
    397 	    JDOHelper.getPersistenceManagerFactory(loader);
    398 	    fail("JDOHelper failed to throw JDOFatalUserException");
    399 	} catch (JDOFatalUserException x) {
    400 	    // the cockles of my heart warmeth
    401 	}
    402     }
    403
    404     public void testNegative03_DuplicateNamedPersistenceUnitsInSameConfig()
    405 	    throws IOException {
    406 	try {
    407 	    URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    408 		    .getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    409 		    + "/Negative03/");
    410
    411 	    JDOHelper.getPersistenceManagerFactory("name.negative03", loader);
    412
    413 	    fail("JDOHelper failed to throw JDOFatalUserException");
    414 	} catch (JDOFatalUserException x) {
    415 	    // warm fuzzies
    416 	}
    417     }
    418
    419     public void testNegative04_DuplicatePUNamePropertyInAttributeAndElement()
    420 	    throws IOException {
    421 	try {
    422 	    URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    423 		    .getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    424 		    + "/Negative04/");
    425
    426 	    JDOHelper.getPersistenceManagerFactory("name.negative04.value0",
    427 		    loader);
    428
    429 	    fail("JDOHelper failed to throw JDOFatalUserException");
    430 	} catch (JDOFatalUserException x) {
    431 	    // no cold pricklies
    432 	}
    433     }
    434
    435     public void testNegative05_DuplicatePropertyInAttributeAndElement()
    436 	    throws IOException {
    437 	try {
    438 	    URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    439 		    .getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    440 		    + "/Negative05/");
    441
    442 	    JDOHelper.getPersistenceManagerFactory(loader);
    443
    444 	    fail("JDOHelper failed to throw JDOFatalUserException");
    445 	} catch (JDOFatalUserException x) {
    446 	    // party!
    447 	}
    448     }
    449
    450     public void testNegative06_DuplicatePUInDifferentConfigFiles()
    451 	    throws IOException {
    452 	try {
    453 	    URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    454 		    .getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    455 		    + "/Negative06/6a/", JDOCONFIG_CLASSPATH_PREFIX
    456 		    + "/Negative06/6b/");
    457
    458 	    JDOHelper.getPersistenceManagerFactory("name.negative06", loader);
    459
    460 	    fail("JDOHelper failed to throw JDOFatalUserException");
    461 	} catch (JDOFatalUserException x) {
    462 	    // clear blue sky
    463 	}
    464     }
    465
    466     public void testNegative07_EmptyServicesFile() throws IOException {
    467 	JDOConfigTestClassLoader testLoader = new JDOConfigTestClassLoader(
    468 		getClass().getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    469 			+ "/Negative07/");
    470 	String shouldBeNull = getPMFClassNameViaServiceLookup(testLoader);
    471 	assertNull(shouldBeNull);
    472     }
    473
    474     public void testNegative08_NoResourcesFound() {
    475 	String resource = "" + RANDOM.nextLong();
    476
    477 	InputStream in = getClass().getClassLoader().getResourceAsStream(
    478 		resource);
    479 	assertNull(in);
    480
    481 	// resource pretty much guaranteed not to exist
    482 	try {
    483 	    JDOHelper.getPersistenceManagerFactory(resource);
    484 	    fail("JDOHelper failed to throw JDOFatalUserException");
    485 	} catch (JDOFatalUserException x) {
    486 	    // happy path
    487 	}
    488     }
    489
    490     public void testNegative08_ServicesFileWithOnlyComments()
    491 	    throws IOException {
    492 	JDOConfigTestClassLoader testLoader = new JDOConfigTestClassLoader(
    493 		getClass().getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    494 			+ "/Negative08/");
    495 	String shouldBeNull = getPMFClassNameViaServiceLookup(testLoader);
    496 	assertNull(shouldBeNull);
    497     }
    498
    499     public void testNegative09_MultipleInvalidClassesInDifferentServicesFiles()
    500 	    throws IOException {
    501
    502 	// no class name in Negative09/jdoconfig.xml
    503 	// 9a and 9b include services/javax.jdo.PersistenceManagerFactory
    504 	// with bad implementations
    505 	try {
    506 	    URLClassLoader loader = new JDOConfigTestClassLoader(getClass()
    507 		    .getClassLoader(), JDOCONFIG_CLASSPATH_PREFIX
    508 		    + "/Negative09/9a/", JDOCONFIG_CLASSPATH_PREFIX
    509 		    + "/Negative09/9b/", TEST_CLASSPATH, API_CLASSPATH);
    510
    511 	    JDOHelper.getPersistenceManagerFactory("name.negative09", loader);
    512
    513 	    fail("JDOHelper failed to throw JDOFatalUserException");
    514 	} catch (JDOFatalException x) {
    515
    516 	    Throwable[] nestedExceptions = x.getNestedExceptions();
    517 	    if (nestedExceptions.length != 2) {
    518 		appendMessage("JDOHelper.getPersistenceManagerFactory wrong number of "
    519 			+ "nested exceptions. Expected 2, got "
    520 			+ nestedExceptions.length + "\n" + x);
    521 	    }
    522 	    for (int i = 0; i < nestedExceptions.length; ++i) {
    523 		Throwable exception = nestedExceptions[i];
    524 		if (!(exception instanceof JDOFatalException)) {
    525 		    appendMessage("Nested exception "
    526 			    + exception.getClass().getName()
    527 			    + " is not a JDOFatalException.");
    528 		}
    529 	    }
    530 	}
    531 	failOnError();
    532     }
    533 }