From: Jonathan Rajotte Date: Tue, 7 Nov 2017 01:03:33 +0000 (-0500) Subject: Add test_ust_java_agent_vs_tools X-Git-Url: http://git.efficios.com/?p=deliverable%2Flttng-ivc.git;a=commitdiff_plain;h=74eb709665e53e922313f01de3b6d3d3fdc1df70 Add test_ust_java_agent_vs_tools Signed-off-by: Jonathan Rajotte --- diff --git a/lttng_ivc/apps/jul-1.0/App.java b/lttng_ivc/apps/jul-1.0/App.java new file mode 100644 index 0000000..e7f7f98 --- /dev/null +++ b/lttng_ivc/apps/jul-1.0/App.java @@ -0,0 +1,50 @@ +import java.io.IOException; +import java.io.File; +import java.util.logging.Logger; +import java.util.logging.Level; +import java.util.logging.ConsoleHandler; +import org.lttng.ust.agent.LTTngAgent; + +public class App +{ + private static final int answer = 42; + + public static void main(String[] argv) throws Exception + { + int nrIter = Integer.parseInt(argv[0]); + String sync_first_tp_hit_path = null; + String sync_wait_before_last = null; + + if (argv.length > 1) { + sync_first_tp_hit_path = argv[1]; + } + if (argv.length > 2) { + sync_wait_before_last = argv[2]; + } + + // Create a logger + Logger logger = Logger.getLogger("jello"); + logger.setLevel(Level.INFO); + + LTTngAgent lttngAgent = LTTngAgent.getLTTngAgent(); + + for (int i=0; i < 0 || i < nrIter; i++) { + if ( i >= 0 && i == nrIter -1 && sync_wait_before_last != null) { + File f = new File(sync_wait_before_last); + while (!f.exists()) { + Thread.sleep(1); + } + } + logger.info("logging the world"); + logger.warning("some warning"); + logger.severe("error!"); + if (i == 0 && sync_first_tp_hit_path != null) { + File f = new File(sync_first_tp_hit_path); + f.createNewFile(); + } + } + + // Not mandatory, but cleaner + lttngAgent.dispose(); + } +} diff --git a/lttng_ivc/apps/jul-1.0/first b/lttng_ivc/apps/jul-1.0/first new file mode 100644 index 0000000..e69de29 diff --git a/lttng_ivc/apps/jul-2.0/App.java b/lttng_ivc/apps/jul-2.0/App.java new file mode 100644 index 0000000..251ff2b --- /dev/null +++ b/lttng_ivc/apps/jul-2.0/App.java @@ -0,0 +1,53 @@ +import java.io.IOException; +import java.io.File; +import java.util.logging.Logger; +import java.util.logging.Handler; +import java.util.logging.Level; +import org.lttng.ust.agent.jul.LttngLogHandler; + +public class App +{ + private static final int answer = 42; + + public static void main(String[] argv) throws Exception + { + int nrIter = Integer.parseInt(argv[0]); + String sync_first_tp_hit_path = null; + String sync_wait_before_last = null; + + if (argv.length > 1) { + sync_first_tp_hit_path = argv[1]; + } + if (argv.length > 2) { + sync_wait_before_last = argv[2]; + } + + // Create a logger + Logger logger = Logger.getLogger("jello"); + logger.setLevel(Level.INFO); + + Handler lttngHandler = new LttngLogHandler(); + + logger.addHandler(lttngHandler); + + for (int i=0; i < 0 || i < nrIter; i++) { + if ( i >= 0 && i == nrIter -1 && sync_wait_before_last != null) { + File f = new File(sync_wait_before_last); + while (!f.exists()) { + Thread.sleep(1); + } + } + logger.info("logging the world"); + logger.warning("some warning"); + logger.severe("error!"); + if (i == 0 && sync_first_tp_hit_path != null) { + File f = new File(sync_first_tp_hit_path); + f.createNewFile(); + } + } + + // Not mandatory, but cleaner + logger.removeHandler(lttngHandler); + lttngHandler.close(); + } +} diff --git a/lttng_ivc/settings.py b/lttng_ivc/settings.py index 182b5b6..7f1785a 100644 --- a/lttng_ivc/settings.py +++ b/lttng_ivc/settings.py @@ -14,6 +14,8 @@ git_remote_folder = os.path.join(base_dir, "runtime/git_remote") apps_folder = os.path.join(base_dir, "apps") apps_gen_events_folder = os.path.join(apps_folder, "gen_ust_events") apps_preload_provider_folder = os.path.join(apps_folder, "preload_provider") +apps_jul_1 = os.path.join(apps_folder, "jul-1.0") +apps_jul_2 = os.path.join(apps_folder, "jul-2.0") # Used for checksum validation project_py_file_location = os.path.join(base_dir, "utils/project.py") diff --git a/lttng_ivc/tests/ust_java_agent_vs_tools/__init__.py b/lttng_ivc/tests/ust_java_agent_vs_tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lttng_ivc/tests/ust_java_agent_vs_tools/test_ust_java_agent_vs_tools.py b/lttng_ivc/tests/ust_java_agent_vs_tools/test_ust_java_agent_vs_tools.py new file mode 100644 index 0000000..854743b --- /dev/null +++ b/lttng_ivc/tests/ust_java_agent_vs_tools/test_ust_java_agent_vs_tools.py @@ -0,0 +1,217 @@ +import pytest +import os +import shutil +import signal +import subprocess + +import lttng_ivc.utils.ProjectFactory as ProjectFactory +import lttng_ivc.utils.utils as utils +import lttng_ivc.utils.runtime as Run +import lttng_ivc.settings as Settings + +""" + +FC: Fully Compatible +BC: Feature of the smallest version number will works. +TU: Tracing unavailable + +Note: actual testing is limited by lttng-ust and lttng-tools abi/api. + ++----------------------------------------------------------------------------------+ +| LTTng UST Java agent protocol vs LTTng session daemon | ++--------------------------+------------+------------+------------+----------------+ +| LTTng UST Java/ LTTng Tools | 2.7 (1.0) | 2.8 (2.0) | 2.9 (2.0) | 2.10 (2.0) | ++--------------------------+------------+------------+------------+----------------+ +| 2.7 (1.0) | FC | TU | TU | TU | +| 2.8 (2.0) | TU | FC | BC | BC | +| 2.9 (2.0) | TU | BC | FC | BC | +| 2.10 (2.0) | TU | BC | BC | FC | ++--------------------------+------------+------------+------------+----------------+ + +""" + +""" +First tuple member: lttng-ust label +Second tuple member: lttng-tool label +Third tuple member: app version to use +Fourth tuple member: expected scenario +""" + +version_to_app = {1: Settings.apps_jul_1, + 2: Settings.apps_jul_2} + +test_matrix_tracing_available = [ + ("lttng-ust-2.7", "lttng-tools-2.7", 1, True), + ("lttng-ust-2.7", "lttng-tools-2.8", 1, False), + ("lttng-ust-2.7", "lttng-tools-2.9", 1, False), + ("lttng-ust-2.7", "lttng-tools-2.10", 1, False), + ("lttng-ust-2.8", "lttng-tools-2.7", 2, False), + ("lttng-ust-2.8", "lttng-tools-2.8", 2, True), + ("lttng-ust-2.8", "lttng-tools-2.9", 2, False), + ("lttng-ust-2.8", "lttng-tools-2.10", 2, False), + ("lttng-ust-2.9", "lttng-tools-2.7", 2, False), + ("lttng-ust-2.9", "lttng-tools-2.8", 2, False), + ("lttng-ust-2.9", "lttng-tools-2.9", 2, True), + ("lttng-ust-2.9", "lttng-tools-2.10", 2, True), + ("lttng-ust-2.10", "lttng-tools-2.7", 2, False), + ("lttng-ust-2.10", "lttng-tools-2.8", 2, False), + ("lttng-ust-2.10", "lttng-tools-2.9", 2, True), + ("lttng-ust-2.10", "lttng-tools-2.10", 2, True), +] + +test_matrix_agent_interface = [ + ("lttng-ust-2.7", "lttng-tools-2.7", 1, "Success"), + ("lttng-ust-2.7", "lttng-tools-2.8", 1, "Unsupported protocol"), + ("lttng-ust-2.7", "lttng-tools-2.9", 1, "Unsupported protocol"), + ("lttng-ust-2.7", "lttng-tools-2.10", 1, "Unsupported protocol"), + ("lttng-ust-2.8", "lttng-tools-2.7", 2, "Unsupported protocol"), + ("lttng-ust-2.8", "lttng-tools-2.8", 2, "Success"), + ("lttng-ust-2.8", "lttng-tools-2.9", 2, "Success"), + ("lttng-ust-2.8", "lttng-tools-2.10", 2, "Success"), + ("lttng-ust-2.9", "lttng-tools-2.7", 2, "Unsupported protocol"), + ("lttng-ust-2.9", "lttng-tools-2.8", 2, "Success"), + ("lttng-ust-2.9", "lttng-tools-2.9", 2, "Success"), + ("lttng-ust-2.9", "lttng-tools-2.10", 2, "Success"), + ("lttng-ust-2.10", "lttng-tools-2.7", 2, "Unsupported protocol"), + ("lttng-ust-2.10", "lttng-tools-2.8", 2, "Success"), + ("lttng-ust-2.10", "lttng-tools-2.9", 2, "Success"), + ("lttng-ust-2.10", "lttng-tools-2.10", 2, "Success"), +] + +runtime_matrix_tracing_available = [] +runtime_matrix_agent_interface = [] + +if not Settings.test_only: + runtime_matrix_tracing_available = test_matrix_tracing_available + runtime_matrix_agent_interface = test_matrix_agent_interface +else: + for tup in test_matrix_tracing_available: + if (tup[0] in Settings.test_only or tup[1] in + Settings.test_only): + runtime_matrix_tracing_available.append(tup) + for tup in test_matrix_agent_interface: + if (tup[0] in Settings.test_only or tup[1] in + Settings.test_only): + runtime_matrix_agent_interface.append(tup) + + +@pytest.mark.parametrize("ust_label,tools_label,app_version,should_trace", runtime_matrix_tracing_available) +def test_ust_java_agent_tracing_available(tmpdir, ust_label, tools_label, app_version, should_trace): + + nb_iter = 100 + nb_events = 3 * nb_iter + + # Prepare environment + ust = ProjectFactory.get_precook(ust_label) + tools = ProjectFactory.get_precook(tools_label) + babeltrace = ProjectFactory.get_precook(Settings.default_babeltrace) + + tools_runtime_path = os.path.join(str(tmpdir), "tools") + ust_runtime_path = os.path.join(str(tmpdir), "ust") + app_path = os.path.join(str(tmpdir), "app") + + with Run.get_runtime(ust_runtime_path) as runtime_app, Run.get_runtime(tools_runtime_path) as runtime_tools: + runtime_tools.add_project(tools) + runtime_tools.add_project(babeltrace) + + runtime_app.add_project(ust) + runtime_app.lttng_home = runtime_tools.lttng_home + + trace_path = os.path.join(runtime_tools.lttng_home, 'trace') + + # Make application using the ust runtime + shutil.copytree(version_to_app[app_version], app_path) + runtime_app.run("javac App.java", cwd=app_path) + + # Start lttng-sessiond + sessiond = utils.sessiond_spawn(runtime_tools) + + # Create session using mi to get path and session name + runtime_tools.run('lttng create trace --output={}'.format(trace_path)) + + runtime_tools.run('lttng enable-event -j jello') + runtime_tools.run('lttng start') + + # Run application + cmd = 'java App {}'.format(nb_iter) + runtime_app.run(cmd, cwd=app_path) + + # Stop tracing + runtime_tools.run('lttng destroy -a') + cp = runtime_tools.subprocess_terminate(sessiond) + if cp.returncode != 0: + pytest.fail("Sessiond return code") + + # Read trace with babeltrace and check for event count via number of line + cmd = 'babeltrace {}'.format(trace_path) + if should_trace: + cp_process, cp_out, cp_err = runtime_tools.run(cmd) + assert(utils.line_count(cp_out) == nb_events) + else: + with pytest.raises(subprocess.CalledProcessError): + cp_process, cp_out, cp_err = runtime_tools.run(cmd) + +@pytest.mark.parametrize("ust_label,tools_label,app_version,outcome", runtime_matrix_agent_interface) +def test_ust_java_agent_interface(tmpdir, ust_label, tools_label, app_version, outcome): + """ + Use the agent coming from ust_label, but run app under tools_version runtime using ust agent. + """ + + nb_iter = 100 + nb_events = 3 * nb_iter + + # Prepare environment + ust = ProjectFactory.get_precook(ust_label) + tools = ProjectFactory.get_precook(tools_label) + babeltrace = ProjectFactory.get_precook(Settings.default_babeltrace) + + tools_runtime_path = os.path.join(str(tmpdir), "tools") + ust_runtime_path = os.path.join(str(tmpdir), "ust") + app_path = os.path.join(str(tmpdir), "app") + + with Run.get_runtime(ust_runtime_path) as runtime_app, Run.get_runtime(tools_runtime_path) as runtime_tools: + runtime_tools.add_project(tools) + runtime_tools.add_project(babeltrace) + + runtime_app.add_project(ust) + runtime_app.lttng_home = runtime_tools.lttng_home + + trace_path = os.path.join(runtime_tools.lttng_home, 'trace') + + # Make application using the ust runtime + shutil.copytree(version_to_app[app_version], app_path) + runtime_app.run("javac App.java", cwd=app_path) + + # Start lttng-sessiond + sessiond = utils.sessiond_spawn(runtime_tools) + + # Create session using mi to get path and session name + runtime_tools.run('lttng create trace --output={}'.format(trace_path)) + + runtime_tools.run('lttng enable-event -j jello') + runtime_tools.run('lttng start') + + # Steal the classpath from ust project + ust_classpath = ust.special_env_variables['CLASSPATH'] + + # Run application with tools runtime + cmd = 'java App {}'.format(nb_iter) + runtime_tools.run(cmd, cwd=app_path, classpath=ust_classpath) + + # Stop tracing + runtime_tools.run('lttng destroy -a') + cp = runtime_tools.subprocess_terminate(sessiond) + if cp.returncode != 0: + pytest.fail("Sessiond return code") + + # Read trace with babeltrace and check for event count via number of line + cmd = 'babeltrace {}'.format(trace_path) + if outcome == "Success": + assert(utils.file_contains(runtime_tools.get_subprocess_stderr_path(sessiond),["New registration for pid"])) + cp_process, cp_out, cp_err = runtime_tools.run(cmd) + assert(utils.line_count(cp_out) == nb_events) + else: + if outcome == "Unsupported protocol": + assert(not(utils.file_contains(runtime_tools.get_subprocess_stderr_path(sessiond),["New registration for pid"]))) + cp_process, cp_out, cp_err = runtime_tools.run(cmd) + assert(utils.line_count(cp_out) == 0) diff --git a/lttng_ivc/utils/project.py b/lttng_ivc/utils/project.py index fbd7f14..71d17e2 100644 --- a/lttng_ivc/utils/project.py +++ b/lttng_ivc/utils/project.py @@ -316,8 +316,10 @@ class Lttng_ust(Project): self.custom_configure_flags.extend(['--enable-python-agent']) self.custom_configure_flags.extend(['--enable-java-agent-jul']) - jul_path = os.path.join(self.installation_path, "share/java") - self.add_special_env_variable("CLASSPATH", "{}".format(jul_path)) + jul_path = os.path.join(self.installation_path, + "share/java/liblttng-ust-agent.jar") + classpath = ":".join([jul_path, Settings.log4j_class_path, '.']) + self.add_special_env_variable("CLASSPATH", classpath) class Lttng_tools(Project): diff --git a/lttng_ivc/utils/runtime.py b/lttng_ivc/utils/runtime.py index b74beee..a409c19 100644 --- a/lttng_ivc/utils/runtime.py +++ b/lttng_ivc/utils/runtime.py @@ -120,7 +120,7 @@ class Runtime(object): _logger.debug("Spawned sub pid: {} args: {} stdout: {} stderr{}".format(p.pid, p.args, out_path, err_path)) return tmp_id - def run(self, command_line, cwd=None, check_return=True, ld_preload=""): + def run(self, command_line, cwd=None, check_return=True, ld_preload="", classpath=""): """ Run the command and return a tuple of a (CompletedProcess, stdout_path, stderr_path). The subprocess is already executed and returned. The @@ -131,6 +131,8 @@ class Runtime(object): if ld_preload: env['LD_PRELOAD'] = ld_preload + if classpath: + env['CLASSPATH'] = classpath tmp_id = self._run_command_count diff --git a/lttng_ivc/utils/utils.py b/lttng_ivc/utils/utils.py index b8a1b37..9bc9d8c 100644 --- a/lttng_ivc/utils/utils.py +++ b/lttng_ivc/utils/utils.py @@ -2,6 +2,9 @@ import signal import hashlib import os import time +import socket + +from contextlib import closing def line_count(file_path): line_count = 0 @@ -43,13 +46,20 @@ def __dummy_sigusr1_handler(): def sessiond_spawn(runtime): + agent_port = find_free_port() previous_handler = signal.signal(signal.SIGUSR1, __dummy_sigusr1_handler) - sessiond = runtime.spawn_subprocess("lttng-sessiond -vvv -S") + sessiond = runtime.spawn_subprocess("lttng-sessiond -vvv -S --agent-tcp-port {}".format(agent_port)) signal.sigtimedwait({signal.SIGUSR1}, 60) previous_handler = signal.signal(signal.SIGUSR1, previous_handler) return sessiond +def find_free_port(): + # There is no guarantee that the port will be free at runtime but should be + # good enough + with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: + s.bind(('', 0)) + return s.getsockname()[1] def file_contains(stderr_file, list_of_string):