package org.ovirt.engine.core.utils.log; import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.classextension.EasyMock.replay; import static org.easymock.classextension.EasyMock.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.Test; import org.ovirt.engine.core.compat.LogCompat; import org.ovirt.engine.core.utils.log.Logged.LogLevel; /** * Tests for the {@link LoggedUtils} class. */ public class LoggedUtilsTest { /* --- Types used for testing purposes --- */ /** * Interface used for DRY testing of {@link LoggedUtils#log}. */ private static interface LogSetup { public void setup(LogCompat mock, String message, Object args); } @Logged(executionLevel = LogLevel.OFF, errorLevel = LogLevel.OFF) public class LoggedClass {} public class LoggedSubclass extends LoggedClass {} @Logged(executionLevel = LogLevel.DEBUG, errorLevel = LogLevel.WARN, parametersLevel = LogLevel.FATAL, returnLevel = LogLevel.FATAL) public class LoggedOverridingSubclass extends LoggedClass {} @Logged(parametersLevel = LogLevel.DEBUG) public class LoggedOverridingSubclassNoParameters extends LoggedClass {} @Logged(returnLevel = LogLevel.DEBUG) public class LoggedOverridingSubclassNoReturn extends LoggedClass {} /* --- Tests for the method "getObjectId" --- */ @Test public void testGetObjectIdFromNull() throws Exception { assertEquals("0", LoggedUtils.getObjectId(null)); } @Test public void testGetObjectIdUniqueForDifferentObjects() throws Exception { assertTrue(! LoggedUtils.getObjectId(new Object()).equals(LoggedUtils.getObjectId(new Object())) ); } @Test public void testGetObjectIdConsistentForSameObject() throws Exception { Object obj = new Object(); assertEquals(LoggedUtils.getObjectId(obj), LoggedUtils.getObjectId(obj)); } /* --- Tests for the method "getAnnotation" --- */ @Test public void testGetAnnotationFromNull() throws Exception { assertNull(LoggedUtils.getAnnotation(null)); } @Test public void testGetAnnotationFromClass() throws Exception { Logged logged = LoggedUtils.getAnnotation(new LoggedClass()); assertEquals(LogLevel.OFF, logged.executionLevel()); assertEquals(LogLevel.OFF, logged.errorLevel()); assertEquals(LogLevel.INFO, logged.parametersLevel()); assertEquals(LogLevel.INFO, logged.returnLevel()); } @Test public void testGetAnnotationFromSubclass() throws Exception { assertSame(LoggedUtils.getAnnotation(new LoggedClass()), LoggedUtils.getAnnotation(new LoggedSubclass())); } @Test public void testGetAnnotationFromOverridingSubclass() throws Exception { Logged logged = LoggedUtils.getAnnotation(new LoggedOverridingSubclass()); assertEquals(LogLevel.DEBUG, logged.executionLevel()); assertEquals(LogLevel.WARN, logged.errorLevel()); assertEquals(LogLevel.FATAL, logged.parametersLevel()); assertEquals(LogLevel.FATAL, logged.returnLevel()); } /* --- Tests for the method "determineMessage" --- */ @Test public void testDetermineMessageReturnsObjectForParameterExpansion() throws Exception { Object obj = new Object(); LogCompat log = createMock(LogCompat.class); expect(log.isDebugEnabled()).andReturn(true); replay(log); assertSame(obj, LoggedUtils.determineMessage(log, LoggedOverridingSubclass.class.getAnnotation(Logged.class), obj)); } @Test public void testDetermineMessageReturnsClassNameForNoParameterExpansion() throws Exception { LogCompat log = createMock(LogCompat.class); expect(log.isDebugEnabled()).andReturn(false).anyTimes(); replay(log); assertEquals("LoggedUtils.determineMessage shouldn't return parameter expansion for a disabled log level.", Object.class.getName(), LoggedUtils.determineMessage(log, LoggedOverridingSubclassNoParameters.class.getAnnotation(Logged.class), new Object())); assertEquals("LoggedUtils.determineMessage shouldn't return parameter expansion when diabled completely.", Object.class.getName(), LoggedUtils.determineMessage(log, LoggedClass.class.getAnnotation(Logged.class), new Object())); } /* --- Tests for the method "log" --- */ @Test public void testLogOffDoesntLog() { LogCompat log = createMock(LogCompat.class); replay(log); LoggedUtils.log(log, LogLevel.OFF, "{0}", new Object()); verify(log); } @Test public void testLogTrace() throws Exception { helpTestLog(LogLevel.TRACE, new LogSetup() { @Override public void setup(LogCompat mock, String message, Object args) { expect(mock.isTraceEnabled()).andReturn(true); mock.traceFormat(message, args); } }); } @Test public void testLogDebug() throws Exception { helpTestLog(LogLevel.DEBUG, new LogSetup() { @Override public void setup(LogCompat mock, String message, Object args) { expect(mock.isDebugEnabled()).andReturn(true); mock.debugFormat(message, args); } }); } @Test public void testLogInfo() throws Exception { helpTestLog(LogLevel.INFO, new LogSetup() { @Override public void setup(LogCompat mock, String message, Object args) { expect(mock.isInfoEnabled()).andReturn(true); mock.infoFormat(message, args); } }); } @Test public void testLogWarn() throws Exception { helpTestLog(LogLevel.WARN, new LogSetup() { @Override public void setup(LogCompat mock, String message, Object args) { expect(mock.isWarnEnabled()).andReturn(true); mock.warnFormat(message, args); } }); } @Test public void testLogError() throws Exception { helpTestLog(LogLevel.ERROR, new LogSetup() { @Override public void setup(LogCompat mock, String message, Object args) { expect(mock.isErrorEnabled()).andReturn(true); mock.errorFormat(message, args); } }); } @Test public void testLogFatal() throws Exception { helpTestLog(LogLevel.FATAL, new LogSetup() { @Override public void setup(LogCompat mock, String message, Object args) { expect(mock.isFatalEnabled()).andReturn(true); mock.fatalFormat(message, args); } }); } /* --- Tests for the method "logEntry" --- */ @Test public void testLogEntryDoesntLogWhenNoAnnotation() throws Exception { LogCompat log = createMock(LogCompat.class); replay(log); LoggedUtils.logEntry(log, "", new Object()); } @Test public void testLogEntryDoesntLogWhenLogLevelInactive() throws Exception { LogCompat log = createMock(LogCompat.class); expect(log.isDebugEnabled()).andReturn(false); replay(log); LoggedUtils.logEntry(log, "", new LoggedOverridingSubclass()); } @Test public void testLogEntryLogsWhenLogLevelActive() throws Exception { String id = ""; LogCompat log = createMock(LogCompat.class); expect(log.isDebugEnabled()).andReturn(true).anyTimes(); log.debugFormat(eq(LoggedUtils.ENTRY_LOG), anyObject(), eq(id)); replay(log); LoggedUtils.logEntry(log, id, new LoggedOverridingSubclass()); } /* --- Tests for the method "logReturn" --- */ @Test public void testLogReturnDoesntLogWhenNoAnnotation() throws Exception { LogCompat log = createMock(LogCompat.class); replay(log); LoggedUtils.logReturn(log, "", new Object(), new Object()); } @Test public void testLogReturnDoesntLogWhenLogLevelInactive() throws Exception { LogCompat log = createMock(LogCompat.class); expect(log.isDebugEnabled()).andReturn(false); replay(log); LoggedUtils.logReturn(log, "", new LoggedOverridingSubclass(), new Object()); } @Test public void testLogReturnLogsWhenLogLevelActiveAndNoExpandReturn() throws Exception { String id = ""; LogCompat log = createMock(LogCompat.class); expect(log.isInfoEnabled()).andReturn(true).anyTimes(); expect(log.isDebugEnabled()).andReturn(false); log.infoFormat(eq(LoggedUtils.EXIT_LOG_VOID), anyObject(), eq(id)); replay(log); LoggedUtils.logReturn(log, id, new LoggedOverridingSubclassNoReturn(), new Object()); } @Test public void testLogReturnLogsWhenLogLevelActiveAndExpandReturn() throws Exception { String id = ""; LogCompat log = createMock(LogCompat.class); expect(log.isDebugEnabled()).andReturn(true).anyTimes(); log.debugFormat(eq(LoggedUtils.EXIT_LOG_RETURN_VALUE), anyObject(), anyObject(), eq(id)); replay(log); LoggedUtils.logReturn(log, id, new LoggedOverridingSubclass(), new Object()); } @Test public void testLogReturnLogsWhenLogLevelActiveAndExpandReturnButNullReturn() throws Exception { String id = ""; LogCompat log = createMock(LogCompat.class); expect(log.isDebugEnabled()).andReturn(true).anyTimes(); log.debugFormat(eq(LoggedUtils.EXIT_LOG_VOID), anyObject(), eq(id)); replay(log); LoggedUtils.logReturn(log, id, new LoggedOverridingSubclass(), null); } /* --- Tests for the method "logError" --- */ @Test public void testLogErrorDoesntLogWhenNoAnnotation() throws Exception { LogCompat log = createMock(LogCompat.class); replay(log); LoggedUtils.logError(log, "", new Object(), new Exception()); } @Test public void testLogErrorDoesntLogWhenLogLevelInactive() throws Exception { LogCompat log = createMock(LogCompat.class); expect(log.isWarnEnabled()).andReturn(false); replay(log); LoggedUtils.logError(log, "", new LoggedOverridingSubclass(), new Exception()); } @Test public void testLogErrorLogsWhenLogLevelActive() throws Exception { String id = ""; LogCompat log = createMock(LogCompat.class); // Expect the call to determine whether to log the parameters or not. expect(log.isDebugEnabled()).andReturn(true); expect(log.isWarnEnabled()).andReturn(true).anyTimes(); log.warnFormat(eq(LoggedUtils.ERROR_LOG), anyObject(), anyObject(), eq(id), anyObject()); replay(log); LoggedUtils.logError(log, id, new LoggedOverridingSubclass(), new Exception()); } /* --- Helper methods --- */ /** * Helper method to test the {@link LoggedUtils#log} method functionality. * @param logLevel Log level to test. * @param logSetup Setup the mocks using an anonymous inner class of this interface. */ private void helpTestLog(LogLevel logLevel, LogSetup logSetup) { LogCompat log = createMock(LogCompat.class); String message = "{0}"; Object args = new Object(); logSetup.setup(log, message, args); replay(log); LoggedUtils.log(log, logLevel, message, args); verify(log); } }