Add tests for filter notification ordering
authorAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Fri, 12 Feb 2016 16:37:05 +0000 (11:37 -0500)
committerAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Fri, 12 Feb 2016 17:07:20 +0000 (12:07 -0500)
There was a bug in the Java agent with regards to agent teardown:
upon disconnection, the list of tracked events was cleared but no
corresponding filter change notifications were sent! This could leave
some event rules dangling, and future listeners would get incorrectly
notified that these events were enabled while they were not.

Add some tests to cover for this use case.

Signed-off-by: Alexandre Montplaisir <alexmonthy@voxpopuli.im>
lttng-ust-java-tests-common/src/main/java/org/lttng/ust/agent/integration/filter/FilterListenerITBase.java
lttng-ust-java-tests-common/src/main/java/org/lttng/ust/agent/integration/filter/FilterListenerOrderingITBase.java [new file with mode: 0644]
lttng-ust-java-tests-jul/src/test/java/org/lttng/ust/agent/integration/filter/JulFilterListenerOrderingIT.java [new file with mode: 0644]
lttng-ust-java-tests-log4j/src/test/java/org/lttng/ust/agent/integration/filter/Log4jFilterListenerOrderingIT.java [new file with mode: 0644]

index 020ad3610594290f74e13b0d840a7cf4d79851ee..dddcaeea74f98efd03c48c33ef667798d17676f5 100644 (file)
@@ -74,6 +74,8 @@ public abstract class FilterListenerITBase {
         listener = new TestFilterListener();
         FilterChangeNotifier.getInstance().registerListener(listener);
         session = ILttngSession.createSession(null, getSessionDomain());
+
+        assertEquals(0, listener.getNbNotifications());
     }
 
     /**
@@ -83,6 +85,7 @@ public abstract class FilterListenerITBase {
     public void teardown() {
         session.close();
         FilterChangeNotifier.getInstance().unregisterListener(listener);
+        listener = null;
         handler.close();
     }
 
@@ -337,7 +340,7 @@ public abstract class FilterListenerITBase {
     /**
      * The filter listener used for tests.
      */
-    private static class TestFilterListener implements IFilterChangeListener {
+    static class TestFilterListener implements IFilterChangeListener {
 
         private final Set<EventRule> currentRules = new HashSet<>();
         private volatile int currentNotifications = 0;
diff --git a/lttng-ust-java-tests-common/src/main/java/org/lttng/ust/agent/integration/filter/FilterListenerOrderingITBase.java b/lttng-ust-java-tests-common/src/main/java/org/lttng/ust/agent/integration/filter/FilterListenerOrderingITBase.java
new file mode 100644 (file)
index 0000000..c226d45
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2016, EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package org.lttng.ust.agent.integration.filter;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.junit.After;
+import org.junit.Test;
+import org.lttng.tools.ILttngSession;
+import org.lttng.ust.agent.filter.FilterChangeNotifier;
+import org.lttng.ust.agent.integration.filter.FilterListenerITBase.TestFilterListener;
+import org.lttng.ust.agent.session.EventRule;
+import org.lttng.ust.agent.utils.EventRuleFactory;
+
+/**
+ * For the filter change notifications to work, several setup steps are
+ * required:
+ *
+ * <ul>
+ * <li>Initialize the Java agent register it to the sessiond [Agent]</li>
+ * <li>Instantiate a filer change listener, and register it to the notifier
+ * [Listener]</li>
+ * <li>Apply some event rule changes in the tracing session (lttng enable-event,
+ * etc.) [Session]</li>
+ * </ul>
+ *
+ * <p>
+ * Then on teardown, the following steps are expected:
+ * </p>
+ *
+ * <ul>
+ * <li>Dispose the Java agent, closing the connection to the sessiond [Agent]
+ * </li>
+ * <li>Destroy the tracing session, removing tracked events [Session]</li>
+ * </ul>
+ *
+ * (and then the filter change listener should be de-registered from the
+ * notifier. If it is deregistered earlier, then obviously no notifications
+ * would be received thereafter).
+ *
+ * <p>
+ * Within these two sets, each step can happen in any order. This results in 6 x
+ * 2 = 12 possibilities. The goal of this test class it to test these 12
+ * possibilities.
+ * </p>
+ */
+@SuppressWarnings("javadoc")
+public abstract class FilterListenerOrderingITBase {
+
+    protected static final String EVENT_NAME_A = "EventA";
+    private static final String EVENT_NAME_B = "EventB";
+
+    private ILttngSession session;
+    private TestFilterListener listener;
+
+    /**
+     * Base class cleanup
+     */
+    @After
+    public void baseTeardown() {
+        /*
+         * Deregister the listener (should always be done after all the other
+         * steps).
+         */
+        FilterChangeNotifier.getInstance().unregisterListener(listener);
+        listener = null;
+    }
+
+    // ------------------------------------------------------------------------
+    // Utility methods
+    // ------------------------------------------------------------------------
+
+    protected abstract ILttngSession.Domain getDomain();
+
+    protected abstract void registerAgent();
+
+    private void registerListener() {
+        listener = new TestFilterListener();
+        FilterChangeNotifier.getInstance().registerListener(listener);
+    }
+
+    private void enableRulesInSession() {
+        session = ILttngSession.createCommandLineSession(null, getDomain());
+        session.enableEvent(EVENT_NAME_A, null, false, null);
+        session.enableEvent(EVENT_NAME_B, null, false, null);
+    }
+
+    protected abstract void deregisterAgent();
+
+    private void destroySession() {
+        session.close();
+        session = null;
+    }
+
+    // ------------------------------------------------------------------------
+    // Test methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Check that the expected event rules are present after setup but before
+     * teardown.
+     */
+    private void checkOngoingConditions() {
+        Set<EventRule> exptectedRules = Stream.of(
+                EventRuleFactory.createRule(EVENT_NAME_A),
+                EventRuleFactory.createRule(EVENT_NAME_B))
+                .collect(Collectors.toSet());
+
+        assertEquals(2, listener.getNbNotifications());
+        assertEquals(exptectedRules, listener.getCurrentRules());
+    }
+
+    /**
+     * Check that the expected event rules are present after/during teardown.
+     */
+    private void checkFinalConditions() {
+        Set<EventRule> expectedRules = Collections.EMPTY_SET;
+
+        assertEquals(4, listener.getNbNotifications());
+        assertEquals(expectedRules, listener.getCurrentRules());
+    }
+
+    @Test
+    public void testAgentListenerSession_AgentSession() {
+        registerAgent();
+        registerListener();
+        enableRulesInSession();
+
+        checkOngoingConditions();
+
+        deregisterAgent();
+        destroySession();
+
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testAgentSessionListener_AgentSession() {
+        registerAgent();
+        enableRulesInSession();
+        registerListener();
+
+        checkOngoingConditions();
+
+        deregisterAgent();
+        destroySession();
+
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testListenerAgentSession_AgentSession() {
+        registerListener();
+        registerAgent();
+        enableRulesInSession();
+
+        checkOngoingConditions();
+
+        deregisterAgent();
+        destroySession();
+
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testListenerSessionAgent_AgentSession() {
+        registerListener();
+        enableRulesInSession();
+        registerAgent();
+
+        checkOngoingConditions();
+
+        deregisterAgent();
+        destroySession();
+
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testSessionAgentListener_AgentSession() {
+        enableRulesInSession();
+        registerAgent();
+        registerListener();
+
+        checkOngoingConditions();
+
+        deregisterAgent();
+        destroySession();
+
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testSessionListenerAgent_AgentSession() {
+        enableRulesInSession();
+        registerListener();
+        registerAgent();
+
+        checkOngoingConditions();
+
+        deregisterAgent();
+        destroySession();
+
+        checkFinalConditions();
+    }
+
+
+
+    @Test
+    public void testAgentListenerSession_SessionAgent() {
+        registerAgent();
+        registerListener();
+        enableRulesInSession();
+
+        checkOngoingConditions();
+
+        destroySession();
+        checkFinalConditions();
+        deregisterAgent();
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testAgentSessionListener_SessionAgent() {
+        registerAgent();
+        enableRulesInSession();
+        registerListener();
+
+        checkOngoingConditions();
+
+        destroySession();
+        checkFinalConditions();
+        deregisterAgent();
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testListenerAgentSession_SessionAgent() {
+        registerListener();
+        registerAgent();
+        enableRulesInSession();
+
+        checkOngoingConditions();
+
+        destroySession();
+        checkFinalConditions();
+        deregisterAgent();
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testListenerSessionAgent_SessionAgent() {
+        registerListener();
+        enableRulesInSession();
+        registerAgent();
+
+        checkOngoingConditions();
+
+        destroySession();
+        checkFinalConditions();
+        deregisterAgent();
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testSessionAgentListener_SessionAgent() {
+        enableRulesInSession();
+        registerAgent();
+        registerListener();
+
+        checkOngoingConditions();
+
+        destroySession();
+        checkFinalConditions();
+        deregisterAgent();
+        checkFinalConditions();
+    }
+
+    @Test
+    public void testSessionListenerAgent_SessionAgent() {
+        enableRulesInSession();
+        registerListener();
+        registerAgent();
+
+        checkOngoingConditions();
+
+        destroySession();
+        checkFinalConditions();
+        deregisterAgent();
+        checkFinalConditions();
+    }
+
+}
diff --git a/lttng-ust-java-tests-jul/src/test/java/org/lttng/ust/agent/integration/filter/JulFilterListenerOrderingIT.java b/lttng-ust-java-tests-jul/src/test/java/org/lttng/ust/agent/integration/filter/JulFilterListenerOrderingIT.java
new file mode 100644 (file)
index 0000000..e4a81b8
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016, EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package org.lttng.ust.agent.integration.filter;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.IOException;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.junit.BeforeClass;
+import org.lttng.tools.LttngToolsHelper;
+import org.lttng.tools.ILttngSession.Domain;
+import org.lttng.ust.agent.jul.LttngLogHandler;
+import org.lttng.ust.agent.utils.JulTestUtils;
+import org.lttng.ust.agent.utils.LttngUtils;
+
+/**
+ * Implementation of {@link FilterListenerOrderingITBase} for the JUL API.
+ */
+public class JulFilterListenerOrderingIT extends FilterListenerOrderingITBase {
+
+    private Logger logger;
+    private Handler handler;
+
+    /**
+     * Class setup
+     */
+    @BeforeClass
+    public static void julClassSetup() {
+        /* Skip tests if we can't find the JNI library or lttng-tools */
+        assumeTrue(JulTestUtils.checkForJulLibrary());
+        assumeTrue(LttngUtils.checkForLttngTools(Domain.JUL));
+
+        LttngToolsHelper.destroyAllSessions();
+    }
+
+    @Override
+    protected Domain getDomain() {
+        return Domain.JUL;
+    }
+
+    @Override
+    protected void registerAgent() {
+        logger = Logger.getLogger(EVENT_NAME_A);
+        logger.setLevel(Level.ALL);
+
+        try {
+            handler = new LttngLogHandler();
+        } catch (SecurityException | IOException e) {
+            fail();
+        }
+        logger.addHandler(handler);
+    }
+
+    @Override
+    protected void deregisterAgent() {
+        logger.removeHandler(handler);
+        logger = null;
+
+        handler.close();
+        handler = null;
+    }
+}
diff --git a/lttng-ust-java-tests-log4j/src/test/java/org/lttng/ust/agent/integration/filter/Log4jFilterListenerOrderingIT.java b/lttng-ust-java-tests-log4j/src/test/java/org/lttng/ust/agent/integration/filter/Log4jFilterListenerOrderingIT.java
new file mode 100644 (file)
index 0000000..e74a5d1
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016, EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package org.lttng.ust.agent.integration.filter;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.IOException;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.junit.BeforeClass;
+import org.lttng.tools.LttngToolsHelper;
+import org.lttng.tools.ILttngSession.Domain;
+import org.lttng.ust.agent.log4j.LttngLogAppender;
+import org.lttng.ust.agent.utils.Log4jTestUtils;
+import org.lttng.ust.agent.utils.LttngUtils;
+
+/**
+ * Implementation of {@link FilterListenerOrderingITBase} for the log4j API.
+ */
+public class Log4jFilterListenerOrderingIT extends FilterListenerOrderingITBase {
+
+    private Logger logger;
+    private Appender appender;
+
+    /**
+     * Class setup
+     */
+    @BeforeClass
+    public static void julClassSetup() {
+        /* Skip tests if we can't find the JNI library or lttng-tools */
+        assumeTrue(Log4jTestUtils.checkForLog4jLibrary());
+        assumeTrue(LttngUtils.checkForLttngTools(Domain.LOG4J));
+
+        LttngToolsHelper.destroyAllSessions();
+    }
+
+    @Override
+    protected Domain getDomain() {
+        return Domain.LOG4J;
+    }
+
+    @Override
+    protected void registerAgent() {
+        logger = Logger.getLogger(EVENT_NAME_A);
+        logger.setLevel(Level.ALL);
+
+        try {
+            appender = new LttngLogAppender();
+        } catch (SecurityException | IOException e) {
+            fail();
+        }
+        logger.addAppender(appender);
+    }
+
+    @Override
+    protected void deregisterAgent() {
+        logger.removeAppender(appender);
+        logger = null;
+
+        appender.close();
+        appender = null;
+    }
+}
This page took 0.028524 seconds and 4 git commands to generate.