Blame tests/unittests/test_builtin_handlers.py

Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service a04d08
"""Tests of the built-in user data handlers."""
Packit Service a04d08
Packit Service a04d08
import copy
Packit Service a04d08
import errno
Packit Service a04d08
import os
Packit Service a04d08
import shutil
Packit Service a04d08
import tempfile
Packit Service a04d08
from textwrap import dedent
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
from cloudinit.tests.helpers import (
Packit Service a04d08
    FilesystemMockingTestCase, CiTestCase, mock, skipUnlessJinja)
Packit Service a04d08
Packit Service a04d08
from cloudinit import handlers
Packit Service a04d08
from cloudinit import helpers
Packit Service 751c4a
from cloudinit import subp
Packit Service a04d08
from cloudinit import util
Packit Service a04d08
Packit Service a04d08
from cloudinit.handlers.cloud_config import CloudConfigPartHandler
Packit Service a04d08
from cloudinit.handlers.jinja_template import (
Packit Service a04d08
    JinjaTemplatePartHandler, convert_jinja_instance_data,
Packit Service a04d08
    render_jinja_payload)
Packit Service a04d08
from cloudinit.handlers.shell_script import ShellScriptPartHandler
Packit Service a04d08
from cloudinit.handlers.upstart_job import UpstartJobPartHandler
Packit Service a04d08
Packit Service a04d08
from cloudinit.settings import (PER_ALWAYS, PER_INSTANCE)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestUpstartJobPartHandler(FilesystemMockingTestCase):
Packit Service a04d08
Packit Service a04d08
    mpath = 'cloudinit.handlers.upstart_job.'
Packit Service a04d08
Packit Service a04d08
    def test_upstart_frequency_no_out(self):
Packit Service a04d08
        c_root = tempfile.mkdtemp()
Packit Service a04d08
        self.addCleanup(shutil.rmtree, c_root)
Packit Service a04d08
        up_root = tempfile.mkdtemp()
Packit Service a04d08
        self.addCleanup(shutil.rmtree, up_root)
Packit Service a04d08
        paths = helpers.Paths({
Packit Service a04d08
            'cloud_dir': c_root,
Packit Service a04d08
            'upstart_dir': up_root,
Packit Service a04d08
        })
Packit Service a04d08
        h = UpstartJobPartHandler(paths)
Packit Service a04d08
        # No files should be written out when
Packit Service a04d08
        # the frequency is ! per-instance
Packit Service a04d08
        h.handle_part('', handlers.CONTENT_START,
Packit Service a04d08
                      None, None, None)
Packit Service a04d08
        h.handle_part('blah', 'text/upstart-job',
Packit Service a04d08
                      'test.conf', 'blah', frequency=PER_ALWAYS)
Packit Service a04d08
        h.handle_part('', handlers.CONTENT_END,
Packit Service a04d08
                      None, None, None)
Packit Service a04d08
        self.assertEqual(0, len(os.listdir(up_root)))
Packit Service a04d08
Packit Service a04d08
    def test_upstart_frequency_single(self):
Packit Service a04d08
        # files should be written out when frequency is ! per-instance
Packit Service a04d08
        new_root = tempfile.mkdtemp()
Packit Service a04d08
        self.addCleanup(shutil.rmtree, new_root)
Packit Service a04d08
Packit Service a04d08
        self.patchOS(new_root)
Packit Service a04d08
        self.patchUtils(new_root)
Packit Service a04d08
        paths = helpers.Paths({
Packit Service a04d08
            'upstart_dir': "/etc/upstart",
Packit Service a04d08
        })
Packit Service a04d08
Packit Service a04d08
        util.ensure_dir("/run")
Packit Service a04d08
        util.ensure_dir("/etc/upstart")
Packit Service a04d08
Packit Service a04d08
        with mock.patch(self.mpath + 'SUITABLE_UPSTART', return_value=True):
Packit Service 751c4a
            with mock.patch.object(subp, 'subp') as m_subp:
Packit Service a04d08
                h = UpstartJobPartHandler(paths)
Packit Service a04d08
                h.handle_part('', handlers.CONTENT_START,
Packit Service a04d08
                              None, None, None)
Packit Service a04d08
                h.handle_part('blah', 'text/upstart-job',
Packit Service a04d08
                              'test.conf', 'blah', frequency=PER_INSTANCE)
Packit Service a04d08
                h.handle_part('', handlers.CONTENT_END,
Packit Service a04d08
                              None, None, None)
Packit Service a04d08
Packit Service a04d08
        self.assertEqual(len(os.listdir('/etc/upstart')), 1)
Packit Service a04d08
Packit Service a04d08
        m_subp.assert_called_once_with(
Packit Service a04d08
            ['initctl', 'reload-configuration'], capture=False)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestJinjaTemplatePartHandler(CiTestCase):
Packit Service a04d08
Packit Service a04d08
    with_logs = True
Packit Service a04d08
Packit Service a04d08
    mpath = 'cloudinit.handlers.jinja_template.'
Packit Service a04d08
Packit Service a04d08
    def setUp(self):
Packit Service a04d08
        super(TestJinjaTemplatePartHandler, self).setUp()
Packit Service a04d08
        self.tmp = self.tmp_dir()
Packit Service a04d08
        self.run_dir = os.path.join(self.tmp, 'run_dir')
Packit Service a04d08
        util.ensure_dir(self.run_dir)
Packit Service a04d08
        self.paths = helpers.Paths({
Packit Service a04d08
            'cloud_dir': self.tmp, 'run_dir': self.run_dir})
Packit Service a04d08
Packit Service a04d08
    def test_jinja_template_part_handler_defaults(self):
Packit Service a04d08
        """On init, paths are saved and subhandler types are empty."""
Packit Service a04d08
        h = JinjaTemplatePartHandler(self.paths)
Packit Service a04d08
        self.assertEqual(['## template: jinja'], h.prefixes)
Packit Service a04d08
        self.assertEqual(3, h.handler_version)
Packit Service a04d08
        self.assertEqual(self.paths, h.paths)
Packit Service a04d08
        self.assertEqual({}, h.sub_handlers)
Packit Service a04d08
Packit Service a04d08
    def test_jinja_template_part_handler_looks_up_sub_handler_types(self):
Packit Service a04d08
        """When sub_handlers are passed, init lists types of subhandlers."""
Packit Service a04d08
        script_handler = ShellScriptPartHandler(self.paths)
Packit Service a04d08
        cloudconfig_handler = CloudConfigPartHandler(self.paths)
Packit Service a04d08
        h = JinjaTemplatePartHandler(
Packit Service a04d08
            self.paths, sub_handlers=[script_handler, cloudconfig_handler])
Packit Service 751c4a
        self.assertCountEqual(
Packit Service a04d08
            ['text/cloud-config', 'text/cloud-config-jsonp',
Packit Service a04d08
             'text/x-shellscript'],
Packit Service a04d08
            h.sub_handlers)
Packit Service a04d08
Packit Service a04d08
    def test_jinja_template_part_handler_looks_up_subhandler_types(self):
Packit Service a04d08
        """When sub_handlers are passed, init lists types of subhandlers."""
Packit Service a04d08
        script_handler = ShellScriptPartHandler(self.paths)
Packit Service a04d08
        cloudconfig_handler = CloudConfigPartHandler(self.paths)
Packit Service a04d08
        h = JinjaTemplatePartHandler(
Packit Service a04d08
            self.paths, sub_handlers=[script_handler, cloudconfig_handler])
Packit Service 751c4a
        self.assertCountEqual(
Packit Service a04d08
            ['text/cloud-config', 'text/cloud-config-jsonp',
Packit Service a04d08
             'text/x-shellscript'],
Packit Service a04d08
            h.sub_handlers)
Packit Service a04d08
Packit Service a04d08
    def test_jinja_template_handle_noop_on_content_signals(self):
Packit Service a04d08
        """Perform no part handling when content type is CONTENT_SIGNALS."""
Packit Service a04d08
        script_handler = ShellScriptPartHandler(self.paths)
Packit Service a04d08
Packit Service a04d08
        h = JinjaTemplatePartHandler(
Packit Service a04d08
            self.paths, sub_handlers=[script_handler])
Packit Service a04d08
        with mock.patch.object(script_handler, 'handle_part') as m_handle_part:
Packit Service a04d08
            h.handle_part(
Packit Service a04d08
                data='data', ctype=handlers.CONTENT_START, filename='part-1',
Packit Service a04d08
                payload='## template: jinja\n#!/bin/bash\necho himom',
Packit Service a04d08
                frequency='freq', headers='headers')
Packit Service a04d08
        m_handle_part.assert_not_called()
Packit Service a04d08
Packit Service a04d08
    @skipUnlessJinja()
Packit Service a04d08
    def test_jinja_template_handle_subhandler_v2_with_clean_payload(self):
Packit Service a04d08
        """Call version 2 subhandler.handle_part with stripped payload."""
Packit Service a04d08
        script_handler = ShellScriptPartHandler(self.paths)
Packit Service a04d08
        self.assertEqual(2, script_handler.handler_version)
Packit Service a04d08
Packit Service a04d08
        # Create required instance-data.json file
Packit Service a04d08
        instance_json = os.path.join(self.run_dir, 'instance-data.json')
Packit Service a04d08
        instance_data = {'topkey': 'echo himom'}
Packit Service a04d08
        util.write_file(instance_json, util.json_dumps(instance_data))
Packit Service a04d08
        h = JinjaTemplatePartHandler(
Packit Service a04d08
            self.paths, sub_handlers=[script_handler])
Packit Service a04d08
        with mock.patch.object(script_handler, 'handle_part') as m_part:
Packit Service a04d08
            # ctype with leading '!' not in handlers.CONTENT_SIGNALS
Packit Service a04d08
            h.handle_part(
Packit Service a04d08
                data='data', ctype="!" + handlers.CONTENT_START,
Packit Service a04d08
                filename='part01',
Packit Service a04d08
                payload='## template: jinja   \t \n#!/bin/bash\n{{ topkey }}',
Packit Service a04d08
                frequency='freq', headers='headers')
Packit Service a04d08
        m_part.assert_called_once_with(
Packit Service a04d08
            'data', '!__begin__', 'part01', '#!/bin/bash\necho himom', 'freq')
Packit Service a04d08
Packit Service a04d08
    @skipUnlessJinja()
Packit Service a04d08
    def test_jinja_template_handle_subhandler_v3_with_clean_payload(self):
Packit Service a04d08
        """Call version 3 subhandler.handle_part with stripped payload."""
Packit Service a04d08
        cloudcfg_handler = CloudConfigPartHandler(self.paths)
Packit Service a04d08
        self.assertEqual(3, cloudcfg_handler.handler_version)
Packit Service a04d08
Packit Service a04d08
        # Create required instance-data.json file
Packit Service a04d08
        instance_json = os.path.join(self.run_dir, 'instance-data.json')
Packit Service a04d08
        instance_data = {'topkey': {'sub': 'runcmd: [echo hi]'}}
Packit Service a04d08
        util.write_file(instance_json, util.json_dumps(instance_data))
Packit Service a04d08
        h = JinjaTemplatePartHandler(
Packit Service a04d08
            self.paths, sub_handlers=[cloudcfg_handler])
Packit Service a04d08
        with mock.patch.object(cloudcfg_handler, 'handle_part') as m_part:
Packit Service a04d08
            # ctype with leading '!' not in handlers.CONTENT_SIGNALS
Packit Service a04d08
            h.handle_part(
Packit Service a04d08
                data='data', ctype="!" + handlers.CONTENT_END,
Packit Service a04d08
                filename='part01',
Packit Service a04d08
                payload='## template: jinja\n#cloud-config\n{{ topkey.sub }}',
Packit Service a04d08
                frequency='freq', headers='headers')
Packit Service a04d08
        m_part.assert_called_once_with(
Packit Service a04d08
            'data', '!__end__', 'part01', '#cloud-config\nruncmd: [echo hi]',
Packit Service a04d08
            'freq', 'headers')
Packit Service a04d08
Packit Service a04d08
    def test_jinja_template_handle_errors_on_missing_instance_data_json(self):
Packit Service a04d08
        """If instance-data is absent, raise an error from handle_part."""
Packit Service a04d08
        script_handler = ShellScriptPartHandler(self.paths)
Packit Service a04d08
        h = JinjaTemplatePartHandler(
Packit Service a04d08
            self.paths, sub_handlers=[script_handler])
Packit Service a04d08
        with self.assertRaises(RuntimeError) as context_manager:
Packit Service a04d08
            h.handle_part(
Packit Service a04d08
                data='data', ctype="!" + handlers.CONTENT_START,
Packit Service a04d08
                filename='part01',
Packit Service a04d08
                payload='## template: jinja  \n#!/bin/bash\necho himom',
Packit Service a04d08
                frequency='freq', headers='headers')
Packit Service a04d08
        script_file = os.path.join(script_handler.script_dir, 'part01')
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            'Cannot render jinja template vars. Instance data not yet present'
Packit Service a04d08
            ' at {}/instance-data.json'.format(
Packit Service a04d08
                self.run_dir), str(context_manager.exception))
Packit Service a04d08
        self.assertFalse(
Packit Service a04d08
            os.path.exists(script_file),
Packit Service a04d08
            'Unexpected file created %s' % script_file)
Packit Service a04d08
Packit Service a04d08
    def test_jinja_template_handle_errors_on_unreadable_instance_data(self):
Packit Service a04d08
        """If instance-data is unreadable, raise an error from handle_part."""
Packit Service a04d08
        script_handler = ShellScriptPartHandler(self.paths)
Packit Service a04d08
        instance_json = os.path.join(self.run_dir, 'instance-data.json')
Packit Service a04d08
        util.write_file(instance_json, util.json_dumps({}))
Packit Service a04d08
        h = JinjaTemplatePartHandler(
Packit Service a04d08
            self.paths, sub_handlers=[script_handler])
Packit Service a04d08
        with mock.patch(self.mpath + 'load_file') as m_load:
Packit Service a04d08
            with self.assertRaises(RuntimeError) as context_manager:
Packit Service a04d08
                m_load.side_effect = OSError(errno.EACCES, 'Not allowed')
Packit Service a04d08
                h.handle_part(
Packit Service a04d08
                    data='data', ctype="!" + handlers.CONTENT_START,
Packit Service a04d08
                    filename='part01',
Packit Service a04d08
                    payload='## template: jinja  \n#!/bin/bash\necho himom',
Packit Service a04d08
                    frequency='freq', headers='headers')
Packit Service a04d08
        script_file = os.path.join(script_handler.script_dir, 'part01')
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            'Cannot render jinja template vars. No read permission on'
Packit Service a04d08
            " '{rdir}/instance-data.json'. Try sudo".format(rdir=self.run_dir),
Packit Service a04d08
            str(context_manager.exception))
Packit Service a04d08
        self.assertFalse(
Packit Service a04d08
            os.path.exists(script_file),
Packit Service a04d08
            'Unexpected file created %s' % script_file)
Packit Service a04d08
Packit Service a04d08
    @skipUnlessJinja()
Packit Service a04d08
    def test_jinja_template_handle_renders_jinja_content(self):
Packit Service a04d08
        """When present, render jinja variables from instance-data.json."""
Packit Service a04d08
        script_handler = ShellScriptPartHandler(self.paths)
Packit Service a04d08
        instance_json = os.path.join(self.run_dir, 'instance-data.json')
Packit Service a04d08
        instance_data = {'topkey': {'subkey': 'echo himom'}}
Packit Service a04d08
        util.write_file(instance_json, util.json_dumps(instance_data))
Packit Service a04d08
        h = JinjaTemplatePartHandler(
Packit Service a04d08
            self.paths, sub_handlers=[script_handler])
Packit Service a04d08
        h.handle_part(
Packit Service a04d08
            data='data', ctype="!" + handlers.CONTENT_START,
Packit Service a04d08
            filename='part01',
Packit Service a04d08
            payload=(
Packit Service a04d08
                '## template: jinja  \n'
Packit Service a04d08
                '#!/bin/bash\n'
Packit Service a04d08
                '{{ topkey.subkey|default("nosubkey") }}'),
Packit Service a04d08
            frequency='freq', headers='headers')
Packit Service a04d08
        script_file = os.path.join(script_handler.script_dir, 'part01')
Packit Service a04d08
        self.assertNotIn(
Packit Service a04d08
            'Instance data not yet present at {}/instance-data.json'.format(
Packit Service a04d08
                self.run_dir),
Packit Service a04d08
            self.logs.getvalue())
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            '#!/bin/bash\necho himom', util.load_file(script_file))
Packit Service a04d08
Packit Service a04d08
    @skipUnlessJinja()
Packit Service a04d08
    def test_jinja_template_handle_renders_jinja_content_missing_keys(self):
Packit Service a04d08
        """When specified jinja variable is undefined, log a warning."""
Packit Service a04d08
        script_handler = ShellScriptPartHandler(self.paths)
Packit Service a04d08
        instance_json = os.path.join(self.run_dir, 'instance-data.json')
Packit Service a04d08
        instance_data = {'topkey': {'subkey': 'echo himom'}}
Packit Service a04d08
        util.write_file(instance_json, util.json_dumps(instance_data))
Packit Service a04d08
        h = JinjaTemplatePartHandler(
Packit Service a04d08
            self.paths, sub_handlers=[script_handler])
Packit Service a04d08
        h.handle_part(
Packit Service a04d08
            data='data', ctype="!" + handlers.CONTENT_START,
Packit Service a04d08
            filename='part01',
Packit Service a04d08
            payload='## template: jinja  \n#!/bin/bash\n{{ goodtry }}',
Packit Service a04d08
            frequency='freq', headers='headers')
Packit Service a04d08
        script_file = os.path.join(script_handler.script_dir, 'part01')
Packit Service a04d08
        self.assertTrue(
Packit Service a04d08
            os.path.exists(script_file),
Packit Service a04d08
            'Missing expected file %s' % script_file)
Packit Service a04d08
        self.assertIn(
Packit Service a04d08
            "WARNING: Could not render jinja template variables in file"
Packit Service a04d08
            " 'part01': 'goodtry'\n",
Packit Service a04d08
            self.logs.getvalue())
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestConvertJinjaInstanceData(CiTestCase):
Packit Service a04d08
Packit Service a04d08
    def test_convert_instance_data_hyphens_to_underscores(self):
Packit Service a04d08
        """Replace hyphenated keys with underscores in instance-data."""
Packit Service a04d08
        data = {'hyphenated-key': 'hyphenated-val',
Packit Service a04d08
                'underscore_delim_key': 'underscore_delimited_val'}
Packit Service a04d08
        expected_data = {'hyphenated_key': 'hyphenated-val',
Packit Service a04d08
                         'underscore_delim_key': 'underscore_delimited_val'}
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected_data,
Packit Service a04d08
            convert_jinja_instance_data(data=data))
Packit Service a04d08
Packit Service a04d08
    def test_convert_instance_data_promotes_versioned_keys_to_top_level(self):
Packit Service a04d08
        """Any versioned keys are promoted as top-level keys
Packit Service a04d08
Packit Service a04d08
        This provides any cloud-init standardized keys up at a top-level to
Packit Service a04d08
        allow ease of reference for users. Intsead of v1.availability_zone,
Packit Service a04d08
        the name availability_zone can be used in templates.
Packit Service a04d08
        """
Packit Service a04d08
        data = {'ds': {'dskey1': 1, 'dskey2': 2},
Packit Service a04d08
                'v1': {'v1key1': 'v1.1'},
Packit Service a04d08
                'v2': {'v2key1': 'v2.1'}}
Packit Service a04d08
        expected_data = copy.deepcopy(data)
Packit Service a04d08
        expected_data.update({'v1key1': 'v1.1', 'v2key1': 'v2.1'})
Packit Service a04d08
Packit Service a04d08
        converted_data = convert_jinja_instance_data(data=data)
Packit Service 751c4a
        self.assertCountEqual(
Packit Service a04d08
            ['ds', 'v1', 'v2', 'v1key1', 'v2key1'], converted_data.keys())
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected_data,
Packit Service a04d08
            converted_data)
Packit Service a04d08
Packit Service a04d08
    def test_convert_instance_data_most_recent_version_of_promoted_keys(self):
Packit Service a04d08
        """The most-recent versioned key value is promoted to top-level."""
Packit Service a04d08
        data = {'v1': {'key1': 'old v1 key1', 'key2': 'old v1 key2'},
Packit Service a04d08
                'v2': {'key1': 'newer v2 key1', 'key3': 'newer v2 key3'},
Packit Service a04d08
                'v3': {'key1': 'newest v3 key1'}}
Packit Service a04d08
        expected_data = copy.deepcopy(data)
Packit Service a04d08
        expected_data.update(
Packit Service a04d08
            {'key1': 'newest v3 key1', 'key2': 'old v1 key2',
Packit Service a04d08
             'key3': 'newer v2 key3'})
Packit Service a04d08
Packit Service a04d08
        converted_data = convert_jinja_instance_data(data=data)
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected_data,
Packit Service a04d08
            converted_data)
Packit Service a04d08
Packit Service a04d08
    def test_convert_instance_data_decodes_decode_paths(self):
Packit Service a04d08
        """Any decode_paths provided are decoded by convert_instance_data."""
Packit Service a04d08
        data = {'key1': {'subkey1': 'aGkgbW9t'}, 'key2': 'aGkgZGFk'}
Packit Service a04d08
        expected_data = copy.deepcopy(data)
Packit Service a04d08
        expected_data['key1']['subkey1'] = 'hi mom'
Packit Service a04d08
Packit Service a04d08
        converted_data = convert_jinja_instance_data(
Packit Service a04d08
            data=data, decode_paths=('key1/subkey1',))
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            expected_data,
Packit Service a04d08
            converted_data)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestRenderJinjaPayload(CiTestCase):
Packit Service a04d08
Packit Service a04d08
    with_logs = True
Packit Service a04d08
Packit Service a04d08
    @skipUnlessJinja()
Packit Service a04d08
    def test_render_jinja_payload_logs_jinja_vars_on_debug(self):
Packit Service a04d08
        """When debug is True, log jinja varables available."""
Packit Service a04d08
        payload = (
Packit Service a04d08
            '## template: jinja\n#!/bin/sh\necho hi from {{ v1.hostname }}')
Packit Service a04d08
        instance_data = {'v1': {'hostname': 'foo'}, 'instance-id': 'iid'}
Packit Service a04d08
        expected_log = dedent("""\
Packit Service a04d08
            DEBUG: Converted jinja variables
Packit Service a04d08
            {
Packit Service a04d08
             "hostname": "foo",
Packit Service a04d08
             "instance_id": "iid",
Packit Service a04d08
             "v1": {
Packit Service a04d08
              "hostname": "foo"
Packit Service a04d08
             }
Packit Service a04d08
            }
Packit Service a04d08
            """)
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            render_jinja_payload(
Packit Service a04d08
                payload=payload, payload_fn='myfile',
Packit Service a04d08
                instance_data=instance_data, debug=True),
Packit Service a04d08
            '#!/bin/sh\necho hi from foo')
Packit Service a04d08
        self.assertEqual(expected_log, self.logs.getvalue())
Packit Service a04d08
Packit Service a04d08
    @skipUnlessJinja()
Packit Service a04d08
    def test_render_jinja_payload_replaces_missing_variables_and_warns(self):
Packit Service a04d08
        """Warn on missing jinja variables and replace the absent variable."""
Packit Service a04d08
        payload = (
Packit Service a04d08
            '## template: jinja\n#!/bin/sh\necho hi from {{ NOTHERE }}')
Packit Service a04d08
        instance_data = {'v1': {'hostname': 'foo'}, 'instance-id': 'iid'}
Packit Service a04d08
        self.assertEqual(
Packit Service a04d08
            render_jinja_payload(
Packit Service a04d08
                payload=payload, payload_fn='myfile',
Packit Service a04d08
                instance_data=instance_data),
Packit Service a04d08
            '#!/bin/sh\necho hi from CI_MISSING_JINJA_VAR/NOTHERE')
Packit Service a04d08
        expected_log = (
Packit Service a04d08
            'WARNING: Could not render jinja template variables in file'
Packit Service a04d08
            " 'myfile': 'NOTHERE'")
Packit Service a04d08
        self.assertIn(expected_log, self.logs.getvalue())
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab