Add filter notifications and TCP client tests
authorAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Fri, 28 Aug 2015 22:59:57 +0000 (18:59 -0400)
committerAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Mon, 31 Aug 2015 21:38:48 +0000 (17:38 -0400)
This required adding log level and filter string functionality
to ILttngSession.

Signed-off-by: Alexandre Montplaisir <alexmonthy@voxpopuli.im>
lttng-tools-java/src/main/java/org/lttng/tools/ILttngSession.java
lttng-tools-java/src/main/java/org/lttng/tools/LttngCommandLineSession.java
lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientDebugListener.java [new file with mode: 0644]
lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientIT.java [new file with mode: 0644]
lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/FilterListenerITBase.java [new file with mode: 0644]
lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/JulFilterListenerIT.java [new file with mode: 0644]
lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/Log4jFilterListenerIT.java [new file with mode: 0644]
lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/utils/ILogLevelStrings.java [new file with mode: 0644]

index e7d65a0f29a8224cba6aa20ecf9737bb4c4525fa..b6d0aedefec830494eaae9d11f27e0baefa362c2 100644 (file)
@@ -98,14 +98,25 @@ public interface ILttngSession extends AutoCloseable {
     // ------------------------------------------------------------------------
 
     /**
-     * Enable all events in the session (as with "enable-event -a").
+     * Enable an individual event, specifying a loglevel and filter string.
      *
-     * @return If the command executed successfully (return code = 0).
+     * @param eventName
+     *            The name of the event to enable
+     * @param loglevel
+     *            The loglevel, will be passed as-is to lttng. May be null to
+     *            not specify it.
+     * @param loglevelOnly
+     *            True to use this log level only (--loglevel-only), or false to
+     *            include all more severe levels (--loglevel). Ignored if
+     *            "loglevel" is null.
+     * @param filter
+     *            The filter string, may be null to not specify one.
+     * @return If the command executed successfully (return code = 0)
      */
-    boolean enableAllEvents();
+    boolean enableEvent(String eventName, String loglevel, boolean loglevelOnly, String filter);
 
     /**
-     * Enable individual event(s).
+     * Enable individual event(s) with no loglevel/filter specified.
      *
      * @param enabledEvents
      *            The list of events to enable. Should not be null or empty
@@ -114,7 +125,14 @@ public interface ILttngSession extends AutoCloseable {
     boolean enableEvents(String... enabledEvents);
 
     /**
-     * Send a disable-event command. Used to disable events that were previously
+     * Enable all events in the session (as with "enable-event -a").
+     *
+     * @return If the command executed successfully (return code = 0).
+     */
+    boolean enableAllEvents();
+
+    /**
+     * Send a disable-event command. Used to disable event(s) that were previously
      * enabled.
      *
      * @param disabledEvents
@@ -123,6 +141,14 @@ public interface ILttngSession extends AutoCloseable {
      */
     boolean disableEvents(String... disabledEvents);
 
+    /**
+     * Disable all events currently enabled in the session
+     * ("lttng disable-event -a").
+     *
+     * @return If the command executed successfully (return code = 0)
+     */
+    boolean disableAllEvents();
+
     /**
      * Start tracing
      *
index 0cd26cca8bb464f4540a09a744de9caa76cde4dd..e2b1ff6b6ce56acdc97041cbc7540eb3cc06df83 100644 (file)
@@ -20,6 +20,7 @@ package org.lttng.tools;
 
 import static org.lttng.tools.utils.ShellUtils.executeCommand;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
@@ -69,6 +70,36 @@ class LttngCommandLineSession implements ILttngSession {
      // FIXME also delete the trace we generated ?
     }
 
+    @Override
+    public boolean enableEvent(String eventName, String loglevel, boolean loglevelOnly, String filter) {
+        channelCreated = true;
+
+        List<String> command = new ArrayList<>();
+        command.add("lttng");
+        command.add("enable-event");
+        command.add(domain.flag());
+        command.add(eventName);
+
+        if (loglevel != null) {
+            if (loglevelOnly) {
+                command.add("--loglevel-only");
+            } else {
+                command.add("--loglevel");
+            }
+            command.add(loglevel);
+        }
+
+        if (filter != null) {
+            command.add("--filter");
+            command.add(filter);
+        }
+
+        command.add("-s");
+        command.add(sessionName);
+
+        return executeCommand(command);
+    }
+
     @Override
     public boolean enableAllEvents() {
         channelCreated = true;
@@ -99,6 +130,12 @@ class LttngCommandLineSession implements ILttngSession {
                 "-s", sessionName));
     }
 
+    @Override
+    public boolean disableAllEvents() {
+        return executeCommand(Arrays.asList(
+                "lttng", "disable-event", domain.flag(), "-a", "-s", sessionName));
+    }
+
     @Override
     public boolean start() {
         /*
diff --git a/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientDebugListener.java b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientDebugListener.java
new file mode 100644 (file)
index 0000000..e2ec3d8
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015, 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.client;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.lttng.ust.agent.client.ILttngTcpClientListener;
+import org.lttng.ust.agent.session.EventRule;
+
+/**
+ * TCP client listener used for test. Instead of "handling" commands, it just
+ * keep tracks of commands it receives.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class TcpClientDebugListener implements ILttngTcpClientListener {
+
+    private final List<EventRule> enabledEventCommands = Collections.synchronizedList(new ArrayList<>());
+    private final List<String> disabledEventCommands = Collections.synchronizedList(new ArrayList<>());
+
+    @Override
+    public boolean eventEnabled(EventRule rule) {
+        enabledEventCommands.add(rule);
+        return true;
+    }
+
+    @Override
+    public boolean eventDisabled(String name) {
+        disabledEventCommands.add(name);
+        return true;
+    }
+
+    /**
+     * Not yet implemented
+     */
+    @Override
+    public Iterable<String> listEnabledEvents() {
+        // TODO NYI
+        return Collections.EMPTY_LIST;
+    }
+
+    /**
+     * @return The "enable-event" commands that were received, since
+     *         instantiation or the last {@link #clearAllCommands}.
+     */
+    public List<EventRule> getEnabledEventCommands() {
+        synchronized (enabledEventCommands) {
+            return new ArrayList<>(enabledEventCommands);
+        }
+    }
+
+    /**
+     * @return The "disable-event" commands that were received, since
+     *         instantiation or the last {@link #clearAllCommands}.
+     */
+    public List<String> getDisabledEventCommands() {
+        synchronized (disabledEventCommands) {
+            return new ArrayList<>(disabledEventCommands);
+        }
+    }
+
+    /**
+     * Clear all tracked data.
+     */
+    public void clearAllCommands() {
+        enabledEventCommands.clear();
+        disabledEventCommands.clear();
+    }
+
+}
diff --git a/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientIT.java b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientIT.java
new file mode 100644 (file)
index 0000000..b9f0d0b
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2015, 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.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.lttng.tools.ILttngSession;
+import org.lttng.tools.LttngToolsHelper;
+import org.lttng.ust.agent.ILttngAgent;
+import org.lttng.ust.agent.client.LttngTcpSessiondClient;
+import org.lttng.ust.agent.session.EventRule;
+import org.lttng.ust.agent.session.LogLevelFilter;
+import org.lttng.ust.agent.session.LogLevelFilter.LogLevelType;
+import org.lttng.ust.agent.utils.ILogLevelStrings;
+
+/**
+ * Tests for the TCP client only, without using an agent.
+ *
+ * This test suite requires that a *root* session daemon is running on the
+ * system. Since we have to explicitly tell the TCP client which sessiond to
+ * connect to, we have to hard-code it in here.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class TcpClientIT {
+
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+
+    private static final LogLevelFilter LOG_LEVEL_UNSPECIFIED = new LogLevelFilter(Integer.MIN_VALUE, 0);
+
+    private static final String EVENT_NAME_A = "eventA";
+    private static final String EVENT_NAME_B = "eventB";
+    private static final String EVENT_NAME_C = "eventC";
+    private static final String EVENT_NAME_ALL = "*";
+
+    /* Test configuration */
+    private static final int DOMAIN_VALUE = ILttngAgent.Domain.JUL.value();
+    private static final ILttngSession.Domain SESSION_DOMAIN = ILttngSession.Domain.JUL;
+    private static final boolean ROOT_SESSIOND = true;
+
+    private static TcpClientDebugListener clientListener;
+    private static LttngTcpSessiondClient client;
+    private static Thread clientThread;
+
+    private ILttngSession session;
+
+    // ------------------------------------------------------------------------
+    // Maintenance
+    // ------------------------------------------------------------------------
+
+    /**
+     * Class setup
+     */
+    @BeforeClass
+    public static void setupClass() {
+        LttngToolsHelper.destroyAllSessions();
+
+        clientListener = new TcpClientDebugListener();
+        client = new LttngTcpSessiondClient(clientListener, DOMAIN_VALUE, ROOT_SESSIOND);
+
+        clientThread = new Thread(client);
+        clientThread.start();
+
+        assumeTrue("Timed out waiting for root sessiond", client.waitForConnection(5));
+    }
+
+    /**
+     * Class teardown
+     */
+    @AfterClass
+    public static void teardownClass() {
+        if (client != null) {
+            client.close();
+        }
+        if (clientThread != null) {
+            try {
+                clientThread.join();
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    /**
+     * Test setup
+     */
+    @Before
+    public void setup() {
+        session = ILttngSession.createSession(null, SESSION_DOMAIN);
+        clientListener.clearAllCommands();
+    }
+
+    /**
+     * Test teardown
+     */
+    @After
+    public void teardown() {
+        session.close();
+    }
+
+
+    private static ILogLevelStrings getLogLevelStrings() {
+        return ILogLevelStrings.JUL_LOGLEVEL_STRINGS;
+    }
+
+    /**
+     * Check that two lists contain the exact same element (including
+     * duplicates), but their order does not matter.
+     */
+    private static <T extends Comparable<T>> boolean containSameElements(List<T> list1, List<T> list2) {
+        List<T> newlist1 = new ArrayList<>(list1);
+        List<T> newlist2 = new ArrayList<>(list2);
+        Collections.sort(newlist1);
+        Collections.sort(newlist2);
+        return (newlist1.equals(newlist2));
+
+    }
+
+    // ------------------------------------------------------------------------
+    // Test cases
+    // ------------------------------------------------------------------------
+
+    /**
+     * Test enabling one event.
+     */
+    @Test
+    public void testEnableEvent() {
+        session.enableEvent(EVENT_NAME_A, null, false, null);
+
+        List<EventRule> expectedCommands = Collections.singletonList(
+                new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, null));
+
+        List<EventRule> actualCommands = clientListener.getEnabledEventCommands();
+        assertEquals(expectedCommands, actualCommands);
+    }
+
+    /**
+     * Test an "enable-event -a" command.
+     */
+    @Test
+    public void testEnableAllEvents() {
+        session.enableAllEvents();
+
+        List<EventRule> expectedCommands = Collections.singletonList(
+                new EventRule(EVENT_NAME_ALL, LOG_LEVEL_UNSPECIFIED, null));
+        List<EventRule> actualCommands = clientListener.getEnabledEventCommands();
+
+        assertEquals(expectedCommands, actualCommands);
+    }
+
+    /**
+     * Test enabling then disabling one event.
+     */
+    @Test
+    public void testEnableThenDisableOneEvent() {
+        session.enableEvent(EVENT_NAME_A, null, false, null);
+        session.disableEvents(EVENT_NAME_A);
+
+        List<EventRule> expectedEnableCommands = Collections.singletonList(
+                new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, null));
+        List<String> expectedDisableCommands = Collections.singletonList(EVENT_NAME_A);
+
+        assertEquals(expectedEnableCommands, clientListener.getEnabledEventCommands());
+        assertTrue(containSameElements(expectedDisableCommands, clientListener.getDisabledEventCommands()));
+    }
+
+    /**
+     * Test enabling some events manually, then disabling all events (-a).
+     */
+    @Test
+    public void testEnableSomeThenDisableAll() {
+        session.enableEvent(EVENT_NAME_A, null, false, null);
+        session.enableEvent(EVENT_NAME_B, null, false, null);
+        session.enableEvent(EVENT_NAME_C, null, false, null);
+        session.disableAllEvents();
+
+        List<EventRule> expectedEnableCommands = Arrays.asList(
+                new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, null),
+                new EventRule(EVENT_NAME_B, LOG_LEVEL_UNSPECIFIED, null),
+                new EventRule(EVENT_NAME_C, LOG_LEVEL_UNSPECIFIED, null));
+        /*
+         * A "disable-event -a" will send one command for each enabled event.
+         * The order may be different though.
+         */
+        List<String> expectedDisableCommands = Arrays.asList(
+                EVENT_NAME_A, EVENT_NAME_B, EVENT_NAME_C);
+
+        assertEquals(expectedEnableCommands, clientListener.getEnabledEventCommands());
+        assertTrue(containSameElements(expectedDisableCommands, clientListener.getDisabledEventCommands()));
+    }
+
+    /**
+     * Test enabling then (enable-event -a) then disabling all (disable-event -a) events.
+     */
+    @Test
+    public void testEnableAllThenDisableAll() {
+        session.enableAllEvents();
+        session.disableAllEvents();
+
+        List<EventRule> expectedEnableCommands = Arrays.asList(
+                new EventRule(EVENT_NAME_ALL, LOG_LEVEL_UNSPECIFIED, null));
+        List<String> expectedDisableCommands = Arrays.asList(
+                EVENT_NAME_ALL);
+
+        assertEquals(expectedEnableCommands, clientListener.getEnabledEventCommands());
+        assertTrue(containSameElements(expectedDisableCommands, clientListener.getDisabledEventCommands()));
+    }
+
+    /**
+     * Test specifying an event with a --loglevel option.
+     */
+    @Test
+    public void testEnableEventLogLevelRange() {
+        LogLevelFilter llf = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_RANGE);
+
+        session.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), false, null);
+
+        List<EventRule> expectedCommands = Collections.singletonList(
+                new EventRule(EVENT_NAME_A, llf, null));
+        List<EventRule> actualCommands = clientListener.getEnabledEventCommands();
+
+        assertEquals(expectedCommands, actualCommands);
+    }
+
+    /**
+     * Test enabling an event with a --loglevel-only option.
+     */
+    @Test
+    public void testEnableEventLogLevelSingle() {
+        LogLevelFilter llf = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_SINGLE);
+
+        session.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), true, null);
+
+        List<EventRule> expectedCommands = Collections.singletonList(
+                new EventRule(EVENT_NAME_A, llf, null));
+        List<EventRule> actualCommands = clientListener.getEnabledEventCommands();
+
+        assertEquals(expectedCommands, actualCommands);
+    }
+
+    /**
+     * Test enabling an event twice, for the same loglevel, with --loglevel followed by --loglevel-only.
+     */
+    @Ignore("See http://bugs.lttng.org/issues/913")
+    @Test
+    public void testEnableEventsLogLevelRangeAndSingle() {
+        LogLevelFilter llf1 = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_RANGE);
+        LogLevelFilter llf2 = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_SINGLE);
+
+        session.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), false, null);
+        session.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), true, null);
+
+        List<EventRule> expectedCommands = Arrays.asList(
+                new EventRule(EVENT_NAME_A, llf1, null),
+                new EventRule(EVENT_NAME_A, llf2, null)
+                );
+        List<EventRule> actualCommands = clientListener.getEnabledEventCommands();
+
+        assertEquals(expectedCommands, actualCommands);
+    }
+
+    /**
+     * Test enabling an event twice, for the same loglevel, with --loglevel--only followed by --loglevel.
+     */
+    @Ignore("See http://bugs.lttng.org/issues/913")
+    @Test
+    public void testEnableEventsLogLevelSingleAndRange() {
+        LogLevelFilter llf1 = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_SINGLE);
+        LogLevelFilter llf2 = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_RANGE);
+
+        session.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), true, null);
+        session.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), false, null);
+
+        List<EventRule> expectedCommands = Arrays.asList(
+                new EventRule(EVENT_NAME_A, llf1, null),
+                new EventRule(EVENT_NAME_A, llf2, null)
+                );
+        List<EventRule> actualCommands = clientListener.getEnabledEventCommands();
+
+        assertEquals(expectedCommands, actualCommands);
+    }
+
+    /**
+     * Test enabling the same event, same loglevel, but different loglevel types
+     * (--loglevel vs --loglevel-only) in two separate sessions.
+     */
+    @Test
+    public void testEnableEventsLogLevelRangeAndSingleDiffSessions() {
+        try (ILttngSession session2 = ILttngSession.createSession(null, SESSION_DOMAIN);) {
+
+            LogLevelFilter llf1 = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_RANGE);
+            LogLevelFilter llf2 = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_SINGLE);
+
+            session.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), false, null);
+            session2.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), true, null);
+
+            List<EventRule> expectedCommands = Arrays.asList(new EventRule(EVENT_NAME_A, llf1, null),
+                    new EventRule(EVENT_NAME_A, llf2, null));
+            List<EventRule> actualCommands = clientListener.getEnabledEventCommands();
+
+            assertEquals(expectedCommands, actualCommands);
+        }
+    }
+}
diff --git a/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/FilterListenerITBase.java b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/FilterListenerITBase.java
new file mode 100644 (file)
index 0000000..e7c537c
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2015, 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.assertTrue;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.lttng.tools.ILttngSession;
+import org.lttng.ust.agent.ILttngHandler;
+import org.lttng.ust.agent.filter.FilterNotificationManager;
+import org.lttng.ust.agent.filter.IFilterChangeListener;
+import org.lttng.ust.agent.session.EventRule;
+import org.lttng.ust.agent.session.LogLevelFilter;
+import org.lttng.ust.agent.session.LogLevelFilter.LogLevelType;
+import org.lttng.ust.agent.utils.ILogLevelStrings;
+import org.lttng.ust.agent.utils.TestPrintRunner;
+
+/**
+ * Base test class for {@link IFilterChangeListener} tests.
+ *
+ * @author Alexandre Montplaisir
+ */
+@RunWith(TestPrintRunner.class)
+public abstract class FilterListenerITBase {
+
+    protected static final LogLevelFilter LOG_LEVEL_UNSPECIFIED = new LogLevelFilter(Integer.MIN_VALUE, 0);
+
+    private static final String EVENT_NAME_A = "eventA";
+    private static final String EVENT_NAME_B = "eventB";
+    private static final String EVENT_NAME_C = "eventC";
+
+    private ILttngSession session;
+    private TestFilterListener listener;
+    private ILttngHandler handler;
+
+    protected abstract ILttngSession.Domain getSessionDomain();
+    protected abstract ILttngHandler getLogHandler() throws SecurityException, IOException;
+    protected abstract ILogLevelStrings getLogLevelStrings();
+
+    /**
+     * Test setup
+     *
+     * @throws SecurityException
+     * @throws IOException
+     */
+    @Before
+    public void setup() throws SecurityException, IOException {
+        handler = getLogHandler();
+        listener = new TestFilterListener();
+        FilterNotificationManager.getInstance().registerListener(listener);
+        session = ILttngSession.createSession(null, getSessionDomain());
+    }
+
+    /**
+     * Test teardown
+     */
+    @After
+    public void teardown() {
+        session.close();
+        FilterNotificationManager.getInstance().unregisterListener(listener);
+        handler.close();
+    }
+
+    /**
+     * Test not sending any commands.
+     */
+    @Test
+    public void testNoRules() {
+        Set<EventRule> rules = Collections.EMPTY_SET;
+        listener.setParameters(0, rules);
+        /* Don't enable any events */
+
+        assertTrue(listener.waitForAllNotifications());
+        assertTrue(listener.checkRules());
+    }
+
+    /**
+     * Test sending one event rule.
+     */
+    @Test
+    public void testOneRule() {
+        Set<EventRule> rules = Collections.singleton(
+                new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, null));
+
+        listener.setParameters(1, rules);
+
+        session.enableEvent(EVENT_NAME_A, null, false, null);
+
+        assertTrue(listener.waitForAllNotifications());
+        assertTrue(listener.checkRules());
+    }
+
+    /**
+     * Test sending many event rules.
+     */
+    @Test
+    public void testManyRules() {
+        Set<EventRule> rules = Stream
+                .of(new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, null),
+                        new EventRule(EVENT_NAME_B, LOG_LEVEL_UNSPECIFIED, null),
+                        new EventRule(EVENT_NAME_C, LOG_LEVEL_UNSPECIFIED, null))
+                .collect(Collectors.toSet());
+
+        listener.setParameters(3, rules);
+
+        session.enableEvent(EVENT_NAME_A, null, false, null);
+        session.enableEvent(EVENT_NAME_B, null, false, null);
+        session.enableEvent(EVENT_NAME_C, null, false, null);
+
+        assertTrue(listener.waitForAllNotifications());
+        assertTrue(listener.checkRules());
+    }
+
+    /**
+     * Test enabling then disabling some events.
+     */
+    @Test
+    public void testManyRulesDisableSome() {
+        Set<EventRule> rules = Collections.singleton(
+                new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, null));
+
+        listener.setParameters(4, rules);
+
+        session.enableEvent(EVENT_NAME_A, null, false, null);
+        session.enableEvent(EVENT_NAME_B, null, false, null);
+        session.enableEvent(EVENT_NAME_C, null, false, null);
+        session.disableEvents(EVENT_NAME_B);
+        session.disableEvents(EVENT_NAME_C);
+
+        assertTrue(listener.waitForAllNotifications());
+        assertTrue(listener.checkRules());
+    }
+
+    /**
+     * Test enabling some rules, then calling disable-event -a.
+     */
+    @Test
+    public void testManyRulesDisableAll() {
+        Set<EventRule> rules = Collections.EMPTY_SET;
+
+        /*
+         * We should receive 6 notifications, because a "disable-event -a" sends
+         * one for each event that was enabled.
+         */
+        listener.setParameters(6, rules);
+
+        session.enableEvent(EVENT_NAME_A, null, false, null);
+        session.enableEvent(EVENT_NAME_B, null, false, null);
+        session.enableEvent(EVENT_NAME_C, null, false, null);
+        session.disableAllEvents();
+
+        assertTrue(listener.waitForAllNotifications());
+        assertTrue(listener.checkRules());
+    }
+
+    /**
+     * Test enabling the same event name with various values of loglevels.
+     */
+    @Ignore("Does not work as expected atm, see http://bugs.lttng.org/issues/913")
+    @Test
+    public void testSameEventsDiffLogLevels() {
+        LogLevelFilter llf1 = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_RANGE);
+        LogLevelFilter llf2 = new LogLevelFilter(getLogLevelStrings().warningInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_SINGLE);
+        LogLevelFilter llf3 = new LogLevelFilter(getLogLevelStrings().infoInt(), LogLevelType.LTTNG_EVENT_LOGLEVEL_RANGE);
+
+        Set<EventRule> rules = Stream.of(
+                    new EventRule(EVENT_NAME_A, llf1, null),
+                    new EventRule(EVENT_NAME_A, llf2, null),
+                    new EventRule(EVENT_NAME_A, llf3, null))
+                .collect(Collectors.toSet());
+
+        listener.setParameters(3, rules);
+
+        session.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), false, null);
+        session.enableEvent(EVENT_NAME_A, getLogLevelStrings().warningName(), true, null);
+        session.enableEvent(EVENT_NAME_A, getLogLevelStrings().infoName(), false, null);
+
+        assertTrue(listener.waitForAllNotifications());
+        assertTrue(listener.checkRules());
+    }
+
+    /**
+     * Test enabling the same event name with various filters.
+     */
+    @Ignore("Filters are not tracked yet")
+    @Test
+    public void testSameEventsDiffFilters() {
+        String filterA = "filterA";
+        String filterB = "filterB";
+
+        Set<EventRule> rules = Stream.of(
+                    new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, null),
+                    new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, filterA),
+                    new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, filterB))
+                .collect(Collectors.toSet());
+
+        listener.setParameters(3, rules);
+
+        session.enableEvent(EVENT_NAME_A, null, false, null);
+        session.enableEvent(EVENT_NAME_B, null, false, filterA);
+        session.enableEvent(EVENT_NAME_C, null, false, filterB);
+
+        assertTrue(listener.waitForAllNotifications());
+        assertTrue(listener.checkRules());
+    }
+
+    /**
+     * The filter listener used for tests.
+     *
+     * <p>
+     * Usage:
+     * <ul>
+     * <li>Specify the expected number of notifications and end rules with
+     * {@link #setParameters}.</li>
+     * <li>Send the commands to LTTng (using {@link ILttngSession} for example.
+     * </li>
+     * <li>Call {@link #waitForAllNotifications()}.</li>
+     * <li>Verify that {@link #checkRules()} returns true.</li>
+     * </ul>
+     * </p>
+     */
+    private static class TestFilterListener implements IFilterChangeListener {
+
+        private final Set<EventRule> currentRules = new HashSet<>();
+        private CountDownLatch remainingExpectedNotifs;
+        private Set<EventRule> expectedRules;
+
+        public TestFilterListener() {}
+
+        @Override
+        public void eventRuleAdded(EventRule rule) {
+            currentRules.add(rule);
+            remainingExpectedNotifs.countDown();
+        }
+
+        @Override
+        public void eventRuleRemoved(EventRule rule) {
+            currentRules.remove(rule);
+            remainingExpectedNotifs.countDown();
+        }
+
+        public void setParameters(int expectedNotifications, Set<EventRule> expectedRulesAtEnd) {
+            this.remainingExpectedNotifs = new CountDownLatch(expectedNotifications);
+            this.expectedRules = expectedRulesAtEnd;
+        }
+
+        public boolean waitForAllNotifications() {
+            System.out.println("Waiting for all notifications to arrive...");
+            try {
+                return remainingExpectedNotifs.await(10, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                return false;
+            }
+        }
+
+        public boolean checkRules() {
+            return ((remainingExpectedNotifs.getCount() == 0) && currentRules.equals(expectedRules));
+        }
+    }
+
+}
diff --git a/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/JulFilterListenerIT.java b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/JulFilterListenerIT.java
new file mode 100644 (file)
index 0000000..b82e41f
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015, 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.Assume.assumeTrue;
+
+import java.io.IOException;
+
+import org.junit.BeforeClass;
+import org.lttng.tools.ILttngSession;
+import org.lttng.tools.LttngToolsHelper;
+import org.lttng.ust.agent.ILttngHandler;
+import org.lttng.ust.agent.jul.LttngLogHandler;
+import org.lttng.ust.agent.utils.ILogLevelStrings;
+import org.lttng.ust.agent.utils.LttngUtils;
+
+/**
+ * Filter notifications tests using the JUL logging API.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class JulFilterListenerIT extends FilterListenerITBase {
+
+    /**
+     * Class setup
+     */
+    @BeforeClass
+    public static void julClassSetup() {
+        /* Skip tests if we can't find the JNI library or lttng-tools */
+        assumeTrue(LttngUtils.checkForJulLibrary());
+        assumeTrue(LttngUtils.checkForLttngTools(ILttngSession.Domain.JUL));
+        LttngToolsHelper.destroyAllSessions();
+    }
+
+    @Override
+    protected ILttngSession.Domain getSessionDomain() {
+        return ILttngSession.Domain.JUL;
+    }
+
+    @Override
+    protected ILttngHandler getLogHandler() throws SecurityException, IOException {
+        return new LttngLogHandler();
+    }
+
+    @Override
+    protected ILogLevelStrings getLogLevelStrings() {
+        return ILogLevelStrings.JUL_LOGLEVEL_STRINGS;
+    }
+
+}
diff --git a/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/Log4jFilterListenerIT.java b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/Log4jFilterListenerIT.java
new file mode 100644 (file)
index 0000000..c01bc84
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015, 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.Assume.assumeTrue;
+
+import java.io.IOException;
+
+import org.junit.BeforeClass;
+import org.lttng.tools.ILttngSession;
+import org.lttng.tools.LttngToolsHelper;
+import org.lttng.ust.agent.ILttngHandler;
+import org.lttng.ust.agent.log4j.LttngLogAppender;
+import org.lttng.ust.agent.utils.ILogLevelStrings;
+import org.lttng.ust.agent.utils.LttngUtils;
+
+/**
+ * Filter notifications tests using the log4j logging API.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class Log4jFilterListenerIT extends FilterListenerITBase {
+
+    /**
+     * Class setup
+     */
+    @BeforeClass
+    public static void log4jClassSetup() {
+        /* Skip tests if we can't find the JNI library or lttng-tools */
+        assumeTrue(LttngUtils.checkForLog4jLibrary());
+        assumeTrue(LttngUtils.checkForLttngTools(ILttngSession.Domain.LOG4J));
+        LttngToolsHelper.destroyAllSessions();
+    }
+
+    @Override
+    protected ILttngSession.Domain getSessionDomain() {
+        return ILttngSession.Domain.LOG4J;
+    }
+
+    @Override
+    protected ILttngHandler getLogHandler() throws SecurityException, IOException {
+        return new LttngLogAppender();
+    }
+
+    @Override
+    protected ILogLevelStrings getLogLevelStrings() {
+        return ILogLevelStrings.LOG4J_LOGLEVEL_STRINGS;
+    }
+
+}
diff --git a/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/utils/ILogLevelStrings.java b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/utils/ILogLevelStrings.java
new file mode 100644 (file)
index 0000000..e46a718
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015, 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.utils;
+
+/**
+ * Interface to match the log level values used by LTTng to their representation
+ * (name and integer value) used by the logging APIs.
+ *
+ * @author Alexandre Montplaisir
+ */
+public interface ILogLevelStrings {
+
+    /**
+     * @return The string representation of the "warning" level
+     */
+    String warningName();
+
+    /**
+     * @return The integer representation of the "warning" level
+     */
+    int warningInt();
+
+    /**
+     * @return The string representation of the "info" level
+     */
+    String infoName();
+
+    /**
+     * @return The integer representation of the "info" level
+     */
+    int infoInt();
+
+    /**
+     * Values for JUL
+     */
+    ILogLevelStrings JUL_LOGLEVEL_STRINGS = new ILogLevelStrings() {
+
+        @Override
+        public String warningName() {
+            return "warning";
+        }
+
+        @Override
+        public int warningInt() {
+            return 900;
+        }
+
+        @Override
+        public String infoName() {
+            return "info";
+        }
+
+        @Override
+        public int infoInt() {
+            return 800;
+        }
+    };
+
+    /**
+     * Values for log4j 1.x
+     */
+    ILogLevelStrings LOG4J_LOGLEVEL_STRINGS = new ILogLevelStrings() {
+
+        @Override
+        public String warningName() {
+            return "warn";
+        }
+
+        @Override
+        public int warningInt() {
+            return 30000;
+        }
+
+        @Override
+        public String infoName() {
+            return "info";
+        }
+
+        @Override
+        public int infoInt() {
+            return 20000;
+        }
+    };
+
+}
This page took 0.035503 seconds and 4 git commands to generate.