From: Alexandre Montplaisir Date: Fri, 28 Aug 2015 22:59:57 +0000 (-0400) Subject: Add filter notifications and TCP client tests X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=f37120c3b2ab31a67fab2da79f5ad6ca0145f5aa;p=lttng-ust-java-tests.git Add filter notifications and TCP client tests This required adding log level and filter string functionality to ILttngSession. Signed-off-by: Alexandre Montplaisir --- 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; + } + }; + +}