/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package fedora.server.search;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Date;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import fedora.server.storage.ConnectionPool;
import fedora.server.storage.DOReader;
import fedora.server.storage.MockRepositoryReader;
import fedora.server.storage.types.Datastream;
import fedora.server.storage.types.DigitalObject;
import static org.junit.Assert.assertEquals;
import static fedora.server.storage.types.ObjectBuilder.addXDatastream;
import static fedora.server.storage.types.ObjectBuilder.getDC;
import static fedora.server.storage.types.ObjectBuilder.getTestObject;
import static fedora.server.storage.types.ObjectBuilder.setDates;
public class FieldSearchSQLImplIntegrationTest {
// test database constants
private static final String driver = "org.apache.derby.jdbc.EmbeddedDriver";
private static final String url = "jdbc:derby:test;create=true";
private static final String username = "test";
private static final String password = "test";
private static final int maxActive = 4;
private static final int maxIdle = 4;
private static final int maxWait = -1;
private static final int minIdle = 0;
private static final long minEvictableIdleTimeMillis = 1800000;
private static final int numTestsPerEvictionRun = 3;
private static final long timeBetweenEvictionRuns = -1;
private static final String validationQuery = "values(1)";
private static final boolean testOnBorrow = true;
private static final boolean testOnReturn = true;
private static final boolean testWhileIdle = true;
private static final byte whenExhaustedAction = 1;
// test fieldsearch impl constants
private static final int maxResultsDefault = 100;
private static final int maxSecondsPerSessionDefault = 600;
private static ConnectionPool cPool;
private MockRepositoryReader m_repo;
private FieldSearchSQLImpl m_impl;
// needs to be set in order for object serializers/deserializers to work
static {
Datastream.defaultChecksumType = "DISABLED";
}
// Test setUp:
// - create cPool if necessary
// - drop doRegistry table (silently fail if it doesn't exist)
// - re-create doRegistry table
@Before
public void setUpTest() throws Exception {
if (cPool == null) {
cPool = new ConnectionPool(driver,
url,
username,
password,
maxActive,
maxIdle,
maxWait,
minIdle,
minEvictableIdleTimeMillis,
numTestsPerEvictionRun,
timeBetweenEvictionRuns,
validationQuery,
testOnBorrow,
testOnReturn,
testWhileIdle,
whenExhaustedAction);
}
Connection conn = cPool.getConnection();
executeUpdate(conn, "DROP TABLE doFields", true);
executeUpdate(conn, "DROP TABLE dcDates", true);
executeUpdate(conn, "CREATE TABLE doFields (\n"
+ "pid VARCHAR(64) NOT NULL,\n"
+ "label VARCHAR(255) NOT NULL,\n"
+ "state VARCHAR(1) NOT NULL,\n"
+ "ownerId VARCHAR(64),\n"
+ "cDate BIGINT NOT NULL,\n"
+ "mDate BIGINT NOT NULL,\n"
+ "dcmDate BIGINT,\n"
+ "dcTitle CLOB,\n"
+ "dcCreator CLOB,\n"
+ "dcSubject CLOB,\n"
+ "dcDescription CLOB,\n"
+ "dcPublisher CLOB,\n"
+ "dcContributor CLOB,\n"
+ "dcDate CLOB,\n"
+ "dcType CLOB,\n"
+ "dcFormat CLOB,\n"
+ "dcIdentifier CLOB,\n"
+ "dcSource CLOB,\n"
+ "dcLanguage CLOB,\n"
+ "dcRelation CLOB,\n"
+ "dcCoverage CLOB,\n"
+ "dcRights CLOB)", false);
executeUpdate(conn,
"CREATE INDEX doFields_pid ON doFields (pid)", false);
executeUpdate(conn, "CREATE TABLE dcDates (\n"
+ "pid VARCHAR(64) NOT NULL,"
+ "dcDate BIGINT NOT NULL)", false);
executeUpdate(conn,
"CREATE INDEX dcDates_pid ON dcDates (pid)", false);
cPool.free(conn);
}
private static void executeUpdate(Connection conn,
String sql,
boolean ignoreError) throws Exception {
Statement st = conn.createStatement();
try {
st.executeUpdate(sql);
} catch (Exception e) {
if (!ignoreError) {
throw e;
}
} finally {
try { st.close(); } catch (Exception e) { }
}
}
// Test tearDown
@AfterClass
public static void tearDownTest() throws Exception {
// FIXME: Although cPool.close() should be called, it causes the removal
// of the Embedded-Derby driver needed by 'ResourceIndexIntegrationTest.java'
//
// if (cPool != null) {
// cPool.close();
// }
}
private void init(int maxResults,
int maxSecondsPerSession,
boolean indexDCFields) throws Exception {
m_repo = new MockRepositoryReader();
m_impl = new FieldSearchSQLImpl(cPool,
m_repo,
maxResults,
maxSecondsPerSession,
indexDCFields);
}
@Test
public void testFindOneSeveralTimesNoDC() throws Exception {
init(maxResultsDefault, maxSecondsPerSessionDefault, true);
// add one object to index
String pid1 = "test:1";
DigitalObject obj1 = getTestObject(pid1, pid1);
setDates(obj1, new Date());
m_repo.putObject(obj1);
DOReader reader1 = m_repo.getReader(false, null, pid1);
m_impl.update(reader1);
// query for everything several times
// should get 1 page w/1 result each time
// and cPool shouldn't be exhausted because the impl should
// release each connection immediately after the query completes
FieldSearchQuery query = new FieldSearchQuery("*");
int[] expected = new int[] { 1, 1 };
for (int i = 0; i < 20; i++) {
checkResults(expected, countResults(query, 10));
}
}
@Test
public void testIndexAndFindByDCIdentifier() throws Exception {
init(maxResultsDefault, maxSecondsPerSessionDefault, true);
// add one object with DC to index
String pid1 = "test:1";
DigitalObject obj1 = getTestObject(pid1, pid1);
String dcContent = "<dc:identifier>" + pid1 + "</dc:identifier>";
addXDatastream(obj1, "DC", getDC(dcContent));
setDates(obj1, new Date());
m_repo.putObject(obj1);
DOReader reader1 = m_repo.getReader(false, null, pid1);
m_impl.update(reader1);
// query for it via dc:identifier
FieldSearchQuery query = new FieldSearchQuery(Condition.getConditions("identifier~" + pid1));
int[] expected = new int[] { 1, 1 };
// first try with client requesting max TEN results per page
// should get 1 page w/1 result
checkResults(expected, countResults(query, 10));
// then try same, but with client requesting max ONE result per page
// should still get 1 page w/1 result
checkResults(expected, countResults(query, 1));
}
// runs the query (all pages) and returns { pageCount, resultCount }
private int[] countResults(FieldSearchQuery query,
int maxResultsPerPage) throws Exception {
int pageCount = 0;
int resultCount = 0;
FieldSearchResult page = m_impl.findObjects(new String[] { "pid" },
maxResultsPerPage,
query);
while (page != null) {
pageCount++;
resultCount += page.objectFieldsList().size();
if (page.getToken() != null) {
m_impl.resumeFindObjects(page.getToken());
} else {
page = null;
}
}
return new int[] { pageCount, resultCount };
}
private static void checkResults(int[] expected, int[] got) throws Exception {
assertEquals("Unexpected page count", expected[0], got[0]);
assertEquals("Unexpected result count", expected[1], got[1]);
}
// Supports legacy test runners
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(FieldSearchSQLImplIntegrationTest.class);
}
}