/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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 li.strolch.persistence.postgresql.dao.test;
import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.CONFIG_SRC;
import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_PASSWORD;
import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_STORE_PATH_DIR;
import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_URL;
import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_USERNAME;
import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.RUNTIME_PATH;
import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.dropSchema;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import li.strolch.agent.api.AuditTrail;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.model.ModelGenerator;
import li.strolch.model.Tags;
import li.strolch.model.audit.AccessType;
import li.strolch.model.audit.Audit;
import li.strolch.model.audit.AuditQuery;
import li.strolch.model.audit.AuditVisitor;
import li.strolch.model.audit.NoStrategyAuditVisitor;
import li.strolch.persistence.api.AbstractTransaction;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.persistence.postgresql.PostgreSqlAuditQueryVisitor;
import li.strolch.privilege.model.Certificate;
import li.strolch.runtime.StrolchConstants;
import li.strolch.testbase.runtime.RuntimeMock;
import li.strolch.utils.StringMatchMode;
import li.strolch.utils.collections.DateRange;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class AuditQueryTest {
private static final Logger logger = LoggerFactory.getLogger(AuditQueryTest.class);
private static RuntimeMock runtimeMock;
private static Date past;
private static Date earlier;
private static Date current;
private static Date later;
private static Date future;
@BeforeClass
public static void beforeClass() throws Exception {
dropSchema(DB_URL, DB_USERNAME, DB_PASSWORD);
File rootPath = new File(RUNTIME_PATH);
File configSrc = new File(CONFIG_SRC);
runtimeMock = new RuntimeMock();
runtimeMock.mockRuntime(rootPath, configSrc);
new File(rootPath, DB_STORE_PATH_DIR).mkdir();
runtimeMock.startContainer();
Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(2000, 1, 1);
past = cal.getTime();
cal.set(2000, 4, 1);
earlier = cal.getTime();
cal.set(2000, 6, 1);
current = cal.getTime();
cal.set(2000, 8, 1);
later = cal.getTime();
cal.set(2000, 11, 1);
future = cal.getTime();
Certificate cert = runtimeMock.getPrivilegeHandler().authenticate("test", "test".getBytes());
StrolchRealm realm = runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM);
int i = 0;
try (StrolchTransaction tx = realm.openTx(cert, "test")) {
((AbstractTransaction) tx).setSuppressAudits(true);
AuditTrail auditTrail = tx.getAuditTrail();
Audit randomAudit;
randomAudit = ModelGenerator.randomAudit();
randomAudit.setId(i++);
randomAudit.setUsername("earlier");
randomAudit.setDate(earlier);
randomAudit.setAccessType(AccessType.CREATE);
randomAudit.setAction("create");
randomAudit.setElementAccessed(randomAudit.getAccessType().name());
auditTrail.add(tx, randomAudit);
randomAudit = ModelGenerator.randomAudit();
randomAudit.setId(i++);
randomAudit.setDate(current);
randomAudit.setUsername("current");
randomAudit.setAccessType(AccessType.READ);
randomAudit.setAction("read");
randomAudit.setElementAccessed(randomAudit.getAccessType().name());
auditTrail.add(tx, randomAudit);
randomAudit = ModelGenerator.randomAudit();
randomAudit.setId(i++);
randomAudit.setDate(later);
randomAudit.setUsername("later");
randomAudit.setAccessType(AccessType.UPDATE);
randomAudit.setAction("update");
randomAudit.setElementAccessed(randomAudit.getAccessType().name());
auditTrail.add(tx, randomAudit);
randomAudit = ModelGenerator.randomAudit();
randomAudit.setId(i++);
randomAudit.setDate(current);
randomAudit.setUsername("current");
randomAudit.setAccessType(AccessType.DELETE);
randomAudit.setAction("delete");
randomAudit.setElementAccessed(randomAudit.getAccessType().name());
auditTrail.add(tx, randomAudit);
randomAudit = ModelGenerator.randomAudit();
randomAudit.setId(i++);
randomAudit.setDate(current);
randomAudit.setUsername("current");
randomAudit.setAccessType(AccessType.CREATE);
randomAudit.setAction("create");
randomAudit.setElementAccessed(randomAudit.getAccessType().name());
auditTrail.add(tx, randomAudit);
tx.commitOnClose();
}
}
@AfterClass
public static void afterClass() {
if (runtimeMock != null)
runtimeMock.destroyRuntime();
}
public Connection openConn() throws SQLException {
String url = "jdbc:postgresql://localhost/testdb";
String username = "testuser";
String password = "test";
Connection connection = DriverManager.getConnection(url, username, password);
connection.setAutoCommit(false);
return connection;
}
@Test
public void shouldQueryTypeAndDateRange() throws SQLException {
AuditVisitor<Audit> visitor = new NoStrategyAuditVisitor();
AuditQuery<Audit> query = new AuditQuery<>(visitor, Tags.AUDIT,
new DateRange().from(earlier, true).to(later, true));
performQuery(query, Arrays.asList("0", "1", "2", "3", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(current, true).to(current, true));
performQuery(query, Arrays.asList("1", "3", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(current, true));
performQuery(query, Arrays.asList("1", "2", "3", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().to(current, true));
performQuery(query, Arrays.asList("0", "1", "3", "4"));
query = new AuditQuery<>(visitor, Tags.RESOURCE, new DateRange().from(past, true).to(future, true));
performQuery(query, Arrays.<String> asList());
}
@Test
public void shouldQueryAudits() throws SQLException {
AuditVisitor<Audit> visitor = new NoStrategyAuditVisitor();
AuditQuery<Audit> query = new AuditQuery<>(visitor, Tags.AUDIT,
new DateRange().from(past, true).to(future, true));
query.action().accessTypes(AccessType.CREATE, AccessType.READ);
performQuery(query, Arrays.asList("0", "1", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.action().accessTypes(AccessType.CREATE);
performQuery(query, Arrays.asList("0", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.action().accessTypes(AccessType.CREATE, AccessType.READ).actions(StringMatchMode.EQUALS_CASE_SENSITIVE,
"create", "read");
performQuery(query, Arrays.asList("0", "1", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.action().accessTypes(AccessType.CREATE, AccessType.READ).actions(StringMatchMode.EQUALS_CASE_SENSITIVE,
"read");
performQuery(query, Arrays.asList("1"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.element().elementAccessed(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "crea");
performQuery(query, Arrays.asList("0", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.element().elementAccessed(StringMatchMode.CONTAINS_CASE_SENSITIVE, "crea");
performQuery(query, Arrays.<String> asList());
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.element().elementAccessed(StringMatchMode.EQUALS_CASE_INSENSITIVE, "create");
performQuery(query, Arrays.asList("0", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.identity().usernames(StringMatchMode.EQUALS_CASE_INSENSITIVE, "earlier");
performQuery(query, Arrays.asList("0"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.identity().usernames(StringMatchMode.EQUALS_CASE_INSENSITIVE, "earlier", "later");
performQuery(query, Arrays.asList("0", "2"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.identity().usernames(StringMatchMode.EQUALS_CASE_INSENSITIVE, "earlier")
.firstnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "enn");
performQuery(query, Arrays.asList("0"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.identity().usernames(StringMatchMode.EQUALS_CASE_INSENSITIVE, "earlier")
.firstnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "enn")
.lastnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "kennedy");
performQuery(query, Arrays.asList("0"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.identity().firstnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "enn")
.lastnames(StringMatchMode.CONTAINS_CASE_INSENSITIVE, "kennedy");
performQuery(query, Arrays.asList("0", "1", "2", "3", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.element().elementSubTypes(StringMatchMode.EQUALS_CASE_SENSITIVE, "Foo");
performQuery(query, Arrays.asList("0", "1", "2", "3", "4"));
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.element().elementSubTypes(StringMatchMode.EQUALS_CASE_SENSITIVE, "Bar");
performQuery(query, Arrays.asList());
query = new AuditQuery<>(visitor, Tags.AUDIT, new DateRange().from(past, true).to(future, true));
query.limit(1).element().elementSubTypes(StringMatchMode.EQUALS_CASE_SENSITIVE, "Foo");
performQuery(query, Arrays.asList("2"));
}
private void performQuery(AuditQuery<Audit> query, List<String> expected) throws SQLException {
PostgreSqlAuditQueryVisitor visitor = new PostgreSqlAuditQueryVisitor("id");
query.accept(visitor);
List<String> ids = queryIds(visitor);
assertEquals(new HashSet<>(expected), new HashSet<>(ids));
}
private List<String> queryIds(PostgreSqlAuditQueryVisitor visitor) throws SQLException {
String sql = visitor.getSql();
logger.info("\n" + sql);
List<String> ids = new ArrayList<>();
try (Connection con = openConn()) {
try (PreparedStatement ps = con.prepareStatement(sql)) {
visitor.setValues(ps);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
ids.add(rs.getString(1));
}
}
}
}
return ids;
}
}