blob: 4356043402cc532fc383ee691c7bf8f714ebfab8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.ace.log.server.store.impl;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.ace.feedback.AuditEvent;
import org.apache.ace.feedback.Descriptor;
import org.apache.ace.feedback.Event;
import org.apache.ace.test.utils.TestUtils;
import org.osgi.service.event.EventAdmin;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class ServerLogStoreTester {
private static final String MAXIMUM_NUMBER_OF_EVENTS = "MaxEvents";
private LogStoreImpl m_logStore;
private File m_dir;
@BeforeMethod(alwaysRun = true)
protected void setUp() throws Exception {
m_dir = File.createTempFile("logstore", "txt");
m_dir.delete();
m_dir.mkdirs();
m_logStore = new LogStoreImpl(m_dir, "log");
TestUtils.configureObject(m_logStore, EventAdmin.class);
m_logStore.start();
}
@AfterMethod(alwaysRun = true)
protected void tearDown() throws IOException {
delete(m_dir);
}
@SuppressWarnings("serial")
@Test()
public void testLog() throws IOException {
Map<String, String> props = new HashMap<>();
props.put("test", "bar");
List<Descriptor> ranges = m_logStore.getDescriptors();
assert ranges.isEmpty() : "New store should have no ranges.";
List<Event> events = new ArrayList<>();
for (String target : new String[] { "g1", "g2", "g3" }) {
for (long log : new long[] { 1, 2, 3, 5 }) {
for (long id : new long[] { 1, 2, 3, 20 }) {
events.add(new Event(target, log, id, System.currentTimeMillis(), AuditEvent.FRAMEWORK_STARTED, props));
}
}
}
m_logStore.put(events);
assert m_logStore.getDescriptors().size() == 3 * 4 : "Incorrect amount of ranges returned from store";
List<Event> stored = getStoredEvents();
Set<String> in = new HashSet<>();
for (Event event : events) {
in.add(event.toRepresentation());
}
Set<String> out = new HashSet<>();
for (Event event : stored) {
out.add(event.toRepresentation());
}
assert in.equals(out) : "Stored events differ from the added.";
}
@SuppressWarnings("serial")
@Test()
public void testLogOutOfOrder() throws IOException {
Map<String, String> props = new HashMap<>();
props.put("test", "bar");
List<Descriptor> ranges = m_logStore.getDescriptors();
assert ranges.isEmpty() : "New store should have no ranges.";
List<Event> events = new ArrayList<>();
events.add(new Event("t1", 1, 2, 2, AuditEvent.FRAMEWORK_STARTED, props));
events.add(new Event("t1", 1, 3, 3, AuditEvent.FRAMEWORK_STARTED, props));
events.add(new Event("t1", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
m_logStore.put(events);
assert m_logStore.getDescriptors().size() == 1 : "Incorrect amount of ranges returned from store";
List<Event> stored = getStoredEvents();
Set<String> out = new HashSet<>();
for (Event event : stored) {
out.add(event.toRepresentation());
}
assert out.size() == 3 : "Stored events differ from the added.";
}
@SuppressWarnings("serial")
@Test()
public void testLogOutOfOrderOneByOne() throws IOException {
Map<String, String> props = new HashMap<>();
props.put("test", "bar");
List<Descriptor> ranges = m_logStore.getDescriptors();
assert ranges.isEmpty() : "New store should have no ranges.";
List<Event> events = new ArrayList<>();
events.add(new Event("t1", 1, 2, 2, AuditEvent.FRAMEWORK_STARTED, props));
m_logStore.put(events);
events.clear();
events.add(new Event("t1", 1, 3, 3, AuditEvent.FRAMEWORK_STARTED, props));
m_logStore.put(events);
events.clear();
events.add(new Event("t1", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
m_logStore.put(events);
assert m_logStore.getDescriptors().size() == 1 : "Incorrect amount of ranges returned from store";
List<Event> stored = getStoredEvents();
Set<String> out = new HashSet<>();
for (Event event : stored) {
out.add(event.toRepresentation());
}
assert out.size() == 3 : "Stored events differ from the added: " + out.size();
}
@SuppressWarnings("serial")
@Test()
public void testLogLowestID() throws IOException {
Map<String, String> props = new HashMap<>();
props.put("test", "bar");
List<Descriptor> ranges = m_logStore.getDescriptors();
assert ranges.isEmpty() : "New store should have no ranges.";
List<Event> events = new ArrayList<>();
assert 0 == m_logStore.getLowestID("target", 1) : "Lowest ID should be 0 by default, not: " + m_logStore.getLowestID("target", 1);
m_logStore.setLowestID("target", 1, 10);
assert 10 == m_logStore.getLowestID("target", 1) : "Lowest ID should be 10, not: " + m_logStore.getLowestID("target", 1);
assert 0 == m_logStore.getLowestID("target", 0) : "Lowest ID should be 0 by default, not: " + m_logStore.getLowestID("target", 1);
assert 0 == m_logStore.getLowestID("target2", 1) : "Lowest ID should be 0 by default, not: " + m_logStore.getLowestID("target", 1);
for (long id = 1; id <= 20; id++) {
events.add(new Event("target", 1, id, System.currentTimeMillis(), AuditEvent.FRAMEWORK_STARTED, props));
}
m_logStore.put(events);
List<Descriptor> descriptors = m_logStore.getDescriptors();
assert descriptors.size() == 1 : "Incorrect amount of ranges returned from store";
String range = descriptors.get(0).getRangeSet().toRepresentation();
assert range.equals("10-20") : "Incorrect range in descriptor: " + range;
List<Event> stored = getStoredEvents();
assert stored.size() == 11 : "Exactly 11 events should have been stored";
m_logStore.setLowestID("target", 1, 20);
stored = getStoredEvents();
assert stored.size() == 1 : "Exactly 1 event should have been stored";
descriptors = m_logStore.getDescriptors();
assert descriptors.size() == 1 : "Incorrect amount of ranges returned from store";
range = descriptors.get(0).getRangeSet().toRepresentation();
assert range.equals("20") : "Incorrect range in descriptor: " + range;
m_logStore.setLowestID("target", 1, 21);
stored = getStoredEvents();
assert stored.size() == 0 : "No events should have been stored";
descriptors = m_logStore.getDescriptors();
assert descriptors.size() == 1 : "Incorrect amount of ranges returned from store";
range = descriptors.get(0).getRangeSet().toRepresentation();
assert range.equals("") : "Incorrect range in descriptor: " + range;
m_logStore.setLowestID("target", 1, 100);
stored = getStoredEvents();
assert stored.size() == 0 : "No events should have been stored";
}
@SuppressWarnings("serial")
@Test()
public void testLogIDGenerationWithLowestID() throws IOException {
Dictionary<String, String> props = new Hashtable<>();
props.put("test", "foo");
long logID = 0;
for (long id = 1; id <= 20; id++) {
Event event = m_logStore.put("target", 1, props);
System.out.println("Event: " + event.toRepresentation());
logID = event.getStoreID();
}
List<Descriptor> descriptors = m_logStore.getDescriptors();
assert descriptors.size() == 1 : "Incorrect amount of ranges returned from store";
String range = descriptors.get(0).getRangeSet().toRepresentation();
assert range.equals("1-20") : "Incorrect range in descriptor: " + range;
List<Event> stored = getStoredEvents();
assert stored.size() == 20 : "Exactly 20 events should have been stored";
m_logStore.setLowestID("target", logID, 10);
assert 10 == m_logStore.getLowestID("target", logID) : "Lowest ID should be 10, not: " + m_logStore.getLowestID("target", logID);
stored = getStoredEvents();
assert stored.size() == 11 : "Exactly 11 events should have been stored, we found " + stored.size();
descriptors = m_logStore.getDescriptors();
assert descriptors.size() == 1 : "Incorrect amount of ranges returned from store";
range = descriptors.get(0).getRangeSet().toRepresentation();
assert range.equals("10-20") : "Incorrect range in descriptor: " + range;
m_logStore.setLowestID("target", logID, 21);
stored = getStoredEvents();
assert stored.size() == 0 : "No events should have been stored, we found " + stored.size();
descriptors = m_logStore.getDescriptors();
assert descriptors.size() == 1 : "Incorrect amount of ranges returned from store";
range = descriptors.get(0).getRangeSet().toRepresentation();
assert range.equals("") : "Incorrect range in descriptor: " + range;
for (long id = 1; id <= 20; id++) {
System.out.println("Event: " + m_logStore.put("target", 1, props).toRepresentation());
}
stored = getStoredEvents();
assert stored.size() == 20 : "Exactly 20 events should have been stored, we found " + stored.size();
descriptors = m_logStore.getDescriptors();
assert descriptors.size() == 1 : "Incorrect amount of ranges returned from store";
range = descriptors.get(0).getRangeSet().toRepresentation();
assert range.equals("21-40") : "Incorrect range in descriptor: " + range;
}
private List<Event> getStoredEvents() throws IOException {
List<Event> stored = new ArrayList<>();
for (Descriptor range : m_logStore.getDescriptors()) {
System.out.println("TID: " + range.getTargetID());
for (Descriptor range2 : m_logStore.getDescriptors(range.getTargetID())) {
stored.addAll(m_logStore.get(m_logStore.getDescriptor(range2.getTargetID(), range2.getStoreID())));
System.out.println(" Range: " + range2.getRangeSet());
}
}
return stored;
}
@Test()
public void testCreateLogMessagesConcurrently() throws Exception {
final Properties props = new Properties();
props.put("test", "bar");
List<Descriptor> ranges = m_logStore.getDescriptors();
assert ranges.isEmpty() : "New store should have no ranges.";
ExecutorService exec = Executors.newFixedThreadPool(10);
for (final String target : new String[] { "g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8", "g9", "g10" }) {
exec.execute(new Runnable() {
public void run() {
for (long id = 0; id < 1000; id++) {
try {
m_logStore.put(target, 1, props);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
};
});
}
exec.shutdown();
exec.awaitTermination(10, TimeUnit.SECONDS);
assert m_logStore.getDescriptors().size() == 10 : "Incorrect amount of ranges returned from store: " + m_logStore.getDescriptors().size();
List<Event> stored = getStoredEvents();
assert stored.size() == 10000 : "Incorrect number of events got stored: " + stored.size();
}
@Test()
public void testLogWithSpecialCharacters() throws IOException {
String targetID = "myta\0rget";
Event event = new Event(targetID, 1, 1, System.currentTimeMillis(), AuditEvent.FRAMEWORK_STARTED);
List<Event> events = new ArrayList<>();
events.add(event);
m_logStore.put(events);
assert m_logStore.getDescriptors().size() == 1 : "Incorrect amount of ranges returned from store: expected 1, found " + m_logStore.getDescriptors().size();
assert m_logStore.getDescriptors(targetID).size() == 1 : "We expect to find a single event: expected 1, found " + m_logStore.getDescriptors(targetID).size();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test()
public void testMaximumNumberOfEvents() throws Exception {
Dictionary settings = new Properties();
settings.put(MAXIMUM_NUMBER_OF_EVENTS, "1");
m_logStore.updated(settings);
List<Event> events = new ArrayList<>();
for (String target : new String[] { "target" }) {
for (long log : new long[] { 1 }) {
for (long id : new long[] { 1, 2 }) {
events.add(new Event(target, log, id, System.currentTimeMillis(), AuditEvent.FRAMEWORK_STARTED, new HashMap<String, String>()));
}
}
}
m_logStore.put(events);
List<Descriptor> allDescriptors = m_logStore.getDescriptors();
assert allDescriptors.size() == 1 : "Expected only one descriptor, found: " + allDescriptors.size();
for (Descriptor range : allDescriptors) {
List<Descriptor> allLogsForTarget = m_logStore.getDescriptors(range.getTargetID());
for (Descriptor range2 : allLogsForTarget) {
List<Event> getEvents = m_logStore.get(m_logStore.getDescriptor(range2.getTargetID(), range2.getStoreID()));
assert getEvents.size() == 1 : "Only one event expected, found " + getEvents.size();
}
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test()
public void testMaximumNumberOfEventsMultipleLogs() throws Exception {
Dictionary settings = new Properties();
settings.put(MAXIMUM_NUMBER_OF_EVENTS, "1");
m_logStore.updated(settings);
List<Event> events = new ArrayList<>();
for (String target : new String[] { "target" }) {
for (long log : new long[] { 1, 2 }) {
for (long id : new long[] { 1, 2 }) {
events.add(new Event(target, log, id, System.currentTimeMillis(), AuditEvent.FRAMEWORK_STARTED, new HashMap<String, String>()));
}
}
}
m_logStore.put(events);
List<Descriptor> allDescriptors = m_logStore.getDescriptors();
assert allDescriptors.size() == 2 : "Expected two descriptor, found: " + allDescriptors.size();
for (Descriptor range : allDescriptors) {
List<Descriptor> allLogsForTarget = m_logStore.getDescriptors(range.getTargetID());
for (Descriptor range2 : allLogsForTarget) {
List<Event> getEvents = m_logStore.get(m_logStore.getDescriptor(range2.getTargetID(), range2.getStoreID()));
assert getEvents.size() == 1 : "Only one event expected, found " + getEvents.size();
}
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test()
public void testClean() throws Exception {
List<Event> events = new ArrayList<>();
for (String target : new String[] { "target" }) {
for (long log : new long[] { 1, 2 }) {
for (long id : new long[] { 1, 2, 3, 4 }) {
events.add(new Event(target, log, id, System.currentTimeMillis(), AuditEvent.FRAMEWORK_STARTED, new HashMap<String, String>()));
}
}
}
m_logStore.put(events);
Dictionary settings = new Properties();
settings.put(MAXIMUM_NUMBER_OF_EVENTS, "1");
m_logStore.updated(settings);
m_logStore.clean();
List<Descriptor> allDescriptors = m_logStore.getDescriptors();
assert allDescriptors.size() == 2 : "Expected two descriptor, found: " + allDescriptors.size();
for (Descriptor range : allDescriptors) {
List<Descriptor> allLogsForTarget = m_logStore.getDescriptors(range.getTargetID());
for (Descriptor range2 : allLogsForTarget) {
List<Event> getEvents = m_logStore.get(m_logStore.getDescriptor(range2.getTargetID(), range2.getStoreID()));
assert getEvents.size() == 1 : "Only one event expected, found " + getEvents.size();
}
}
}
@SuppressWarnings("serial")
@Test()
public void testConcurrentLog() throws IOException, InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(8);
final Map<String, String> props = new HashMap<>();
props.put("test", "bar");
List<Descriptor> ranges = m_logStore.getDescriptors();
assert ranges.isEmpty() : "New store should have no ranges.";
for (String target : new String[] { "g1", "g2", "g3" }) {
for (long log : new long[] { 1, 2, 3, 5 }) {
for (long id = 0; id < 500; id++) {
final String t = target;
final long l = log;
final long i = id;
es.execute(new Runnable() {
@Override
public void run() {
List<Event> list = new ArrayList<>();
list.add(new Event(t, l, i, System.currentTimeMillis(), AuditEvent.FRAMEWORK_STARTED, props));
try {
m_logStore.put(list);
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
}
es.shutdown();
es.awaitTermination(60, TimeUnit.SECONDS);
int size = m_logStore.getDescriptors().size();
assert size == 3 * 4 : "Incorrect amount of ranges returned from store: " + size;
List<Event> stored = getStoredEvents();
Set<String> out = new HashSet<>();
for (Event event : stored) {
out.add(event.toRepresentation());
}
}
private void delete(File root) {
if (root.isDirectory()) {
for (File child : root.listFiles()) {
delete(child);
}
}
root.delete();
}
}