/*
* JBoss, Home of Professional Open Source
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
*/
package org.searchisko.persistence.service;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.searchisko.api.ContentObjectFields;
import org.searchisko.api.testtools.TestUtils;
import org.searchisko.api.util.SearchUtils;
/**
* Unit test for {@link JdbcContentPersistenceService}
*
* @author Vlastimil Elias (velias at redhat dot com)
* @author Lukas Vlcek
*/
public class JdbcContentPersistenceServiceTest extends JpaTestBase {
@Test
public void tableNameCaseDoesNotMatter() {
JdbcContentPersistenceService.ConcurrentUpperCaseHashMap map = new JdbcContentPersistenceService.ConcurrentUpperCaseHashMap(10);
map.put("lower", true);
Assert.assertTrue(map.containsKey("lower"));
Assert.assertTrue(map.containsKey("Lower"));
Assert.assertTrue(map.containsKey("LOWER"));
Assert.assertTrue(map.get("lower"));
Assert.assertTrue(map.get("Lower"));
Assert.assertTrue(map.get("LOWER"));
map.putIfAbsent("UPPER", true);
Assert.assertTrue(map.containsKey("upper"));
Assert.assertTrue(map.containsKey("Upper"));
Assert.assertTrue(map.containsKey("UPPER"));
Assert.assertTrue(map.get("upper"));
Assert.assertTrue(map.get("Upper"));
Assert.assertTrue(map.get("UPPER"));
Set<String> keys = map.keySet();
Assert.assertEquals(2, keys.size());
Assert.assertTrue(keys.contains("LOWER"));
Assert.assertTrue(keys.contains("UPPER"));
clearDatabase();
}
@Test
public void checkAndEnsureTableExists() {
JdbcContentPersistenceService tested = getTested();
Assert.assertFalse(tested.checkTableExists("table1"));
Assert.assertFalse(tested.checkTableExists("table1"));
tested.ensureTableExists("table1");
Assert.assertTrue(tested.checkTableExists("table1"));
tested.ensureTableExists("table1");
Assert.assertTrue(tested.checkTableExists("table1"));
Assert.assertTrue(tested.checkTableExists("table1"));
Assert.assertFalse(tested.checkTableExists("table_2"));
tested.ensureTableExists("table_2");
Assert.assertTrue(tested.checkTableExists("table_2"));
Assert.assertTrue(tested.checkTableExists("table1"));
clearDatabase();
}
@Test
public void checkAndEnsureTableExistsWithCasing() {
JdbcContentPersistenceService tested = getTested();
Assert.assertFalse(tested.checkTableExists("table1"));
Assert.assertFalse(tested.checkTableExists("TABLE1"));
tested.ensureTableExists("table1");
Assert.assertTrue(tested.checkTableExists("TABLE1"));
Assert.assertTrue(tested.checkTableExists("table1"));
tested.ensureTableExists("TABLE1");
Assert.assertTrue(tested.checkTableExists("table1"));
Assert.assertTrue(tested.checkTableExists("TABLE1"));
Assert.assertFalse(tested.checkTableExists("TABLE_2"));
tested.ensureTableExists("table_2");
Assert.assertTrue(tested.checkTableExists("TABLE_2"));
Assert.assertTrue(tested.checkTableExists("TABLE1"));
clearDatabase();
}
@Test
public void simulateClusterTableCreation() {
JdbcContentPersistenceService tested = getTested();
Assert.assertFalse(tested.checkTableExists("table1"));
createTable("TABLE1");
Assert.assertTrue(tested.checkTableExists("table1"));
clearDatabase();
}
@Test
public void store_get_delete() throws Exception {
JdbcContentPersistenceService tested = getTested();
// case - get from noexisting table
Assert.assertNull(tested.get("a-1", "tt"));
String sysContentType = "testtype_1";
Map<String, Object> content = null;
// case - store into nonexisting table, nonexisting id
tested.store("aaa-1", sysContentType, content);
assertRowCount(tested, sysContentType, 1);
Assert.assertNull(tested.get("aaa-1", sysContentType));
// case - get nonexisting id from existing table
Assert.assertNull(tested.get("a-1", sysContentType));
// case - test persistence after commit
assertRowCount(tested, sysContentType, 1);
Assert.assertNull(tested.get("aaa-1", sysContentType));
// case - store into existing table, nonexisting id
content = new HashMap<String, Object>();
content.put("testkey", "testvalue");
tested.store("aaa-2", sysContentType, content);
assertRowCount(tested, sysContentType, 2);
Assert.assertNull(tested.get("aaa-1", sysContentType));
TestUtils.assertJsonContent("{\"testkey\" : \"testvalue\"}", tested.get("aaa-2", sysContentType));
// case - store into existing table, existing id so update, sys_updated is Date instance
content.put(ContentObjectFields.SYS_UPDATED, new Date(65463750000l));
tested.store("aaa-1", sysContentType, content);
assertRowCount(tested, sysContentType, 2);
TestUtils.assertJsonContent("{\"testkey\" : \"testvalue\", \"sys_updated\":\"1972-01-28T16:22:30.000Z\"}",
tested.get("aaa-1", sysContentType));
assertTableContent(tested, sysContentType, "aaa-1",
SearchUtils.getISODateFormat().parse("1972-01-28T16:22:30.000+0000"));
// case - store into existing table, existing id so update, sys_updated is ISO String instance
content.put(ContentObjectFields.SYS_UPDATED, "1973-01-28T17:22:30.000+0100");
tested.store("aaa-2", sysContentType, content);
assertRowCount(tested, sysContentType, 2);
TestUtils.assertJsonContent("{\"testkey\" : \"testvalue\", \"sys_updated\":\"1973-01-28T17:22:30.000+0100\"}",
tested.get("aaa-2", sysContentType));
assertTableContent(tested, sysContentType, "aaa-2",
SearchUtils.getISODateFormat().parse("1973-01-28T17:22:30.000+0100"));
// case - store into existing table, existing id so update, sys_updated is invalid String instance but no
// exception and table is correctly filled
content.put(ContentObjectFields.SYS_UPDATED, "sdfasdf");
tested.store("aaa-2", sysContentType, content);
assertRowCount(tested, sysContentType, 2);
TestUtils.assertJsonContent("{\"testkey\" : \"testvalue\", \"sys_updated\":\"sdfasdf\"}",
tested.get("aaa-2", sysContentType));
assertTableContent(tested, sysContentType, "aaa-2", null);
// case - delete from nonexisting table
tested.delete("aaa", "jj");
// case - delete from existing table, nonexisting id
tested.delete("a-1", sysContentType);
assertRowCount(tested, sysContentType, 2);
// case - delete existing id
tested.delete("aaa-1", sysContentType);
assertRowCount(tested, sysContentType, 1);
Assert.assertNull(tested.get("aaa-1", sysContentType));
Assert.assertNotNull(tested.get("aaa-2", sysContentType));
clearDatabase();
}
@Test
public void listRequest() {
JdbcContentPersistenceService tested = getTested();
tested.LIST_PAGE_SIZE = 3;
String sysContentType = "testtypelist";
// case - no table exists for type
{
ListRequest req = tested.listRequestInit(sysContentType);
Assert.assertFalse(req.hasContent());
}
// case - data handling test
{
// store in reverse order to see if listing uses correct ordering
for (int i = 7; i >= 1; i--)
addContent(tested, sysContentType, "aaa-" + i);
ListRequest req = tested.listRequestInit(sysContentType);
Assert.assertTrue(req.hasContent());
Assert.assertNotNull(req.content());
Assert.assertEquals(3, req.content().size());
Assert.assertEquals("aaa-1", req.content().get(0).getId());
// assert content is correctly loaded
Assert.assertEquals("aaa-1", req.content().get(0).getContent().get(ContentObjectFields.SYS_ID));
Assert.assertEquals("value aaa-1", req.content().get(0).getContent().get(ContentObjectFields.SYS_DESCRIPTION));
// assert id only for others
Assert.assertEquals("aaa-2", req.content().get(1).getId());
Assert.assertEquals("aaa-3", req.content().get(2).getId());
req = tested.listRequestNext(req);
Assert.assertTrue(req.hasContent());
Assert.assertNotNull(req.content());
Assert.assertEquals(3, req.content().size());
Assert.assertEquals("aaa-4", req.content().get(0).getId());
Assert.assertEquals("aaa-5", req.content().get(1).getId());
Assert.assertEquals("aaa-6", req.content().get(2).getId());
req = tested.listRequestNext(req);
Assert.assertTrue(req.hasContent());
Assert.assertNotNull(req.content());
Assert.assertEquals(1, req.content().size());
Assert.assertEquals("aaa-7", req.content().get(0).getId());
req = tested.listRequestNext(req);
Assert.assertFalse(req.hasContent());
}
clearDatabase();
}
@Test
public void countRecords() {
JdbcContentPersistenceService tested = getTested();
String CT = "count_test_type";
// case - nonexisting table
Assert.assertEquals(0, tested.countRecords(CT));
// case - existing empty table
tested.ensureTableExists(tested.getTableName(CT));
Assert.assertEquals(0, tested.countRecords(CT));
Map<String, Object> content = new HashMap<>();
tested.store("1", CT, content);
Assert.assertEquals(1, tested.countRecords(CT));
tested.store("2", CT, content);
tested.store("3", CT, content);
tested.store("asdas", CT, content);
Assert.assertEquals(4, tested.countRecords(CT));
clearDatabase();
}
private void addContent(JdbcContentPersistenceService tested, String sysContentType, String id) {
Map<String, Object> content = new HashMap<String, Object>();
content.put(ContentObjectFields.SYS_ID, id);
content.put(ContentObjectFields.SYS_CONTENT_TYPE, sysContentType);
content.put(ContentObjectFields.SYS_DESCRIPTION, "value " + id);
tested.store(id, sysContentType, content);
}
private void assertRowCount(JdbcContentPersistenceService tested, String sysContentType, int expectedCount) {
final String tablename = tested.getTableName(sysContentType);
int result = 0;
try (final Connection conn = this.getTested().searchiskoDs.getConnection();
final PreparedStatement statement = conn.prepareStatement(String.format("select count(*) from %s", tablename));
final ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
result = rs.getInt(1);
}
Assert.assertEquals(expectedCount, result);
} catch (SQLException e) {
Assert.fail(e.getMessage());
}
}
private void assertTableContent(final JdbcContentPersistenceService tested, final String sysContentType,
final String id, final Date expectedUpdated) {
final String tablename = tested.getTableName(sysContentType);
try (final Connection conn = this.getTested().searchiskoDs.getConnection();
final PreparedStatement statement = conn.prepareStatement(String.format(
"select sys_content_type, updated from %s where id = ?", tablename))) {
statement.setString(1, id);
try (final ResultSet rs = statement.executeQuery()) {
Assert.assertTrue(rs.next());
Assert.assertEquals(sysContentType, rs.getString(1));
Timestamp actualTimestamp = rs.getTimestamp(2);
if (expectedUpdated != null) {
Assert.assertEquals(new Timestamp(expectedUpdated.getTime()), actualTimestamp);
} else {
Assert.assertNotNull(actualTimestamp);
}
}
} catch (SQLException e) {
Assert.fail(e.getMessage());
}
}
private static JdbcContentPersistenceService tested;
protected JdbcContentPersistenceService getTested() {
try {
DataSource ds = Mockito.mock(DataSource.class);
Mockito.when(ds.getConnection()).then(new Answer<Connection>() {
@Override
public Connection answer(InvocationOnMock invocation) throws Throwable {
return getConnectionProvider().getConnection();
}
});
tested.searchiskoDs = ds;
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
return tested;
}
/**
* Directly create a table in the database. This can be used
* to simulate a second EAP node creating a new table.
*
* @param tableName table name to create
* @see JdbcContentPersistenceService#ensureTableExists
*/
protected void createTable(String tableName) {
try {
final Connection conn = this.getTested().searchiskoDs.getConnection();
conn.prepareStatement("create table " + tableName + " ( column1 INT )").execute();
// conn.commit();
} catch (SQLException e) {
Assert.fail(e.getMessage());
}
}
/**
* Drop all tables found in JdbcContentPersistenceService.TABLES_EXISTS
* map after each test and also clear this map itself.
*/
public void clearDatabase() {
try {
final Connection conn = this.getTested().searchiskoDs.getConnection();
Set<String> tables = JdbcContentPersistenceService.TABLES_EXISTS.keySet();
for (String table : tables) {
conn.prepareStatement("drop table if exists " + table).execute();
}
// conn.commit();
JdbcContentPersistenceService.TABLES_EXISTS.clear();
} catch (SQLException e) {
Assert.fail(e.getMessage());
}
}
@BeforeClass
public static void beforeClass() {
tested = new JdbcContentPersistenceService();
tested.log = Logger.getLogger("test logger");
}
}