/******************************************************************************* * 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.testing.framework; import java.io.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.persistence.internal.helper.ConversionManager; import org.eclipse.persistence.sessions.DatabaseSession; import org.eclipse.persistence.sessions.Project; import org.eclipse.persistence.sessions.Session; import org.eclipse.persistence.logging.SessionLog; import org.eclipse.persistence.sessions.DatabaseLogin; import org.eclipse.persistence.sessions.Login; import org.eclipse.persistence.testing.framework.TestExecutor; import org.eclipse.persistence.sessions.factories.SessionManager; /** * <p><b>Purpose</b>: Test model is a collection of test suites and/or sub test models. When a * test model is executed all the test suites and models registered with it are * executed one by one. */ public class TestModel extends TestCollection { /** Configurations that must be set before this model is run */ private Vector requiredSystems; /** The model will force these Configurations to be set even if they are set before */ private Vector forcedRequiredSystems; /** Used to store tests added when the model is built. */ private Vector originalTests; /** Keep track of setup state. */ private boolean isSetup; /** Ensure the login and log are not corrupted if the session is changed. */ private Login login; private SessionLog sessionLog; /** * Flag used to determine if tables should be recreated/populated before each test model. * true means tests will take longer to run, but run more consistently as bad tests will not effect other models. * Uses system property "org.eclipse.persistence.testing.reset-system". */ private static Boolean shouldResetSystemAfterEachTestModel; /** * Flag used to determine if tables should be recreated/populated before each test model. * true means tests will take longer to run, but run more consistently as bad tests will not effect other models. * Uses system property "org.eclipse.persistence.testing.reset-system". */ public static boolean shouldResetSystemAfterEachTestModel() { if (shouldResetSystemAfterEachTestModel == null) { String systemProperty = System.getProperty("org.eclipse.persistence.testing.reset-system"); if (systemProperty == null) { shouldResetSystemAfterEachTestModel = Boolean.TRUE; } else { if (systemProperty.equals("false")) { shouldResetSystemAfterEachTestModel = Boolean.FALSE; } else { shouldResetSystemAfterEachTestModel = Boolean.TRUE; } } } return shouldResetSystemAfterEachTestModel.booleanValue(); } /** * Flag used to determine if tables should be recreated/populated before each test model. * true means tests will take longer to run, but run more consistently as bad tests will not effect other models. * Uses system property "org.eclipse.persistence.testing.reset-system". */ public static void setShouldResetSystemAfterEachTestModel(boolean value) { if (value) { shouldResetSystemAfterEachTestModel = Boolean.TRUE; } else { shouldResetSystemAfterEachTestModel = Boolean.FALSE; } } public TestModel() { this.requiredSystems = new Vector(); this.forcedRequiredSystems = new Vector(); this.isSetup = false; this.originalTests = new Vector(); } /** * The system add will be forced to be initialized again even if it is already configured. * Basically this means that required system will recreate new database. */ public final void addForcedRequiredSystem(TestSystem requiredSystem) { getForcedRequiredSystems().addElement(requiredSystem); } /** * The system add will be forced to be initialized again even if it is already configured. * Basically this means that required system will recreate new database. This method should always * be overwritten in the subclasses if the model needs some persistence system to be already configured * before it is run. */ public void addForcedRequiredSystems() { } /** * The system add will be configured if it has not been already configured. * Basically this means that required system will recreate new database. */ public final void addRequiredSystem(TestSystem requiredSystem) { getRequiredSystems().addElement(requiredSystem); } /** * The system add will be configured if it has not been already configured. * Basically this means that required system will recreate new database. * This method should always be overwritten in the subclasses if the model * needs some persistence system to be already configured before it is run. */ public void addRequiredSystems() { } /** * The subclasses must overwrite this method. To add tests to the model. * It could be collection of test suites or test models themselves. */ public void addTests() { } /** * The subclasses must overwrite this method. To add tests to the model. * It could be collection of test suites or test models themselves. */ public void addSRGTests() { } /** * Build the required systems, but ensure that the variable is not modified. */ public Vector buildForcedRequiredSystems() { Vector constructedSystems = (Vector)getForcedRequiredSystems().clone(); addForcedRequiredSystems(); Vector allSystems = getForcedRequiredSystems(); setForcedRequiredSystems(constructedSystems); return allSystems; } /** * Build the required systems, but ensure that the variable is not modified. */ public Vector buildRequiredSystems() { Vector constructedSystems = (Vector)getRequiredSystems().clone(); addRequiredSystems(); Vector allSystems = getRequiredSystems(); setRequiredSystems(constructedSystems); return allSystems; } /** * Goes through each systems and configures them. */ private void configure() throws Exception { Vector systems = buildRequiredSystems(); for (Enumeration enumtr = systems.elements(); enumtr.hasMoreElements();) { TestSystem system = (TestSystem)enumtr.nextElement(); // To improve test consistency always force systems to be reset. if (shouldResetSystemAfterEachTestModel()) { getExecutor().forceConfigureSystem(system); } else { getExecutor().configureSystem(system); } } systems = buildForcedRequiredSystems(); for (Enumeration enumtr = systems.elements(); enumtr.hasMoreElements();) { TestSystem system = (TestSystem)enumtr.nextElement(); getExecutor().forceConfigureSystem(system); } } /** * Executes all the test entities in the collection. */ public void execute(TestExecutor executor) throws Throwable { setSummary(new TestResultsSummary(this)); setExecutor(executor); long startTime = System.currentTimeMillis(); try { setupEntity(); setFinishedTests(new Vector()); try { for (Enumeration tests = getTests().elements(); tests.hasMoreElements();) { junit.framework.Test test = (junit.framework.Test)tests.nextElement(); if ((TestExecutor.getDefaultJUnitTestResult() != null) && TestExecutor.getDefaultJUnitTestResult().shouldStop()) { break; } executor.execute(test); getFinishedTests().addElement(test); } } catch (Throwable exception) { try { resetEntity(); } catch (Throwable ignore) { } throw exception; } resetEntity(); } finally { long endTime = System.currentTimeMillis(); getSummary().setTotalTime(endTime - startTime); } } /** * Return all the required systems that need to be configured even if they are already configured. */ public Vector getForcedRequiredSystems() { return forcedRequiredSystems; } /** * Return test that existed before setup. */ protected Vector getOriginalTests() { return originalTests; } /** * Return all the required systems that need to be configured if they are not already configured. */ public Vector getRequiredSystems() { return requiredSystems; } public boolean isSetup() { return isSetup; } /** * Format the test output on the print stream. */ protected void logFootNote(Writer log) { try { log.write(org.eclipse.persistence.internal.helper.Helper.cr() + getIndentationString() + "RESULTS OF TEST MODEL: " + getName() + org.eclipse.persistence.internal.helper.Helper.cr()); } catch (IOException exception) { } } /** * Format the test output on the print stream. * This method is added to migrate tests to Ora*Tst */ protected void logRegressionHeadNote(Writer log) { try { log.write(org.eclipse.persistence.internal.helper.Helper.cr() + getIndentationString() + "TEST MODEL NAME: " + getName() + org.eclipse.persistence.internal.helper.Helper.cr()); log.write(getIndentationString() + "MODEL DESCRIPTION: " + getDescription() + org.eclipse.persistence.internal.helper.Helper.cr()); } catch (IOException exception) { } } /** * Format the test output on the print stream. */ protected void logHeadNote(Writer log) { try { log.write(org.eclipse.persistence.internal.helper.Helper.cr() + getIndentationString() + "VERSION: " + org.eclipse.persistence.sessions.DatabaseLogin.getVersion()); log.write(org.eclipse.persistence.internal.helper.Helper.cr() + getIndentationString() + "TEST MODEL NAME: " + getName() + org.eclipse.persistence.internal.helper.Helper.cr()); log.write(getIndentationString() + "MODEL DESCRIPTION: " + getDescription() + org.eclipse.persistence.internal.helper.Helper.cr()); } catch (IOException exception) { } } /** * This is a optional method and it should be overridden if their is something * that test collection should perform after running itself. */ public void reset() { return; } /** * If setupEntity has been called then this must be called to reset the model again. */ public void resetEntity() { if (isSetup()) { setTests(getOriginalTests()); setIsSetup(false); } if(this.getSummary().didSetupWarn()) { return; } reset(); // To improve test consistency cleanup the session and executor better. getSession().getIdentityMapAccessor().initializeIdentityMaps(); if (shouldResetSystemAfterEachTestModel()) { getExecutor().setConfiguredSystems(new Vector()); // Logout and clean/reset the session in case test model failed ungracefully. if (getSession().isDatabaseSession()) { try { getDatabaseSession().logout(); } catch (Exception ignore) { } } if (this.login == null) { this.login = getSession().getDatasourceLogin(); this.sessionLog = getSession().getSessionLog(); } // Check if login or log were corrupted. if (this.login.getClass() != getSession().getDatasourceLogin().getClass()) { System.out.println("Login changed by test model:" + this); } if (this.sessionLog.getLevel() != getSession().getSessionLog().getLevel()) { System.out.println("Log level changed by test model:" + this); } if (this.login instanceof DatabaseLogin) { DatabaseLogin login = (DatabaseLogin)this.login; if (login.shouldBindAllParameters() != getSession().getLogin().shouldBindAllParameters()) { System.out.println("Binding changed by test model:" + this); } if (login.shouldCacheAllStatements() != getSession().getLogin().shouldCacheAllStatements()) { System.out.println("Statement caching changed by test model:" + this); } if (login.shouldUseBatchWriting() != getSession().getLogin().shouldUseBatchWriting()) { System.out.println("Batch writing changed by test model:" + this); } if (login.shouldUseJDBCBatchWriting() != getSession().getLogin().shouldUseJDBCBatchWriting()) { System.out.println("JDBC batch writing changed by test model:" + this); } if (login.shouldUseNativeSQL() != getSession().getLogin().shouldUseNativeSQL()) { System.out.println("Native SQL changed by test model:" + this); } if (login.getTableQualifier() != getSession().getLogin().getTableQualifier()) { System.out.println("Table qualifier changed by test model:" + this); } } DatabaseSession session = new Project(this.login).createDatabaseSession(); session.setSessionLog(this.sessionLog); getExecutor().setSession(session); // Check if default conversion manager was corrupted. if (!ConversionManager.getDefaultManager().shouldUseClassLoaderFromCurrentThread()) { System.out.println("ConversionManager corrupted by test model:" + this); } ConversionManager.setDefaultManager(null); getSession().getDatasourceLogin().getDatasourcePlatform().setConversionManager(null); SessionManager.getManager().setSessions(new ConcurrentHashMap<String, Session>()); getDatabaseSession().login(); } setIsSetup(false); } /** * Set all the required systems that need to be configured even if they are already configured. */ public void setForcedRequiredSystems(Vector systems) { this.forcedRequiredSystems = systems; } protected void setIsSetup(boolean isSetup) { this.isSetup = isSetup; } /** * Set the test that existed before setup. */ protected void setOriginalTests(Vector originalTests) { this.originalTests = originalTests; } /** * Set all the required sytems that need to be configured if they are not already configured. */ public void setRequiredSystems(Vector systems) { this.requiredSystems = systems; } /** * This is a optional method and it should be overridden if their is something * that test collection should perform before running itself. */ public void setup() { return; } /** * To set up the model also look at resetEntity */ public void setupEntity() throws Throwable { if (isSetup()) { return; } if (getSession() != null) { // Force field names to uppercase for postgres. if (getSession().getDatasourcePlatform().isPostgreSQL()) { getSession().getPlatform().setShouldForceFieldNamesToUpperCase(true); } this.login = getSession().getDatasourceLogin().clone(); this.sessionLog = (SessionLog)getSession().getSessionLog().clone(); } try { setOriginalTests((Vector)getTests().clone()); configure(); setup(); if (isSRG) { addSRGTests(); } else { addTests(); } // Check for faulty models leaving transaction open. if ((getAbstractSession() != null) && getAbstractSession().isInTransaction()) { try { int count = 0; while (getAbstractSession().isInTransaction() && (count < 10)) { getAbstractSession().rollbackTransaction(); count++; } } catch (Throwable ignore) { } TestProblemException exception = new TestProblemException(this + " is a faulty test, transaction was left open and must always be closed."); throw exception; } } catch (Throwable exception) { getSummary().setSetupException(exception); try { resetEntity(); } catch (Throwable resetException) { } throw exception; } setIsSetup(true); } /** * Returns the number of tests in this suite. * If not setup, return the finished tests. */ public int testCount() { if (isSetup() || (!getTests().isEmpty())) { return super.testCount(); } return getFinishedTests().size(); } /** * Returns the tests as an enumeration. * If not setup, return the finished tests. */ public Enumeration tests() { if (isSetup() || (!getTests().isEmpty())) { return super.tests(); } return getFinishedTests().elements(); } /** * Returns the test at the given index. * If not setup, return the finished tests. */ public junit.framework.Test testAt(int index) { if (isSetup() || (!getTests().isEmpty())) { return super.testAt(index); } return (junit.framework.Test)getFinishedTests().elementAt(index); } }