db-torque-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From g.@apache.org
Subject svn commit: r1870385 [1/2] - in /db/torque/torque4/trunk/torque-test: ./ src/test/java/org/apache/torque/testcontainer/ src/test/profile/mysql/ src/test/profile/mysql/docker-resources/ src/test/profile/mysql/docker-resources/db/ src/test/resources/
Date Mon, 25 Nov 2019 15:22:33 GMT
Author: gk
Date: Mon Nov 25 15:22:32 2019
New Revision: 1870385

URL: http://svn.apache.org/viewvc?rev=1870385&view=rev
Log:
Showcase Java Testcontainer
- in profile mysql/docker-resources
- used for mysql adapter + just one test class: DataContainerTest.java (from DataTest.java)
- no need for a running mysql database installed locally
- still support pre-installed database and docker containerized test (cft. pom.xml)

pom.xml:
- generation: need to use docker-maven-plugin to init a temporary database image to generate sql (in maven torque-maven-plugin), stopping it after this is done
- separate id-table generation and pass on insert into dockerfile (may use some shell script indirection later)

- remove not used log4j.properties

- TODO use torque.wrapper.configuration.file instead of hard-coded configuration file path, add tests, add adapters

Added:
    db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/
    db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/BaseDatabaseContainerTestCase.java   (with props)
    db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/DataContainerTest.java   (with props)
    db/torque/torque4/trunk/torque-test/src/test/profile/mysql/Torque4Test.xml   (with props)
    db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/
    db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/
    db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/.dockerignore
    db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/Dockerfile
    db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/docker-java.properties.template
    db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/testcontainers.properties   (with props)
    db/torque/torque4/trunk/torque-test/src/test/profile/mysql/torque.usersettings.properties   (with props)
Removed:
    db/torque/torque4/trunk/torque-test/src/test/resources/log4j.properties
Modified:
    db/torque/torque4/trunk/torque-test/pom.xml

Modified: db/torque/torque4/trunk/torque-test/pom.xml
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-test/pom.xml?rev=1870385&r1=1870384&r2=1870385&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-test/pom.xml (original)
+++ db/torque/torque4/trunk/torque-test/pom.xml Mon Nov 25 15:22:32 2019
@@ -30,6 +30,9 @@
   Troubleshooting:
   Exception org.apache.torque.generator.source.transform.SourceTransformerException: Option torque.database must be set:
   You did not specify a correct profile name, see above.
+  
+  Eclipse classpath generation: 
+  First run mvn test -Pmysql -DskipTests=true, then mvn eclipse:eclipse -Dmaven.antrun.skip=true -Pmysql
  -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <parent>
@@ -54,6 +57,9 @@
     <torque.test.mysql.log4j2.version>2.12.1</torque.test.mysql.log4j2.version>
     <torque.test.oracle.version>10.2.0.3.0</torque.test.oracle.version>
     <torque.test.postgres.version>9.1-901.jdbc4</torque.test.postgres.version>
+    <torque.test.testcontainer.version>1.12.3</torque.test.testcontainer.version>
+    <!-- -->
+    <torque.test.idmethod>native</torque.test.idmethod>
   </properties>
   
   <scm>
@@ -105,6 +111,19 @@
       <artifactId>fulcrum-yaafi</artifactId>
       <scope>test</scope>
     </dependency>
+    <!-- testcontainer minimal shared resources -->
+    <dependency>
+      <groupId>org.testcontainers</groupId>
+      <artifactId>testcontainers</artifactId>
+      <version>${torque.test.testcontainer.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.testcontainers</groupId>
+      <artifactId>junit-jupiter</artifactId>
+      <version>${torque.test.testcontainer.version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
@@ -138,6 +157,7 @@
                 <copy todir="target/torque/test/schema">
                   <fileset dir="src/main/schema" />
                   <filterset>
+                  
                     <filter token="DATABASE_DEFAULT" value="bookstore" />
                     <filter token="DATABASE_ID_METHOD" value="${torque.test.idmethod}" />
                     <filter token="DATABASE_SCHEMA" value="${torque.test.databaseSchema}" />
@@ -282,7 +302,7 @@
               <packaging>classpath</packaging>
               <configPackage>org.apache.torque.templates.idtable</configPackage>
               <sourceDir>target/torque/test/schema</sourceDir>
-              <defaultOutputDir>target/generated-sql</defaultOutputDir>
+              <defaultOutputDir>target/generated-sql-init</defaultOutputDir>
               <defaultOutputDirUsage>none</defaultOutputDirUsage>
               <loglevel>error</loglevel>
               <options>
@@ -453,7 +473,7 @@
               <autocommit>true</autocommit>
               <orderFile>ascending</orderFile>
               <fileset>
-                <basedir>${basedir}/target/generated-sql</basedir>
+                <basedir>${basedir}/target/generated-sql-init</basedir>
                 <includes>
                   <include>*idtable-init.sql</include>
                 </includes>
@@ -493,9 +513,10 @@
             <include>**/${torque.test.include.managers}</include>
           </includes>
           <excludes>
-            <exclude>**/BaseRuntimeTestCase.java</exclude>
+             <exclude>**/BaseDatabaseTestCase.java</exclude>
+             <exclude>**/*Container*.java</exclude>
           </excludes>
-          <forkMode>none</forkMode><!-- normally pertest, if remote debugging with mvnDebug port 8000, setting in console -DforkMode=none seems to have no effect, set here -->
+          <forkMode>pertest</forkMode><!-- normally pertest, if remote debugging with mvnDebug port 8000, setting in console -DforkMode=none seems to have no effect, set here -->
           <systemProperties>
             <property>
               <name>torque.configuration.file</name>
@@ -1149,6 +1170,187 @@
         </plugins>
       </build>
     </profile>
+    <!-- 
+    mvn clean test -Pmysql,docker-testcontainer
+    -->
+    <profile>
+      <id>docker-testcontainer</id>
+      <activation>
+        <activeByDefault>false</activeByDefault>
+      </activation>
+      <build>
+        <plugins>
+            <!-- requires a started docker host - starts database for sql-maven-plugin.
+            caution: Cancelling the maven process before life cycle process-classes is reached, the docker has to be stopped manually, docker stop <id>.
+            -->
+            <plugin>
+                <groupId>io.fabric8</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <version>0.30.0</version>
+                <configuration>
+                    <filter>mysql:${torque.test.mysql.version}</filter>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>prepare-mysql-database</id>
+                        <phase>initialize</phase>
+                        <goals>
+                            <goal>start</goal>
+                        </goals>
+                        <configuration>
+                            <images>
+                                <image>
+                                    <name>mysql:${torque.test.mysql.version}</name>
+                                    <alias>mysql-generate-helper-database</alias>
+                                    <run>
+                                         <env>
+                                            <MYSQL_ROOT_PASSWORD>${torque.database.password}</MYSQL_ROOT_PASSWORD>
+                                            <MYSQL_DATABASE>bookstore</MYSQL_DATABASE>
+                                            <MYSQL_USER>${torque.database.user}</MYSQL_USER>
+                                            <MYSQL_PASSWORD>${torque.database.password}</MYSQL_PASSWORD>
+                                        </env>
+                                        <ports>
+                                            <port>3306:3306</port>
+                                        </ports>
+                                        <!--wait>
+                                            <log>database system is ready to accept connections.</log>
+                                            <time>20000</time>
+                                        </wait-->
+                                    </run>
+                                </image>
+                            </images>
+                        </configuration>
+                    </execution>
+                    <!-- close this init generate sources database outside tests, before starting tests -->
+                    <execution>
+                        <id>remove-mysql-database</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>stop</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+           <!-- skip and use testcontaiers docker -->          
+           <plugin>
+               <groupId>org.codehaus.mojo</groupId>
+               <artifactId>sql-maven-plugin</artifactId>
+               <executions>
+                    <execution>
+                        <id>execute-ext-ddl</id>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                    </execution>
+                    <execution>
+                       <id>execute-ddl</id>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                    </execution>
+                   <execution>
+                        <id>execute-idtable-sql</id>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                    </execution><execution>
+                        <id>shutdown-db-after-ddl</id>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                    </execution> 
+                </executions>
+            </plugin>
+            <!-- skip database test or do it in a later phase.. -->
+            <plugin>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>test-database-filled</id>
+                        <phase>generate-sources</phase>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                     </execution>
+                </executions>
+            </plugin>
+            <plugin>
+              <artifactId>maven-resources-plugin</artifactId>
+              <version>2.6</version>
+              <executions>
+                <execution>
+                  <id>copy-resources</id>
+                  <phase>validate</phase>
+                  <goals>
+                    <goal>copy-resources</goal>
+                  </goals>
+                  <configuration>
+                    <outputDirectory>${basedir}/target</outputDirectory>
+                    <resources>
+                      <resource>
+                        <directory>src/test/profile/mysql/docker-resources/db</directory>
+                        <filtering>false</filtering>
+                        <includes>
+                            <include>Dockerfile</include>
+                            <include>.dockerignore</include>
+                          </includes>
+                      </resource>
+                    </resources> 
+                    </configuration>
+                </execution>
+              </executions>
+            </plugin>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-surefire-plugin</artifactId>
+              <configuration>
+                <systemProperties>
+                  <property>
+                    <!-- file is sued, but not this configuration setting, cft.   -->
+                    <name>torque.wrapper.configuration.file</name>
+                    <value>src/test/profile/${torque.test.profileDirectory}/Torque4Test.xml</value>
+                  </property>
+                </systemProperties>
+                <excludes>
+                    <exclude>**/Base*.java</exclude>
+                </excludes>
+                <includes>
+                     <include>**/DataContainerTest.java</include>
+                </includes>
+              </configuration>
+              <executions>
+                <execution>
+                  <id>default-test</id>
+                  <configuration>
+                    <!--groups>docker</groups-->
+                  </configuration>
+                </execution>
+              </executions>
+            </plugin>
+          </plugins>
+      </build>
+      <dependencies>
+        <!-- docker testcontainer:  mvn test -Pmysql,docker-testcontainer  -->
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>testcontainers</artifactId>
+            <version>${torque.test.testcontainer.version}</version>
+            <scope>test</scope>
+          </dependency>
+          <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>${torque.test.testcontainer.version}</version>
+            <scope>test</scope>
+          </dependency>
+          <dependency>
+              <groupId>org.testcontainers</groupId>
+              <artifactId>mysql</artifactId>
+              <version>${torque.test.testcontainer.version}</version>
+              <scope>test</scope>
+          </dependency>
+      </dependencies>
+    </profile>
 
     <profile>
       <id>apache-release</id>

Added: db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/BaseDatabaseContainerTestCase.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/BaseDatabaseContainerTestCase.java?rev=1870385&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/BaseDatabaseContainerTestCase.java (added)
+++ db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/BaseDatabaseContainerTestCase.java Mon Nov 25 15:22:32 2019
@@ -0,0 +1,380 @@
+package org.apache.torque.testcontainer;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.torque.Torque;
+import org.apache.torque.TorqueException;
+import org.apache.torque.adapter.Adapter;
+import org.apache.torque.adapter.MysqlAdapter;
+import org.apache.torque.criteria.Criteria;
+import org.apache.torque.om.mapper.StringMapper;
+import org.apache.torque.test.dbobject.Author;
+import org.apache.torque.test.dbobject.Book;
+import org.apache.torque.test.peer.AuthorPeer;
+import org.apache.torque.test.peer.BookPeer;
+import org.apache.torque.util.BasePeerImpl;
+import org.apache.torque.util.CountHelper;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.images.builder.ImageFromDockerfile;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+
+
+/**
+ * Base functionality for Test cases which use standard database setup.
+ * 
+ * Uses T E S T C O N T A I N E R S 
+ * 
+ * https://www.testcontainers.org/features/configuration/
+ * 
+ * Copy docker-java.properties.template to docker-java.properties and adapt it to your needs.
+ *
+ * @author <a href="mailto:seade@backstagetech.com.au">Scott Eade</a>
+ * @author <a href="mailto:gk@apache.org">Georg Kallidis</a>
+ * @version $Id: BaseDatabaseTestCase.java 1839288 2018-08-27 09:48:33Z tv $
+ */
+@Tag("docker")
+@Testcontainers
+public abstract class BaseDatabaseContainerTestCase
+{
+    private static final String TORQUE_WRAPPER_CONFIGURATION_FILE = "src/test/profile/mysql/Torque4Test.xml";
+    /** TODO: use this key insted of hard coding
+     * The system property containing the path to the configuration file. 
+     * */
+    public static final String CONFIG_FILE_SYSTEM_PROPERTY = "torque.wrapper.configuration.file";
+
+    protected static Adapter defaultAdapter;
+    
+    // copied from src/test/profile/mysql/docker-resources/db/
+    public static final String DOCKERFILE = "./target/Dockerfile";
+    
+    private static Logger log = LogManager.getLogger();
+    
+    public static int SERVICE_PORT = 3306;
+
+    public static String DATABASE_NAME = "bookstore";
+
+    Connection connection;
+    
+    @Container
+    public static GenericContainer MY_SQL_CONTAINER =   new GenericContainer<>(
+            new ImageFromDockerfile()
+            .withDockerfile(new File(DOCKERFILE).toPath())
+        ).withExposedPorts( SERVICE_PORT ) //.withStartupAttempts( 2 )
+         .withEnv(  "MYSQL_DATABASE", DATABASE_NAME )
+         .withEnv( "MYSQL_USER", "torque"  )
+         .withEnv( "MYSQL_PASSWORD", "torque" )
+         .withEnv( "MYSQL_ROOT_PASSWORD","torque" );
+
+    /**
+     * Initialize Torque on the first setUp().  Subclasses which override
+     * setUp() must call super.setUp() as their first action.
+     * @throws TorqueException 
+     * @throws InterruptedException 
+     * @throws IOException 
+     * @throws UnsupportedOperationException 
+     */
+    @BeforeAll
+    public static void init() throws TorqueException, UnsupportedOperationException, IOException, InterruptedException {
+        log.info("Starting from dockerfile: {}", DOCKERFILE);
+
+        //before torque init
+        MY_SQL_CONTAINER.setStartupAttempts( 3 );
+        
+        startDatabaseContainer();
+        
+        //MY_SQL_CONTAINER.execInContainer("mysql -h localhost -u root -ptorque -P 3306 "+ DATABASE_NAME);
+        
+        // TODO do resource filtering and read from properties
+        File targetFile = new File(TORQUE_WRAPPER_CONFIGURATION_FILE);
+        Path torqueConfBase = Paths.get(targetFile.toURI()).getParent();
+        updateTorque(torqueConfBase);
+        
+        synchronized (BaseDatabaseContainerTestCase.class)
+        {
+            if (!Torque.isInit())
+            {
+                Torque.init(
+                        TORQUE_WRAPPER_CONFIGURATION_FILE);
+            }
+        }
+        defaultAdapter = Torque.getDatabase(Torque.getDefaultDB()).getAdapter();
+        log.info("using adapter: {}", defaultAdapter);
+
+    }
+    
+    protected static void updateTorque(Path torqueConfBase) {
+        try {      
+            String jdbcConnectionString = generateJdbcUrl();
+            String customUrl = "torque.dsfactory.bookstore.connection.url="+ jdbcConnectionString;
+            // override and set mapped port in url, which is known only at runtime.
+            File file = torqueConfBase.resolve("torque.usersettings.properties").toFile();
+            try (FileOutputStream fop = new FileOutputStream(file )) {
+                if (!file.exists()) {
+                    file.createNewFile();
+                }
+                fop.write( customUrl.getBytes() );
+                fop.flush();
+            }
+         } catch (Exception e) {
+            fail();
+         }
+    }
+    
+    public static void startDatabaseContainer() {
+       if (!MY_SQL_CONTAINER.isRunning()) {
+          MY_SQL_CONTAINER.waitingFor(Wait.forListeningPort());
+          MY_SQL_CONTAINER.start();
+       }
+    }
+    
+    /**
+     * 
+     * @returns the JDBC string with mapped port binding
+     */
+    public static String generateJdbcUrl() {
+       startDatabaseContainer();
+       if (!MY_SQL_CONTAINER.isRunning()) { throw new RuntimeException("Could not find RUNNING database container"); }
+       
+       //MY_SQL_CONTAINER.withCreateContainerCmdModifier(modifier) //    
+       String serviceHost = MY_SQL_CONTAINER.getContainerIpAddress();
+       Integer mappedPort = MY_SQL_CONTAINER.getMappedPort(SERVICE_PORT);// e.g. 32811
+       log.info("generate jdbc url from {}, mapped Port: {}, bounded port: {}", serviceHost, mappedPort, MY_SQL_CONTAINER.getBoundPortNumbers());
+       
+       String targetJDBC = //genJDBC;
+       String.format("jdbc:mysql://%s:%d/%s?loggerLevel=OFF", serviceHost,
+                     mappedPort, DATABASE_NAME);
+       log.info( "used connect url: {}", targetJDBC);
+       return targetJDBC;
+    }
+
+    /**
+     * Queries mysql for its version.
+     * @return the version String mysql returns
+     * @throws TorqueException if the database is not mysql or the query fails.
+     */
+    protected String getMysqlVersion() throws TorqueException
+    {
+        Adapter adapter
+        = Torque.getDatabase(Torque.getDefaultDB()).getAdapter();
+        if (!(adapter instanceof MysqlAdapter))
+        {
+            throw new TorqueException(
+                    "getMysqlVersion called but database adapter is "
+                            + adapter.getClass().getName());
+        }
+        List<String> records = new BasePeerImpl<String>().doSelect(
+                "show variables like \"version\"",
+                new StringMapper(1),
+                (String) null);
+        return records.get(0);
+    }
+
+    /**
+     * Queries mysql for its major version. (format is major.minor.release)
+     * @return the major version of mysql
+     * @throws TorqueException if the database is not mysql or the query fails.
+     * @throws NumberFormatException if the mysql major version cannot be
+     *         converted to an int
+     */
+    protected int getMysqlMajorVersion()
+            throws TorqueException
+    {
+        String completeVersion = getMysqlVersion();
+        String majorVersion
+        = completeVersion.substring(0, completeVersion.indexOf('.'));
+        return Integer.parseInt(majorVersion);
+    }
+
+    /**
+     * Queries mysql for its minor version. (format is major.minor.release)
+     * @return the minor version of mysql
+     * @throws TorqueException if the database is not mysql or the query fails.
+     */
+    protected int getMysqlMinorVersion()
+            throws TorqueException
+    {
+        String completeVersion = getMysqlVersion();
+        if (completeVersion.indexOf('-') != -1) // handle x.y.z-ubuntuSomething
+        {
+            completeVersion = completeVersion.substring(
+                    0,
+                    completeVersion.indexOf('-'));
+        }
+        String minorVersion
+        = completeVersion.substring(
+                completeVersion.indexOf('.') + 1,
+                completeVersion.lastIndexOf('.'));
+        return Integer.parseInt(minorVersion);
+    }
+
+    /**
+     * Queries the database for its major version.
+     *
+     * @param connection a connection to the database.
+     *
+     * @return the version String from the connection metadata
+     *
+     * @throws TorqueException if the query fails.
+     */
+    protected int getDatabaseMajorVersion(final Connection connection)
+            throws TorqueException
+    {
+        try
+        {
+            return connection.getMetaData().getDatabaseMajorVersion();
+        }
+        catch (SQLException e)
+        {
+            throw new TorqueException(e);
+        }
+    }
+
+    /**
+     * Deletes all authors and books in the bookstore tables.
+     *
+     * @throws TorqueException if the bookstore could not be cleaned
+     */
+    protected void cleanBookstore() throws TorqueException
+    {
+        Criteria criteria = new Criteria();
+        BookPeer.doDelete(criteria);
+
+        criteria = new Criteria();
+        AuthorPeer.doDelete(criteria);
+    }
+
+    /**
+     * Inserts test data into the bookstore tables.
+     *
+     * @return the list of added authors, which in turn contain the added books.
+     *
+     * @throws TorqueException if filling data fails.
+     */
+    protected List<Author> insertBookstoreData() throws TorqueException
+    {
+        List<Author> result = new ArrayList<>();
+        for (int i = 1; i <= 10; i++)
+        {
+            Author author = new Author();
+            author.setName("Author " + i);
+            author.save();
+            result.add(author);
+            assertTrue("authorId should not be 0 after insert",
+                    author.getAuthorId() != 0);
+
+            for (int j = 1; j <= 10; j++)
+            {
+                Book book = new Book();
+                author.addBook(book);
+                book.setTitle("Book " + j + " - Author " + i);
+                if (j < 10)
+                {
+                    book.setIsbn("ISBN " + j + " - " + i);
+                }
+                else
+                {
+                    book.setIsbn(null);
+                }
+                book.save();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Checks that the bookstore tables contain exactly the records
+     * in the passed list.
+     * The books in the authors are also checked.
+     *
+     * @param toVerify the list of authors to check.
+     *
+     * @throws TorqueException if reading data fails.
+     */
+    protected void verifyBookstore(final List<Author> toVerify) throws TorqueException
+    {
+        int numBooks = 0;
+
+        for (Author author : toVerify)
+        {
+            Criteria criteria = new Criteria()
+                    .where(AuthorPeer.NAME, author.getName())
+                    .and(AuthorPeer.AUTHOR_ID, author.getAuthorId());
+            criteria.setSingleRecord(true);
+            List<Author> selectedAuthorList = AuthorPeer.doSelect(criteria);
+            assertEquals("Could not find author with id "
+                    + author.getAuthorId()
+                    + " and name "
+                    + author.getName(),
+                    1,
+                    selectedAuthorList.size());
+
+            numBooks += author.getBooks().size();
+
+            for (Book book : author.getBooks())
+            {
+                criteria = new Criteria()
+                        .where(BookPeer.TITLE, book.getTitle())
+                        .and(BookPeer.BOOK_ID, book.getBookId())
+                        .and(BookPeer.AUTHOR_ID, book.getAuthorId())
+                        .and(BookPeer.ISBN, book.getIsbn());
+                criteria.setSingleRecord(true);
+                List<Book> selectedBookList = BookPeer.doSelect(criteria);
+                assertEquals("Could not find book with id "
+                        + book.getBookId()
+                        + " title "
+                        + book.getTitle()
+                        + " ISBN "
+                        + book.getIsbn()
+                        + " authorId "
+                        + book.getAuthorId(),
+                        1,
+                        selectedBookList.size());
+            }
+        }
+
+        assertEquals(
+                toVerify.size(),
+                new CountHelper().count(AuthorPeer.getTableMap()));
+        assertEquals(
+                numBooks,
+                new CountHelper().count(BookPeer.getTableMap()));
+    }
+
+}

Propchange: db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/BaseDatabaseContainerTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/DataContainerTest.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/DataContainerTest.java?rev=1870385&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/DataContainerTest.java (added)
+++ db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/DataContainerTest.java Mon Nov 25 15:22:32 2019
@@ -0,0 +1,1452 @@
+package org.apache.torque.testcontainer;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static org.junit.Assert.*;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.torque.ColumnImpl;
+import org.apache.torque.ForeignKeySchemaData;
+import org.apache.torque.TestInterface;
+import org.apache.torque.TestPeerInterface;
+import org.apache.torque.Torque;
+import org.apache.torque.TorqueException;
+import org.apache.torque.adapter.Adapter;
+import org.apache.torque.adapter.DerbyAdapter;
+import org.apache.torque.adapter.HsqldbAdapter;
+import org.apache.torque.adapter.MssqlAdapter;
+import org.apache.torque.adapter.MysqlAdapter;
+import org.apache.torque.criteria.Criteria;
+import org.apache.torque.criteria.Criterion;
+import org.apache.torque.om.mapper.CompositeMapper;
+import org.apache.torque.om.mapper.IntegerMapper;
+import org.apache.torque.om.mapper.RecordMapper;
+import org.apache.torque.test.InheritanceClassnameTestChild1;
+import org.apache.torque.test.InheritanceClassnameTestChild2;
+import org.apache.torque.test.dbobject.Author;
+import org.apache.torque.test.dbobject.BigintType;
+import org.apache.torque.test.dbobject.Book;
+import org.apache.torque.test.dbobject.CompPkContainsFk;
+import org.apache.torque.test.dbobject.IfcTable;
+import org.apache.torque.test.dbobject.InheritanceChildB;
+import org.apache.torque.test.dbobject.InheritanceChildC;
+import org.apache.torque.test.dbobject.InheritanceChildD;
+import org.apache.torque.test.dbobject.InheritanceClassnameTest;
+import org.apache.torque.test.dbobject.InheritanceTest;
+import org.apache.torque.test.dbobject.IntegerType;
+import org.apache.torque.test.dbobject.LocalIfcTable;
+import org.apache.torque.test.dbobject.LocalTestInterface;
+import org.apache.torque.test.dbobject.MultiPk;
+import org.apache.torque.test.dbobject.Nopk;
+import org.apache.torque.test.dbobject.OIntegerPk;
+import org.apache.torque.test.dbobject.VarcharType;
+import org.apache.torque.test.peer.AuthorPeer;
+import org.apache.torque.test.peer.BigintTypePeer;
+import org.apache.torque.test.peer.BookPeer;
+import org.apache.torque.test.peer.CompPkContainsFkPeer;
+import org.apache.torque.test.peer.IfcTablePeer;
+import org.apache.torque.test.peer.IfcTablePeerImpl;
+import org.apache.torque.test.peer.InheritanceClassnameTestPeer;
+import org.apache.torque.test.peer.InheritanceTestPeer;
+import org.apache.torque.test.peer.IntegerTypePeer;
+import org.apache.torque.test.peer.LocalIfcTablePeer;
+import org.apache.torque.test.peer.LocalIfcTablePeerImpl;
+import org.apache.torque.test.peer.LocalTestPeerInterface;
+import org.apache.torque.test.peer.MultiPkPeer;
+import org.apache.torque.test.peer.NopkPeer;
+import org.apache.torque.test.peer.VarcharTypePeer;
+import org.apache.torque.test.recordmapper.AuthorRecordMapper;
+import org.apache.torque.test.recordmapper.BookRecordMapper;
+import org.apache.torque.util.BasePeerImpl;
+import org.apache.torque.util.CountHelper;
+import org.apache.torque.util.Transaction;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+/**
+ * Runtime tests.
+ *
+ * @author <a href="mailto:seade@backstagetech.com.au">Scott Eade</a>
+ * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
+ * @author <a href="mailto:fischer@seitenbau.de">Thomas Fischer</a>
+ * @author <a href="mailto:patrick.carl@web.de">Patrick Carl</a>
+ * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
+ * @author <a href="mailto:gk@apache.org">Georg Kallidis</a>
+ * @version $Id: DataTest.java 1869081 2019-10-28 16:17:11Z gk $
+ */
+@Tag("docker")
+@Testcontainers
+public class DataContainerTest extends BaseDatabaseContainerTestCase
+{
+    private static Logger log = LogManager.getLogger();
+
+    /**
+     * test whether we can connect to the database at all
+     * @throws Exception if no connection can be established
+     */
+    @Test
+    @Tag("docker")
+    public void testConnect() throws Exception
+    {
+        Connection connection = null;
+        try
+        {
+            connection = Torque.getConnection();
+            connection.close();
+            connection = null;
+        }
+        finally
+        {
+            if (connection != null)
+            {
+                connection.close();
+            }
+        }
+    }
+
+    /**
+     * multiple pk test (TRQ12)
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testMultiplePk() throws Exception
+    {
+        // clean table
+        Criteria criteria = new Criteria();
+        criteria.where(MultiPkPeer.PK1, (Object) null, Criteria.NOT_EQUAL);
+        MultiPkPeer.doDelete(criteria);
+
+        // do test
+        MultiPk mpk = new MultiPk();
+        mpk.setPrimaryKey("Svarchar:N5:Schar:N3:N-42:N3:N4:N5:N6:D9999999999:");
+        mpk.save();
+        // TODO assert saved values
+    }
+
+    private static final String[] validTitles = {
+            "Book 6 - Author 4", "Book 6 - Author 5", "Book 6 - Author 6",
+            "Book 6 - Author 7", "Book 6 - Author 8",
+            "Book 7 - Author 4", "Book 7 - Author 5", "Book 7 - Author 6",
+            "Book 7 - Author 7", "Book 7 - Author 8"
+    };
+
+    /**
+     * test limit/offset
+     *
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testLimitOffset() throws Exception
+    {
+        cleanBookstore();
+        insertBookstoreData();
+        Set<String> titleSet = new HashSet<>();
+        for (int j = 0; j < validTitles.length; j++)
+        {
+            titleSet.add(validTitles[j]);
+        }
+
+        Criteria crit = new Criteria();
+        Criterion c = new Criterion(BookPeer.TITLE,
+                "Book 6 - Author 1", Criteria.GREATER_EQUAL);
+        c.and(new Criterion(BookPeer.TITLE,
+                "Book 8 - Author 3", Criteria.LESS_EQUAL));
+        crit.where(c);
+        crit.addDescendingOrderByColumn(BookPeer.BOOK_ID);
+        crit.setLimit(10);
+        crit.setOffset(5);
+        List<Book> books = BookPeer.doSelect(crit);
+        assertEquals("List should have 10 books", 10, books.size());
+        for (Book book : books)
+        {
+            String title = book.getTitle();
+            assertTrue("Incorrect title: " + title,
+                    titleSet.contains(title));
+        }
+
+
+        // Test limit of zero works
+        if (defaultAdapter instanceof DerbyAdapter || defaultAdapter instanceof HsqldbAdapter)
+        {
+            log.info("testLimitOffset(): "
+                    + "A limit of 0 is not supported for Derby or Hsqldb");
+        }
+        else
+        {
+            crit = new Criteria();
+            crit.setLimit(0);
+            books = BookPeer.doSelect(crit);
+            assertEquals("List should have 0 books", 0, books.size());
+        }
+
+        // check that Offset also works without limit
+        crit = new Criteria();
+        crit.setOffset(5);
+        books = BookPeer.doSelect(crit);
+        assertEquals("List should have 95 books", 95, books.size());
+
+        // Check that limiting also works if a table with an equal column name
+        // is joined. This is problematic for oracle, see TORQUE-10.
+
+        crit = new Criteria();
+        crit.setLimit(10);
+        crit.setOffset(5);
+        books = BookPeer.doSelectJoinAuthor(crit);
+        assertEquals("List should have 10 books", 10, books.size());
+    }
+
+    /**
+     * Checks whether the setSingleRecord() method in criteria works
+     */
+    @Test
+    public void testSingleRecord() throws Exception
+    {
+        cleanBookstore();
+        insertBookstoreData();
+        Criteria criteria = new Criteria();
+        criteria.setSingleRecord(true);
+        criteria.setLimit(1);
+        criteria.setOffset(5);
+        List<Book> books = BookPeer.doSelect(criteria);
+        assertTrue("List should have 1 books, not " + books.size(),
+                books.size() == 1);
+
+        criteria = new Criteria();
+        criteria.setSingleRecord(true);
+        criteria.setLimit(2);
+        try
+        {
+            books = BookPeer.doSelect(criteria);
+            fail("doSelect should have failed "
+                    + "because two records were selected "
+                    + " and one was expected");
+        }
+        catch (TorqueException e)
+        {
+        }
+    }
+
+    /**
+     * Tests whether selects work correctly if the value <code>null</code>
+     * is used.
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testNullSelects() throws Exception
+    {
+        // clean table
+        VarcharTypePeer.doDelete(new Criteria());
+        IntegerTypePeer.doDelete(new Criteria());
+
+        // add test data
+        VarcharType varcharType = new VarcharType();
+        varcharType.setId("text2");
+        varcharType.setVarcharValue("text2");
+        varcharType.save();
+        varcharType = new VarcharType();
+        varcharType.setId("text");
+        varcharType.save();
+
+        IntegerType integerTypeNotNull = new IntegerType();
+        integerTypeNotNull.setIntegerObjectValue(1);
+        integerTypeNotNull.save();
+        IntegerType integerTypeNull = new IntegerType();
+        integerTypeNull.save();
+
+        // check for comparison NOT_EQUAL and value null
+        Criteria criteria = new Criteria();
+        criteria.where(VarcharTypePeer.ID, null, Criteria.NOT_EQUAL)
+        .and(VarcharTypePeer.VARCHAR_VALUE, null, Criteria.NOT_EQUAL);
+        List<VarcharType> varcharResult = VarcharTypePeer.doSelect(criteria);
+        assertEquals(1, varcharResult.size());
+        assertEquals("text2", varcharResult.get(0).getId());
+
+        criteria = new Criteria();
+        criteria.where(IntegerTypePeer.ID, null, Criteria.NOT_EQUAL)
+        .and(IntegerTypePeer.INTEGER_OBJECT_VALUE, null, Criteria.NOT_EQUAL);
+        List<IntegerType> integerResult = IntegerTypePeer.doSelect(criteria);
+        assertEquals(1, integerResult.size());
+        assertEquals(integerTypeNotNull.getId(), integerResult.get(0).getId());
+
+        // check for comparison EQUAL and value null
+        criteria = new Criteria();
+        criteria.where(VarcharTypePeer.VARCHAR_VALUE, null, Criteria.EQUAL);
+        varcharResult = VarcharTypePeer.doSelect(criteria);
+        assertEquals(1, varcharResult.size());
+        assertEquals("text", varcharResult.get(0).getId());
+
+        criteria = new Criteria();
+        criteria.where(IntegerTypePeer.INTEGER_OBJECT_VALUE, null, Criteria.EQUAL);
+        integerResult = IntegerTypePeer.doSelect(criteria);
+        assertEquals(1, integerResult.size());
+        assertEquals(integerTypeNull.getId(), integerResult.get(0).getId());
+    }
+
+    /**
+     * Test whether an update works and whether it only affects the
+     * specified record.
+     * @throws Exception if anything in the test goes wrong.
+     */
+    @Test
+    public void testUpdate() throws Exception
+    {
+        cleanBookstore();
+
+        Author otherAuthor = new Author();
+        otherAuthor.setName("OtherName");
+        otherAuthor.save();
+
+        Author author = new Author();
+        author.setName("Name");
+        author.save();
+
+
+        // Test doUpdate methods in Peer explicitly
+        Connection connection = Transaction.begin(AuthorPeer.DATABASE_NAME);
+        author.setName("NewName2");
+        AuthorPeer.doUpdate(author);
+        Transaction.commit(connection);
+
+        Criteria criteria = new Criteria();
+        criteria.addAscendingOrderByColumn(AuthorPeer.NAME);
+
+        List<Author> authors = AuthorPeer.doSelect(criteria);
+        assertEquals("List should contain 2 authors", 2, authors.size());
+        assertEquals("First Author's name should be \"NewName2\"",
+                "NewName2",
+                authors.get(0).getName());
+        assertEquals("Second Author's name should be \"OtherName\"",
+                "OtherName",
+                authors.get(1).getName());
+
+        author.setName("NewName3");
+        AuthorPeer.doUpdate(author);
+
+        criteria = new Criteria();
+        criteria.addAscendingOrderByColumn(AuthorPeer.NAME);
+
+        authors = AuthorPeer.doSelect(criteria);
+        assertEquals("List should contain 2 authors", 2, authors.size());
+        assertEquals("First Author's name should be \"NewName3\"",
+                "NewName3",
+                authors.get(0).getName());
+        assertEquals("Second Author's name should be \"OtherName\"",
+                "OtherName",
+                authors.get(1).getName());
+
+        Nopk nopk = new Nopk();
+        nopk.setName("name");
+        nopk.save();
+
+        // check the doPupdate Peer methods throw exceptions on a modified
+        // object without primary keys
+        try
+        {
+            NopkPeer.doUpdate(new Nopk());
+            fail("A Torque exception should be thrown (2)");
+        }
+        catch (TorqueException e)
+        {
+        }
+
+        connection = Transaction.begin(NopkPeer.DATABASE_NAME);
+        try
+        {
+            NopkPeer.doUpdate(new Nopk(),connection);
+            fail("A Torque exception should be thrown (3)");
+        }
+        catch (TorqueException e)
+        {
+        }
+        Transaction.safeRollback(connection);
+
+    }
+
+    /**
+     * test special cases in the select clause
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testSelectClause() throws Exception
+    {
+        // test double functions in select columns
+        Criteria criteria = new Criteria();
+        criteria.addSelectColumn(
+                new ColumnImpl("count(distinct(" + BookPeer.BOOK_ID + "))"));
+        new BasePeerImpl<>().doSelect(criteria, new IntegerMapper());
+
+        // test qualifiers in function in select columns
+        criteria = new Criteria();
+        criteria.addSelectColumn(
+                new ColumnImpl("count(distinct " + BookPeer.BOOK_ID + ")"));
+        new BasePeerImpl<>().doSelect(criteria, new IntegerMapper());
+    }
+
+    /**
+     * test if a select from the "default" database works
+     * @throws Exception (NPE) if the test fails
+     */
+    @Test
+    public void testSelectFromDefault() throws Exception
+    {
+        Criteria criteria = new Criteria("default");
+
+        criteria.addSelectColumn(BookPeer.BOOK_ID);
+
+        new BasePeerImpl<>().doSelect(criteria, new IntegerMapper());
+    }
+
+    /**
+     * Test the behaviour if a connection is supplied to access the database,
+     * but it is null. All methods on the user level should be fail
+     * because these methods will be only needed if a method should be executed
+     * in a transaction context. If one assumes that a transaction is open
+     * (connection is not null), but it is not (connection == null),
+     * it is a bad idea to silently start one as this behaviour is very
+     * difficult to tell from the correct one. A clean failure is much easier
+     * to test for.
+     */
+    @Test
+    public void testNullConnection() throws Exception
+    {
+        try
+        {
+            Criteria criteria = new Criteria();
+            AuthorPeer.doSelect(criteria, new IntegerMapper(), null);
+            fail("NullPointerException expected");
+        }
+        catch (NullPointerException e)
+        {
+            //expected
+        }
+
+        try
+        {
+            Criteria criteria = new Criteria();
+            criteria.where(BookPeer.BOOK_ID, (Long) null, Criteria.NOT_EQUAL);
+            BookPeer.doDelete(criteria, (Connection) null);
+            fail("NullPointerException expected");
+        }
+        catch (NullPointerException e)
+        {
+            //expected
+        }
+
+        try
+        {
+            Author author = new Author();
+            author.setName("name");
+            author.save((Connection) null);
+            fail("TorqueException expected");
+        }
+        catch (TorqueException e)
+        {
+            //expected
+            assertEquals("connection is null", e.getMessage());
+        }
+    }
+
+    /**
+     * test the order by, especially in joins and with aliases
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testOrderBy() throws Exception
+    {
+        cleanBookstore();
+
+        // insert test data
+        Author firstAuthor = new Author();
+        firstAuthor.setName("Author 1");
+        firstAuthor.save();
+        Book book = new Book();
+        book.setAuthor(firstAuthor);
+        book.setTitle("Book 1");
+        book.setIsbn("unknown");
+        book.save();
+
+        Author secondAuthor = new Author();
+        secondAuthor.setName("Author 2");
+        secondAuthor.save();
+        for (int bookNr = 2; bookNr <=4; bookNr++)
+        {
+            book = new Book();
+            book.setAuthor(secondAuthor);
+            book.setTitle("Book " + bookNr);
+            book.setIsbn("unknown");
+            book.save();
+        }
+
+        // test simple ascending order by
+        Criteria criteria = new Criteria();
+        criteria.addAscendingOrderByColumn(BookPeer.TITLE);
+        List<Book> bookList = BookPeer.doSelect(criteria);
+        if (bookList.size() != 4)
+        {
+            fail("Ascending Order By: "
+                    + "incorrect numbers of books found : "
+                    + bookList.size()
+                    + ", should be 4");
+        }
+        if (! "Book 1".equals(bookList.get(0).getTitle()))
+        {
+            fail("Ascending Order By: "
+                    + "Title of first Book is "
+                    + bookList.get(0).getTitle()
+                    + ", should be \"Book 1\"");
+        }
+        if (! "Book 4".equals(bookList.get(3).getTitle()))
+        {
+            fail("Ascending Order By: "
+                    + "Title of fourth Book is "
+                    + bookList.get(3).getTitle()
+                    + ", should be \"Book 4\"");
+        }
+
+        // test simple descending order by
+        criteria = new Criteria();
+        criteria.addDescendingOrderByColumn(BookPeer.TITLE);
+        bookList = BookPeer.doSelect(criteria);
+        if (bookList.size() != 4)
+        {
+            fail("Descending Order By: "
+                    + "incorrect numbers of books found : "
+                    + bookList.size()
+                    + ", should be 4");
+        }
+        if (! "Book 1".equals(bookList.get(3).getTitle()))
+        {
+            fail("Descending Order By: "
+                    + "Title of fourth Book is "
+                    + bookList.get(3).getTitle()
+                    + ", should be \"Book 1\"");
+        }
+        if (! "Book 4".equals((bookList.get(0)).getTitle()))
+        {
+            fail("Descending Order By: "
+                    + "Title of first Book is "
+                    + bookList.get(0).getTitle()
+                    + ", should be \"Book 4\"");
+        }
+
+        criteria = new Criteria();
+        criteria.addAlias("b", BookPeer.TABLE_NAME);
+        criteria.addJoin(BookPeer.AUTHOR_ID, AuthorPeer.AUTHOR_ID);
+        criteria.addJoin(
+                AuthorPeer.AUTHOR_ID,
+                new ColumnImpl("b." + BookPeer.AUTHOR_ID.getColumnName()));
+        criteria.addAscendingOrderByColumn(
+                new ColumnImpl("b." + BookPeer.TITLE.getColumnName()));
+        criteria.addDescendingOrderByColumn(BookPeer.TITLE);
+        // the retrieved columns are
+        // author    book   b
+        // author1  book1   book1
+        // author2  book4   book2
+        // author2  book3   book2
+        // author2  book2   book2
+        // author2  book4   book3
+        // ...
+        bookList = BookPeer.doSelect(criteria);
+        if (bookList.size() != 10)
+        {
+            fail("ordering by Aliases: "
+                    + "incorrect numbers of books found : "
+                    + bookList.size()
+                    + ", should be 10");
+        }
+        if (!"Book 4".equals(bookList.get(1).getTitle()))
+        {
+            fail("ordering by Aliases: "
+                    + "Title of second Book is "
+                    + bookList.get(1).getTitle()
+                    + ", should be \"Book 4\"");
+        }
+        if (!"Book 3".equals(bookList.get(2).getTitle()))
+        {
+            fail("ordering by Aliases: "
+                    + "Title of third Book is "
+                    + bookList.get(2).getTitle()
+                    + ", should be \"Book 3\"");
+        }
+
+        criteria = new Criteria();
+        criteria.addAlias("b", BookPeer.TABLE_NAME);
+        criteria.addJoin(BookPeer.AUTHOR_ID, AuthorPeer.AUTHOR_ID);
+        criteria.addJoin(
+                AuthorPeer.AUTHOR_ID,
+                new ColumnImpl("b." + BookPeer.AUTHOR_ID.getColumnName()));
+        criteria.addAscendingOrderByColumn(BookPeer.TITLE);
+        criteria.addDescendingOrderByColumn(
+                new ColumnImpl("b." + BookPeer.TITLE.getColumnName()));
+        // the retrieved columns are
+        // author    book   b
+        // author1  book1   book1
+        // author2  book2   book4
+        // author2  book2   book3
+        // author2  book2   book2
+        // author2  book3   book4
+        // ...
+        bookList = BookPeer.doSelect(criteria);
+        if (bookList.size() != 10)
+        {
+            fail("ordering by Aliases (2): "
+                    + "incorrect numbers of books found : "
+                    + bookList.size()
+                    + ", should be 10");
+        }
+        if (!"Book 2".equals(bookList.get(1).getTitle()))
+        {
+            fail("ordering by Aliases (2, PS): "
+                    + "Title of second Book is "
+                    + bookList.get(1).getTitle()
+                    + ", should be \"Book 2\"");
+        }
+        if (!"Book 2".equals(bookList.get(2).getTitle()))
+        {
+            fail("ordering by Aliases (2, PS): "
+                    + "Title of third Book is "
+                    + bookList.get(2).getTitle()
+                    + ", should be \"Book 2\"");
+        }
+
+        // test usage of Expressions in order by
+        criteria = new Criteria();
+        criteria.addAscendingOrderByColumn(
+                new ColumnImpl("UPPER(" + BookPeer.TITLE + ")"));
+        criteria.setIgnoreCase(true);
+        BookPeer.doSelect(criteria);
+    }
+
+
+    /**
+     * Tests whether ignoreCase works correctly
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testIgnoreCase() throws Exception
+    {
+        cleanBookstore();
+
+        // check ignore case in selects
+        Author author = new Author();
+        author.setName("AuTHor");
+        author.save();
+
+        Criteria criteria = new Criteria();
+        criteria.where(AuthorPeer.NAME, author.getName().toLowerCase());
+        criteria.setIgnoreCase(true);
+        List<Author> result = AuthorPeer.doSelect(criteria);
+        assertTrue("Size of result is not 1, but " + result.size(),
+                result.size() == 1);
+
+        // LIKE treatment might be different (e.g. postgres), so check extra
+        criteria = new Criteria();
+        criteria.where(
+                AuthorPeer.NAME,
+                author.getName().toLowerCase().replace('r', '%'),
+                Criteria.LIKE);
+        criteria.setIgnoreCase(true);
+        result = AuthorPeer.doSelect(criteria);
+        assertTrue("Size of result is not 1, but " + result.size(),
+                result.size() == 1);
+
+        // Test ignore case in criterion
+        criteria = new Criteria();
+        Criterion criterion1 = new Criterion(
+                AuthorPeer.NAME,
+                author.getName().toLowerCase(),
+                Criteria.EQUAL);
+        criterion1.setIgnoreCase(true);
+        Criterion criterion2 = new Criterion(
+                AuthorPeer.AUTHOR_ID, null, Criteria.NOT_EQUAL);
+        criterion1.and(criterion2);
+
+        result = AuthorPeer.doSelect(criteria);
+
+        // ignore case should not be set either in Criteria
+        // nor in other criterions
+        assertFalse(criteria.isIgnoreCase());
+        assertFalse(criterion2.isIgnoreCase());
+        assertTrue("Size of result is not 1, but " + result.size(),
+                result.size() == 1);
+
+
+        // Test ignore case in attached criterion
+        criteria = new Criteria();
+        criterion1 = new Criterion(
+                AuthorPeer.AUTHOR_ID, null, Criteria.NOT_EQUAL);
+        criterion2 = new Criterion(
+                AuthorPeer.NAME,
+                author.getName().toLowerCase(),
+                Criteria.EQUAL);
+        criterion2.setIgnoreCase(true);
+        criterion1.and(criterion2);
+
+        result = AuthorPeer.doSelect(criteria);
+
+        // ignore case should not be set either in Criteria
+        // nor in other criterions
+        assertFalse(criteria.isIgnoreCase());
+        assertFalse(criterion1.isIgnoreCase());
+
+        assertTrue("Size of result is not 1, but " + result.size(),
+                result.size() == 1);
+
+        // ignore case in "in" query
+        {
+            criteria = new Criteria();
+            Set<String> names = new HashSet<>();
+            names.add(author.getName().toLowerCase());
+            criteria.where(AuthorPeer.NAME, names, Criteria.IN);
+            criteria.setIgnoreCase(true);
+
+            result = AuthorPeer.doSelect(criteria);
+            assertEquals("Expected result of size 1 but got " + result.size(),
+                    result.size(),
+                    1);
+        }
+
+        // Check that case is not ignored if ignoreCase is not set
+        // This is known not to work for mysql
+        author = new Author();
+        author.setName("author");
+        author.save();
+
+        Adapter adapter = Torque.getAdapter(Torque.getDefaultDB());
+        if (adapter instanceof MysqlAdapter
+                || adapter instanceof MssqlAdapter)
+        {
+            log.error("testIgnoreCase(): "
+                    + "Case sensitive comparisons are known not to work"
+                    + " with Mysql and MSSQL");
+            // failing is "expected", so bypass without error
+        }
+        else
+        {
+            criteria = new Criteria();
+            criteria.where(AuthorPeer.NAME, author.getName());
+            result = AuthorPeer.doSelect(criteria);
+            assertTrue("Size of result is not 1, but " + result.size(),
+                    result.size() == 1);
+
+            // again check LIKE treatment
+            criteria = new Criteria();
+            criteria.where(
+                    AuthorPeer.NAME,
+                    author.getName().replace('r', '%'),
+                    Criteria.LIKE);
+            result = AuthorPeer.doSelect(criteria);
+            assertTrue("Size of result is not 1, but " + result.size(),
+                    result.size() == 1);
+
+            // Test different ignore cases in criterions
+            criteria = new Criteria();
+            criterion1 = new Criterion(
+                    AuthorPeer.NAME,
+                    author.getName().toLowerCase(),
+                    Criteria.NOT_EQUAL);
+            criterion2 = new Criterion(
+                    AuthorPeer.NAME,
+                    author.getName().toLowerCase(),
+                    Criteria.EQUAL);
+            criterion2.setIgnoreCase(true);
+            criterion1.and(criterion2);
+            criteria.where(criterion1);
+
+            result = AuthorPeer.doSelect(criteria);
+            assertTrue("Size of result is not 1, but " + result.size(),
+                    result.size() == 1);
+
+            // ignore case in "in" query
+            {
+                criteria = new Criteria();
+                Set<String> names = new HashSet<>();
+                names.add(author.getName());
+                criteria.where(AuthorPeer.NAME, names, Criteria.IN);
+
+                result = AuthorPeer.doSelect(criteria);
+                assertEquals("Expected result of size 1 but got " + result.size(),
+                        result.size(),
+                        1);
+            }
+        }
+
+        cleanBookstore();
+        author = new Author();
+        author.setName("AA");
+        author.save();
+        author = new Author();
+        author.setName("BB");
+        author.save();
+        author = new Author();
+        author.setName("ba");
+        author.save();
+        author = new Author();
+        author.setName("ab");
+        author.save();
+
+        // check ignoreCase in Criteria
+        criteria = new Criteria();
+        criteria.setIgnoreCase(true);
+        criteria.addAscendingOrderByColumn(AuthorPeer.NAME);
+        result = AuthorPeer.doSelect(criteria);
+        assertTrue("Size of result is not 4, but " + result.size(),
+                result.size() == 4);
+        assertEquals("AA", result.get(0).getName());
+        assertEquals("ab", result.get(1).getName());
+        assertEquals("ba", result.get(2).getName());
+        assertEquals("BB", result.get(3).getName());
+
+        // check ignoreCase in orderBy
+        criteria = new Criteria();
+        criteria.addAscendingOrderByColumn(AuthorPeer.NAME, true);
+        result = AuthorPeer.doSelect(criteria);
+        assertTrue("Size of result is not 4, but " + result.size(),
+                result.size() == 4);
+        assertEquals(result.get(0).getName(), "AA");
+        assertEquals(result.get(1).getName(), "ab");
+        assertEquals(result.get(2).getName(), "ba");
+        assertEquals(result.get(3).getName(), "BB");
+    }
+
+    /**
+     * tests whether AsColumns produce valid SQL code
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testAsColumn() throws Exception
+    {
+        Criteria criteria = new Criteria();
+        criteria.addAsColumn("ALIASNAME", AuthorPeer.NAME);
+        // we need an additional column to select from,
+        // to indicate the table we want use
+        criteria.addSelectColumn(AuthorPeer.AUTHOR_ID);
+        new BasePeerImpl<>().doSelect(criteria, new DoNothingMapper());
+    }
+
+    /**
+     * Test whether same column name in different tables
+     * are handled correctly
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testSameColumnName() throws Exception
+    {
+        cleanBookstore();
+        Author author = new Author();
+        author.setName("Name");
+        author.save();
+
+        author = new Author();
+        author.setName("NotCorrespondingName");
+        author.save();
+
+        Book book = new Book();
+        book.setTitle("Name");
+        book.setAuthor(author);
+        book.setIsbn("unknown");
+        book.save();
+
+        Criteria criteria = new Criteria();
+        criteria.addJoin(BookPeer.TITLE, AuthorPeer.NAME);
+        BookPeer.addSelectColumns(criteria);
+        AuthorPeer.addSelectColumns(criteria);
+        // basically a BaseBookPeer.setDbName(criteria);
+        // and BasePeer.doSelect(criteria);
+        CompositeMapper mapper = new CompositeMapper();
+        mapper.addMapper(new BookRecordMapper(), 0);
+        mapper.addMapper(
+                new AuthorRecordMapper(),
+                BookPeer.numColumns);
+
+        List<List<Object>> queryResult
+        = BookPeer.doSelect(criteria, mapper);
+        List<Object> mappedRow = queryResult.get(0);
+        book = (Book) mappedRow.get(0);
+        author = (Author) mappedRow.get(1);
+
+        if (book.getAuthorId() == author.getAuthorId())
+        {
+            fail("wrong Ids read");
+        }
+    }
+
+    /**
+     * tests whether large primary keys are inserted and read correctly
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testLargePk() throws Exception
+    {
+        if (defaultAdapter instanceof MssqlAdapter) {
+            log.error("testLargePk(): "
+                    + "MSSQL does not support inserting defined PK values");
+            return;
+        }
+        BigintTypePeer.doDelete(new Criteria());
+
+        long longId = 8771507845873286l;
+        BigintType bigintType = new BigintType();
+        bigintType.setId(longId);
+        bigintType.save();
+
+        List<BigintType> bigintTypeList = BigintTypePeer.doSelect(new Criteria());
+        BigintType readBigintType = bigintTypeList.get(0);
+        assertEquals(bigintType.getId(), readBigintType.getId());
+        assertEquals(longId, readBigintType.getId());
+    }
+
+    /**
+     * tests whether large bigint values are inserted and read correctly
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testLargeValue() throws Exception
+    {
+        BigintTypePeer.doDelete(new Criteria());
+
+        long longValue = 8771507845873286l;
+        BigintType bigintType = new BigintType();
+        bigintType.setBigintValue(longValue);
+        bigintType.save();
+
+        List<BigintType> bigintTypeList = BigintTypePeer.doSelect(new Criteria());
+        BigintType readBigintType = bigintTypeList.get(0);
+        assertEquals(bigintType.getId(), readBigintType.getId());
+        assertEquals(longValue, readBigintType.getBigintValue());
+    }
+
+    /**
+     * Tests the CountHelper class
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testCountHelper() throws Exception
+    {
+        cleanBookstore();
+        Author author = new Author();
+        author.setName("Name");
+        author.save();
+
+        author = new Author();
+        author.setName("Name2");
+        author.save();
+
+        author = new Author();
+        author.setName("Name");
+        author.save();
+
+        Criteria criteria = new Criteria();
+        int count = new CountHelper().count(
+                criteria,
+                null,
+                AuthorPeer.AUTHOR_ID);
+
+        if (count != 3) {
+            fail("counted " + count + " datasets, should be 3 ");
+        }
+
+        criteria = new Criteria();
+        criteria.setDistinct();
+        count = new CountHelper().count(criteria, null, AuthorPeer.NAME);
+
+        if (count != 2) {
+            fail("counted " + count + " distinct datasets, should be 2 ");
+        }
+
+        criteria = new Criteria();
+        criteria.where(AuthorPeer.NAME, "Name2");
+        count = new CountHelper().count(criteria);
+
+        if (count != 1) {
+            fail("counted " + count + " datasets with name Name2,"
+                    + " should be 1 ");
+        }
+    }
+
+
+    /**
+     * Tests whether we can handle multiple primary keys some of which are
+     * also foreign keys
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testMultiplePrimaryForeignKey() throws Exception
+    {
+        ForeignKeySchemaData.clearTablesInDatabase();
+
+        OIntegerPk oIntegerPk = new OIntegerPk();
+        oIntegerPk.save();
+        CompPkContainsFk compPkContainsFk = new CompPkContainsFk();
+        compPkContainsFk.setId1(oIntegerPk.getId());
+        compPkContainsFk.setId2("test");
+        compPkContainsFk.save();
+
+        List<CompPkContainsFk> selectedList
+        = CompPkContainsFkPeer.doSelect(new Criteria());
+        assertEquals(1, selectedList.size());
+        CompPkContainsFk selected = selectedList.get(0);
+        assertEquals(oIntegerPk.getId(), selected.getId1());
+        assertEquals("test", selected.getId2());
+    }
+
+    /**
+     * Tests inserting single quotes in Strings.
+     * This may not crash now, but in a later task like datasql,
+     * so the data has to be inserted in a table which does not get cleaned
+     * during the runtime test.
+     * @throws Exception if inserting the test data fails
+     */
+    @Test
+    public void testSingleQuotes() throws Exception
+    {
+        cleanBookstore();
+
+        Author author = new Author();
+        author.setName("has Single ' Quote");
+        author.save();
+    }
+
+    /**
+     * Test whether equals() is working correctly
+     * @throws Exception
+     */
+    @Test
+    public void testEquals() throws Exception
+    {
+        Author author = new Author();
+        author.setAuthorId(1000);
+
+        Book book = new Book();
+        book.setBookId(1000);
+
+        Book bookNotEqual = new Book();
+        bookNotEqual.setBookId(2000);
+
+        Book bookEqual = new Book();
+        bookEqual.setBookId(1000);
+
+        assertFalse("Author and Book should not be equal",
+                author.equals(book));
+        assertTrue("Book compared with itself should be equal",
+                book.equals(book));
+        assertTrue("Book compared with book with same id should be equal",
+                book.equals(bookEqual));
+        assertFalse("Book compared with book with different id "
+                + "should not be equal",
+                book.equals(bookNotEqual));
+    }
+
+    /**
+     * Tests whether a table implementing an interface actually
+     * returns an instance of this interface
+     * @throws Exception if the test fails
+     */
+    @Test
+    public void testInterface() throws Exception
+    {
+        Criteria criteria = new Criteria();
+        criteria.where(IfcTablePeer.ID, -1, Criteria.NOT_EQUAL);
+        IfcTablePeer.doDelete(criteria);
+
+        IfcTable ifc = new IfcTable();
+
+        assertTrue("IfcTable should be an instance of TestInterface",
+                ifc instanceof TestInterface);
+
+        ifc.setID(1);
+        ifc.setName("John Doe");
+        ifc.save();
+
+        List<IfcTable> results = IfcTablePeer.doSelect(new Criteria());
+
+        for (IfcTable ifcTable : results)
+        {
+            assertTrue("IfcTablePeer.doSelect should return"
+                    + " instances of TestInterface",
+                    ifcTable instanceof TestInterface);
+        }
+
+        IfcTablePeerImpl peerImpl = IfcTablePeer.getIfcTablePeerImpl();
+        assertTrue("IfcTablePeerImpl should be an instance of "
+                + "TestPeerInterface",
+                peerImpl instanceof TestPeerInterface);
+
+        LocalIfcTable localIfc = new LocalIfcTable();
+
+        assertTrue("LocalIfcTable should be an instance of LocalTestInterface",
+                localIfc instanceof LocalTestInterface);
+
+        List<LocalIfcTable> results2 = LocalIfcTablePeer.doSelect(new Criteria());
+
+        for (LocalIfcTable readLocalIfcTable : results2)
+        {
+            assertTrue("IfcTable2Peer.doSelect should return"
+                    + " instances of LocalTestInterface",
+                    readLocalIfcTable instanceof LocalTestInterface);
+        }
+
+        LocalIfcTablePeerImpl localPeerImpl = LocalIfcTablePeer.getLocalIfcTablePeerImpl();
+        assertTrue("LocalIfcTablePeerImpl should be an instance of "
+                + "LocalTestPeerInterface",
+                localPeerImpl instanceof LocalTestPeerInterface);
+    }
+
+    @Test
+    public void testInheritanceWithKeys() throws Exception
+    {
+        // make sure that the InheritanceTest table is empty before the test
+        Criteria criteria = new Criteria();
+        criteria.where(
+                InheritanceTestPeer.INHERITANCE_TEST,
+                (Object) null,
+                Criteria.ISNOTNULL);
+        InheritanceTestPeer.doDelete(criteria);
+        criteria = new Criteria();
+        criteria.where(
+                InheritanceTestPeer.INHERITANCE_TEST,
+                (Object) null,
+                Criteria.ISNOTNULL);
+        assertEquals(0,
+                new CountHelper().count(criteria));
+
+        // create & save test data
+        InheritanceTest inheritanceTest = new InheritanceTest();
+        inheritanceTest.setPayload("payload1");
+        inheritanceTest.save();
+        InheritanceChildB inheritanceChildB = new InheritanceChildB();
+        inheritanceChildB.setPayload("payload 2");
+        inheritanceChildB.save();
+        InheritanceChildC inheritanceChildC = new InheritanceChildC();
+        inheritanceChildC.setPayload("payload 3");
+        inheritanceChildC.save();
+        InheritanceChildD inheritanceChildD = new InheritanceChildD();
+        inheritanceChildD.setPayload("payload 4");
+        inheritanceChildD.save();
+
+        // Check that all objects are saved into the InheritanceTest table
+        criteria = new Criteria();
+        criteria.where(
+                InheritanceTestPeer.INHERITANCE_TEST,
+                null,
+                Criteria.ISNOTNULL);
+        assertEquals("InheritanceTestTable should contain 4 rows",
+                4,
+                new CountHelper().count(criteria));
+        criteria = new Criteria();
+        criteria.addAscendingOrderByColumn(
+                InheritanceTestPeer.INHERITANCE_TEST);
+
+        // Check that the class of the object is retained when loading
+        List<InheritanceTest> inheritanceObjects
+        = InheritanceTestPeer.doSelect(criteria);
+        assertEquals(
+                InheritanceTest.class,
+                inheritanceObjects.get(0).getClass());
+        assertEquals(
+                InheritanceChildB.class,
+                inheritanceObjects.get(1).getClass());
+        assertEquals(
+                InheritanceChildC.class,
+                inheritanceObjects.get(2).getClass());
+        assertEquals(
+                InheritanceChildD.class,
+                inheritanceObjects.get(3).getClass());
+    }
+
+    @Test
+    public void testInheritanceWithClassname() throws Exception
+    {
+        // make sure that the InheritanceTest table is empty before the test
+        Criteria criteria = new Criteria();
+        InheritanceClassnameTestPeer.doDelete(criteria);
+        criteria = new Criteria();
+        criteria.where(
+                InheritanceClassnameTestPeer.INHERITANCE_TEST,
+                null,
+                Criteria.ISNOTNULL);
+        assertEquals(0,
+                new CountHelper().count(criteria));
+
+        // create & save test data
+        InheritanceClassnameTest inheritanceClassnameTest
+            = new InheritanceClassnameTest();
+        inheritanceClassnameTest.setPayload("0 parent");
+        inheritanceClassnameTest.save();
+        InheritanceClassnameTestChild1 inheritanceClassnameChild1
+            = new InheritanceClassnameTestChild1();
+        inheritanceClassnameChild1.setPayload("1 child");
+        inheritanceClassnameChild1.save();
+        InheritanceClassnameTestChild2 inheritanceClassnameChild2
+            = new InheritanceClassnameTestChild2();
+        inheritanceClassnameChild2.setPayload("2 child");
+        inheritanceClassnameChild2.save();
+
+        // Check that all objects are saved into the InheritanceTest table
+        criteria = new Criteria();
+        criteria.where(
+                InheritanceClassnameTestPeer.INHERITANCE_TEST,
+                null,
+                Criteria.ISNOTNULL);
+        assertEquals("InheritanceClassnameTest table should contain 3 rows",
+                3,
+                new CountHelper().count(criteria));
+        criteria = new Criteria();
+        criteria.addAscendingOrderByColumn(
+                InheritanceClassnameTestPeer.PAYLOAD);
+
+        // Check that the class of the object is retained when loading
+        List<InheritanceClassnameTest> inheritanceObjects
+        = InheritanceClassnameTestPeer.doSelect(criteria);
+        assertEquals(
+                InheritanceClassnameTest.class,
+                inheritanceObjects.get(0).getClass());
+        assertEquals("0 parent", inheritanceObjects.get(0).getPayload());
+        assertEquals(
+                InheritanceClassnameTestChild1.class,
+                inheritanceObjects.get(1).getClass());
+        assertEquals("1 child", inheritanceObjects.get(1).getPayload());
+        assertEquals(
+                InheritanceClassnameTestChild2.class,
+                inheritanceObjects.get(2).getClass());
+        assertEquals("2 child", inheritanceObjects.get(2).getPayload());
+    }
+
+    /**
+     * Checks whether selects with unqualified column names work.
+     *
+     * @throws Exception if a problem occurs.
+     */
+    @Test
+    public void testUnqualifiedColumnNames() throws Exception
+    {
+        cleanBookstore();
+        Author author = new Author();
+        author.setName("Joshua Bloch");
+        author.save();
+
+        Criteria criteria = new Criteria();
+        criteria.where(AuthorPeer.AUTHOR_ID, (Object) null, Criteria.NOT_EQUAL);
+        criteria.and(new ColumnImpl("name"), "Joshua Bloch", Criteria.EQUAL);
+        List<Author> authors = AuthorPeer.doSelect(criteria);
+        assertEquals(1, authors.size());
+    }
+
+    @Test
+    public void testLikeClauseEscaping() throws Exception
+    {
+        String[] authorNames
+        = {"abc", "bbc", "a_c", "a%c", "a\\c",
+                "a\"c", "a'c", "a?c", "a*c" };
+
+        Map<String, String> likeResults = new LinkedHashMap<>();
+
+        likeResults.put("a\\_c", "a_c");
+        likeResults.put("a\\_%", "a_c");
+        likeResults.put("%\\_c", "a_c");
+
+        likeResults.put("a\\%c", "a%c");
+        likeResults.put("a\\%%", "a%c");
+        likeResults.put("%\\%c", "a%c"); // escaped second %
+
+        likeResults.put("a\\\\c", "a\\c"); // escaped \ three times
+        likeResults.put("a\\\\%", "a\\c");
+        
+        // mysql: like '%\\c' ESCAPE '|' succeeds, but
+        // %\\\\c fails, see https://dev.mysql.com/doc/refman/8.0/en/string-comparison-functions.html, 
+        // MySQL uses C escape syntax in strings..  you must double any \ that you use in LIKE strings.
+        // That is platform specific mysql:
+        // likeResults.put("%\\\\\\\\c", "a\\c"); // succeeds in mysql
+        // other platforms ?
+        //likeResults.put("%\\\\c", "a\\c"); // fails in mysql
+        
+        likeResults.put("a\\*c", "a*c");
+        likeResults.put("a\\*%", "a*c");
+        //likeResults.put("%\\*c", "a*c"); // mysql: %\\*c fails, only underscore (_) is wild card
+        // this matches multiple users
+        //likeResults.put("%*c", "a%c"); 
+        likeResults.put("_\\*c", "a*c"); 
+
+        likeResults.put("a\\?c", "a?c");
+        likeResults.put("a\\?%", "a?c");
+        likeResults.put("%\\?c", "a?c");
+
+        likeResults.put("a\"c", "a\"c");
+        likeResults.put("a\"%", "a\"c");
+        likeResults.put("%\"c", "a\"c");
+
+        likeResults.put("a'c", "a'c");
+        likeResults.put("a'%", "a'c");
+        likeResults.put("%'c", "a'c");
+        cleanBookstore();
+
+        // Save authors
+        for (int i = 0; i < authorNames.length; ++i)
+        {
+            Author author = new Author();
+            author.setName(authorNames[i]);
+            author.save();
+        }
+
+        // Check authors are in the database
+        for (int i = 0; i < authorNames.length; ++i)
+        {
+            Criteria criteria = new Criteria();
+            criteria.where(AuthorPeer.NAME, authorNames[i]);
+            List<Author> authorList = AuthorPeer.doSelect(criteria);
+            assertEquals(
+                    "AuthorList should contain one author"
+                            + " when querying for " + authorNames[i],
+                            1,
+                            authorList.size());
+            Author author = authorList.get(0);
+            assertEquals("Name of author should be " + authorNames[i],
+                    authorNames[i],
+                    author.getName());
+        }
+
+        for (Map.Entry<String, String> likeResult : likeResults.entrySet())
+        {
+            // System.out.println("Key: " + likeResult.getKey() + " - Value: " + likeResult.getValue());
+            Criteria criteria = new Criteria();
+            criteria.where(
+                    AuthorPeer.NAME,
+                    likeResult.getKey(),
+                    Criteria.LIKE);
+            List<Author> authorList;
+            try
+            {
+                authorList = AuthorPeer.doSelect(criteria);
+            }
+            catch (Exception e)
+            {
+                throw new Exception(
+                        "error executing select using like content "
+                                + likeResult.getKey(),
+                                e);
+            }
+            assertEquals(
+                    "AuthorList contained " + authorList.size() + ", but should contain one author"
+                            + " when querying for " + likeResult.getKey(),
+                            1,
+                            authorList.size());
+            Author author = authorList.get(0);
+            assertEquals("Name of author should be "
+                    + likeResult.getValue()
+                    + " when querying for "
+                    + likeResult.getKey(),
+                    likeResult.getValue(),
+                    author.getName());
+        }
+
+        // check that case insensitivity is maintained if
+        // a like is replaced with an equals (no wildcard present)
+        // This might be a problem for databases which use ILIKE
+        Criteria criteria = new Criteria();
+        criteria.where(AuthorPeer.NAME, "AbC", Criteria.LIKE);
+        criteria.setIgnoreCase(true);
+        List<Author> authorList = AuthorPeer.doSelect(criteria);
+        assertEquals(
+                "AuthorList should contain one author",
+                1,
+                authorList.size());
+        Author author = authorList.get(0);
+        assertEquals("Name of author should be abc",
+                "abc",
+                author.getName());
+
+        // check that the escape clause (where needed) also works
+        // with limit, offset and order by
+        criteria = new Criteria();
+        Criterion criterion1 = new Criterion(
+                AuthorPeer.NAME,
+                "b%",
+                Criteria.LIKE);
+        Criterion criterion2 = new Criterion(
+                AuthorPeer.NAME,
+                "a\\%%",
+                Criteria.LIKE);
+        Criterion criterion3 = new Criterion(
+                AuthorPeer.NAME,
+                "cbc",
+                Criteria.LIKE);
+        criteria.where(criterion1.or(criterion2).or(criterion3));
+        criteria.addAscendingOrderByColumn(AuthorPeer.NAME);
+        criteria.setOffset(1);
+        criteria.setLimit(1);
+        authorList = AuthorPeer.doSelect(criteria);
+        assertEquals(
+                "AuthorList should contain one author",
+                1,
+                authorList.size());
+        author = authorList.get(0);
+        assertEquals("Name of author should be bbc",
+                "bbc",
+                author.getName());
+    }
+
+
+    /**
+     * Strips the schema and table name from a fully qualified colum name
+     * This is useful for creating Query with aliases, as the constants
+     * for the colum names in the data objects are fully qualified.
+     * @param fullyQualifiedColumnName the fully qualified column name, not null
+     * @return the column name stripped from the table (and schema) prefixes
+     */
+    public static String getRawColumnName(final String fullyQualifiedColumnName)
+    {
+        int dotPosition = fullyQualifiedColumnName.lastIndexOf(".");
+        if (dotPosition == -1)
+        {
+            return fullyQualifiedColumnName;
+        }
+        String result = fullyQualifiedColumnName.substring(
+                dotPosition + 1,
+                fullyQualifiedColumnName.length());
+        return result;
+    }
+
+    static class DoNothingMapper implements RecordMapper<Object>
+    {
+
+        /** Serial version */
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public Object processRow(
+                final ResultSet resultSet,
+                final int rowOffset,
+                final Criteria criteria)
+                        throws TorqueException
+        {
+            return null;
+        }
+    }
+}

Propchange: db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/testcontainer/DataContainerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/torque/torque4/trunk/torque-test/src/test/profile/mysql/Torque4Test.xml
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-test/src/test/profile/mysql/Torque4Test.xml?rev=1870385&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-test/src/test/profile/mysql/Torque4Test.xml (added)
+++ db/torque/torque4/trunk/torque-test/src/test/profile/mysql/Torque4Test.xml Mon Nov 25 15:22:32 2019
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<!-- from the docs:  CombinedConfigurationBuilder takes care that properties defined in the first file (the user file) are found; other properties which the user has not changed will still be returned from the second file (the defaults file). -->
+
+<configuration>
+ <properties config-name="torqueuser" fileName="torque.usersettings.properties" config-optional="true" config-forceCreate="true"/> 
+ <properties config-name="torque" fileName="Torque.properties" throwExceptionOnMissing="true"/>
+</configuration>
\ No newline at end of file

Propchange: db/torque/torque4/trunk/torque-test/src/test/profile/mysql/Torque4Test.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/.dockerignore
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/.dockerignore?rev=1870385&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/.dockerignore (added)
+++ db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/.dockerignore Mon Nov 25 15:22:32 2019
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+*/tmp*
+*/*/tmp*
+tmp?
\ No newline at end of file

Added: db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/Dockerfile
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/Dockerfile?rev=1870385&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/Dockerfile (added)
+++ db/torque/torque4/trunk/torque-test/src/test/profile/mysql/docker-resources/db/Dockerfile Mon Nov 25 15:22:32 2019
@@ -0,0 +1,10 @@
+FROM mysql:8.0.18
+
+COPY [ "./generated-createddb-sql/*", "./generated-sql/*", "/docker-entrypoint-initdb.d/" ] 
+
+ENV MYSQL_DATABASE ${MYSQL_DATABASE} 
+ENV MYSQL_USER=${MYSQL_USER} 
+ENV MYSQL_PASSWORD=${MYSQL_PASSWORD} 
+ENV MYSQL_HOST=%
+
+ENV MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}



---------------------------------------------------------------------
To unsubscribe, e-mail: torque-dev-unsubscribe@db.apache.org
For additional commands, e-mail: torque-dev-help@db.apache.org


Mime
View raw message