Introduce save load test
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Mon, 13 Nov 2017 16:44:46 +0000 (11:44 -0500)
committerJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Mon, 13 Nov 2017 16:44:46 +0000 (11:44 -0500)
Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
lttng_ivc/settings.py
lttng_ivc/tests/tools_save-load/__init__.py [new file with mode: 0644]
lttng_ivc/tests/tools_save-load/test_save_load.py [new file with mode: 0644]
lttng_ivc/utils/utils.py

index 55d0a1c796d2bb78746e9b360ceeada3eafcfbd0..8a07dd205ca67b829754d64a6fda72e311b8f140 100644 (file)
@@ -25,4 +25,8 @@ tmp_object_prefix = "lttng-ivc-"
 
 default_babeltrace = "babeltrace-1.5"
 
+
 lttng_test_procfile = "/proc/lttng-test-filter-event"
+
+save_ext = ".lttng"
+
diff --git a/lttng_ivc/tests/tools_save-load/__init__.py b/lttng_ivc/tests/tools_save-load/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/lttng_ivc/tests/tools_save-load/test_save_load.py b/lttng_ivc/tests/tools_save-load/test_save_load.py
new file mode 100644 (file)
index 0000000..a513934
--- /dev/null
@@ -0,0 +1,287 @@
+import pytest
+import os
+import shutil
+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
+
+from lttng_ivc.utils.utils import xpath_query
+
+"""
+"""
+
+
+test_matrix_app_contexts = [
+    ("lttng-tools-2.8", "lttng-tools-2.7",   False),
+    ("lttng-tools-2.9", "lttng-tools-2.8",   True),
+    ("lttng-tools-2.8", "lttng-tools-2.9",   True),
+    pytest.param("lttng-tools-2.8", "lttng-tools-2.10",  True, marks=pytest.mark.xfail(reason="See https://bugs.lttng.org/issues/1136")),
+]
+
+test_matrix_blocking_timeout = [
+        ("lttng-tools-2.10", "lttng-tools-2.7",   False),
+        ("lttng-tools-2.10", "lttng-tools-2.8",   False),
+        ("lttng-tools-2.10", "lttng-tools-2.9",   False),
+        ("lttng-tools-2.10", "lttng-tools-2.10",  True),
+]
+
+test_matrix_monitor_timer_interval = [
+        ("lttng-tools-2.10", "lttng-tools-2.7",   False),
+        ("lttng-tools-2.10", "lttng-tools-2.8",   False),
+        ("lttng-tools-2.10", "lttng-tools-2.9",   False),
+        ("lttng-tools-2.10", "lttng-tools-2.10",  True),
+]
+
+runtime_matrix_app_contexts = []
+runtime_matrix_blocking_timeout = []
+runtime_matrix_monitor_timer_interval = []
+
+
+if not Settings.test_only:
+    runtime_matrix_app_contexts = test_matrix_app_contexts
+    runtime_matrix_blocking_timeout = test_matrix_blocking_timeout
+    runtime_matrix_monitor_timer_interval = test_matrix_monitor_timer_interval
+else:
+    for tup in test_matrix_app_contexts:
+        if(tup[0] in Settings.test_only or tup[1] in Settings.test_only):
+            runtime_matrix_app_contexts.append(tup)
+    for tup in test_matrix_blocking_timeout:
+        if(tup[0] in Settings.test_only or tup[1] in Settings.test_only):
+            runtime_matrix_blocking_timeout.append(tup)
+    for tup in test_matrix_monitor_timer_interval:
+        if(tup[0] in Settings.test_only or tup[1] in Settings.test_only):
+            runtime_matrix_monitor_timer_interval.append(tup)
+
+
+def validate_app_context(session_name, save_file):
+    xpath_provider_name = '/sessions/session[name="{}"]/domains/domain[type="JUL" or type="LOG4J"]/channels/channel/contexts/context/app/provider_name'.format(session_name)
+    xpath_ctx_name = '/sessions/session[name="{}"]/domains/domain[type="JUL" or type="LOG4J"]/channels/channel/contexts/context/app/ctx_name'.format(session_name)
+    xpath_node_expected = 2
+
+    # Check that the file is present
+    assert(os.path.isfile(save_file))
+    # Validate provider name
+    node_list = xpath_query(save_file, xpath_provider_name)
+    assert(len(node_list) == xpath_node_expected)
+    for node in node_list:
+        assert(node.text == "myRetriever")
+
+    # Validate ctx_name
+    node_list = xpath_query(save_file, xpath_ctx_name)
+    assert(len(node_list) == xpath_node_expected)
+    for node in node_list:
+        assert(node.text == "intCtx")
+
+
+@pytest.mark.parametrize("tools_save_l,tools_load_l,should_load", runtime_matrix_app_contexts)
+def test_save_load_app_contexts(tmpdir, tools_save_l, tools_load_l, should_load):
+
+    # Prepare environment
+    t_save = ProjectFactory.get_precook(tools_save_l)
+    t_load = ProjectFactory.get_precook(tools_load_l)
+
+    t_save_runtime_path = os.path.join(str(tmpdir), "tools-save")
+    t_load_runtime_path = os.path.join(str(tmpdir), "tools-load")
+    save_load_path = os.path.join(str(tmpdir), 'save_load')
+    validation_path = os.path.join(str(tmpdir), 'validation')
+
+    trace_name = "saved_trace"
+    trace_filename = trace_name + Settings.save_ext
+    trace_file_path = os.path.join(save_load_path, trace_filename)
+
+    validation_file_path = os.path.join(validation_path, trace_filename)
+
+    # Craft the save
+    with Run.get_runtime(t_save_runtime_path) as runtime:
+        runtime.add_project(t_save)
+
+        # Start lttng-sessiond
+        sessiond = utils.sessiond_spawn(runtime)
+
+        runtime.run("lttng create {}".format(trace_name))
+        runtime.run("lttng enable-event --jul hello")
+        runtime.run("lttng enable-event --log4j hello")
+        # NOTE:  For now there is a bug/quirk for which app context is applied
+        # everywhere. Might need to be revisited. This influence the number of
+        # node we expect in the saved file.
+        runtime.run("lttng add-context --jul --type='$app.myRetriever:intCtx'")
+        runtime.run("lttng save --output-path={}".format(save_load_path))
+
+        cp = runtime.subprocess_terminate(sessiond)
+        if cp.returncode != 0:
+            pytest.fail("Sessiond on save return code")
+
+    validate_app_context(trace_name, trace_file_path)
+
+    # Load the save
+    with Run.get_runtime(t_load_runtime_path) as runtime:
+        runtime.add_project(t_load)
+
+        # Start lttng-sessiond
+        sessiond = utils.sessiond_spawn(runtime)
+
+        cmd = "lttng load --input-path={} {}".format(save_load_path, trace_name)
+
+        if not should_load:
+            cp, out, err = runtime.run(cmd, check_return=False)
+            assert(cp.returncode != 0)
+            assert(utils.file_contains(err, ['Session configuration file validation failed']))
+            return
+
+        runtime.run(cmd)
+
+        # Since lttng list does not include context we need to re-save and
+        # validate that the contexts are presend in the newly saved file.
+        runtime.run("lttng save --output-path={}".format(validation_path))
+
+        cp = runtime.subprocess_terminate(sessiond)
+        if cp.returncode != 0:
+            pytest.fail("Sessiond on load return code")
+
+    validate_app_context(trace_name, validation_file_path)
+
+
+@pytest.mark.parametrize("tools_save_l,tools_load_l,should_load", runtime_matrix_blocking_timeout)
+def test_save_load_blocking_timeout(tmpdir, tools_save_l, tools_load_l, should_load):
+
+    # Prepare environment
+    t_save = ProjectFactory.get_precook(tools_save_l)
+    t_load = ProjectFactory.get_precook(tools_load_l)
+
+    t_save_runtime_path = os.path.join(str(tmpdir), "tools-save")
+    t_load_runtime_path = os.path.join(str(tmpdir), "tools-load")
+    save_load_path = os.path.join(str(tmpdir), 'save_load')
+
+    trace_name = "saved_trace"
+    channel_name = "my_channel"
+    trace_filename = trace_name + Settings.save_ext
+    trace_file_path = os.path.join(save_load_path, trace_filename)
+
+    blocking_timeout = 1000
+
+    # Craft the save
+    with Run.get_runtime(t_save_runtime_path) as runtime:
+        runtime.add_project(t_save)
+
+        # Start lttng-sessiond
+        sessiond = utils.sessiond_spawn(runtime)
+
+        runtime.run("lttng create {}".format(trace_name))
+        runtime.run("lttng enable-channel -u --blocking-timeout {} {}".format(blocking_timeout, channel_name))
+        runtime.run("lttng save --output-path={}".format(save_load_path))
+
+
+        cp = runtime.subprocess_terminate(sessiond)
+        if cp.returncode != 0:
+            pytest.fail("Sessiond on save return code")
+
+    assert(os.path.isfile(trace_file_path))
+
+    xpath_blocking_timeout = '/sessions/session[name="{}"]/domains/domain[type="UST"]/channels/channel[name="{}"]/blocking_timeout'.format(trace_name, channel_name)
+    node = xpath_query(trace_file_path, xpath_blocking_timeout)
+    assert(len(node) == 1)
+    assert(node[0].text == str(blocking_timeout))
+
+    # Load the save
+    with Run.get_runtime(t_load_runtime_path) as runtime:
+        runtime.add_project(t_load)
+
+        # Start lttng-sessiond
+        sessiond = utils.sessiond_spawn(runtime)
+
+        if should_load:
+            runtime.run("lttng load --input-path={} {}".format(save_load_path, trace_name))
+        else:
+            with pytest.raises(subprocess.CalledProcessError):
+                runtime.run("lttng load --input-path={} {}".format(save_load_path, trace_name))
+            cp = runtime.subprocess_terminate(sessiond)
+            if cp.returncode != 0:
+                pytest.fail("Sessiond on load return code")
+            return
+
+        cp, mi_out, err = runtime.run("lttng --mi xml list {}".format(trace_name))
+
+        cp = runtime.subprocess_terminate(sessiond)
+        if cp.returncode != 0:
+            pytest.fail("Sessiond on load return code")
+
+    assert(os.path.isfile(mi_out))
+    xpath_mi_blocking_timeout = '/command/output/sessions/session/domains/domain/channels/channel/attributes/blocking_timeout'
+    node = xpath_query(mi_out, xpath_mi_blocking_timeout)
+    assert(len(node) == 1)
+    assert(node[0].text == str(blocking_timeout))
+
+
+@pytest.mark.parametrize("tools_save_l,tools_load_l,should_load", runtime_matrix_monitor_timer_interval)
+def test_save_load_timer_interval(tmpdir, tools_save_l, tools_load_l, should_load):
+
+    # Prepare environment
+    t_save = ProjectFactory.get_precook(tools_save_l)
+    t_load = ProjectFactory.get_precook(tools_load_l)
+
+    t_save_runtime_path = os.path.join(str(tmpdir), "tools-save")
+    t_load_runtime_path = os.path.join(str(tmpdir), "tools-load")
+    save_load_path = os.path.join(str(tmpdir), 'save_load')
+
+    trace_name = "saved_trace"
+    channel_name = "my_channel"
+    trace_filename = trace_name + Settings.save_ext
+    trace_file_path = os.path.join(save_load_path, trace_filename)
+
+    monitor_timer_interval = 1000
+
+    # Craft the save
+    with Run.get_runtime(t_save_runtime_path) as runtime:
+        runtime.add_project(t_save)
+
+        # Start lttng-sessiond
+        sessiond = utils.sessiond_spawn(runtime)
+
+        runtime.run("lttng create {}".format(trace_name))
+        runtime.run("lttng enable-channel -u --monitor-timer={} {}".format(monitor_timer_interval, channel_name))
+        runtime.run("lttng save --output-path={}".format(save_load_path))
+
+        assert(os.path.isfile(trace_file_path))
+
+        cp = runtime.subprocess_terminate(sessiond)
+        if cp.returncode != 0:
+            pytest.fail("Sessiond on save return code")
+
+    assert(os.path.isfile(trace_file_path))
+
+    xpath_monitor_interval = '/sessions/session/domains/domain[type="UST"]/channels/channel/monitor_timer_interval'
+    node = xpath_query(trace_file_path, xpath_monitor_interval)
+    assert(len(node) == 1)
+    assert(node[0].text == str(monitor_timer_interval))
+
+    # Load the save
+    with Run.get_runtime(t_load_runtime_path) as runtime:
+        runtime.add_project(t_load)
+
+        # Start lttng-sessiond
+        sessiond = utils.sessiond_spawn(runtime)
+
+        if should_load:
+            runtime.run("lttng load --input-path={} {}".format(save_load_path, trace_name))
+        else:
+            with pytest.raises(subprocess.CalledProcessError):
+                runtime.run("lttng load --input-path={} {}".format(save_load_path, trace_name))
+            cp = runtime.subprocess_terminate(sessiond)
+            if cp.returncode != 0:
+                pytest.fail("Sessiond on load return code")
+            return
+
+        cp, mi_out, err = runtime.run("lttng --mi xml list {}".format(trace_name))
+
+        cp = runtime.subprocess_terminate(sessiond)
+        if cp.returncode != 0:
+            pytest.fail("Sessiond on load return code")
+
+    assert(os.path.isfile(mi_out))
+    xpath_mi = '/command/output/sessions/session/domains/domain/channels/channel/attributes/monitor_timer_interval'
+    node = xpath_query(mi_out, xpath_mi)
+    assert(len(node) == 1)
+    assert(node[0].text == str(monitor_timer_interval))
index c174b44e192b17d5b45fff99fe43638adf15bf8d..37e09e197226ec1b9c9abf9a5da5f17aaa60ae6a 100644 (file)
@@ -4,8 +4,10 @@ import os
 import time
 import socket
 
+from lxml import etree
 from contextlib import closing
 
+
 def line_count(file_path):
     line_count = 0
     with open(file_path) as f:
@@ -62,9 +64,9 @@ def find_free_port():
         return s.getsockname()[1]
 
 
-def file_contains(stderr_file, list_of_string):
-    with open(stderr_file, 'r') as stderr:
-        for line in stderr:
+def file_contains(file_path, list_of_string):
+    with open(file_path, 'r') as f:
+        for line in f:
             for s in list_of_string:
                 if s in line:
                     return True
@@ -77,7 +79,26 @@ def find_dir(root, name):
     abs_path = None
     for base, dirs, files in os.walk(root):
         for tmp in dirs:
-            print(tmp)
             if tmp.endswith(name):
                 abs_path = os.path.abspath(os.path.join(base, tmp))
     return abs_path
+
+
+def xpath_query(xml_file, xpath):
+    """
+    Return a list of xml node corresponding to the xpath. The list can be of lenght
+    zero.
+    """
+    with open(xml_file, 'r') as f:
+        tree = etree.parse(f)
+        root = tree.getroot()
+        # Remove all namespace
+        # https://stackoverflow.com/questions/18159221/remove-namespace-and-prefix-from-xml-in-python-using-lxml
+        for elem in root.getiterator():
+            if not hasattr(elem.tag, 'find'):
+                continue
+            i = elem.tag.find('}')
+            if i >= 0:
+                elem.tag = elem.tag[i+1:]
+
+        return root.xpath(xpath)
This page took 0.028357 seconds and 5 git commands to generate.