/*
* #!
* 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);
}
}