def test_retrieve_binaries_data(self):
        features.register(DockerFeature())
        load_registered_features()
        action = actions.get(
            'docker:display-info')  # type:DockerDisplayInfoAction

        assert [] == action._retrieve_binaries_data(Dotty({}))
        assert [] == action._retrieve_binaries_data(Dotty({'toto': 'toto'}))
        assert [] == action._retrieve_binaries_data(
            Dotty({'labels': {
                'toto': '123'
            }}))
        assert ['npm-simple'] == action._retrieve_binaries_data(
            Dotty({
                'labels': {
                    'ddb.emit.docker:binary[npm-simple](name)': 'npm-simple',
                    'ddb.emit.docker:binary[npm-simple](workdir)': '/app'
                }
            }))
        assert ['npm', 'npm-simple'] == sorted(
            action._retrieve_binaries_data(
                Dotty({
                    'labels': {
                        'ddb.emit.docker:binary[npm](name)': 'npm',
                        'ddb.emit.docker:binary[npm-simple](name)':
                        'npm-simple',
                        'ddb.emit.docker:binary[npm-simple](workdir)': '/app'
                    }
                })))
    def test_execute_extra_services(self, capsys: CaptureFixture,
                                    project_loader):
        project_loader("extra-services")

        features.register(DockerFeature())
        features.register(TraefikFeature())
        load_registered_features()
        config.args.type = None
        action = actions.get(
            'docker:display-info')  # type:DockerDisplayInfoAction
        action.execute()

        capture = capsys.readouterr()
        assert capture.out
        assert not capture.err
        assert ('\n'.join([
            '+-------------------------+', '| web                     |',
            '+-------------------------+', '| https://web.domain.tld/ |',
            '+-------------------------+', '',
            '+-----------------------------------------------+',
            '| foo (extra)                                   |',
            '+-----------------------------------------------+',
            '| https://sub.test --> http://192.168.99.1:8080 |',
            '+-----------------------------------------------+', '\n'
        ])) == capture.out
    def test_extra_services(self, project_loader):
        project_loader("extra-services")

        features.register(CoreFeature())
        features.register(TraefikFeature())
        features.register(DockerFeature())
        features.register(JsonnetFeature())
        load_registered_features()

        install_action = TraefikExtraServicesAction()
        install_action.initialize()
        install_action.execute()

        files = {
            "api": {
                "generated": "sub.project.test.extra-service.api.toml",
                "expected": "sub.project.test.extra-service.api.expected.toml"
            },
            "rule": {
                "generated": "rule.project.test.extra-service.web.toml",
                "expected":
                "rule.project.test.extra-service.web.expected.toml",
                "replaces": {
                    "{{ip}}": config.data.get('docker.debug.host')
                }
            },
            "secured": {
                "generated":
                "secured.project.test.extra-service.redirect.toml",
                "expected":
                "secured.project.test.extra-service.redirect.expected.toml"
            },
            "secured_path_prefix": {
                "generated":
                "secured.project.test.extra-service.path_prefix.toml",
                "expected":
                "secured.project.test.extra-service.path_prefix.expected.toml"
            },
            "secured_path_prefix_with_redirect": {
                "generated":
                "secured.project.test.extra-service.path_prefix_with_redirect.toml",
                "expected":
                "secured.project.test.extra-service.path_prefix_with_redirect.expected.toml"
            }
        }

        for file in files:
            generated = os.path.join(
                config.data['traefik']['config_directory'],
                files.get(file).get('generated'))
            assert os.path.exists(generated)
            expected = Path(
                os.path.join(config.data['traefik']['config_directory'],
                             files.get(file).get('expected'))).read_text()
            if files.get(file).get('replaces'):
                for replace in files.get(file).get('replaces'):
                    expected = expected.replace(
                        replace,
                        files.get(file).get('replaces').get(replace))
            assert expected == Path(generated).read_text()
    def test_empty_project_without_core(self, project_loader):
        project_loader("empty")

        features.register(DockerFeature())
        load_registered_features()

        action = actions.get('docker:emit-docker-compose-config'
                             )  # type:EmitDockerComposeConfigAction
        action.execute()
    def test_binary_options(self, project_loader):
        project_loader("binary-options")

        features.register(DockerFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        action = actions.get('docker:emit-docker-compose-config'
                             )  # type:EmitDockerComposeConfigAction
        action.execute()

        assert len(list(binaries.all())) == 3
        assert binaries.has("npm-simple")
        assert binaries.has("npm-conditions")
        assert binaries.has("mysql")

        npm_simple_set = binaries.get("npm-simple")
        assert len(npm_simple_set) == 1
        npm_simple = list(npm_simple_set)[0]
        assert npm_simple.command() == (
            ''.join(effective_command("docker-compose")) +
            " run --rm --workdir=/app/. --label traefik.enable=false node"
        ).split()
        assert npm_simple.command("serve") == (
            ''.join(effective_command("docker-compose")) +
            ' run --rm --workdir=/app/. --label traefik.enable=false node'
        ).split()
        assert npm_simple.command("run serve") == (
            ''.join(effective_command("docker-compose")) +
            ' run --rm --workdir=/app/. --label traefik.enable=false node'
        ).split()

        npm_conditions_set = binaries.get("npm-conditions")
        assert len(npm_conditions_set) == 1
        npm_conditions = list(npm_conditions_set)[0]
        assert npm_conditions.command() == (
            ''.join(effective_command("docker-compose")) +
            " run --rm --workdir=/app/. --label traefik.enable=false node"
        ).split()
        assert npm_conditions.command("serve") == (
            ''.join(effective_command("docker-compose")) +
            ' run --rm --workdir=/app/. --label traefik.enable=false node'
        ).split()
        assert npm_conditions.command("run serve") == (
            ''.join(effective_command("docker-compose")) +
            ' run --rm --workdir=/app/. node').split()

        mysql_set = binaries.get("mysql")
        assert len(mysql_set) == 1
        mysql = list(mysql_set)[0]
        assert mysql.command() == (
            ''.join(effective_command("docker-compose")) +
            ' run --rm --workdir=/app/. db mysql -hdb -uproject-management-tool -pproject-management-tool'
        ).split()
    def test_binary_workdir(self, project_loader):
        project_loader("binary-workdir")

        features.register(DockerFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        action = actions.get('docker:emit-docker-compose-config'
                             )  # type:EmitDockerComposeConfigAction
        action.execute()

        assert len(list(binaries.all())) == 2
        assert binaries.has("npm")
        assert binaries.has("node")
    def test_retrieve_environment_data(self):
        features.register(DockerFeature())
        load_registered_features()
        action = actions.get(
            'docker:display-info')  # type:DockerDisplayInfoAction

        assert {} == action._retrieve_environment_data(Dotty({}))
        assert {} == action._retrieve_environment_data(Dotty({'toto': 'toto'}))
        assert {
            'AZERTY': '123'
        } == action._retrieve_environment_data(
            Dotty({'environment': {
                'AZERTY': '123'
            }}))
    def test_local_volume_related(self, project_loader):
        project_loader("local-volume-related")

        features.register(DockerFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        action = actions.get('docker:emit-docker-compose-config'
                             )  # type:EmitDockerComposeConfigAction
        action.execute()

        assert not os.path.exists('node-path')
        assert os.path.isdir('new_directory')
        assert os.path.isdir('child')
        assert os.path.isdir(os.path.join('new_directory', 'some', 'child'))
    def test_extra_services_redirect(self, project_loader):
        project_loader("extra-services-redirect")

        features.register(CoreFeature())
        features.register(TraefikFeature())
        features.register(DockerFeature())
        features.register(JsonnetFeature())
        load_registered_features()

        install_action = TraefikExtraServicesAction()
        install_action.initialize()
        install_action.execute()

        api_toml = os.path.join(config.data['traefik']['config_directory'],
                                "sub.project.test.extra-service.api.toml")
        assert os.path.exists(api_toml)

        api_toml_expected = Path(
            os.path.join(config.data['traefik']['config_directory'],
                         "sub.project.test.extra-service.api.expected.toml"))

        assert api_toml_expected.read_text() == Path(api_toml).read_text()

        web_toml = os.path.join(config.data['traefik']['config_directory'],
                                "rule.project.test.extra-service.web.toml")
        assert os.path.exists(web_toml)

        web_toml_expected = Path(
            os.path.join(config.data['traefik']['config_directory'],
                         "rule.project.test.extra-service.web.expected.toml"))

        assert web_toml_expected.read_text().replace(
            '{{ip}}', config.data.get('docker.debug.host')) == Path(
                web_toml).read_text()

        secured_toml = os.path.join(
            config.data['traefik']['config_directory'],
            "secured.project.test.extra-service.no-redirect.toml")
        assert os.path.exists(secured_toml)

        secured_toml_expected = Path(
            os.path.join(
                config.data['traefik']['config_directory'],
                "secured.project.test.extra-service.no-redirect.expected.toml")
        )

        assert secured_toml_expected.read_text() == Path(
            secured_toml).read_text()
Example #10
0
    def test_docker_compose_variants(self, project_loader, variant):
        project_loader("docker_compose" + variant)

        features.register(CoreFeature())
        features.register(FileFeature())
        features.register(DockerFeature())
        features.register(JsonnetFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        action = FileWalkAction()
        action.initialize()
        action.execute()

        assert os.path.exists('docker-compose.yml')
        with open('docker-compose.yml', 'r') as f:
            rendered = yaml.load(f.read(), yaml.SafeLoader)

        with open('docker-compose.expected.yml', 'r') as f:
            expected_data = f.read()

            if os.name == 'nt':
                mapped_cwd = re.sub(r"^([a-zA-Z]):", r"/\1", os.getcwd())
                mapped_cwd = pathlib.Path(mapped_cwd).as_posix()

                expected_data = expected_data.replace("%ddb.path.project%",
                                                      mapped_cwd)
            else:
                expected_data = expected_data.replace("%ddb.path.project%",
                                                      os.getcwd())
            expected_data = expected_data.replace(
                "%uid%", str(config.data.get('docker.user.uid')))
            expected_data = expected_data.replace(
                "%gid%", str(config.data.get('docker.user.gid')))
            expected_data = expected_data.replace(
                "%docker.debug.host%",
                str(config.data.get('docker.debug.host')))

            expected = yaml.load(expected_data, yaml.SafeLoader)

        assert rendered == expected

        if variant == '_mount_single_volume':
            assert os.path.isdir('volumes/shared-volume')

        if variant == '_mount_single_volume_with_default':
            assert os.path.isdir('shared-volume')
Example #11
0
    def test_docker_compose_traefik_defaults(self, project_loader, variant):
        def before_load_config():
            os.rename("ddb.%s.yml" % variant, "ddb.yml")
            os.rename("docker-compose.expected.%s.yml" % variant,
                      "docker-compose.expected.yml")

        project_loader("docker_compose_traefik_defaults", before_load_config)

        features.register(CoreFeature())
        features.register(FileFeature())
        features.register(DockerFeature())
        features.register(JsonnetFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        action = FileWalkAction()
        action.initialize()
        action.execute()

        assert os.path.exists('docker-compose.yml')
        with open('docker-compose.yml', 'r') as f:
            rendered = yaml.load(f.read(), yaml.SafeLoader)

        with open('docker-compose.expected.yml', 'r') as f:
            expected_data = f.read()

            if os.name == 'nt':
                mapped_cwd = re.sub(r"^([a-zA-Z]):", r"/\1", os.getcwd())
                mapped_cwd = pathlib.Path(mapped_cwd).as_posix()

                expected_data = expected_data.replace("%ddb.path.project%",
                                                      mapped_cwd)
            else:
                expected_data = expected_data.replace("%ddb.path.project%",
                                                      os.getcwd())
            expected_data = expected_data.replace(
                "%uid%", str(config.data.get('docker.user.uid')))
            expected_data = expected_data.replace(
                "%gid%", str(config.data.get('docker.user.gid')))
            expected_data = expected_data.replace(
                "%docker.debug.host%",
                str(config.data.get('docker.debug.host')))

            expected = yaml.load(expected_data, yaml.SafeLoader)

        assert rendered == expected
    def test_retrieve_vhosts_data(self):
        features.register(DockerFeature())
        load_registered_features()
        action = actions.get(
            'docker:display-info')  # type:DockerDisplayInfoAction

        assert [] == action._retrieve_vhosts_data(Dotty({}))
        assert [] == action._retrieve_vhosts_data(Dotty({'toto': 'toto'}))
        assert [] == action._retrieve_vhosts_data(
            Dotty({'labels': {
                'toto': '123'
            }}))
        assert ['http://web.domain.tld/'] == action._retrieve_vhosts_data(
            Dotty({
                'labels': {
                    'traefik.http.routers.defaults-project.rule':
                    'Host(`web.domain.tld`)',
                    'ddb.emit.docker:binary[npm-simple](workdir)': '/app'
                }
            }))
        assert ['http://test.tld/',
                'http://web.domain.tld/'] == sorted(
                    action._retrieve_vhosts_data(
                        Dotty({
                            'labels': {
                                'traefik.http.routers.defaults-project.rule':
                                'Host(`web.domain.tld`)',
                                'traefik.http.routers.test-project.rule':
                                'Host(`test.tld`)',
                                'ddb.emit.docker:binary[npm-simple](workdir)':
                                '/app'
                            }
                        })))
        assert ['http://test.tld/', 'https://web.domain.tld/'] == sorted(
            action._retrieve_vhosts_data(
                Dotty({
                    'labels': {
                        'traefik.http.routers.defaults-project.rule':
                        'Host(`web.domain.tld`)',
                        'traefik.http.routers.defaults-project-tls.rule':
                        'Host(`web.domain.tld`)',
                        'traefik.http.routers.test-project.rule':
                        'Host(`test.tld`)',
                        'ddb.emit.docker:binary[npm-simple](workdir)': '/app'
                    }
                })))
    def test_execute_traefik_cert(self, capsys: CaptureFixture,
                                  project_loader):
        project_loader("traefik-cert")

        features.register(DockerFeature())
        load_registered_features()
        config.args.type = None
        action = actions.get(
            'docker:display-info')  # type:DockerDisplayInfoAction
        action.execute()

        capture = capsys.readouterr()
        assert capture.out
        assert not capture.err
        assert ('\n'.join([
            '+-------------------------+', '| web                     |',
            '+-------------------------+', '| https://web.domain.tld/ |',
            '+-------------------------+', '\n'
        ])) == capture.out
    def test_emit_one_arg(self, project_loader):
        project_loader("emit-one-arg")

        features.register(DockerFeature())
        load_registered_features()

        custom_event_listeners = []

        def listener(data):
            custom_event_listeners.append(data)

        bus.on("some:test", listener)

        action = actions.get('docker:emit-docker-compose-config'
                             )  # type:EmitDockerComposeConfigAction
        action.execute()

        assert len(custom_event_listeners) == 1
        assert custom_event_listeners[0] == "emit-one-arg"
    def test_local_volume_simple(self, project_loader):
        project_loader("local-volume-simple")

        features.register(DockerFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        action = actions.get('docker:emit-docker-compose-config'
                             )  # type:EmitDockerComposeConfigAction
        action.execute()

        assert not os.path.exists('node-path')
        assert os.path.isdir('existing-directory')
        assert os.path.isdir('new_directory')
        assert os.path.isfile('existing-file.txt')
        assert os.path.isfile('new_file')
        assert os.path.isfile('another_new_file.txt')

        with open('existing-file.txt', 'r') as f:
            assert f.read() == 'existing-file.txt'
    def test_retrieve_ports_data(self):
        features.register(DockerFeature())
        load_registered_features()
        action = actions.get(
            'docker:display-info')  # type:DockerDisplayInfoAction

        assert [] == action._retrieve_service_ports(Dotty({}))
        assert [] == action._retrieve_service_ports(Dotty({'toto': 'toto'}))
        assert [ServicePort(45, 123, None, None, None)
                ] == action._retrieve_service_ports(
                    Dotty({'ports': [{
                        'published': '123',
                        'target': '45'
                    }]}))
        assert [ServicePort(45, 123, None, None,
                            None)] == action._retrieve_service_ports(
                                Dotty({'ports': ['123:45']}))
        assert [ServicePort(45, 123, 'tcp', None,
                            None)] == action._retrieve_service_ports(
                                Dotty({'ports': ['123:45/tcp']}))
Example #17
0
    def test_autofix_variables_only(self, project_loader):
        project_loader("autofix_variables_only")

        config.args.autofix = True

        history = (
            PropertyMigration("old_property", "new_property", since="v1.1.0"),
            PropertyMigration("some.deep.old.property",
                              "some.another.new.property",
                              since="v1.1.0"),
        )

        migrations.set_history(history)

        features.register(CoreFeature())
        features.register(FileFeature())
        features.register(DockerFeature())
        features.register(JsonnetFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        action = FileWalkAction()
        action.initialize()
        action.execute()

        assert os.path.exists('variables.json')
        with open('variables.json', 'r') as f:
            rendered = f.read()

        with open('variables.expected.json', 'r') as f:
            expected = f.read()

        assert expected == rendered

        with open('variables.json.jsonnet', 'r') as f:
            source = f.read()

        with open('variables.json.autofix', 'r') as f:
            fixed = f.read()

        assert source == fixed
    def test_emit_complex(self, project_loader):
        project_loader("emit-complex")

        features.register(DockerFeature())
        load_registered_features()

        some_events = []
        another_events = []

        def someListener(*args, **kwargs):
            some_events.append({"args": args, "kwargs": kwargs})

        def anotherListener(*args, **kwargs):
            another_events.append({"args": args, "kwargs": kwargs})

        bus.on("some:test", someListener)
        bus.on("another:test", anotherListener)

        action = actions.get('docker:emit-docker-compose-config'
                             )  # type:EmitDockerComposeConfigAction
        action.execute()

        assert len(some_events) == 3
        assert {"args": ("emit-one-arg", ), "kwargs": {}} in some_events
        assert {"args": ("emit-one-arg-2", ), "kwargs": {}} in some_events
        # docker-compose >= 1.27.0 returns major version only. see https://github.com/docker/compose/issues/7730
        assert {"args": ("emit-some-arg",),
                "kwargs": {'image': 'ubuntu', 'kw1': 'emit-one-kwarg', 'kw2': 7, 'version': '3.7'}} in some_events or \
               {"args": ("emit-some-arg",),
                "kwargs": {'image': 'ubuntu', 'kw1': 'emit-one-kwarg', 'kw2': 7, 'version': '3'}} in some_events

        assert len(another_events) == 2
        assert {"args": ("emit-another-arg", ), "kwargs": {}} in another_events
        assert {
            "args": (),
            "kwargs": {
                "kw1": "emit-another-kwarg"
            }
        } in another_events
Example #19
0
    def test_docker_compose_xdebug(self, project_loader, variant):
        def before_load_config():
            os.rename("ddb.%s.yml" % variant, "ddb.yml")
            os.rename("docker-compose.expected.%s.yml" % variant,
                      "docker-compose.expected.yml")

        project_loader("docker_compose_xdebug", before_load_config)

        print(os.getcwd())

        features.register(CoreFeature())
        features.register(FileFeature())
        features.register(DockerFeature())
        features.register(JsonnetFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        action = FileWalkAction()
        action.initialize()
        action.execute()

        assert os.path.exists('docker-compose.yml')
        with open('docker-compose.yml', 'r') as f:
            rendered = yaml.load(f.read(), yaml.SafeLoader)

        with open('docker-compose.expected.yml', 'r') as f:
            expected_data = f.read()

            expected_data = expected_data.replace(
                "%uid%", str(config.data.get('docker.user.uid')))
            expected_data = expected_data.replace(
                "%gid%", str(config.data.get('docker.user.gid')))
            expected_data = expected_data.replace(
                "%docker.debug.host%",
                str(config.data.get('docker.debug.host')))

            expected = yaml.load(expected_data, yaml.SafeLoader)

        assert rendered == expected
Example #20
0
    def test_docker_compose_included_services(self, project_loader):
        project_loader("docker_compose_included_services")

        features.register(CoreFeature())
        features.register(FileFeature())
        features.register(DockerFeature())
        features.register(JsonnetFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        action = FileWalkAction()
        action.initialize()
        action.execute()

        assert os.path.exists('docker-compose.yml')
        with open('docker-compose.yml', 'r') as f:
            rendered = yaml.load(f.read(), yaml.SafeLoader)

        with open('docker-compose.expected.yml', 'r') as f:
            expected_data = f.read()
            expected = yaml.load(expected_data, yaml.SafeLoader)

        assert rendered == expected
    def test_ubuntu(self, project_loader):
        project_loader("ubuntu")

        features.register(DockerFeature())
        load_registered_features()

        custom_event_listeners = []

        def listener(docker_compose_config):
            custom_event_listeners.append(docker_compose_config)

        bus.on("docker:docker-compose-config", listener)

        action = actions.get('docker:emit-docker-compose-config'
                             )  # type:EmitDockerComposeConfigAction
        action.execute()

        assert len(custom_event_listeners) == 1
        assert custom_event_listeners[0] in [
            # docker-compose >= 1.27.0 returns major version only. see https://github.com/docker/compose/issues/7730
            {
                "version": "3",
                "services": {
                    "docker": {
                        "image": "ubuntu"
                    }
                }
            },
            {
                "version": "3.7",
                "services": {
                    "docker": {
                        "image": "ubuntu"
                    }
                }
            }
        ]
    def test_output_data(self, project_loader):
        features.register(DockerFeature())
        load_registered_features()
        action = actions.get(
            'docker:display-info')  # type:DockerDisplayInfoAction

        config.args.type = None

        assert '' == action._output_data('test', dict(), [], [], [])

        test_vhosts = action._retrieve_vhosts_data(
            Dotty({
                'labels': {
                    'traefik.http.routers.defaults-project.rule':
                    'Host(`web.domain.tld`)',
                    'traefik.http.routers.defaults-project-tls.rule':
                    'Host(`web.domain.tld`)',
                    'traefik.http.routers.test-project.rule':
                    'Host(`test.tld`)',
                    'ddb.emit.docker:binary[npm-simple](workdir)': '/app'
                }
            }))

        assert ('\n'.join([
            '+-------------------------+', '| test                    |',
            '+-------------------------+', '| http://test.tld/        |',
            '| https://web.domain.tld/ |', '+-------------------------+'
        ])) == action._output_data('test', dict(), [], [], test_vhosts)

        test_binaries = action._retrieve_binaries_data(
            Dotty({
                'labels': {
                    'ddb.emit.docker:binary[npm](name)': 'npm',
                    'ddb.emit.docker:binary[npm-simple](name)': 'npm-simple',
                    'ddb.emit.docker:binary[npm-simple](workdir)': '/app'
                }
            }))

        assert ('\n'.join([
            '+-------------------------+', '| test                    |',
            '+-------------------------+', '| npm                     |',
            '| npm-simple              |', '+-------------------------+',
            '| http://test.tld/        |', '| https://web.domain.tld/ |',
            '+-------------------------+'
        ])) == action._output_data('test', dict(), [], test_binaries,
                                   test_vhosts)

        test_envs = action._retrieve_environment_data(
            Dotty({'environment': {
                'AZERTY': '123'
            }}))
        assert ('\n'.join([
            '+-------------------------+', '| test                    |',
            '+-------------------------+', '| AZERTY: 123             |',
            '+-------------------------+', '| npm                     |',
            '| npm-simple              |', '+-------------------------+',
            '| http://test.tld/        |', '| https://web.domain.tld/ |',
            '+-------------------------+'
        ])) == action._output_data('test', test_envs, [], test_binaries,
                                   test_vhosts)

        test_ports = action._retrieve_service_ports(
            Dotty({'ports': [{
                'published': '12123',
                'target': '123'
            }]}))
        assert ('\n'.join([
            '+-------------------------+', '| test                    |',
            '+-------------------------+', '| AZERTY: 123             |',
            '+-------------------------+', '| 12123:123/tcp           |',
            '+-------------------------+', '| npm                     |',
            '| npm-simple              |', '+-------------------------+',
            '| http://test.tld/        |', '| https://web.domain.tld/ |',
            '+-------------------------+'
        ])) == action._output_data('test', test_envs, test_ports,
                                   test_binaries, test_vhosts)

        config.args.type = 'nothing'
        assert '' == action._output_data('test', dict(), [], [], test_vhosts)

        config.args.type = 'vhost'
        assert ('\n'.join([
            '+-------------------------+', '| test                    |',
            '+-------------------------+', '| http://test.tld/        |',
            '| https://web.domain.tld/ |', '+-------------------------+'
        ])) == action._output_data('test', dict(), [], [], test_vhosts)
    def test_traefik_cert(self, project_loader,
                          module_scoped_container_getter):
        project_loader("traefik-cert")

        features.register(CertsFeature())
        features.register(TraefikFeature())
        features.register(DockerFeature())
        load_registered_features()
        register_actions_in_event_bus(True)

        setup_cfssl(module_scoped_container_getter)

        shutil.copyfile("docker-compose.yml", "docker-compose.original.yml")

        action = actions.get('docker:emit-docker-compose-config'
                             )  # type:EmitDockerComposeConfigAction
        action.execute()

        assert os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web.domain.tld.key"))
        assert os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web.domain.tld.crt"))
        assert os.path.exists(
            os.path.join(config.paths.home, "certs", "web.domain.tld.key"))
        assert os.path.exists(
            os.path.join(config.paths.home, "certs", "web.domain.tld.crt"))
        assert os.path.exists(
            os.path.join(config.paths.home, "traefik", "config",
                         "web.domain.tld.ssl.toml"))

        shutil.copyfile("docker-compose.removed.yml", "docker-compose.yml")
        action.execute()

        assert not os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web.domain.tld.key"))
        assert not os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web.domain.tld.crt"))
        assert not os.path.exists(
            os.path.join(config.paths.home, "certs", "web.domain.tld.key"))
        assert not os.path.exists(
            os.path.join(config.paths.home, "certs", "web.domain.tld.crt"))
        assert not os.path.exists(
            os.path.join(config.paths.home, "traefik", "config",
                         "web.domain.tld.ssl.toml"))

        shutil.copyfile("docker-compose.original.yml", "docker-compose.yml")
        action.execute()

        assert os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web.domain.tld.key"))
        assert os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web.domain.tld.crt"))
        assert os.path.exists(
            os.path.join(config.paths.home, "certs", "web.domain.tld.key"))
        assert os.path.exists(
            os.path.join(config.paths.home, "certs", "web.domain.tld.crt"))
        assert os.path.exists(
            os.path.join(config.paths.home, "traefik", "config",
                         "web.domain.tld.ssl.toml"))

        shutil.copyfile("docker-compose.changed.yml", "docker-compose.yml")
        action.execute()

        assert not os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web.domain.tld.key"))
        assert not os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web.domain.tld.crt"))
        assert not os.path.exists(
            os.path.join(config.paths.home, "certs", "web.domain.tld.key"))
        assert not os.path.exists(
            os.path.join(config.paths.home, "certs", "web.domain.tld.crt"))
        assert not os.path.exists(
            os.path.join(config.paths.home, "traefik", "config",
                         "web.domain.tld.ssl.toml"))

        assert os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web-changed.domain.tld.key"))
        assert os.path.exists(
            os.path.join(config.paths.project_home, ".certs",
                         "web-changed.domain.tld.crt"))
        assert os.path.exists(
            os.path.join(config.paths.home, "certs",
                         "web-changed.domain.tld.key"))
        assert os.path.exists(
            os.path.join(config.paths.home, "certs",
                         "web-changed.domain.tld.crt"))
        assert os.path.exists(
            os.path.join(config.paths.home, "traefik", "config",
                         "web-changed.domain.tld.ssl.toml"))