Add test infrastructure for tests that use logging and mocking
Change-Id: I5a38a5fd3256ca05e91d234c2bec7d18c06a75a2
This commit is contained in:

committed by
David Pursehouse

parent
d1b1a8801b
commit
e362959d05
@@ -0,0 +1,177 @@
|
||||
// Copyright (C) 2013 The Android Open Source Project
|
||||
//
|
||||
// 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 com.google.gerrit.testutil;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class FilesystemLoggingMockingTestCase extends LoggingMockingTestCase {
|
||||
|
||||
private Collection<File> toCleanup = Lists.newArrayList();
|
||||
|
||||
/**
|
||||
* Asserts that a given file exists.
|
||||
*
|
||||
* @param file The file to test.
|
||||
*/
|
||||
protected void assertExists(File file) {
|
||||
assertTrue("File '" + file.getAbsolutePath() + "' does not exist",
|
||||
file.exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a given file does not exist.
|
||||
*
|
||||
* @param file The file to test.
|
||||
*/
|
||||
protected void assertDoesNotExist(File file) {
|
||||
assertFalse("File '" + file.getAbsolutePath() + "' exists", file.exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a given file exists and is a directory.
|
||||
*
|
||||
* @param file The file to test.
|
||||
*/
|
||||
protected void assertDirectory(File file) {
|
||||
// Although isDirectory includes checking for existence, we nevertheless
|
||||
// explicitly check for existence, to get more appropriate error messages
|
||||
assertExists(file);
|
||||
assertTrue("File '" + file.getAbsolutePath() + "' is not a directory",
|
||||
file.isDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that creating a directory from the given file worked
|
||||
*
|
||||
* @param file The directory to create
|
||||
*/
|
||||
protected void assertMkdirs(File file) {
|
||||
assertTrue("Could not create directory '" + file.getAbsolutePath() + "'",
|
||||
file.mkdirs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that creating a directory from the specified file worked
|
||||
*
|
||||
* @param parent The parent of the directory to create
|
||||
* @param name The name of the directoryto create (relative to {@code parent}
|
||||
* @return The created directory
|
||||
*/
|
||||
protected File assertMkdirs(File parent, String name) {
|
||||
File file = new File(parent, name);
|
||||
assertMkdirs(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that creating a file worked
|
||||
*
|
||||
* @param file The file to create
|
||||
*/
|
||||
protected void assertCreateFile(File file) throws IOException {
|
||||
assertTrue("Could not create file '" + file.getAbsolutePath() + "'",
|
||||
file.createNewFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that creating a file worked
|
||||
*
|
||||
* @param parent The parent of the file to create
|
||||
* @param name The name of the file to create (relative to {@code parent}
|
||||
* @return The created file
|
||||
*/
|
||||
protected File assertCreateFile(File parent, String name) throws IOException {
|
||||
File file = new File(parent, name);
|
||||
assertCreateFile(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file in the system's default folder for temporary files.
|
||||
*
|
||||
* The file/directory automatically gets removed during tearDown.
|
||||
*
|
||||
* The name of the created file begins with 'gerrit_test_', and is located
|
||||
* in the system's default folder for temporary files.
|
||||
*
|
||||
* @param suffix Trailing part of the file name.
|
||||
* @return The temporary file.
|
||||
* @throws IOException If a file could not be created.
|
||||
*/
|
||||
private File createTempFile(String suffix) throws IOException {
|
||||
String prefix ="gerrit_test_";
|
||||
if (!Strings.isNullOrEmpty(getName())) {
|
||||
prefix += getName() + "_";
|
||||
}
|
||||
File tmp = File.createTempFile(prefix, suffix);
|
||||
toCleanup.add(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file in the system's default folder for temporary files.
|
||||
*
|
||||
* The file/directory automatically gets removed during tearDown.
|
||||
*
|
||||
* The name of the created file begins with 'gerrit_test_', and is located
|
||||
* in the system's default folder for temporary files.
|
||||
*
|
||||
* @return The temporary file.
|
||||
* @throws IOException If a file could not be created.
|
||||
*/
|
||||
protected File createTempFile() throws IOException {
|
||||
return createTempFile("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a directory in the system's default folder for temporary files.
|
||||
*
|
||||
* The directory (and all it's contained files/directory) automatically get
|
||||
* removed during tearDown.
|
||||
*
|
||||
* The name of the created directory begins with 'gerrit_test_', and is be
|
||||
* located in the system's default folder for temporary files.
|
||||
*
|
||||
* @return The temporary directory.
|
||||
* @throws IOException If a file could not be created.
|
||||
*/
|
||||
protected File createTempDir() throws IOException {
|
||||
File tmp = createTempFile(".dir");
|
||||
if (!tmp.delete()) {
|
||||
throw new IOException("Cannot delete temporary file '" + tmp.getPath()
|
||||
+ "'");
|
||||
}
|
||||
tmp.mkdir();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void cleanupCreatedFiles() throws IOException {
|
||||
for (File file : toCleanup) {
|
||||
FileUtils.delete(file, FileUtils.RECURSIVE);
|
||||
}
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
cleanupCreatedFiles();
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
@@ -0,0 +1,134 @@
|
||||
// Copyright (C) 2013 The Android Open Source Project
|
||||
//
|
||||
// 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 com.google.gerrit.testutil;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.testutil.log.LogUtil;
|
||||
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
import org.junit.After;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Testcase capturing associated logs and allowing to assert on them.
|
||||
*
|
||||
* For a test case SomeNameTest, the log for SomeName gets captured. Assertions
|
||||
* on logs run against the coptured log events from this logger. After the
|
||||
* tests, the logger are set back to their original settings.
|
||||
*/
|
||||
public abstract class LoggingMockingTestCase extends MockingTestCase {
|
||||
private String loggerName;
|
||||
private LogUtil.LoggerSettings loggerSettings;
|
||||
private java.util.Collection<LoggingEvent> loggedEvents;
|
||||
|
||||
/**
|
||||
* Assert a logged event with a given string.
|
||||
* <p>
|
||||
* If such a event is found, it is removed from the captured logs.
|
||||
*
|
||||
* @param needle The string to look for.
|
||||
*/
|
||||
protected final void assertLogMessageContains(String needle) {
|
||||
LoggingEvent hit = null;
|
||||
Iterator<LoggingEvent> iter = loggedEvents.iterator();
|
||||
while (hit == null && iter.hasNext()) {
|
||||
LoggingEvent event = iter.next();
|
||||
if (event.getRenderedMessage().contains(needle)) {
|
||||
hit = event;
|
||||
}
|
||||
}
|
||||
assertNotNull("Could not find log message containing '" + needle + "'",
|
||||
hit);
|
||||
assertTrue("Could not remove log message containing '" + needle + "'",
|
||||
loggedEvents.remove(hit));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a logged event whose throwable contains a given string
|
||||
* <p>
|
||||
* If such a event is found, it is removed from the captured logs.
|
||||
*
|
||||
* @param needle The string to look for.
|
||||
*/
|
||||
protected final void assertLogThrowableMessageContains(String needle) {
|
||||
LoggingEvent hit = null;
|
||||
Iterator<LoggingEvent> iter = loggedEvents.iterator();
|
||||
while (hit == null && iter.hasNext()) {
|
||||
LoggingEvent event = iter.next();
|
||||
if (event.getThrowableInformation().getThrowable().toString()
|
||||
.contains(needle)) {
|
||||
hit = event;
|
||||
}
|
||||
}
|
||||
assertNotNull("Could not find log message with a Throwable containing '"
|
||||
+ needle + "'", hit);
|
||||
assertTrue("Could not remove log message with a Throwable containing '"
|
||||
+ needle + "'", loggedEvents.remove(hit));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that all logged events have been asserted
|
||||
*/
|
||||
// As the PowerMock runner does not pass through runTest, we inject log
|
||||
// verification through @After
|
||||
@After
|
||||
public final void assertNoUnassertedLogEvents() {
|
||||
if (loggedEvents.size() > 0) {
|
||||
LoggingEvent event = loggedEvents.iterator().next();
|
||||
String msg = "Found untreated logged events. First one is:\n";
|
||||
msg += event.getRenderedMessage();
|
||||
if (event.getThrowableInformation() != null) {
|
||||
msg += "\n" + event.getThrowableInformation().getThrowable();
|
||||
}
|
||||
fail(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
loggedEvents = Lists.newArrayList();
|
||||
|
||||
// The logger we're interested is class name without the trailing "Test".
|
||||
// While this is not the most general approach it is sufficient for now,
|
||||
// and we can improve later to allow tests to specify which loggers are
|
||||
// to check.
|
||||
loggerName = this.getClass().getCanonicalName();
|
||||
loggerName = loggerName.substring(0, loggerName.length()-4);
|
||||
loggerSettings = LogUtil.logToCollection(loggerName, loggedEvents);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
super.runTest();
|
||||
// Plain JUnit runner does not pick up @After, so we add it here
|
||||
// explicitly. Note, that we cannot put this into tearDown, as failure
|
||||
// to verify mocks would bail out and might leave open resources from
|
||||
// subclasses open.
|
||||
assertNoUnassertedLogEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
if (loggerName != null && loggerSettings != null) {
|
||||
Logger logger = LogManager.getLogger(loggerName);
|
||||
loggerSettings.pushOntoLogger(logger);
|
||||
}
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
@@ -0,0 +1,155 @@
|
||||
// Copyright (C) 2013 The Android Open Source Project
|
||||
//
|
||||
// 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 com.google.gerrit.testutil;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.easymock.IMocksControl;
|
||||
import org.junit.After;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.api.easymock.PowerMock;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Test case with some support for automatically verifying mocks.
|
||||
*
|
||||
* This test case works transparently with EasyMock and PowerMock.
|
||||
*/
|
||||
public abstract class MockingTestCase extends TestCase {
|
||||
private Collection<Object> mocks;
|
||||
private Collection<IMocksControl> mockControls;
|
||||
private boolean mocksReplayed;
|
||||
private boolean usePowerMock;
|
||||
|
||||
/**
|
||||
* Create and register a mock control.
|
||||
*
|
||||
* @return The mock control instance.
|
||||
*/
|
||||
protected final IMocksControl createMockControl() {
|
||||
IMocksControl mockControl = EasyMock.createControl();
|
||||
assertTrue("Adding mock control failed", mockControls.add(mockControl));
|
||||
return mockControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and register a mock.
|
||||
*
|
||||
* Creates a mock and registers it in the list of created mocks, so it gets
|
||||
* treated automatically upon {@code replay} and {@code verify};
|
||||
* @param toMock The class to create a mock for.
|
||||
* @return The mock instance.
|
||||
*/
|
||||
protected final <T> T createMock(Class<T> toMock) {
|
||||
return createMock(toMock, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock for a mock control and register a mock.
|
||||
*
|
||||
* Creates a mock and registers it in the list of created mocks, so it gets
|
||||
* treated automatically upon {@code replay} and {@code verify};
|
||||
* @param toMock The class to create a mock for.
|
||||
* @param control The mock control to create the mock on. If null, do not use
|
||||
* a specific control.
|
||||
* @return The mock instance.
|
||||
*/
|
||||
protected final <T> T createMock(Class<T> toMock, IMocksControl control) {
|
||||
assertFalse("Mocks have already been set to replay", mocksReplayed);
|
||||
final T mock;
|
||||
if (control == null) {
|
||||
if (usePowerMock) {
|
||||
mock = PowerMock.createMock(toMock);
|
||||
} else {
|
||||
mock = EasyMock.createMock(toMock);
|
||||
}
|
||||
assertTrue("Adding " + toMock.getName() + " mock failed",
|
||||
mocks.add(mock));
|
||||
} else {
|
||||
mock = control.createMock(toMock);
|
||||
}
|
||||
return mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all registered mocks to replay
|
||||
*/
|
||||
protected final void replayMocks() {
|
||||
assertFalse("Mocks have already been set to replay", mocksReplayed);
|
||||
if (usePowerMock) {
|
||||
PowerMock.replayAll();
|
||||
} else {
|
||||
EasyMock.replay(mocks.toArray());
|
||||
}
|
||||
for (IMocksControl mockControl : mockControls) {
|
||||
mockControl.replay();
|
||||
}
|
||||
mocksReplayed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify all registered mocks
|
||||
*
|
||||
* This method is called automatically at the end of a test. Nevertheless,
|
||||
* it is safe to also call it beforehand, if this better meets the
|
||||
* verification part of a test.
|
||||
*/
|
||||
// As the PowerMock runner does not pass through runTest, we inject mock
|
||||
// verification through @After
|
||||
@After
|
||||
public final void verifyMocks() {
|
||||
if (!mocks.isEmpty() || !mockControls.isEmpty()) {
|
||||
assertTrue("Created mocks have not been set to replay. Call replayMocks "
|
||||
+ "within the test", mocksReplayed);
|
||||
if (usePowerMock) {
|
||||
PowerMock.verifyAll();
|
||||
} else {
|
||||
EasyMock.verify(mocks.toArray());
|
||||
}
|
||||
for (IMocksControl mockControl : mockControls) {
|
||||
mockControl.verify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
usePowerMock = false;
|
||||
RunWith runWith = this.getClass().getAnnotation(RunWith.class);
|
||||
if (runWith != null) {
|
||||
usePowerMock = PowerMockRunner.class.isAssignableFrom(runWith.value());
|
||||
}
|
||||
|
||||
mocks = new ArrayList<Object>();
|
||||
mockControls = new ArrayList<IMocksControl>();
|
||||
mocksReplayed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
super.runTest();
|
||||
// Plain JUnit runner does not pick up @After, so we add it here
|
||||
// explicitly. Note, that we cannot put this into tearDown, as failure
|
||||
// to verify mocks would bail out and might leave open resources from
|
||||
// subclasses open.
|
||||
verifyMocks();
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2013 The Android Open Source Project
|
||||
//
|
||||
// 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 com.google.gerrit.testutil;
|
||||
|
||||
import com.google.gwtorm.client.KeyUtil.Encoder;
|
||||
|
||||
public class PassThroughKeyUtilEncoder extends Encoder {
|
||||
@Override
|
||||
public String encode(String e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decode(String e) {
|
||||
return e;
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2013 The Android Open Source Project
|
||||
//
|
||||
// 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 com.google.gerrit.testutil;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.easymock.IArgumentMatcher;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Match for Iterables via set equals
|
||||
*
|
||||
* Converts both expected and actual parameter to a set and compares those two
|
||||
* sets via equals to determine whether or not they match.
|
||||
*/
|
||||
public class SetMatcher<T> implements IArgumentMatcher {
|
||||
public static <S extends Iterable<T>,T> S setEq(S expected) {
|
||||
EasyMock.reportMatcher(new SetMatcher<T>(expected));
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<T> expected;
|
||||
|
||||
public SetMatcher(Iterable<T> expected) {
|
||||
this.expected = Sets.newHashSet(expected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object actual) {
|
||||
if (actual instanceof Iterable<?>) {
|
||||
Set<?> actualSet = Sets.newHashSet((Iterable<?>)actual);
|
||||
return expected.equals(actualSet);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuffer buffer) {
|
||||
buffer.append(expected);
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2013 The Android Open Source Project
|
||||
//
|
||||
// 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 com.google.gerrit.testutil.log;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.apache.log4j.AppenderSkeleton;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Log4j appender that logs into a list
|
||||
*/
|
||||
public class CollectionAppender extends AppenderSkeleton {
|
||||
private Collection<LoggingEvent> events;
|
||||
|
||||
public CollectionAppender() {
|
||||
events = new LinkedList<LoggingEvent>();
|
||||
}
|
||||
|
||||
public CollectionAppender(Collection<LoggingEvent> events) {
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresLayout() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(LoggingEvent event) {
|
||||
if (! events.add(event)) {
|
||||
throw new RuntimeException("Could not append event " + event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public Collection<LoggingEvent> getLoggedEvents() {
|
||||
return Lists.newLinkedList(events);
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
// Copyright (C) 2013 The Android Open Source Project
|
||||
//
|
||||
// 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 com.google.gerrit.testutil.log;
|
||||
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
public class LogUtil {
|
||||
/**
|
||||
* Change logger's setting so it only logs to a collection.
|
||||
*
|
||||
* @param logName Name of the logger to modify.
|
||||
* @param collection The collection to log into.
|
||||
* @return The logger's original settings.
|
||||
*/
|
||||
public static LoggerSettings logToCollection(String logName,
|
||||
Collection<LoggingEvent> collection) {
|
||||
Logger logger = LogManager.getLogger(logName);
|
||||
LoggerSettings loggerSettings = new LoggerSettings(logger);
|
||||
logger.removeAllAppenders();
|
||||
logger.setAdditivity(false);
|
||||
CollectionAppender listAppender = new CollectionAppender(collection);
|
||||
logger.addAppender(listAppender);
|
||||
return loggerSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Capsule for a logger's settings that get mangled by rerouting logging to a collection
|
||||
*/
|
||||
public static class LoggerSettings {
|
||||
private final boolean additive;
|
||||
private final List<Appender> appenders;
|
||||
|
||||
/**
|
||||
* Read off logger settings from an instance.
|
||||
*
|
||||
* @param logger The logger to read the settings off from.
|
||||
*/
|
||||
private LoggerSettings(Logger logger) {
|
||||
this.additive = logger.getAdditivity();
|
||||
|
||||
Enumeration<?> appenders = logger.getAllAppenders();
|
||||
this.appenders = new ArrayList<Appender>();
|
||||
while (appenders.hasMoreElements()) {
|
||||
Object appender = appenders.nextElement();
|
||||
if (appender instanceof Appender) {
|
||||
this.appenders.add((Appender)appender);
|
||||
} else {
|
||||
throw new RuntimeException("getAllAppenders of " + logger
|
||||
+ " contained an object that is not an Appender");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes this settings back onto a logger.
|
||||
*
|
||||
* @param logger the logger on which to push the settings.
|
||||
*/
|
||||
public void pushOntoLogger(Logger logger) {
|
||||
logger.setAdditivity(additive);
|
||||
|
||||
logger.removeAllAppenders();
|
||||
for (Appender appender : appenders) {
|
||||
logger.addAppender(appender);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user