/* * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. * * 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. * * Contributors: * Nuxeo - initial API and implementation * * $Id: TestEventConfService.java 28493 2008-01-04 19:51:30Z sfermigier $ */ package org.nuxeo.ecm.platform.audit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.io.Serializable; import java.security.Principal; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.management.MBeanServer; import javax.management.ObjectName; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.PathRef; import org.nuxeo.ecm.core.api.SimplePrincipal; import org.nuxeo.ecm.core.api.security.SecurityConstants; import org.nuxeo.ecm.core.event.Event; import org.nuxeo.ecm.core.event.EventContext; import org.nuxeo.ecm.core.event.EventService; import org.nuxeo.ecm.core.event.impl.DocumentEventContext; import org.nuxeo.ecm.core.event.impl.EventContextImpl; import org.nuxeo.ecm.core.event.impl.UnboundEventContext; import org.nuxeo.ecm.core.test.DefaultRepositoryInit; import org.nuxeo.ecm.core.test.TransactionalFeature; import org.nuxeo.ecm.core.test.annotations.Granularity; import org.nuxeo.ecm.core.test.annotations.RepositoryConfig; import org.nuxeo.ecm.platform.audit.TestNXAuditEventsService.MyInit; import org.nuxeo.ecm.platform.audit.api.BuiltinLogEntryData; import org.nuxeo.ecm.platform.audit.api.FilterMapEntry; import org.nuxeo.ecm.platform.audit.api.LogEntry; import org.nuxeo.ecm.platform.audit.api.Logs; import org.nuxeo.ecm.platform.audit.service.DefaultAuditBackend; import org.nuxeo.ecm.platform.audit.service.NXAuditEventsService; import org.nuxeo.ecm.platform.audit.service.extension.AdapterDescriptor; import org.nuxeo.ecm.platform.audit.service.management.AuditEventMetricFactory; import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.management.ObjectNameFactory; import org.nuxeo.runtime.management.ServerLocator; import org.nuxeo.runtime.test.runner.Features; import org.nuxeo.runtime.test.runner.FeaturesRunner; import org.nuxeo.runtime.test.runner.LocalDeploy; /** * Test the event conf service. * * @author <a href="mailto:ja@nuxeo.com">Julien Anguenot</a> */ @RunWith(FeaturesRunner.class) @Features(AuditFeature.class) @RepositoryConfig(init = MyInit.class, cleanup = Granularity.METHOD) @LocalDeploy("org.nuxeo.ecm.platform.audit:test-audit-contrib.xml") public class TestNXAuditEventsService { protected static MyInit repo; public static class MyInit extends DefaultRepositoryInit { { repo = this; } protected DocumentModel source; @Override public void populate(CoreSession session) { super.populate(session); DocumentModel rootDocument = session.getRootDocument(); DocumentModel model = session.createDocumentModel(rootDocument.getPathAsString(), "youps", "File"); model.setProperty("dublincore", "title", "huum"); session.createDocument(model); source = session.getDocument(new PathRef("/youps")); } } @Inject Logs serviceUnderTest; protected MBeanServer mbeanServer; @Inject protected EventService eventService; @Inject CoreSession session; @Inject TransactionalFeature txFeature; @Before public void setUp() throws Exception { mbeanServer = Framework.getLocalService(ServerLocator.class).lookupServer(); } public void waitForAsyncCompletion() throws InterruptedException { txFeature.nextTransaction(20, TimeUnit.SECONDS); } @Test public void testAuditContribution() throws Exception { NXAuditEventsService auditService = (NXAuditEventsService) Framework.getRuntime() .getComponent(NXAuditEventsService.NAME); assertNotNull(auditService); Set<AdapterDescriptor> registeredAdapters = auditService.getDocumentAdapters(); assertEquals(1, registeredAdapters.size()); AdapterDescriptor ad = registeredAdapters.iterator().next(); assertEquals("myadapter", ad.getName()); } @Test public void testLogDocumentMessageWithoutCategory() throws InterruptedException { EventContext ctx = new DocumentEventContext(session, session.getPrincipal(), repo.source); Event event = ctx.newEvent("documentSecurityUpdated"); // auditable event.setInline(false); event.setImmediate(true); eventService.fireEvent(event); waitForAsyncCompletion(); List<LogEntry> entries = serviceUnderTest.getLogEntriesFor(repo.source.getId()); assertEquals(2, entries.size()); // entries are not ordered => skip creation log for (LogEntry entry : entries) { if ("documentSecurityUpdated".equals(entry.getEventId())) { assertEquals("eventDocumentCategory", entry.getCategory()); assertNull(entry.getComment()); assertEquals("project", entry.getDocLifeCycle()); assertEquals("/youps", entry.getDocPath()); assertEquals("File", entry.getDocType()); assertEquals("documentSecurityUpdated", entry.getEventId()); assertEquals("Administrator", entry.getPrincipalName()); } else { assertEquals("documentCreated", entry.getEventId()); } assertEquals("test", entry.getRepositoryId()); } } @Test public void testLogDocumentMessageWithCategory() throws InterruptedException { EventContext ctx = new DocumentEventContext(session, session.getPrincipal(), repo.source); ctx.setProperty("category", "myCategory"); Event event = ctx.newEvent("documentSecurityUpdated"); // auditable event.setInline(false); event.setImmediate(true); eventService.fireEvent(event); waitForAsyncCompletion(); List<LogEntry> entries = serviceUnderTest.getLogEntriesFor(repo.source.getId(), repo.source.getRepositoryName()); assertEquals(2, entries.size()); // entries are not ordered => skip creation log for (LogEntry entry : entries) { if ("documentSecurityUpdated".equals(entry.getEventId())) { assertEquals("myCategory", entry.getCategory()); assertNull(entry.getComment()); assertEquals("project", entry.getDocLifeCycle()); assertEquals("/youps", entry.getDocPath()); assertEquals("File", entry.getDocType()); assertEquals("documentSecurityUpdated", entry.getEventId()); assertEquals("Administrator", entry.getPrincipalName()); } else { assertEquals("documentCreated", entry.getEventId()); } assertEquals("test", entry.getRepositoryId()); } } @Test public void testLogMiscMessage() throws InterruptedException { DefaultAuditBackend backend = (DefaultAuditBackend) serviceUnderTest; List<String> eventIds = backend.getLoggedEventIds(); int n = eventIds.size(); EventContext ctx = new EventContextImpl(); // not:DocumentEventContext Event event = ctx.newEvent("documentModified"); // auditable event.setInline(false); event.setImmediate(true); eventService.fireEvent(event); waitForAsyncCompletion(); eventIds = backend.getLoggedEventIds(); assertEquals(n + 1, eventIds.size()); } @Test public void testsyncLogCreation() throws Exception { DocumentModel rootDocument = session.getRootDocument(); long count = serviceUnderTest.syncLogCreationEntries(session.getRepositoryName(), rootDocument.getPathAsString(), true); assertEquals(14, count); String query = String.format("log.docUUID = '%s' and log.eventId = 'documentCreated'", rootDocument.getId()); List<LogEntry> entries = serviceUnderTest.nativeQueryLogs(query, 1, 1); assertEquals(1, entries.size()); LogEntry entry = entries.get(0); assertEquals("eventDocumentCategory", entry.getCategory()); assertNull(entry.getComment()); assertEquals("/", entry.getDocPath()); assertEquals("Root", entry.getDocType()); assertEquals("documentCreated", entry.getEventId()); assertEquals(SecurityConstants.SYSTEM_USERNAME, entry.getPrincipalName()); } @Test public void simplePincipalNameIsLoggedAsPrincipalName() throws Exception { // Given a simple principal Principal principal = new SimplePrincipal("testuser"); // When i fire an event with it EventContext ctx = new UnboundEventContext(principal, new HashMap<String, Serializable>()); eventService.fireEvent(ctx.newEvent("loginSuccess")); waitForAsyncCompletion(); // Then then event is logged with the principal's name assertEquals(1, serviceUnderTest.getEventsCount("loginSuccess").intValue()); LogEntry logEntry = serviceUnderTest.nativeQueryLogs("log.eventId ='loginSuccess'", 1, 1).get(0); assertEquals("testuser", logEntry.getPrincipalName()); } @Test public void testExtendedInfos() throws InterruptedException { DocumentModel rootDocument = session.getRootDocument(); DocumentModel model = session.createDocumentModel(rootDocument.getPathAsString(), "youps", "File"); model.setProperty("dublincore", "title", "huum"); model = session.createDocument(model); long count = serviceUnderTest.syncLogCreationEntries(session.getRepositoryName(), model.getPathAsString(), true); assertEquals(1, count); String query = String.format("log.docUUID = '%s' and log.eventId = 'documentCreated'", model.getId()); List<LogEntry> entries = serviceUnderTest.nativeQueryLogs(query, 1, 1); assertEquals(1, entries.size()); LogEntry entry = entries.get(0); assertEquals("eventDocumentCategory", entry.getCategory()); assertEquals("test", entry.getRepositoryId()); assertEquals("huum", entry.getExtendedInfos().get("title").getSerializableValue()); assertEquals("/", entry.getExtendedInfos().get("parentPath").getSerializableValue()); session.removeDocument(model.getRef()); session.save(); waitForAsyncCompletion(); FilterMapEntry filterByDocRemoved = new FilterMapEntry(); filterByDocRemoved.setColumnName(BuiltinLogEntryData.LOG_EVENT_ID); filterByDocRemoved.setOperator("="); filterByDocRemoved.setQueryParameterName(BuiltinLogEntryData.LOG_EVENT_ID); filterByDocRemoved.setObject("documentRemoved"); Map<String, FilterMapEntry> filterMap = new HashMap<String, FilterMapEntry>(); filterMap.put("eventId", filterByDocRemoved); entries = serviceUnderTest.getLogEntriesFor(model.getId(), filterMap, true); assertEquals(1, entries.size()); assertNull(entries.get(0).getExtendedInfos().get("title")); assertEquals("/", entries.get(0).getExtendedInfos().get("parentPath").getSerializableValue()); } protected Set<ObjectName> doQuery(String name) { String qualifiedName = ObjectNameFactory.getQualifiedName(name); ObjectName objectName = ObjectNameFactory.getObjectName(qualifiedName); return mbeanServer.queryNames(objectName, null); } public void TODOtestCount() throws Exception { DocumentModel rootDocument = session.getRootDocument(); DocumentModel model = session.createDocumentModel(rootDocument.getPathAsString(), "youps", "File"); model.setProperty("dublincore", "title", "huum"); session.createDocument(model); session.save(); waitForAsyncCompletion(); ObjectName objectName = AuditEventMetricFactory.getObjectName("documentCreated"); Long count = (Long) mbeanServer.getAttribute(objectName, "count"); assertEquals(new Long(1L), count); } }