package org.ovirt.engine.core.dao;

import java.sql.Connection;
import java.sql.Statement;
import java.util.Properties;

import javax.sql.DataSource;

import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.XmlDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dal.dbbroker.DbFacadeLocator;
import org.ovirt.engine.core.dal.dbbroker.generic.DBConfigUtils;
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;

/**
 * <code>BaseDAOTestCase</code> provides a foundation for creating unit tests for the persistence layer. The annotation
 * <code>@Transactional</code>, and the listener <code>TransactionalTestExecutionListener</code> ensure that all test
 * cases (<code>@Test</code> methods) are executed inside a transaction, and the transaction is automatically rolled
 * back on completion of the test.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
@ContextConfiguration(loader = CustomizedContextLoader.class)
@Transactional
public abstract class BaseDAOTestCase {
    protected static final Guid PRIVILEGED_USER_ID = new Guid("9bf7c640-b620-456f-a550-0348f366544b");
    protected static final Guid UNPRIVILEGED_USER_ID = new Guid("9bf7c640-b620-456f-a550-0348f366544a");

    protected static DbFacade dbFacade;
    private static Object dataFactory;
    protected static boolean needInitializationSql = false;
    protected static String initSql;
    protected static DataSource dataSource;
    private static IDataSet dataset;

    @BeforeClass
    public static void initTestCase() throws Exception {
        if(dataSource == null) {
            dataSource = createDataSource();

            dataset = initDataSet();
            dbFacade = new DbFacade();
            dbFacade.setDbEngineDialect(DbFacadeLocator.loadDbEngineDialect());
            dbFacade.setTemplate(dbFacade.getDbEngineDialect().createJdbcTemplate(dataSource));

            // load data from fixtures to DB
            DatabaseOperation.CLEAN_INSERT.execute(getConnection(), dataset);
        }
    }

    @Before
    public void setUp() throws Exception {
    }

    private static IDataSet initDataSet() throws Exception {
        return new XmlDataSet(BaseDAOTestCase.class.getResourceAsStream(
                "/fixtures.xml"));
    }

    protected void setUpDatabaseConfig(DatabaseConfig config) {
        config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, dataFactory);
    }

    protected static IDatabaseConnection getConnection() throws Exception {
        // get connection and setup it's meta data
        Connection con = dataSource.getConnection();
        IDatabaseConnection connection = new DatabaseConnection(con);
        connection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, dataFactory);
        if (needInitializationSql) {
            Statement stmt = con.createStatement();
            stmt.executeUpdate(initSql);
        }
        return connection;
    }

    private static DataSource createDataSource() {
        DataSource result = null;
        Properties properties = new Properties();

        Config.setConfigUtils(new DBConfigUtils(false));

        try {
            String job = System.getProperty("JOB_NAME");
            if (job == null)
                job = "";
            String number = System.getProperty("BUILD_NUMBER");
            if (number == null)
                number = "";
            String schemaNamePostfix = job + number;
            properties.load(BaseDAOTestCase.class.getResourceAsStream(
                    "/test-database.properties"));
            ClassLoader.getSystemClassLoader().loadClass(
                    properties.getProperty("database.driver"));
            String dbUrl = properties.getProperty("database.url") + schemaNamePostfix;
            result = new SingleConnectionDataSource(
                    dbUrl,
                    properties.getProperty("database.username"),
                    properties.getProperty("database.password"), true);

            initSql = properties.getProperty("database.initsql");

            loadDataFactory(properties.getProperty("database.testing.datafactory"));

            if (initSql != null && !initSql.isEmpty())
            {
                needInitializationSql = true;
            }
        } catch (Exception error) {
            error.printStackTrace();
            throw new RuntimeException("Cannot create data source", error);
        }

        return result;
    }

    private static void loadDataFactory(String dataFactoryClassname) throws Exception {
        Class<?> clazz = Class.forName(dataFactoryClassname);
        dataFactory = clazz.newInstance();
    }

    public static DbFacade getDbFacade() {
        return dbFacade;
    }

    public static DataSource getDataSource() {
        return dataSource;
    }
}

@@ -462,16 +462,44 @@
 eClass;%0A
+import org.junit.ClassRule;%0A
 import o
@@ -792,16 +792,198 @@
 gUtils;%0A
+import org.ovirt.engine.core.utils.MockEJBStrategyRule;%0Aimport org.ovirt.engine.core.utils.ejb.ContainerManagedResourceType;%0Aimport org.ovirt.engine.core.utils.ejb.EJBUtilsStrategy;%0A
 import o
@@ -2487,16 +2487,156 @@
 dataset;
+%0A    private static EJBUtilsStrategy oldStrategy;%0A%0A    @ClassRule%0A    public static MockEJBStrategyRule ejbRule = new MockEJBStrategyRule();
 %0A%0A    @B
@@ -2777,25 +2777,24 @@
 taSource();%0A
-%0A
             
@@ -2797,33 +2797,85 @@
     
-dataset = initDataSet(
+ejbRule.mockResource(ContainerManagedResourceType.DATA_SOURCE, dataSource
 );%0A
+%0A
     
@@ -2887,30 +2887,28 @@
    d
-bFacade = new DbFacade
+ataset = initDataSet
 ();%0A
@@ -2923,24 +2923,78 @@
     dbFacade
+ = DbFacadeLocator.getDbFacade();%0A            dbFacade
 .setDbEngine
@@ -3041,109 +3041,12 @@
 ect(
-));%0A            dbFacade.setTemplate(dbFacade.getDbEngineDialect().createJdbcTemplate(dataSource
 ));%0A
-%0A
     

Fix dao tests not to print lookup error