/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.test.platformsplugin.model; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; import java.util.SortedSet; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.eclipse.persistence.tools.workbench.platformsmodel.CorruptXMLException; import org.eclipse.persistence.tools.workbench.platformsmodel.DatabasePlatform; import org.eclipse.persistence.tools.workbench.platformsmodel.DatabasePlatformRepository; import org.eclipse.persistence.tools.workbench.platformsmodel.DatabaseType; import org.eclipse.persistence.tools.workbench.platformsmodel.JDBCType; import org.eclipse.persistence.tools.workbench.platformsmodel.JDBCTypeRepository; import org.eclipse.persistence.tools.workbench.platformsmodel.JDBCTypeToDatabaseTypeMapping; import org.eclipse.persistence.tools.workbench.platformsmodel.JDBCTypeToJavaTypeDeclarationMapping; import org.eclipse.persistence.tools.workbench.platformsmodel.JavaTypeDeclaration; import org.eclipse.persistence.tools.workbench.platformsmodel.JavaTypeDeclarationToJDBCTypeMapping; import org.eclipse.persistence.tools.workbench.test.platformsplugin.TestDatabasePlatformRepositoryFactory; import org.eclipse.persistence.tools.workbench.test.utility.TestTools; import org.eclipse.persistence.tools.workbench.utility.AbstractModel; import org.eclipse.persistence.tools.workbench.utility.ClassTools; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; import org.eclipse.persistence.tools.workbench.utility.diff.Diff; import org.eclipse.persistence.tools.workbench.utility.diff.DiffEngine; import org.eclipse.persistence.tools.workbench.utility.diff.ReflectiveDifferentiator; import org.eclipse.persistence.tools.workbench.utility.io.FileTools; import org.eclipse.persistence.tools.workbench.utility.iterators.TransformationIterator; import org.eclipse.persistence.tools.workbench.utility.node.AbstractNodeModel; public class DatabasePlatformRepositoryTests extends TestCase { private DatabasePlatformRepository repository; public static Test suite() { return new TestSuite(DatabasePlatformRepositoryTests.class); } public DatabasePlatformRepositoryTests(String name) { super(name); } /** * Hack-o-rama: * Some I/O-related tests (e.g. DatabasePlatformTests#testCorruptXMLMissingRoot()) * fail about 50% of the time because DatabasePlatformRepository#writePlatforms() * will fail trying to create the 'platforms' subdirectory. (Other tests also fail for the * same reason - DatabasePlatformTests#testCorruptXMLMissingName() in particular - * but the "missing root" test seems to fail the most. This might be related to the fact * that the "missing root" test is the first I/O-related test in the DatabasePlatformTests * suite. This is true across the suites: The first I/O-related test will fail the most often, * at least when executing the suites individually, as opposed to under the AllTests * umbrella suite....) * * I can't, for the life of me, figure out what is causing the problem. It appears to be * a timing problem where the JVM and the O/S are slightly out of synch. * Anyway, waiting a second and trying again seems to fix the problem. Also, the * state of the repository should be OK to repeat the write, since creating the * 'platforms' directory is the first thing done in the write. * ~bjv */ static void write(DatabasePlatformRepository repository) throws Exception { try { repository.write(); } catch (RuntimeException ex) { if (ex.getMessage().startsWith("unable to create platforms directory: ")) { Thread.sleep(1000); // System.out.println("write problem: " + this.getName()); repository.write(); } } } protected void setUp() throws Exception { super.setUp(); this.repository = TestDatabasePlatformRepositoryFactory.instance().createRepository(); } protected void tearDown() throws Exception { TestTools.clear(this); super.tearDown(); } public void testName() { assertEquals("Test Repository", this.repository.getName()); boolean exCaught = false; try { this.repository.setName(null); } catch (NullPointerException ex) { exCaught = true; } assertTrue(exCaught); assertEquals("Test Repository", this.repository.getName()); } public void testFile() throws Exception { assertNull(this.repository.getFile()); boolean exCaught = false; try { this.repository.setFile(null); } catch (NullPointerException ex) { exCaught = true; } assertTrue(exCaught); assertNull(this.repository.getFile()); // now set the file and write out the repository File file = this.buildTestRepositoryFile(); this.repository.setFile(file); DatabasePlatformRepositoryTests.write(this.repository); assertTrue(this.repository.isCleanBranch()); assertTrue(file.exists()); // now change the name of the file but not its location this.repository.setFile(this.buildAlternateTestRepositoryFile()); assertTrue(this.repository.isDirty()); for (Iterator stream = this.repository.platforms(); stream.hasNext(); ) { DatabasePlatform platform = (DatabasePlatform) stream.next(); assertTrue(platform.isCleanBranch()); } DatabasePlatformRepositoryTests.write(this.repository); assertTrue(this.repository.isCleanBranch()); assertFalse(file.exists()); // now change the location of the file but not its name this.repository.setFile(this.buildAlternateTestRepositoryLocationFile()); assertTrue(this.repository.isDirty()); for (Iterator stream = this.repository.platforms(); stream.hasNext(); ) { DatabasePlatform platform = (DatabasePlatform) stream.next(); assertTrue(platform.isDirty()); } DatabasePlatformRepositoryTests.write(this.repository); assertTrue(this.repository.isCleanBranch()); } private File buildAlternateTestRepositoryLocationFile() throws Exception { return new File(this.buildAlternateTestRepositoryDirectory(), "alternate test repos.dpr"); } private File buildAlternateTestRepositoryFile() throws Exception { return new File(this.buildTestRepositoryDirectory(), "alternate test repos.dpr"); } private File buildTestRepositoryFile() throws Exception { return new File(this.buildTestRepositoryDirectory(), "test repos.dpr"); } private File buildTestRepositoryDirectory() throws Exception { // C:/temp/DatabasePlatformRepositoryTests return FileTools.emptyTemporaryDirectory(ClassTools.shortClassNameForObject(this) + "." + this.getName()); } private File buildAlternateTestRepositoryDirectory() throws Exception { // C:/temp/alternate DatabasePlatformRepositoryTests return FileTools.emptyTemporaryDirectory(ClassTools.shortClassNameForObject(this) + "." + this.getName() + "." + "alternate"); } public void testPlatforms() throws Exception { assertEquals(3, this.repository.platformsSize()); Iterator stream = this.repository.platforms(); stream.next(); stream.remove(); assertEquals(2, this.repository.platformsSize()); } public void testAddPlatform() throws Exception { boolean exCaught = false; try { this.repository.addPlatform("Foo Platform", "xxx"); } catch (IllegalArgumentException ex) { if (ex.getMessage().indexOf("Foo Platform") != -1) { exCaught = true; } } assertTrue(exCaught); exCaught = false; try { this.repository.addPlatform("Joo Platform", "fooplatform.xml"); } catch (IllegalArgumentException ex) { if (ex.getMessage().indexOf("fooplatform.xml") != -1) { exCaught = true; } } assertTrue(exCaught); } public void testDefaultPlatform() throws Exception { DatabasePlatform platform = this.repository.platformNamed("Foo Platform"); assertEquals(platform, this.repository.getDefaultPlatform()); this.repository.removePlatform(platform); assertFalse(this.repository.getDefaultPlatform().equals(platform)); for (Iterator stream = this.repository.platforms(); stream.hasNext(); ) { stream.next(); stream.remove(); } assertNull(this.repository.getDefaultPlatform()); } public void testRuntimePlatform() throws Exception { DatabasePlatform platform = this.repository.platformNamed("Foo Platform"); assertEquals(platform, this.repository.platformForRuntimePlatformClassNamed("com.foo.FooPlatform")); } public void testProblems() throws Exception { for (Iterator stream = this.repository.platforms(); stream.hasNext(); ) { stream.next(); stream.remove(); } this.repository.validateBranch(); assertEquals(1, this.repository.problemsSize()); } public void testClonePlatform() throws Exception { DatabasePlatform original = this.repository.platformNamed("Foo Platform"); DatabasePlatform clone = this.repository.clone(original); assertNotSame(original, clone); assertFalse(original.getName().equals(clone.getName())); assertEquals("Foo Platform2", clone.getName()); assertFalse(original.getShortFileName().equals(clone.getShortFileName())); assertEquals("fooplatform2.xml", clone.getShortFileName()); assertEquals(original.getRuntimePlatformClassName(), clone.getRuntimePlatformClassName()); assertEquals(original.supportsNativeSequencing(), clone.supportsNativeSequencing()); assertEquals(original.supportsIdentityClause(), clone.supportsIdentityClause()); assertEquals(original.databaseTypesSize(), clone.databaseTypesSize()); assertEquals(this.typeNamesFor(original.databaseTypes()), this.typeNamesFor(clone.databaseTypes())); for (Iterator stream = original.databaseTypes(); stream.hasNext(); ) { DatabaseType originalType = (DatabaseType) stream.next(); DatabaseType cloneType = clone.databaseTypeNamed(originalType.getName()); assertNotSame(originalType, cloneType); this.verifyType(originalType, cloneType); } assertEquals(original.jdbcTypeToDatabaseTypeMappingsSize(), clone.jdbcTypeToDatabaseTypeMappingsSize()); for (Iterator stream = original.jdbcTypeToDatabaseTypeMappings(); stream.hasNext(); ) { JDBCTypeToDatabaseTypeMapping mapping = (JDBCTypeToDatabaseTypeMapping) stream.next(); DatabaseType originalDatabaseType = mapping.getDatabaseType(); DatabaseType cloneDatabaseType = clone.databaseTypeForJDBCTypeCode(mapping.getJDBCType().getCode()); assertNotSame(originalDatabaseType, cloneDatabaseType); assertEquals(originalDatabaseType.getName(), cloneDatabaseType.getName()); } } private SortedSet typeNamesFor(Iterator databaseTypes) { return CollectionTools.sortedSet(this.names(databaseTypes)); } private Iterator names(Iterator databaseTypes) { return new TransformationIterator(databaseTypes) { protected Object transform(Object next) { return ((DatabaseType) next).getName(); } }; } private void verifyType(DatabaseType originalType, DatabaseType cloneType) { assertEquals(originalType.getName(), cloneType.getName()); assertEquals(originalType.allowsSize(), cloneType.allowsSize()); assertEquals(originalType.requiresSize(), cloneType.requiresSize()); assertEquals(originalType.getInitialSize(), cloneType.getInitialSize()); assertEquals(originalType.allowsSubSize(), cloneType.allowsSubSize()); assertEquals(originalType.allowsNull(), cloneType.allowsNull()); assertSame(originalType.getJDBCType(), cloneType.getJDBCType()); } public void testIO() throws Exception { DatabasePlatformRepository repos1 = DatabasePlatformRepository.getDefault(); File file = this.buildTestRepositoryFile(); repos1.setFile(file); repos1.write(); DatabasePlatformRepository repos2 = new DatabasePlatformRepository(file); DiffEngine diffEngine = this.buildDiffEngine(); // diffEngine.setLog("C:/temp/diff.log"); Diff diff = diffEngine.diff(repos1, repos2); assertTrue(diff.getDescription(), diff.identical()); } private DiffEngine buildDiffEngine() { DiffEngine diffEngine = new DiffEngine(); ReflectiveDifferentiator rd; rd = diffEngine.addReflectiveDifferentiator(AbstractModel.class, "changeSupport"); rd = diffEngine.addReflectiveDifferentiator(AbstractNodeModel.class); rd.ignoreFieldsNamed(new String[] {"branchProblems", "dirty", "dirtyBranch", "problems"}); rd.addReferenceFieldNamed("parent"); rd = diffEngine.addReflectiveDifferentiator(this.classForName("org.eclipse.persistence.tools.workbench.platformsmodel.AbstractJDBCTypeToJavaTypeDeclarationMapping")); rd.addKeyFieldsNamed("jdbcType", "javaTypeDeclaration"); rd.addReferenceFieldNamed("jdbcType"); rd = diffEngine.addReflectiveDifferentiator(JavaTypeDeclarationToJDBCTypeMapping.class); rd = diffEngine.addReflectiveDifferentiator(JDBCTypeToJavaTypeDeclarationMapping.class); rd = diffEngine.addReflectiveDifferentiator(DatabasePlatform.class); rd.addKeyFieldNamed("name"); rd.addCollectionFieldsNamed("databaseTypes", "jdbcTypeToDatabaseTypeMappings"); rd = diffEngine.addReflectiveDifferentiator(DatabasePlatformRepository.class); rd.addKeyFieldNamed("name"); rd.ignoreFieldsNamed("file", "originalFile", "originalPlatformShortFileNames"); rd.addReferenceFieldNamed("defaultPlatform"); rd.addCollectionFieldNamed("platforms"); rd = diffEngine.addReflectiveDifferentiator(DatabaseType.class); rd.addKeyFieldNamed("name"); rd.addReferenceFieldNamed("jdbcType"); rd = diffEngine.addReflectiveDifferentiator(JavaTypeDeclaration.class); rd.addKeyFieldsNamed("javaClassName", "arrayDepth"); rd = diffEngine.addReflectiveDifferentiator(JDBCType.class); rd.addKeyFieldNamed("name"); rd = diffEngine.addReflectiveDifferentiator(JDBCTypeRepository.class); rd.addReferenceFieldNamed("defaultJDBCType"); rd.addCollectionFieldsNamed("javaTypeDeclarationToJDBCTypeMappings", "jdbcTypes", "jdbcTypeToJavaTypeDeclarationMappings"); rd = diffEngine.addReflectiveDifferentiator(JDBCTypeToDatabaseTypeMapping.class); rd.addKeyFieldNamed("jdbcType"); rd.addReferenceFieldsNamed("jdbcType", "databaseType"); return diffEngine; } private Class classForName(String className) { try { return Class.forName(className); } catch (ClassNotFoundException ex) { throw new RuntimeException(ex); } } public void testNewPlatformWrite() throws Exception { File reposFile = this.buildTestRepositoryFile(); this.repository.setFile(reposFile); DatabasePlatformRepositoryTests.write(this.repository); assertTrue(reposFile.exists()); reposFile.delete(); assertFalse(reposFile.exists()); DatabasePlatform fooPlatform = this.repository.platformNamed("Foo Platform"); File fooFile = new File(this.platformsDirectory(this.repository), fooPlatform.getShortFileName()); fooFile.delete(); assertFalse(fooFile.exists()); DatabasePlatform clonePlatform = this.repository.clone(fooPlatform); // this should write the clone's file but not the repository's or the original's files DatabasePlatformRepositoryTests.write(this.repository); assertFalse(reposFile.exists()); assertFalse(fooFile.exists()); File cloneFile = new File(this.platformsDirectory(this.repository), clonePlatform.getShortFileName()); assertTrue(cloneFile.exists()); // this should cause the repository's file to be written this.repository.setDefaultPlatform(clonePlatform); DatabasePlatformRepositoryTests.write(this.repository); assertTrue(reposFile.exists()); } public void testPlatformOnlyWrite() throws Exception { File reposFile = this.buildTestRepositoryFile(); this.repository.setFile(reposFile); DatabasePlatformRepositoryTests.write(this.repository); assertTrue(reposFile.exists()); reposFile.delete(); assertFalse(reposFile.exists()); DatabasePlatform fooPlatform = this.repository.platformNamed("Foo Platform"); File fooFile = new File(this.platformsDirectory(this.repository), fooPlatform.getShortFileName()); fooFile.delete(); assertFalse(fooFile.exists()); DatabasePlatform barPlatform = this.repository.platformNamed("Bar Platform"); File barFile = new File(this.platformsDirectory(this.repository), barPlatform.getShortFileName()); barFile.delete(); assertFalse(barFile.exists()); DatabasePlatform bazPlatform = this.repository.platformNamed("Baz Platform"); File bazFile = new File(this.platformsDirectory(this.repository), bazPlatform.getShortFileName()); bazFile.delete(); assertFalse(bazFile.exists()); // ONLY the repository file should be written out this.repository.setDefaultPlatform(barPlatform); DatabasePlatformRepositoryTests.write(this.repository); assertTrue(reposFile.exists()); assertFalse(fooFile.exists()); assertFalse(barFile.exists()); assertFalse(bazFile.exists()); } public void testPlatformFileDelete() throws Exception { File reposFile = this.buildTestRepositoryFile(); this.repository.setFile(reposFile); DatabasePlatformRepositoryTests.write(this.repository); DatabasePlatform fooPlatform = this.repository.platformNamed("Foo Platform"); File fooFile = new File(this.platformsDirectory(this.repository), fooPlatform.getShortFileName()); DatabasePlatform barPlatform = this.repository.platformNamed("Bar Platform"); File barFile = new File(this.platformsDirectory(this.repository), barPlatform.getShortFileName()); DatabasePlatform bazPlatform = this.repository.platformNamed("Baz Platform"); File bazFile = new File(this.platformsDirectory(this.repository), bazPlatform.getShortFileName()); assertTrue(reposFile.exists()); assertTrue(fooFile.exists()); assertTrue(barFile.exists()); assertTrue(bazFile.exists()); // the baz file should be deleted this.repository.removePlatform(barPlatform); DatabasePlatformRepositoryTests.write(this.repository); assertTrue(reposFile.exists()); assertTrue(fooFile.exists()); assertFalse(barFile.exists()); assertTrue(bazFile.exists()); } public void testCorruptXMLMissingRoot() throws Exception { this.verifyCorruptXML(new String[] {"<platforms>", "<bogus>", "</platforms>", "</bogus>"}); } public void testCorruptXMLMissingName() throws Exception { this.verifyCorruptXML("<name>Test Repository</name>", "<repos-name>Test Repository</repos-name>"); } public void testCorruptXMLMissingDefaultPlatform() throws Exception { this.verifyCorruptXML("<default-platform>Foo Platform</default-platform>", "<default-xxx>Foo Platform</default-xxx>"); } public void testCorruptXMLInvalidDefaultPlatform() throws Exception { this.verifyCorruptXML("<default-platform>Foo Platform</default-platform>", "<default-platform>XXX Platform</default-platform>"); } private String platformsDirectoryName() { return TestDatabasePlatformRepositoryFactory.platformsDirectoryName(); } private File platformsDirectory(DatabasePlatformRepository repos) { return new File(repos.getFile().getParentFile(), this.platformsDirectoryName()); } public void testCorruptXMLDefaultPlatformButNoPlatforms() throws Exception { File file = this.buildTestRepositoryFile(); this.repository.setFile(file); DatabasePlatformRepositoryTests.write(this.repository); File dir = this.platformsDirectory(this.repository); FileTools.deleteDirectoryContents(dir); boolean exCaught = false; try { DatabasePlatformRepository bogusRepository = new DatabasePlatformRepository(file); assertNull(bogusRepository); } catch (CorruptXMLException ex) { exCaught = true; } assertTrue(exCaught); } public void testCorruptXMLDuplicatePlatform() throws Exception { File file = this.buildTestRepositoryFile(); this.repository.setFile(file); DatabasePlatformRepositoryTests.write(this.repository); File dir = this.platformsDirectory(this.repository); FileTools.copyToFile(new File(dir, "fooplatform.xml"), new File(dir, "xxxplatform.xml")); boolean exCaught = false; try { DatabasePlatformRepository bogusRepository = new DatabasePlatformRepository(file); assertNull(bogusRepository); } catch (CorruptXMLException ex) { exCaught = true; } assertTrue(exCaught); } private void verifyCorruptXML(String string, String bogusString) throws Exception { this.verifyCorruptXML(new String[] {string, bogusString}); } private void verifyCorruptXML(String[] stringPairs) throws Exception { File file = this.buildTestRepositoryFile(); this.repository.setFile(file); DatabasePlatformRepositoryTests.write(this.repository); InputStream inStream = new BufferedInputStream(new FileInputStream(file)); int fileSize = inStream.available(); byte[] buf = new byte[fileSize]; inStream.read(buf); inStream.close(); String rawDocument = new String(buf); for (int i = 0; i < stringPairs.length; ) { rawDocument = rawDocument.replaceAll(stringPairs[i], stringPairs[i + 1]); i += 2; } OutputStream outStream = new BufferedOutputStream(new FileOutputStream(file), 2048); outStream.write(rawDocument.getBytes()); outStream.close(); boolean exCaught = false; try { DatabasePlatformRepository bogusRepository = new DatabasePlatformRepository(file); assertNull(bogusRepository); } catch (CorruptXMLException ex) { exCaught = true; } assertTrue(exCaught); } }