You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ma...@apache.org on 2013/04/09 10:18:48 UTC
svn commit: r1465924 [3/3] - in /ace/trunk/org.apache.ace.log: ./ src/
src/org/ src/org/apache/ src/org/apache/ace/ src/org/apache/ace/log/
src/org/apache/ace/log/listener/ src/org/apache/ace/log/server/
src/org/apache/ace/log/server/servlet/ src/org/a...
Added: ace/trunk/org.apache.ace.log/src/org/apache/ace/log/target/task/LogSyncTask.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/src/org/apache/ace/log/target/task/LogSyncTask.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/src/org/apache/ace/log/target/task/LogSyncTask.java (added)
+++ ace/trunk/org.apache.ace.log/src/org/apache/ace/log/target/task/LogSyncTask.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,209 @@
+/*
+ * 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.target.task;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.ace.connectionfactory.ConnectionFactory;
+import org.apache.ace.discovery.Discovery;
+import org.apache.ace.identification.Identification;
+import org.apache.ace.log.LogDescriptor;
+import org.apache.ace.log.LogEvent;
+import org.apache.ace.log.target.store.LogStore;
+import org.apache.ace.range.RangeIterator;
+import org.apache.ace.range.SortedRangeSet;
+import org.osgi.service.log.LogService;
+
+// TODO there are two versions of this class around, the other ohne being the server.LogSyncTask,
+// and both are fairly similar
+public class LogSyncTask implements Runnable {
+
+ private static final String COMMAND_QUERY = "query";
+ private static final String COMMAND_SEND = "send";
+ private static final String PARAMETER_TARGETID = "tid";
+ private static final String PARAMETER_LOGID = "logid";
+
+ // injected by dependencymanager
+ private volatile Discovery m_discovery;
+ private volatile Identification m_identification;
+ private volatile LogService m_log;
+ private volatile LogStore m_LogStore;
+ private volatile ConnectionFactory m_connectionFactory;
+
+ private final String m_endpoint;
+
+ public LogSyncTask(String endpoint) {
+ m_endpoint = endpoint;
+ }
+
+ /**
+ * Synchronize the log events available remote with the events available locally.
+ */
+ public void run() {
+ URL host = m_discovery.discover();
+
+ if (host == null) {
+ // expected if there's no discovered
+ // ps or relay server
+ m_log.log(LogService.LOG_WARNING, "Unable to synchronize log with remote (endpoint=" + m_endpoint + ") - none available");
+ return;
+ }
+
+ if ("file".equals(host.getProtocol())) {
+ // if the discovery URL is a file, we cannot sync, so we silently return here
+ return;
+ }
+
+ String targetId = m_identification.getID();
+ URLConnection sendConnection = null;
+ try {
+ sendConnection = m_connectionFactory.createConnection(new URL(host, m_endpoint + "/" + COMMAND_SEND));
+ sendConnection.setDoOutput(true);
+ if (sendConnection instanceof HttpURLConnection) {
+ // ACE-294: enable streaming mode causing only small amounts of memory to be
+ // used for this commit. Otherwise, the entire input stream is cached into
+ // memory prior to sending it to the server...
+ ((HttpURLConnection) sendConnection).setChunkedStreamingMode(8192);
+ }
+
+ long[] logIDs = m_LogStore.getLogIDs();
+ for (int i = 0; i < logIDs.length; i++) {
+ URL url = new URL(host, m_endpoint + "/" + COMMAND_QUERY + "?" + PARAMETER_TARGETID + "=" + targetId + "&" + PARAMETER_LOGID + "=" + logIDs[i]);
+
+ URLConnection queryConnection = m_connectionFactory.createConnection(url);
+ // TODO: make sure no actual call is made using sendConnection
+ // when there's nothing to sync
+ synchronizeLog(logIDs[i], queryConnection.getInputStream(), sendConnection);
+ }
+
+ // Make sure to send the actual POST request...
+ sendConnection.getContent();
+ }
+ catch (ConnectException e) {
+ m_log.log(LogService.LOG_WARNING, "Unable to connect to remote (endpoint=" + m_endpoint + ")");
+ }
+ catch (IOException e) {
+ m_log.log(LogService.LOG_ERROR, "Unable to (fully) synchronize log with remote (endpoint=" + m_endpoint + ")", e);
+ }
+ finally {
+ if (sendConnection instanceof HttpURLConnection) {
+ ((HttpURLConnection) sendConnection).disconnect();
+ }
+ }
+ }
+
+ /**
+ * Synchronizes a single log (there can be multiple log/logid's per target).
+ *
+ * @param logID
+ * ID of the log to synchronize.
+ * @param queryInput
+ * Stream pointing to a query result for the events available remotely for this log id
+ * @param sendConnection
+ * .getOutputStream() Stream to write the events to that are missing on the remote side.
+ * @throws java.io.IOException
+ * If synchronization could not be completed due to an I/O failure.
+ */
+ protected void synchronizeLog(long logID, InputStream queryInput, URLConnection sendConnection) throws IOException {
+ long highestLocal = m_LogStore.getHighestID(logID);
+ if (highestLocal == 0) {
+ // No events, no need to synchronize
+ return;
+ }
+
+ SortedRangeSet localRange = new SortedRangeSet("1-" + highestLocal);
+ SortedRangeSet remoteRange = getDescriptor(queryInput).getRangeSet();
+ SortedRangeSet delta = remoteRange.diffDest(localRange);
+ RangeIterator rangeIterator = delta.iterator();
+
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(sendConnection.getOutputStream()));
+
+ if (rangeIterator.hasNext()) {
+ long lowest = rangeIterator.next();
+ long highest = delta.getHigh();
+ if (lowest <= highest) {
+ List events = m_LogStore.get(logID, lowest, highestLocal > highest ? highest : highestLocal);
+ Iterator iter = events.iterator();
+ while (iter.hasNext()) {
+ LogEvent current = (LogEvent) iter.next();
+ while ((current.getID() > lowest) && rangeIterator.hasNext()) {
+ lowest = rangeIterator.next();
+ }
+ if (current.getID() == lowest) {
+ // before we send the LogEvent to the other side, we fill out the
+ // appropriate identification
+ LogEvent event = new LogEvent(m_identification.getID(), current);
+ writer.write(event.toRepresentation() + "\n");
+ }
+ }
+ }
+ }
+
+ writer.flush();
+ }
+
+ /**
+ * Retrieves a LogDescriptor object from the specified stream.
+ *
+ * @param queryInput
+ * Stream containing a LogDescriptor object.
+ * @return LogDescriptor object reflecting the range contained in the stream.
+ * @throws java.io.IOException
+ * If no range could be determined due to an I/O failure.
+ */
+ protected LogDescriptor getDescriptor(InputStream queryInput) throws IOException {
+ BufferedReader queryReader = null;
+ try {
+ queryReader = new BufferedReader(new InputStreamReader(queryInput));
+ String rangeString = queryReader.readLine();
+ if (rangeString != null) {
+ try {
+ return new LogDescriptor(rangeString);
+ }
+ catch (IllegalArgumentException iae) {
+ throw new IOException("Could not determine highest remote event id, received malformed event range (" + rangeString + ")");
+ }
+ }
+ else {
+ throw new IOException("Could not construct LogDescriptor from stream because stream is empty");
+ }
+ }
+ finally {
+ if (queryReader != null) {
+ try {
+ queryReader.close();
+ }
+ catch (Exception ex) {
+ // not much we can do
+ }
+ }
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.log/src/org/apache/ace/log/util/Codec.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/src/org/apache/ace/log/util/Codec.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/src/org/apache/ace/log/util/Codec.java (added)
+++ ace/trunk/org.apache.ace.log/src/org/apache/ace/log/util/Codec.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,89 @@
+/*
+ * 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.util;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+
+public class Codec
+{
+
+ public static String decode(String source) throws IllegalArgumentException {
+ StringBuffer result = new StringBuffer();
+ StringCharacterIterator sci = new StringCharacterIterator(source);
+ for (char c = sci.current(); c != CharacterIterator.DONE; c = sci.next()) {
+ if (c == '$') {
+ c = sci.next();
+ if (c != CharacterIterator.DONE) {
+ if (c == '$') {
+ result.append('$');
+ }
+ else if (c == 'k') {
+ result.append(',');
+ }
+ else if (c == 'n') {
+ result.append('\n');
+ }
+ else if (c == 'r') {
+ result.append('\r');
+ }
+ else if (c == 'e') {
+ return null;
+ }
+ else {
+ throw new IllegalArgumentException("Unknown escape character: " + c);
+ }
+ }
+ else {
+ throw new IllegalArgumentException("Unexpected end of input: " + source);
+ }
+ }
+ else {
+ result.append(c);
+ }
+ }
+ return result.toString();
+ }
+
+ public static String encode(String source) {
+ if (source == null) {
+ return "$e";
+ }
+ StringBuffer result = new StringBuffer();
+ StringCharacterIterator sci = new StringCharacterIterator(source);
+ for (char c = sci.current(); c != CharacterIterator.DONE; c = sci.next()) {
+ if (c == '$') {
+ result.append("$$");
+ }
+ else if (c == ',') {
+ result.append("$k");
+ }
+ else if (c == '\n') {
+ result.append("$n");
+ }
+ else if (c == '\r') {
+ result.append("$r");
+ }
+ else {
+ result.append(c);
+ }
+ }
+ return result.toString();
+ }
+}
\ No newline at end of file
Added: ace/trunk/org.apache.ace.log/target.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/target.bnd?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/target.bnd (added)
+++ ace/trunk/org.apache.ace.log/target.bnd Tue Apr 9 08:18:47 2013
@@ -0,0 +1,4 @@
+Private-Package: org.apache.ace.log.target,\
+ org.apache.ace.log.target.task
+Bundle-Activator: org.apache.ace.log.target.Activator
+Bundle-Version: 1.0.0
Added: ace/trunk/org.apache.ace.log/target.store.impl.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/target.store.impl.bnd?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/target.store.impl.bnd (added)
+++ ace/trunk/org.apache.ace.log/target.store.impl.bnd Tue Apr 9 08:18:47 2013
@@ -0,0 +1,4 @@
+Private-Package: org.apache.ace.log.target.store.impl
+Bundle-Activator: org.apache.ace.log.target.store.impl.Activator
+Export-Package: org.apache.ace.log.target.store
+Bundle-Version: 1.0.0
Added: ace/trunk/org.apache.ace.log/test/org/apache/ace/log/LogDescriptorTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/test/org/apache/ace/log/LogDescriptorTest.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/test/org/apache/ace/log/LogDescriptorTest.java (added)
+++ ace/trunk/org.apache.ace.log/test/org/apache/ace/log/LogDescriptorTest.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import org.apache.ace.range.SortedRangeSet;
+import org.testng.annotations.Test;
+
+public class LogDescriptorTest {
+
+ @Test(groups = { UNIT })
+ public void serializeDescriptor() {
+ LogDescriptor descriptor = new LogDescriptor("gwid", 1, new SortedRangeSet("2-3"));
+ assert descriptor.toRepresentation().equals("gwid,1,2-3") : "The representation of our descriptor is incorrect:" + descriptor.toRepresentation();
+ }
+
+ @Test(groups = { UNIT })
+ public void deserializeDescriptor() {
+ LogDescriptor descriptor = new LogDescriptor("gwid,1,2-3");
+ assert descriptor.getTargetID().equals("gwid") : "Target ID not correctly parsed.";
+ assert descriptor.getLogID() == 1 : "Log ID not correctly parsed.";
+ assert descriptor.getRangeSet().toRepresentation().equals("2-3") : "There should be nothing in the diff between the set in the descriptor and the check-set.";
+ }
+
+ @Test(groups = { UNIT })
+ public void deserializeMultiRangeDescriptor() {
+ LogDescriptor descriptor = new LogDescriptor("gwid,1,1-4$k6$k8$k10-20");
+ assert descriptor.getTargetID().equals("gwid") : "Target ID not correctly parsed.";
+ assert descriptor.getLogID() == 1 : "Log ID not correctly parsed.";
+ String representation = descriptor.getRangeSet().toRepresentation();
+ assert representation.equals("1-4,6,8,10-20") : "There should be nothing in the diff between the set in the descriptor and the check-set, but we parsed: " + representation;
+ }
+
+ @Test(groups = { UNIT })
+ public void deserializeMultiRangeDescriptorWithFunnyGWID() {
+ String line = "gw$$id,1,1-4$k6$k8$k10-20";
+ LogDescriptor descriptor = new LogDescriptor(line);
+ assert descriptor.getTargetID().equals("gw$id") : "Target ID not correctly parsed.";
+ assert descriptor.getLogID() == 1 : "Log ID not correctly parsed.";
+ assert line.equals(descriptor.toRepresentation()) : "Converting the line back to the representation failed.";
+ String representation = descriptor.getRangeSet().toRepresentation();
+ assert representation.equals("1-4,6,8,10-20") : "There should be nothing in the diff between the set in the descriptor and the check-set, but we parsed: " + representation;
+ }
+
+ @Test(groups = { UNIT }, expectedExceptions = IllegalArgumentException.class)
+ public void deserializeInvalidDescriptor() throws Exception {
+ new LogDescriptor("invalidStringRepresentation");
+ }
+}
Added: ace/trunk/org.apache.ace.log/test/org/apache/ace/log/LogEventTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/test/org/apache/ace/log/LogEventTest.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/test/org/apache/ace/log/LogEventTest.java (added)
+++ ace/trunk/org.apache.ace.log/test/org/apache/ace/log/LogEventTest.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.testng.annotations.Test;
+
+public class LogEventTest {
+ @Test(groups = { UNIT })
+ public void serializeLogEvent() {
+ LogEvent e = new LogEvent("gwid", 1, 2, 3, AuditEvent.FRAMEWORK_STARTED, new Properties());
+ assert e.toRepresentation().equals("gwid,1,2,3," + AuditEvent.FRAMEWORK_STARTED);
+ Properties p = new Properties();
+ p.put(AuditEvent.KEY_ID, "my first value");
+ e = new LogEvent("gwid", 1, 2, 3, AuditEvent.BUNDLE_INSTALLED, p);
+ assert e.toRepresentation().equals("gwid,1,2,3," + AuditEvent.BUNDLE_INSTALLED + "," + AuditEvent.KEY_ID + ",my first value");
+ e = new LogEvent("gwid,gwid\n\r$", 1, 2, 3, AuditEvent.FRAMEWORK_STARTED, new Properties());
+ assert e.toRepresentation().equals("gwid$kgwid$n$r$$,1,2,3," + AuditEvent.FRAMEWORK_STARTED);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test(groups = { UNIT })
+ public void deserializeLogEvent() {
+ LogEvent e = new LogEvent("gwid$kgwid$n$r$$,1,2,3," + AuditEvent.FRAMEWORK_STARTED + ",a,1,b,2,c,3");
+ assert e.getTargetID().equals("gwid,gwid\n\r$") : "Target ID is not correctly parsed";
+ assert e.getLogID() == 1 : "Log ID is not correctly parsed";
+ assert e.getID() == 2 : "ID is not correctly parsed";
+ assert e.getTime() == 3 : "Time is not correctly parsed";
+ assert e.getType() == AuditEvent.FRAMEWORK_STARTED : "Event type is wrong";
+ Dictionary p = e.getProperties();
+ assert p != null : "Properties are not correctly parsed";
+ assert p.get("a").equals("1") : "Property a should be 1";
+ assert p.get("b").equals("2") : "Property a should be 1";
+ assert p.get("c").equals("3") : "Property a should be 1";
+ }
+ @Test(groups = { UNIT })
+ public void deserializeIllegalLogEvent() {
+ try {
+ new LogEvent("garbage in, garbage out!");
+ assert false : "Parsing garbage should result in an exception";
+ }
+ catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ new LogEvent("g$z,1,2,3," + AuditEvent.BUNDLE_STOPPED);
+ assert false : "Parsing illegal token should result in an exception";
+ }
+ catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ new LogEvent("g$,1,2,3," + AuditEvent.BUNDLE_STOPPED);
+ assert false : "Parsing half of a token should result in an exception";
+ }
+ catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ new LogEvent("g$,1,2,3," + AuditEvent.BUNDLE_STOPPED + ",a");
+ assert false : "Parsing only a key should result in an exception";
+ }
+ catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.log/test/org/apache/ace/log/listener/LogTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/test/org/apache/ace/log/listener/LogTest.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/test/org/apache/ace/log/listener/LogTest.java (added)
+++ ace/trunk/org.apache.ace.log/test/org/apache/ace/log/listener/LogTest.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,167 @@
+/*
+ * 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.listener;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.ace.log.AuditEvent;
+import org.apache.ace.log.Log;
+import org.apache.ace.log.listener.MockLog.LogEntry;
+import org.apache.ace.test.utils.TestUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class LogTest {
+
+ private LogProxy m_logProxy;
+
+ private Log m_mockLog;
+
+ @BeforeMethod(alwaysRun = true)
+ protected void setUp() throws Exception {
+ m_logProxy = new LogProxy();
+ m_mockLog = new MockLog();
+ }
+
+ /**
+ * Test whether logging to the cache and setting a new Log causes the log entries to be flushed to this new Log.
+ */
+ @SuppressWarnings("unchecked")
+ @Test(groups = { UNIT })
+ public void testLogCacheFlush() throws Exception {
+ assert ((MockLog) m_mockLog).getLogEntries().size() == 0 : "MockLog is not empty on start of test";
+
+ Dictionary props = new Properties();
+ String test = "test";
+ String value = "value";
+ props.put(test, value);
+ m_logProxy.log(1, props);
+
+ assert ((MockLog) m_mockLog).getLogEntries().size() == 0 : "MockLog is not empty, but should be as the log should be in the cache";
+
+ m_logProxy.setLog(m_mockLog);
+
+ assert ((MockLog) m_mockLog).getLogEntries().size() == 1 : "Log should contain 1 entry";
+ assert ((MockLog.LogEntry) ((MockLog) m_mockLog).getLogEntries().get(0)).getProperties().get(test).equals(value) : "The property should be 'test:value'";
+ }
+
+ /**
+ * Test whether after unsetting the Log, no new log entries are added, but that they are added to the cache instead
+ * (test the latter by flushing the cache).
+ */
+ @SuppressWarnings("unchecked")
+ @Test(groups = { UNIT })
+ public void testUnsettingLog() throws Exception {
+ assert ((MockLog) m_mockLog).getLogEntries().size() == 0 : "MockLog is not empty on start of test";
+ m_logProxy.setLog(m_mockLog);
+
+ Dictionary props = new Properties();
+ props.put("test", "value");
+ m_logProxy.log(1, props);
+
+ assert ((MockLog) m_mockLog).getLogEntries().size() == 1 : "MockLog should have 1 log entry";
+
+ m_logProxy.setLog(null);
+
+ Dictionary props2 = new Properties();
+ props2.put("test2", "value2");
+ m_logProxy.log(2, props2);
+
+ assert ((MockLog) m_mockLog).getLogEntries().size() == 1 : "MockLog should still have 1 log entry";
+
+ m_logProxy.setLog(m_mockLog);
+
+ assert ((MockLog) m_mockLog).getLogEntries().size() == 2 : "MockLog should have 2 log entries";
+ }
+
+ /**
+ * Basic functionality of the ListenerImpl is covered, the rest of the situations will probably be covered by integration
+ * tests. Note: test the deployment event INSTALL only when a BundleContext is available
+ */
+ @SuppressWarnings("unchecked")
+ @Test(groups = { UNIT })
+ public void testEventConverting() throws Exception {
+ ListenerImpl listeners = new ListenerImpl(null, m_logProxy);
+ listeners.startInternal();
+ m_logProxy.setLog(m_mockLog);
+
+ final String symbolicName = "org.apache.ace.auditlog.listener.testbundle.a";
+ final long bundleId = 123;
+ final String bundleVersion = "1.2.3";
+ final String bundleLocation = "/home/apache/ace/testbundlea.jar";
+
+ Bundle testBundleA = TestUtils.createMockObjectAdapter(Bundle.class, new Object() {
+ @SuppressWarnings("all")
+ public long getBundleId() {
+ return bundleId;
+ }
+
+ @SuppressWarnings("all")
+ public String getSymbolicName() {
+ return symbolicName;
+ }
+
+ @SuppressWarnings("all")
+ public Dictionary getHeaders() {
+ Dictionary dict = new Properties();
+ dict.put(Constants.BUNDLE_VERSION, bundleVersion);
+ return dict;
+ }
+
+ @SuppressWarnings("all")
+ public String getLocation() {
+ return bundleLocation;
+ }
+ });
+
+ BundleEvent bundleEvent = new BundleEvent(BundleEvent.INSTALLED, testBundleA);
+ FrameworkEvent frameworkEvent = new FrameworkEvent(FrameworkEvent.INFO, testBundleA, new IllegalStateException());
+
+ listeners.bundleChanged(bundleEvent);
+ listeners.frameworkEvent(frameworkEvent);
+ listeners.stopInternal();
+
+ List logEntries = ((MockLog) m_mockLog).getLogEntries();
+ assert logEntries.size() == 2 : "2 log entries should be logged";
+
+ LogEntry bundleEntry = (LogEntry) logEntries.get(0);
+ assert bundleEntry.getType() == AuditEvent.BUNDLE_INSTALLED : "state BUNDLE_INSTALLED (" + AuditEvent.BUNDLE_INSTALLED + ") should be in log but '" + bundleEntry.getType() + "' is in log instead";
+ Dictionary bundleProps = bundleEntry.getProperties();
+ assert bundleProps.size() == 4 : "4 properties should be stored, but found: " + bundleProps.size();
+ assert bundleProps.get(AuditEvent.KEY_ID).equals(Long.toString(bundleId)) : "id should be " + bundleId + " but is: " + bundleProps.get(AuditEvent.KEY_ID);
+ assert bundleProps.get(AuditEvent.KEY_NAME).equals(symbolicName) : "symbolicName should be " + symbolicName + " but is " + bundleProps.get(AuditEvent.KEY_NAME);
+ assert bundleProps.get(AuditEvent.KEY_VERSION).equals(bundleVersion) : "version should be " + bundleVersion + " but is " + bundleProps.get(AuditEvent.KEY_VERSION);
+ assert bundleProps.get(AuditEvent.KEY_LOCATION).equals(bundleLocation) : "location should be " + bundleLocation + " but is " + bundleProps.get(AuditEvent.KEY_LOCATION);
+
+ LogEntry frameworkEntry = (LogEntry) logEntries.get(1);
+ assert frameworkEntry.getType() == AuditEvent.FRAMEWORK_INFO : "state FRAMEWORK_INFO (" + AuditEvent.FRAMEWORK_INFO + ") should be in log but '" + frameworkEntry.getType() + "' is in log instead";
+ Dictionary frameworkProps = frameworkEntry.getProperties();
+ assert frameworkProps.size() == 2 : "2 properties should be stored, but found: " + frameworkProps.size();
+ assert frameworkProps.get(AuditEvent.KEY_ID).equals(Long.toString(bundleId)) : "id should be " + bundleId + " but is: " + frameworkProps.get(AuditEvent.KEY_ID);
+ assert frameworkProps.get(AuditEvent.KEY_TYPE).equals(IllegalStateException.class.getName()) : "exceptionType should be " + IllegalStateException.class.getName() + " but is: " + frameworkProps.get(AuditEvent.KEY_TYPE);
+ }
+}
Added: ace/trunk/org.apache.ace.log/test/org/apache/ace/log/listener/MockLog.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/test/org/apache/ace/log/listener/MockLog.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/test/org/apache/ace/log/listener/MockLog.java (added)
+++ ace/trunk/org.apache.ace.log/test/org/apache/ace/log/listener/MockLog.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,71 @@
+/*
+ * 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.listener;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.ace.log.Log;
+
+public class MockLog implements Log {
+
+ @SuppressWarnings("unchecked")
+ private List m_logEntries;
+
+ @SuppressWarnings("unchecked")
+ public MockLog() {
+ m_logEntries = Collections.synchronizedList(new ArrayList());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void log(int type, Dictionary properties) {
+ m_logEntries.add(new LogEntry(type, properties));
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getLogEntries() {
+ return new ArrayList(m_logEntries);
+ }
+
+ public void clear() {
+ m_logEntries.clear();
+ }
+
+ public class LogEntry {
+ private int m_type;
+ @SuppressWarnings("unchecked")
+ private Dictionary m_properties;
+ @SuppressWarnings("unchecked")
+ public LogEntry(int type, Dictionary properties) {
+ m_type = type;
+ m_properties = properties;
+ }
+
+ public int getType() {
+ return m_type;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Dictionary getProperties() {
+ return m_properties;
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/servlet/LogServletTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/servlet/LogServletTest.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/servlet/LogServletTest.java (added)
+++ ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/servlet/LogServletTest.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,166 @@
+/*
+ * 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.servlet;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+
+import org.apache.ace.log.LogDescriptor;
+import org.apache.ace.log.LogEvent;
+import org.apache.ace.log.server.servlet.LogServlet;
+import org.apache.ace.log.server.store.LogStore;
+import org.apache.ace.range.SortedRangeSet;
+import org.apache.ace.test.utils.TestUtils;
+import org.osgi.service.log.LogService;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class LogServletTest {
+
+ private LogServlet m_logServlet;
+ private LogDescriptor m_range = new LogDescriptor("tID", 123, new SortedRangeSet("1-3"));
+ private LogEvent m_event1 = new LogEvent("tID", 123, 1, 888888, 1, new Properties());
+ private LogEvent m_event2 = new LogEvent("tID", 123, 2, 888888, 2, new Properties());
+ private MockLogStore m_mockStore;
+
+ @BeforeMethod(alwaysRun = true)
+ protected void setUp() throws Exception {
+ m_logServlet = new LogServlet("test", false /* useAuth */);
+ TestUtils.configureObject(m_logServlet, LogService.class);
+ m_mockStore = new MockLogStore();
+ TestUtils.configureObject(m_logServlet, LogStore.class, m_mockStore);
+ }
+
+ @AfterMethod(alwaysRun = true)
+ protected void tearDown() throws Exception {
+ }
+
+ @Test(groups = { UNIT })
+ public void queryLog() throws Exception {
+ MockServletOutputStream output = new MockServletOutputStream();
+ boolean result = m_logServlet.handleQuery(m_range.getTargetID(), String.valueOf(m_range.getLogID()), null, output);
+ assert result;
+ assert m_range.toRepresentation().equals(output.m_text);
+ output.m_text = "";
+ result = m_logServlet.handleQuery(null, null, null, output);
+ assert result;
+ assert (m_range.toRepresentation() + "\n").equals(output.m_text);
+ }
+
+ @Test(groups = { UNIT })
+ public void receiveLog() throws Exception {
+ MockServletOutputStream output = new MockServletOutputStream();
+ boolean result = m_logServlet.handleReceive(m_range.getTargetID(), String.valueOf(m_range.getLogID()), "1", null, output);
+ assert result;
+ String expected = m_event1.toRepresentation() + "\n";
+ String actual = output.m_text;
+ assert expected.equals(actual) : "We expected '" + expected + "', but received '" + actual + "'";
+
+ output = new MockServletOutputStream();
+ result = m_logServlet.handleReceive(m_range.getTargetID(), String.valueOf(m_range.getLogID()), null , null, output);
+ assert result;
+ expected = m_event1.toRepresentation() + "\n" + m_event2.toRepresentation() + "\n";
+ actual = output.m_text;
+ assert expected.equals(actual) : "We expected '" + expected + "', but received '" + actual + "'";;
+ }
+
+ @Test(groups = { UNIT })
+ public void sendLog() throws Exception {
+ MockServletInputStream input = new MockServletInputStream();
+ String expected = m_event1.toRepresentation() + "\n" + m_event2.toRepresentation() + "\n";
+ input.setBytes(expected.getBytes());
+ m_logServlet.handleSend(input);
+
+ String actual = "";
+ for (Iterator<LogEvent> i = m_mockStore.m_events.iterator(); i.hasNext();) {
+ LogEvent event = i.next();
+ actual = actual + event.toRepresentation() + "\n";
+ }
+ assert expected.equals(actual);
+ }
+
+ private class MockLogStore implements LogStore {
+ public List<LogEvent> m_events = new ArrayList<LogEvent>();
+
+ public List<LogEvent> get(LogDescriptor range) {
+ List<LogEvent> events = new ArrayList<LogEvent>();
+ if (range.getRangeSet().contains(1)) {
+ events.add(m_event1);
+ }
+ if (range.getRangeSet().contains(2)) {
+ events.add(m_event2);
+ }
+ return events;
+ }
+ public List<LogDescriptor> getDescriptors(String targetID) {
+ return null;
+ }
+ public List<LogDescriptor> getDescriptors() {
+ List<LogDescriptor> ranges = new ArrayList<LogDescriptor>();
+ ranges.add(m_range);
+ return ranges;
+ }
+ public LogDescriptor getDescriptor(String targetID, long logID) throws IOException {
+ return m_range;
+ }
+ public void put(List<LogEvent> events) throws IOException {
+ m_events = events;
+ }
+ }
+
+ private class MockServletOutputStream extends ServletOutputStream {
+ public String m_text = "";
+
+ @Override
+ public void print(String s) throws IOException {
+ m_text = m_text.concat(s);
+ }
+ @Override
+ public void write(int arg0) throws IOException {
+ }
+ }
+
+ private class MockServletInputStream extends ServletInputStream {
+ private int i = 0;
+ private byte[] m_bytes;
+
+ @Override
+ public int read() throws IOException {
+ int result = -1;
+ if (i < m_bytes.length) {
+ result = m_bytes[i];
+ i++;
+ }
+ return result;
+ }
+
+ public void setBytes(byte[] bytes) {
+ m_bytes = bytes;
+ }
+ }
+}
Added: ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/store/impl/ServerLogStoreTester.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/store/impl/ServerLogStoreTester.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/store/impl/ServerLogStoreTester.java (added)
+++ ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/store/impl/ServerLogStoreTester.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,116 @@
+/*
+ * 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 static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.ace.log.AuditEvent;
+import org.apache.ace.log.LogDescriptor;
+import org.apache.ace.log.LogEvent;
+import org.apache.ace.log.server.store.impl.LogStoreImpl;
+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 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(groups = { UNIT })
+ public void testLog() throws IOException {
+ List<LogDescriptor> ranges = m_logStore.getDescriptors();
+ assert ranges.isEmpty() : "New store should have no ranges.";
+ List<LogEvent> events = new ArrayList<LogEvent>();
+ 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 LogEvent(target, log, id, System.currentTimeMillis(), AuditEvent.FRAMEWORK_STARTED, new Properties() {
+ {
+ put("test", "bar");
+ }
+ }));
+ }
+ }
+ }
+ m_logStore.put(events);
+ assert m_logStore.getDescriptors().size() == 3 * 4 : "Incorrect amount of ranges returned from store";
+ List<LogEvent> stored = new ArrayList<LogEvent>();
+ for (LogDescriptor range : m_logStore.getDescriptors()) {
+ for (LogDescriptor range2 : m_logStore.getDescriptors(range.getTargetID())) {
+ stored.addAll(m_logStore.get(m_logStore.getDescriptor(range2.getTargetID(), range2.getLogID())));
+ }
+ }
+
+ Set<String> in = new HashSet<String>();
+ for (LogEvent event : events) {
+ in.add(event.toRepresentation());
+ }
+ Set<String> out = new HashSet<String>();
+ for (LogEvent event : stored) {
+ out.add(event.toRepresentation());
+ }
+ assert in.equals(out) : "Stored events differ from the added.";
+ }
+
+ @Test( groups = { TestUtils.UNIT } )
+ public void testLogWithSpecialCharacters() throws IOException {
+ String targetID = "myta\0rget";
+ LogEvent event = new LogEvent(targetID, 1, 1, System.currentTimeMillis(), AuditEvent.FRAMEWORK_STARTED, new Properties());
+ List<LogEvent> events = new ArrayList<LogEvent>();
+ 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();
+ }
+
+ private void delete(File root) {
+ if (root.isDirectory()) {
+ for (File child : root.listFiles()) {
+ delete(child);
+ }
+ }
+ root.delete();
+ }
+}
Added: ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/task/LogTaskTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/task/LogTaskTest.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/task/LogTaskTest.java (added)
+++ ace/trunk/org.apache.ace.log/test/org/apache/ace/log/server/task/LogTaskTest.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,107 @@
+/*
+ * 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.task;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.ace.log.LogDescriptor;
+import org.apache.ace.log.server.task.LogSyncTask;
+import org.apache.ace.range.RangeIterator;
+import org.apache.ace.range.SortedRangeSet;
+import org.testng.annotations.Test;
+
+public class LogTaskTest {
+
+ private class MockLogSyncTask extends LogSyncTask {
+ public List<LogDescriptor> m_calledWith = new ArrayList<LogDescriptor>();
+
+ public MockLogSyncTask(String endpoint, String name) {
+ super(endpoint, name, LogSyncTask.Mode.PUSH);
+ }
+
+ @Override
+ protected void writeLogDescriptor(LogDescriptor descriptor, Writer writer) throws IOException {
+ m_calledWith.add(descriptor);
+ }
+
+ }
+
+ /**
+ * This test tests both delta computation and push behavior.
+ */
+ @Test(groups = { UNIT })
+ public void testDeltaComputation() throws IOException {
+ // TODO: Test the new LogDescriptor.
+ List<LogDescriptor> src = new ArrayList<LogDescriptor>();
+ List<LogDescriptor> dest = new ArrayList<LogDescriptor>();
+ MockLogSyncTask task = new MockLogSyncTask("mocklog", "mocklog");
+ // compare two empty lists
+ task.writeDelta(task.calculateDelta(src, dest), null);
+ assert task.m_calledWith.isEmpty() : "Delta of two empty lists should be empty";
+ // add something to the source
+ src.add(new LogDescriptor("gwid", 1, new SortedRangeSet("1-5")));
+ task.writeDelta(task.calculateDelta(src, dest), null);
+ assert task.m_calledWith.size() == 1 : "Delta should be 1 instead of: " + task.m_calledWith.size();
+ task.m_calledWith.clear();
+ // add an overlapping destination
+ dest.add(new LogDescriptor("gwid", 1, new SortedRangeSet("1-3")));
+ task.writeDelta(task.calculateDelta(src, dest), null);
+ assert task.m_calledWith.size() == 1 : "Delta should be 1 instead of: " + task.m_calledWith.size();
+ RangeIterator i = task.m_calledWith.get(0).getRangeSet().iterator();
+ assert i.next() == 4 : "Illegal value in SortedRangeSet";
+ assert i.next() == 5 : "Illegal value in SortedRangeSet";
+ assert !i.hasNext() : "Illegal value in SortedRangeSet";
+ task.m_calledWith.clear();
+ // add a non-overlapping destination
+ dest.add(new LogDescriptor("gwid", 2, new SortedRangeSet("50-100")));
+ task.writeDelta(task.calculateDelta(src, dest), null);
+ assert task.m_calledWith.size() == 1 : "Delta should be 1 instead of: " + task.m_calledWith.size();
+ i = task.m_calledWith.get(0).getRangeSet().iterator();
+ assert i.next() == 4 : "Illegal value in SortedRangeSet";
+ assert i.next() == 5 : "Illegal value in SortedRangeSet";
+ assert !i.hasNext() : "Illegal value in SortedRangeSet";
+ task.m_calledWith.clear();
+ // add non-overlapping source
+ src.add(new LogDescriptor("gwid", 2, new SortedRangeSet("1-49")));
+ task.writeDelta(task.calculateDelta(src, dest), null);
+ assert task.m_calledWith.size() == 2 : "Delta should be 2 instead of: " + task.m_calledWith.size();
+ task.m_calledWith.clear();
+ // add a source with gaps
+ src.add(new LogDescriptor("gwid", 3, new SortedRangeSet("1-10")));
+ dest.add(new LogDescriptor("gwid", 3, new SortedRangeSet("3,5-8")));
+ task.writeDelta(task.calculateDelta(src, dest), null);
+ assert task.m_calledWith.size() == 3 : "Delta should be 3 instead of: " + task.m_calledWith.size();
+ for (LogDescriptor l : task.m_calledWith) {
+ if (l.getLogID() == 3) {
+ i = l.getRangeSet().iterator();
+ }
+ }
+ assert i.next() == 1 : "Illegal value in SortedRangeSet";
+ assert i.next() == 2 : "Illegal value in SortedRangeSet";
+ assert i.next() == 4 : "Illegal value in SortedRangeSet";
+ assert i.next() == 9 : "Illegal value in SortedRangeSet";
+ assert i.next() == 10 : "Illegal value in SortedRangeSet";
+ assert !i.hasNext() : "Illegal value in SortedRangeSet";
+ }
+}
Added: ace/trunk/org.apache.ace.log/test/org/apache/ace/log/target/store/impl/GatewayLogStoreTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/test/org/apache/ace/log/target/store/impl/GatewayLogStoreTest.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/test/org/apache/ace/log/target/store/impl/GatewayLogStoreTest.java (added)
+++ ace/trunk/org.apache.ace.log/test/org/apache/ace/log/target/store/impl/GatewayLogStoreTest.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,104 @@
+/*
+ * 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.target.store.impl;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.ace.identification.Identification;
+import org.apache.ace.log.AuditEvent;
+import org.apache.ace.log.LogEvent;
+import org.apache.ace.log.target.store.LogStore;
+import org.apache.ace.log.target.store.impl.LogStoreImpl;
+import org.apache.ace.test.utils.TestUtils;
+import org.osgi.service.log.LogService;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class GatewayLogStoreTest {
+ private LogStoreImpl m_logStore;
+ private File m_dir = null;
+
+ @BeforeMethod(alwaysRun = true)
+ protected void setUp() throws Exception {
+ m_dir = File.createTempFile(LogStore.class.getName(), null);
+ m_dir.delete();
+ m_logStore = new LogStoreImpl(m_dir);
+ TestUtils.configureObject(m_logStore, LogService.class);
+ TestUtils.configureObject(m_logStore, Identification.class, TestUtils.createMockObjectAdapter(Identification.class, new Object() {
+ @SuppressWarnings("unused")
+ public String getID() {
+ return "test";
+ }
+ }));
+ m_logStore.start();
+ }
+
+ @AfterMethod(alwaysRun = true)
+ protected void tearDown() throws IOException {
+ m_logStore.stop();
+ delete(m_dir);
+ m_logStore = null;
+ }
+
+ @SuppressWarnings({ "serial", "unchecked" })
+ @Test(groups = {UNIT})
+ public void testLog() throws IOException {
+ long[] ids = m_logStore.getLogIDs();
+ assert ids.length == 1 : "New store should have only one id";
+ List<String> events = new ArrayList<String>();
+ events.add(m_logStore.put(AuditEvent.FRAMEWORK_STARTED, new Properties() {{put("test", "test");}}).toRepresentation());
+ events.add(m_logStore.put(AuditEvent.BUNDLE_INSTALLED, new Properties() {{put("test", "test");}}).toRepresentation());
+ events.add(m_logStore.put(AuditEvent.DEPLOYMENTADMIN_COMPLETE, new Properties() {{put("test", "test");}}).toRepresentation());
+ ids = m_logStore.getLogIDs();
+ assert ids.length == 1 : "Error free store should have only one id";
+ long highest = m_logStore.getHighestID(ids[0]);
+ assert highest == 3 : "Store with 3 entries should have 3 as highest id but was: " + highest;
+ List<String> result = new ArrayList<String>();
+ for (LogEvent event : (List<LogEvent>) m_logStore.get(ids[0])) {
+ result.add(event.toRepresentation());
+ }
+ assert result.equals(events) : "Events " + events + " should equal full log " + result;
+ result = new ArrayList<String>();
+ for (LogEvent event : (List<LogEvent>) m_logStore.get(ids[0], 1, highest)) {
+ result.add(event.toRepresentation());
+ }
+ assert result.equals(events) : "Events " + events + " should equal full log " + result;
+ }
+
+ @Test(groups = {UNIT}, expectedExceptions = {IOException.class})
+ public void testExceptionHandling() throws IOException {
+ m_logStore.handleException(m_logStore.getLog(4711), new IOException("test"));
+ }
+
+ private static void delete(File target) {
+ if (target.isDirectory()) {
+ for (File child : target.listFiles()) {
+ delete(child);
+ }
+ }
+ target.delete();
+ }
+}
Added: ace/trunk/org.apache.ace.log/test/org/apache/ace/log/target/task/LogSyncTaskTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.log/test/org/apache/ace/log/target/task/LogSyncTaskTest.java?rev=1465924&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.log/test/org/apache/ace/log/target/task/LogSyncTaskTest.java (added)
+++ ace/trunk/org.apache.ace.log/test/org/apache/ace/log/target/task/LogSyncTaskTest.java Tue Apr 9 08:18:47 2013
@@ -0,0 +1,172 @@
+/*
+ * 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.target.task;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.ace.discovery.Discovery;
+import org.apache.ace.identification.Identification;
+import org.apache.ace.log.LogDescriptor;
+import org.apache.ace.log.LogEvent;
+import org.apache.ace.log.target.store.LogStore;
+import org.apache.ace.log.target.task.LogSyncTask;
+import org.apache.ace.range.SortedRangeSet;
+import org.apache.ace.test.utils.TestUtils;
+import org.osgi.service.log.LogService;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class LogSyncTaskTest {
+
+ private static final String TARGET_ID = "gwID";
+ private LogSyncTask m_task;
+
+ @BeforeMethod(alwaysRun = true)
+ protected void setUp() throws Exception {
+ m_task = new LogSyncTask("testlog");
+ TestUtils.configureObject(m_task, LogService.class);
+ TestUtils.configureObject(m_task, Identification.class, new Identification() {
+ public String getID() {
+ return TARGET_ID;
+ }
+ });
+ TestUtils.configureObject(m_task, Discovery.class);
+ TestUtils.configureObject(m_task, LogStore.class);
+ }
+
+ @Test(groups = { UNIT })
+ public synchronized void getRange() throws Exception {
+ final LogDescriptor range = new LogDescriptor(TARGET_ID, 1, new SortedRangeSet("1-10"));
+ m_task.getDescriptor(new InputStream() {
+ int m_count = 0;
+ byte[] m_bytes = (range.toRepresentation() + "\n").getBytes();
+ @Override
+ public int read() throws IOException {
+ if (m_count < m_bytes.length) {
+ byte b = m_bytes[m_count];
+ m_count++;
+ return b;
+ } else {
+ return -1;
+ }
+ }
+ });
+ }
+
+ @Test(groups = { UNIT })
+ public synchronized void synchronizeLog() throws Exception {
+ final LogDescriptor range = new LogDescriptor(TARGET_ID, 1, new SortedRangeSet(new long[] {0}));
+ final LogEvent event = new LogEvent(TARGET_ID, 1, 1, 1, 1, new Properties());
+ final List<LogEvent> events = new ArrayList<LogEvent>();
+ events.add(event);
+
+ InputStream input = new InputStream() {
+ byte[] bytes = range.toRepresentation().getBytes();
+ int count = 0;
+ @Override
+ public int read() throws IOException {
+ if (count < bytes.length) {
+ byte b = bytes[count];
+ count++;
+ return b;
+ } else {
+ return -1;
+ }
+ }
+ };
+ TestUtils.configureObject(m_task, LogStore.class, new LogStore() {
+ public List<?> get(long logID, long from, long to) throws IOException {
+ return events;
+ }
+ public long getHighestID(long logID) throws IOException {
+ return event.getID();
+ }
+ public List<?> get(long logID) throws IOException { return null; }
+ public long[] getLogIDs() throws IOException { return null; }
+ @SuppressWarnings("unchecked")
+ public LogEvent put(int type, Dictionary props) throws IOException { return null; }
+ });
+ MockConnection connection = new MockConnection(new URL("http://mock"));
+
+ m_task.synchronizeLog(1, input, connection);
+ String expectedString = event.toRepresentation() + "\n";
+ String actualString = connection.getString();
+
+ assert actualString.equals(expectedString) : "We expected " + expectedString + " but received " + actualString;
+ }
+
+ private class MockConnection extends HttpURLConnection {
+
+ private MockOutputStream m_output;
+
+ public MockConnection(URL url) throws IOException {
+ super(url);
+ m_output = new MockOutputStream();
+ }
+
+ public String getString() {
+ return m_output.getString();
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ return m_output;
+ }
+
+ @Override
+ public void disconnect() {
+ // Nop
+ }
+
+ @Override
+ public boolean usingProxy() {
+ return false;
+ }
+
+ @Override
+ public void connect() throws IOException {
+ // Nop
+ }
+ }
+
+ private class MockOutputStream extends OutputStream {
+ byte[] bytes = new byte[8*1024];
+ int count = 0;
+ @Override
+ public void write(int arg0) throws IOException {
+ bytes[count] = (byte) arg0;
+ count++;
+ }
+
+ public String getString() {
+ return new String(bytes, 0, count);
+ }
+ }
+
+}