/* * #! * Ontopia DB2TM * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed 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. * !# */ package net.ontopia.topicmaps.db2tm; import au.com.bytecode.opencsv.CSVReader; import java.util.Map; import java.util.List; import java.io.File; import java.io.FileReader; import java.io.FileOutputStream; import java.io.IOException; import java.sql.Statement; import java.sql.Connection; import java.sql.SQLException; import net.ontopia.utils.FileUtils; import net.ontopia.utils.TestFileUtils; import net.ontopia.utils.StringUtils; import net.ontopia.utils.PropertyUtils; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.utils.ImportExportUtils; import net.ontopia.topicmaps.xml.CanonicalXTMWriter; import net.ontopia.persistence.proxy.DefaultConnectionFactory; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; /** * INTERNAL: Test for sync with changelogs. Requires H2 database. */ @RunWith(Parameterized.class) public class ChangelogTestCase { private final static String testdataDirectory = "db2tm"; @Parameters public static List<String[]> generateTests() throws IOException { TestFileUtils.transferTestInputDirectory(testdataDirectory + "/in/sync"); return TestFileUtils.getTestInputFiles(testdataDirectory, "in/sync", ".xml"); } private String base; private String casename; public ChangelogTestCase(String root, String xmlfile) { this.casename = xmlfile.substring(0, xmlfile.length() - 4); this.base = TestFileUtils.getTestdataOutputDirectory() + testdataDirectory; } @Test public void testFile() throws IOException, SQLException { // this particular test file is for FullRescanEventTest, and we don't // want to test it again here. we lack the -changelog.csv in any case. if (casename.equals("EVENTS")) return; TestFileUtils.verifyDirectory(base, "out"); String cfg = TestFileUtils.getTransferredTestInputFile(testdataDirectory, "in", "sync", casename + ".xml").getPath(); String tm = TestFileUtils.getTransferredTestInputFile(testdataDirectory, "in", "sync", casename + ".ltm").getPath(); File out = TestFileUtils.getTestOutputFile(testdataDirectory, "out", casename + ".cxtm"); String baseline = TestFileUtils.getTestInputFile(testdataDirectory, "in/sync/baseline", casename + ".cxtm"); // Connect to the DB Connection conn = getConnection(); Statement stm = conn.createStatement(); // Load the starter data into the table importCSV(stm, casename, casename + "-before.csv"); // Create the changelog table (DB2TM.add needs it), but leave it empty importCSV(stm, casename + "_changelog", casename + "-changelog.csv", false); // Import the topic map seed. TopicMapIF topicmap = ImportExportUtils.getReader("file:" + tm).read(); // Extend the topic map seed with the the config file. DB2TM.add(cfg, topicmap); // Now load the database with the changed data importCSV(stm, casename, casename + "-after.csv"); importCSV(stm, casename + "_changelog", casename + "-changelog.csv"); conn.commit(); // necessary to avoid timeout from DB2TM connection // OK, now, finally, we can sync! DB2TM.sync(cfg, topicmap); // Canonicalize! FileOutputStream fos = new FileOutputStream(out); (new CanonicalXTMWriter(fos)).write(topicmap); fos.close(); // Check that the cxtm output matches the baseline. Assert.assertTrue("The canonicalized conversion from " + casename + " does not match the baseline: " + out + " " + baseline, FileUtils.compareFileToResource(out, baseline)); } // public so it can be accessed from FullRescanEventTest public static Connection getConnection() throws SQLException, IOException { String propfile = TestFileUtils.getTransferredTestInputFile(testdataDirectory, "in", "sync", "h2.properties").getPath(); Map<Object, Object> props = PropertyUtils.loadProperties(propfile); props.put("net.ontopia.topicmaps.impl.rdbms.ConnectionPool", "false"); DefaultConnectionFactory cf = new DefaultConnectionFactory(props, false); return cf.requestConnection(); } // public so it can be accessed from FullRescanEventTest public static void importCSV(Statement stm, String table, String file) throws IOException, SQLException { importCSV(stm, table, file, true); } private static void importCSV(Statement stm, String table, String file, boolean load_data) throws IOException, SQLException { // first, get rid of the table if it's already there try { stm.executeUpdate("drop table " + table); } catch (SQLException e) { // table wasn't there. never mind } // open the CSV file String csv = TestFileUtils.getTransferredTestInputFile(testdataDirectory, "in", "sync", file).getPath(); FileReader reader = new FileReader(csv); CSVReader csvreader = new CSVReader(reader, ';', '"'); // read the first line to get the column names String[] colnames = csvreader.readNext(); String[] columndefs = new String[colnames.length]; for (int ix = 0; ix < colnames.length; ix++) columndefs[ix] = colnames[ix] + " varchar"; // now we can create the table stm.executeUpdate("create table " + table + " (" + StringUtils.join(columndefs, ", ") + ")"); // are we just creating the table, or should we load the data? if (!load_data) return; // ok, now insert the actual data String cols = StringUtils.join(colnames, ", "); String[] tuple = csvreader.readNext(); while (tuple != null) { String[] values = new String[tuple.length]; for (int ix = 0; ix < tuple.length; ix++) values[ix] = "'" + tuple[ix] + "'"; // escaping? hah! stm.executeUpdate("insert into " + table + " (" + cols + ") values (" + StringUtils.join(values, ", ") + ")"); tuple = csvreader.readNext(); } } // ===== FUNCTION METHODS // this method is used from the XML file of at least one test case public static String parseID(String pkey) { int pos = pkey.indexOf('='); return pkey.substring(pos + 1); } }