From f37120c3b2ab31a67fab2da79f5ad6ca0145f5aa Mon Sep 17 00:00:00 2001
From: Alexandre Montplaisir
Date: Fri, 28 Aug 2015 18:59:57 -0400
Subject: [PATCH] Add filter notifications and TCP client tests
This required adding log level and filter string functionality
to ILttngSession.
Signed-off-by: Alexandre Montplaisir
---
.../java/org/lttng/tools/ILttngSession.java | 36 +-
.../lttng/tools/LttngCommandLineSession.java | 37 ++
.../client/TcpClientDebugListener.java | 88 +++++
.../agent/integration/client/TcpClientIT.java | 334 ++++++++++++++++++
.../filter/FilterListenerITBase.java | 290 +++++++++++++++
.../filter/JulFilterListenerIT.java | 66 ++++
.../filter/Log4jFilterListenerIT.java | 66 ++++
.../ust/agent/utils/ILogLevelStrings.java | 101 ++++++
8 files changed, 1013 insertions(+), 5 deletions(-)
create mode 100644 lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientDebugListener.java
create mode 100644 lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientIT.java
create mode 100644 lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/FilterListenerITBase.java
create mode 100644 lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/JulFilterListenerIT.java
create mode 100644 lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/Log4jFilterListenerIT.java
create mode 100644 lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/utils/ILogLevelStrings.java
diff --git a/lttng-tools-java/src/main/java/org/lttng/tools/ILttngSession.java b/lttng-tools-java/src/main/java/org/lttng/tools/ILttngSession.java
index e7d65a0..b6d0aed 100644
--- a/lttng-tools-java/src/main/java/org/lttng/tools/ILttngSession.java
+++ b/lttng-tools-java/src/main/java/org/lttng/tools/ILttngSession.java
@@ -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
*
diff --git a/lttng-tools-java/src/main/java/org/lttng/tools/LttngCommandLineSession.java b/lttng-tools-java/src/main/java/org/lttng/tools/LttngCommandLineSession.java
index 0cd26cc..e2b1ff6 100644
--- a/lttng-tools-java/src/main/java/org/lttng/tools/LttngCommandLineSession.java
+++ b/lttng-tools-java/src/main/java/org/lttng/tools/LttngCommandLineSession.java
@@ -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 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
index 0000000..e2ec3d8
--- /dev/null
+++ b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientDebugListener.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015, EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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 enabledEventCommands = Collections.synchronizedList(new ArrayList<>());
+ private final List 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 listEnabledEvents() {
+ // TODO NYI
+ return Collections.EMPTY_LIST;
+ }
+
+ /**
+ * @return The "enable-event" commands that were received, since
+ * instantiation or the last {@link #clearAllCommands}.
+ */
+ public List getEnabledEventCommands() {
+ synchronized (enabledEventCommands) {
+ return new ArrayList<>(enabledEventCommands);
+ }
+ }
+
+ /**
+ * @return The "disable-event" commands that were received, since
+ * instantiation or the last {@link #clearAllCommands}.
+ */
+ public List 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
index 0000000..b9f0d0b
--- /dev/null
+++ b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/client/TcpClientIT.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2015, EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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 > boolean containSameElements(List list1, List list2) {
+ List newlist1 = new ArrayList<>(list1);
+ List 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 expectedCommands = Collections.singletonList(
+ new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, null));
+
+ List actualCommands = clientListener.getEnabledEventCommands();
+ assertEquals(expectedCommands, actualCommands);
+ }
+
+ /**
+ * Test an "enable-event -a" command.
+ */
+ @Test
+ public void testEnableAllEvents() {
+ session.enableAllEvents();
+
+ List expectedCommands = Collections.singletonList(
+ new EventRule(EVENT_NAME_ALL, LOG_LEVEL_UNSPECIFIED, null));
+ List 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 expectedEnableCommands = Collections.singletonList(
+ new EventRule(EVENT_NAME_A, LOG_LEVEL_UNSPECIFIED, null));
+ List 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 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 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 expectedEnableCommands = Arrays.asList(
+ new EventRule(EVENT_NAME_ALL, LOG_LEVEL_UNSPECIFIED, null));
+ List 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 expectedCommands = Collections.singletonList(
+ new EventRule(EVENT_NAME_A, llf, null));
+ List 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 expectedCommands = Collections.singletonList(
+ new EventRule(EVENT_NAME_A, llf, null));
+ List 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 expectedCommands = Arrays.asList(
+ new EventRule(EVENT_NAME_A, llf1, null),
+ new EventRule(EVENT_NAME_A, llf2, null)
+ );
+ List 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 expectedCommands = Arrays.asList(
+ new EventRule(EVENT_NAME_A, llf1, null),
+ new EventRule(EVENT_NAME_A, llf2, null)
+ );
+ List 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 expectedCommands = Arrays.asList(new EventRule(EVENT_NAME_A, llf1, null),
+ new EventRule(EVENT_NAME_A, llf2, null));
+ List 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
index 0000000..e7c537c
--- /dev/null
+++ b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/FilterListenerITBase.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2015, EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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 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 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 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 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 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 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 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.
+ *
+ *
+ * Usage:
+ *
+ * - Specify the expected number of notifications and end rules with
+ * {@link #setParameters}.
+ * - Send the commands to LTTng (using {@link ILttngSession} for example.
+ *
+ * - Call {@link #waitForAllNotifications()}.
+ * - Verify that {@link #checkRules()} returns true.
+ *
+ *
+ */
+ private static class TestFilterListener implements IFilterChangeListener {
+
+ private final Set currentRules = new HashSet<>();
+ private CountDownLatch remainingExpectedNotifs;
+ private Set 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 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
index 0000000..b82e41f
--- /dev/null
+++ b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/JulFilterListenerIT.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015, EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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
index 0000000..c01bc84
--- /dev/null
+++ b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/integration/filter/Log4jFilterListenerIT.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015, EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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
index 0000000..e46a718
--- /dev/null
+++ b/lttng-ust-java-tests/src/test/java/org/lttng/ust/agent/utils/ILogLevelStrings.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015, EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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;
+ }
+ };
+
+}
--
2.34.1