| /* |
| * Copyright (c) 1998, 2021 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 v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // 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; |
| } |
| |
| /** |
| * 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. |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| public void execute(TestExecutor executor) throws Throwable { |
| setSummary(new TestResultsSummary(this)); |
| setExecutor(executor); |
| long startTime = System.nanoTime(); |
| 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.nanoTime(); |
| 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. |
| */ |
| @Override |
| 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 |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| 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 |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| public junit.framework.Test testAt(int index) { |
| if (isSetup() || (!getTests().isEmpty())) { |
| return super.testAt(index); |
| } |
| return (junit.framework.Test)getFinishedTests().elementAt(index); |
| } |
| } |