<rdf:RDF
    xmlns:s='http://snipsnap.org/rdf/snip-schema#'
    xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
    xml:base='http://www.stefanrufer.ch/snipsnap/rdf'>
    <s:Snip rdf:about='http://www.stefanrufer.ch/snipsnap/rdf#My+Projects/dbbuild'
         s:cUser='stefan'
         s:oUser='stefan'
         s:mUser='stefan'>
        <s:name>My Projects/dbbuild</s:name>
        <s:content>{image:My Projects/dbbuild/jazoonlogo_web.gif|Jazoon08|gif}&#xD;&#xA;&#xD;&#xA;1 Introduction&#xD;&#xA;&#xD;&#xA;As follow up of the presentation {link:3020 - Let the Continuous Build Embrace the Database|http://jazoon.com/jazoon08/en/conference/presentations/tl/3020} at {link:Jazoon 08|http://jazoon.com} the following software is published. &#xD;&#xA;&#xD;&#xA;Note that it is {link:License Free Software|http://en.wikipedia.org/wiki/License-free_software} so feel free to use. We are open for discussions and suggestions but the software is distributed as-is - without support warranty or whatsoever.&#xD;&#xA;&#xD;&#xA;Many thanks to {link:Telekurs Card Solutions|http://www.telekurs.com} for allowing us to publish this work!&#xD;&#xA;&#xD;&#xA;&#xD;&#xA;1 Continuous Database Build&#xD;&#xA;&#xD;&#xA;This software distribution allows you to set up a continuous database build as described in the presentation. It consists of two parts:&#xD;&#xA;&#xD;&#xA; - Setup: Run this scripts once on the database schemas where your continuous database build should operate or where it should be installed. It adds a few infrastructure objects that are required to keep track of the SQL scripts that have been installed in the database.&#xD;&#xA; - Build: This is the collection of shell and SQL scripts that is able to run a database build. It can be run by a continuous integration system but as well directly from a shell. We use the scripts under Linux (SuSE) and Solaris 8. &#xD;&#xA;&#xD;&#xA;There are some Flash movies showing a continuous database build system in action:&#xD;&#xA; - {link:Create new table and add new column|http://www.stefanrufer.ch/java/jazoon08/jazoon08-3020_demo-1.htm}&#xD;&#xA; - {link:Rename a column|http://www.stefanrufer.ch/java/jazoon08/jazoon08-3020_demo-2.htm}&#xD;&#xA; - {link:Install a database release using the shell script built by the database build|http://www.stefanrufer.ch/java/jazoon08/jazoon08-3020_demo-3.htm}&#xD;&#xA;&#xD;&#xA;Downloads:&#xD;&#xA; - {link:Download Setup Part.|space/My Projects/dbbuild/database-2008-06-21-011038.zip}&#xD;&#xA; - {link:Download Build Part.|space/My Projects/dbbuild/setup-2008-06-21-011038.zip}&#xD;&#xA;&#xD;&#xA;Contact:&#xD;&#xA; - Michael Wernli (michael dot wernli at telekurs dot com)&#xD;&#xA;&#xD;&#xA;1 JUnit Extension&#xD;&#xA;&#xD;&#xA;This software distribution allows you to implement JUnit based test cases that clean up all database modifications after a test run using a rollback operation.&#xD;&#xA;&#xD;&#xA;A simple example test case is included below.&#xD;&#xA;&#xD;&#xA;Downloads:&#xD;&#xA; - {link:Download JAR.|http://stefanrufer.ch/mvn/internal/ch/stefanrufer/libraries/junitextension/junitextension/1.0.4/junitextension-1.0.4.jar}&#xD;&#xA; - {link:Download Source JAR.|http://stefanrufer.ch/mvn/internal/ch/stefanrufer/libraries/junitextension/junitextension/1.0.4/junitextension-1.0.4-sources.jar}&#xD;&#xA; - {link:Maven Site Documentation|http://stefanrufer.ch/mvn/internal/ch/stefanrufer/libraries/junitextension/junitextension/1.0.4/site/}&#xD;&#xA; - {link:JUnit Extension Auto Rollback Demo Project|space/My+Projects/dbbuild/junitextension-demo-autorollback.zip} - ready to run from Eclipse&#xD;&#xA; - {link:Multimodule Maven and Eclipse Setup Demo|space/My+Projects/dbbuild/junitextension-demo-config.zip} - a minimal multimodule build setup that demonstrates how to define database connection information in one place for both Maven 2 and Eclipse project setups.&#xD;&#xA;&#xD;&#xA;Contact:&#xD;&#xA; - Stefan Rufer (mail@stefanrufer.ch)&#xD;&#xA;&#xD;&#xA;{code:java}&#xD;&#xA;package ch.stefanrufer.libraries.junitextension.jdbc;&#xD;&#xA;&#xD;&#xA;import java.sql.ResultSet;&#xD;&#xA;import java.sql.SQLException;&#xD;&#xA;import java.sql.Statement;&#xD;&#xA;&#xD;&#xA;import javax.sql.DataSource;&#xD;&#xA;&#xD;&#xA;/**&#xD;&#xA; * Demo how to use the {@link AutoRollbackTestCase}.&#xD;&#xA; * &#xD;&#xA; * It specifically shows how all of the insert/update/delete&#xD;&#xA; * operations in each test method work isolated because a &#xD;&#xA; * rollback is executed during test tear down.&#xD;&#xA; */&#xD;&#xA;public class ExampleRollbackTestCase extends AutoRollbackTestCase {&#xD;&#xA;&#xD;&#xA;  /**&#xD;&#xA;   * Set up test table in database.&#xD;&#xA;   * &#xD;&#xA;   * @param ds the initialized data source&#xD;&#xA;   * @throws SQLException if DB access fails&#xD;&#xA;   */&#xD;&#xA;  @Override&#xD;&#xA;  public void setUp(DataSource ds) throws SQLException {&#xD;&#xA;    Statement stmt = ds.getConnection().createStatement();&#xD;&#xA;    stmt.execute(&quot;CREATE TABLE testtable (testcolumn VARCHAR(1))&quot;);&#xD;&#xA;    stmt.close();&#xD;&#xA;  }&#xD;&#xA;  &#xD;&#xA;  /**&#xD;&#xA;   * Try to execute a DB insert and see if the table really contains&#xD;&#xA;   * the row at the end.&#xD;&#xA;   * &#xD;&#xA;   * @throws SQLException if DB access fails&#xD;&#xA;   */&#xD;&#xA;  public void testDbInsert() throws SQLException {&#xD;&#xA;    Statement stmt = getDataSource().getConnection().createStatement();&#xD;&#xA;    int rowCount = stmt.executeUpdate(&quot;DELETE FROM testtable&quot;);&#xD;&#xA;    assertEquals(&quot;Excpect table to be empty initially&quot;, 0, rowCount);&#xD;&#xA;    rowCount = stmt.executeUpdate(&quot;INSERT INTO testtable values (&apos;X&apos;)&quot;);&#xD;&#xA;    assertEquals(&quot;Expect insert to affect exactly 1 row&quot;, 1, rowCount);&#xD;&#xA;    &#xD;&#xA;    ResultSet rs = stmt.executeQuery(&quot;SELECT * FROM testtable&quot;);&#xD;&#xA;    assertTrue(&quot;expect 1 row&quot;, rs.next());&#xD;&#xA;    assertEquals(&quot;X&quot;, rs.getString(&quot;testcolumn&quot;));&#xD;&#xA;    assertFalse(&quot;expect only 1 row&quot;, rs.next());&#xD;&#xA;  }&#xD;&#xA;  &#xD;&#xA;  /**&#xD;&#xA;   * Try to execute a DB update and see if the table really contains&#xD;&#xA;   * the updated values at the end.&#xD;&#xA;   * &#xD;&#xA;   * @throws SQLException if DB access fails&#xD;&#xA;   */&#xD;&#xA;  public void testDbUpdate() throws SQLException {&#xD;&#xA;    Statement stmt = getDataSource().getConnection().createStatement();&#xD;&#xA;    stmt.executeUpdate(&quot;INSERT INTO testtable values (&apos;X&apos;)&quot;);&#xD;&#xA;    int rowCount = stmt.executeUpdate(&quot;UPDATE testtable SET testcolumn=&apos;Y&apos; WHERE testcolumn=&apos;X&apos;&quot;);&#xD;&#xA;    assertEquals(&quot;expect exactly 1 update&quot;, 1, rowCount);&#xD;&#xA;    &#xD;&#xA;    ResultSet rs = stmt.executeQuery(&quot;SELECT * FROM testtable&quot;);&#xD;&#xA;    // works because we are always on the same connection&#xD;&#xA;    assertTrue(&quot;expect 1 row&quot;, rs.next());&#xD;&#xA;    assertEquals(&quot;Y&quot;, rs.getString(&quot;testcolumn&quot;));&#xD;&#xA;    assertFalse(&quot;expect exactly 1 row&quot;, rs.next());&#xD;&#xA;  }&#xD;&#xA;  &#xD;&#xA;  /**&#xD;&#xA;   * Check if deleting everything works as expected.&#xD;&#xA;   * &#xD;&#xA;   * @throws SQLException if DB access fails&#xD;&#xA;   */&#xD;&#xA;  public void testDelete() throws SQLException {&#xD;&#xA;    Statement stmt = getDataSource().getConnection().createStatement();&#xD;&#xA;    stmt.executeUpdate(&quot;INSERT INTO testtable values (&apos;X&apos;)&quot;);&#xD;&#xA;    stmt.executeUpdate(&quot;INSERT INTO testtable values (&apos;Y&apos;)&quot;);&#xD;&#xA;    int rowCount = stmt.executeUpdate(&quot;DELETE FROM testtable&quot;);&#xD;&#xA;    assertEquals(&quot;Excpect 2 rows to be deleted&quot;, 2, rowCount);&#xD;&#xA;&#xD;&#xA;    ResultSet rs = stmt.executeQuery(&quot;SELECT * FROM testtable&quot;);&#xD;&#xA;    assertFalse(&quot;expect 0 rows after delete&quot;, rs.next());&#xD;&#xA;  }&#xD;&#xA;  &#xD;&#xA;  /**&#xD;&#xA;   * Check if the test table that we have is initially empty.&#xD;&#xA;   * &#xD;&#xA;   * @throws SQLException if DB access fails&#xD;&#xA;   */&#xD;&#xA;  public void testInitiallyEmpty() throws SQLException {&#xD;&#xA;    Statement stmt = getDataSource().getConnection().createStatement();&#xD;&#xA;    &#xD;&#xA;    ResultSet rs = stmt.executeQuery(&quot;SELECT * FROM testtable&quot;);&#xD;&#xA;    // previous inserts in other unit tests must not affect this&#xD;&#xA;    assertFalse(&quot;expect 0 rows&quot;, rs.next());&#xD;&#xA;  }&#xD;&#xA;  &#xD;&#xA;  /**&#xD;&#xA;   * Tear down test table in database.&#xD;&#xA;   * &#xD;&#xA;   * @param ds the initialized data source&#xD;&#xA;   * @throws SQLException if DB access fails&#xD;&#xA;   */&#xD;&#xA;  @Override&#xD;&#xA;  public void tearDown(DataSource ds) throws SQLException {&#xD;&#xA;    Statement stmt = ds.getConnection().createStatement();&#xD;&#xA;    stmt.execute(&quot;DROP TABLE testtable&quot;);&#xD;&#xA;    stmt.close();&#xD;&#xA;  }&#xD;&#xA;  &#xD;&#xA;}&#xD;&#xA;{code}&#xD;&#xA;</s:content>
        <s:mTime>2009-07-14 23:36:47.37</s:mTime>
        <s:cTime>2008-06-21 01:19:39.291</s:cTime>
        <s:comments
             rdf:type='http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag'/>
        <s:snipLinks>
            <rdf:Bag>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#My Projects'/>
                <rdf:li rdf:resource='#leon'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#My Projects/Lava Lamp'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#My Projects/Virtual Server'/>
                <rdf:li rdf:resource='#gabi'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#Curriculum Vitae'/>
                <rdf:li rdf:resource='#snipsnap-index'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#Curriculum Vitae/netcetera'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#leon/old-images'/>
                <rdf:li rdf:resource='#Photos'/>
                <rdf:li rdf:resource='#stefan'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#Virtual+Brain/Linux'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#My Projects/Geigenhof Pool'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#stefan/mainnav'/>
                <rdf:li rdf:resource='#Unternehmungen'/>
                <rdf:li rdf:resource='#Buch'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#Virtual Brain/Java'/>
                <rdf:li rdf:resource='http://www.stefanrufer.ch/snipsnap/rdf#My+Projects'/>
            </rdf:Bag>
        </s:snipLinks>
        <s:attachments>
            <rdf:Bag>
                <rdf:li>
                    <s:Attachment rdf:about='http://www.stefanrufer.ch/snipsnap/space/My+Projects/dbbuild/database-2008-06-21-011038.zip'
                         s:fileName='database-2008-06-21-011038.zip'
                         s:contentType='application/zip'
                         s:size='81744'>
                        <s:date>Sat Jun 21 02:06:35 CEST 2008</s:date>
                    </s:Attachment>
                </rdf:li>
                <rdf:li>
                    <s:Attachment rdf:about='http://www.stefanrufer.ch/snipsnap/space/My+Projects/dbbuild/jazoonlogo_web.gif'
                         s:fileName='jazoonlogo_web.gif'
                         s:contentType='image/gif'
                         s:size='7522'>
                        <s:date>Sat Jun 21 01:30:37 CEST 2008</s:date>
                    </s:Attachment>
                </rdf:li>
                <rdf:li>
                    <s:Attachment rdf:about='http://www.stefanrufer.ch/snipsnap/space/My+Projects/dbbuild/junitextension-demo-autorollback.zip'
                         s:fileName='junitextension-demo-autorollback.zip'
                         s:contentType='application/zip'
                         s:size='2839651'>
                        <s:date>Tue Jun 24 18:35:11 CEST 2008</s:date>
                    </s:Attachment>
                </rdf:li>
                <rdf:li>
                    <s:Attachment rdf:about='http://www.stefanrufer.ch/snipsnap/space/My+Projects/dbbuild/junitextension-demo-config.zip'
                         s:fileName='junitextension-demo-config.zip'
                         s:contentType='application/zip'
                         s:size='9773'>
                        <s:date>Tue Jun 24 18:35:23 CEST 2008</s:date>
                    </s:Attachment>
                </rdf:li>
                <rdf:li>
                    <s:Attachment rdf:about='http://www.stefanrufer.ch/snipsnap/space/My+Projects/dbbuild/setup-2008-06-21-011038.zip'
                         s:fileName='setup-2008-06-21-011038.zip'
                         s:contentType='application/zip'
                         s:size='5358'>
                        <s:date>Sat Jun 21 02:06:52 CEST 2008</s:date>
                    </s:Attachment>
                </rdf:li>
            </rdf:Bag>
        </s:attachments>
    </s:Snip>
</rdf:RDF>

