import textwrap
from typing import Sequence

from debputy.plugin.api.spec import DSD
from debputy.plugin.api.test_api import (
    build_virtual_file_system,
    package_metadata_context,
)
from debputy.plugin.api import virtual_path_def
from debputy.plugin.api.test_api.test_impl import initialize_plugin_under_test_preloaded
from debputy.plugin.api.test_api.test_spec import DetectedService
from debputy.plugin.debputy.debputy_plugin import initialize_debputy_features
from debputy.plugin.debputy.service_management import SystemdServiceContext


def test_debputy_packager_provided_files():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    ppf_by_stem = plugin.packager_provided_files_by_stem()
    # Verify that all the files are loaded
    assert set(ppf_by_stem.keys()) == {
        "tmpfiles",
        "sysusers",
        "bash-completion",
        "pam",
        "ppp.ip-up",
        "ppp.ip-down",
        "logrotate",
        "logcheck.cracking",
        "logcheck.violations",
        "logcheck.violations.ignore",
        "logcheck.ignore.workstation",
        "logcheck.ignore.server",
        "logcheck.ignore.paranoid",
        "mime",
        "sharedmimeinfo",
        "if-pre-up",
        "if-up",
        "if-down",
        "if-post-down",
        "cron.hourly",
        "cron.daily",
        "cron.weekly",
        "cron.monthly",
        "cron.yearly",
        "cron.d",
        "initramfs-hook",
        "modprobe",
        "gsettings-override",
        "lintian-overrides",
        "bug-script",
        "bug-control",
        "bug-presubj",
        "changelog",
        "NEWS",
        "copyright",
        "README.Debian",
        "TODO",
        "doc-base",
        "shlibs",
        "symbols",
        "alternatives",
        "init",
        "default",
        # dh_installsytemd
        "mount",
        "path",
        "service",
        "socket",
        "target",
        "timer",
        "@path",
        "@service",
        "@socket",
        "@target",
        "@timer",
    }
    # Verify the post_rewrite_hook
    assert (
        ppf_by_stem["logcheck.ignore.paranoid"].compute_dest("foo.bar")[1] == "foo_bar"
    )
    # Verify custom formats work
    assert ppf_by_stem["tmpfiles"].compute_dest("foo.bar")[1] == "foo.bar.conf"
    assert ppf_by_stem["sharedmimeinfo"].compute_dest("foo.bar")[1] == "foo.bar.xml"
    assert ppf_by_stem["modprobe"].compute_dest("foo.bar")[1] == "foo.bar.conf"
    assert (
        ppf_by_stem["gsettings-override"].compute_dest("foo.bar", assigned_priority=20)[
            1
        ]
        == "20_foo.bar.gschema.override"
    )


def test_debputy_docbase_naming() -> None:
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    doc_base_pff = plugin.packager_provided_files_by_stem()["doc-base"]
    fs_root = build_virtual_file_system(
        [virtual_path_def("foo.doc-base", content="Document: bar")]
    )
    _, basename = doc_base_pff.compute_dest("foo", path=fs_root["foo.doc-base"])
    assert basename == "foo.bar"


def test_debputy_adr_examples() -> None:
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    issues = plugin.automatic_discard_rules_examples_with_issues()
    assert not issues


def test_debputy_metadata_detector_gsettings_dependencies():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    # By default, the plugin will not add a substvars
    fs_root = build_virtual_file_system(["./bin/ls"])
    metadata = plugin.run_metadata_detector("gsettings-dependencies", fs_root)
    assert "misc:Depends" not in metadata.substvars

    # It will not react if there is only directories or non-files
    fs_root = build_virtual_file_system(["./usr/share/glib-2.0/schemas/some-dir/"])
    metadata = plugin.run_metadata_detector("gsettings-dependencies", fs_root)
    assert "misc:Depends" not in metadata.substvars

    # However, it will if there is a file beneath the schemas dir
    fs_root = build_virtual_file_system(["./usr/share/glib-2.0/schemas/foo.xml"])
    metadata = plugin.run_metadata_detector("gsettings-dependencies", fs_root)
    assert (
        metadata.substvars["misc:Depends"]
        == "dconf-gsettings-backend | gsettings-backend"
    )


def test_debputy_metadata_detector_initramfs_hooks():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    metadata_detector_id = "initramfs-hooks"

    # By default, the plugin will not add a trigger
    fs_root = build_virtual_file_system(["./bin/ls"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.triggers == []

    # It will not react if the directory is empty
    fs_root = build_virtual_file_system(
        [
            # Use an absolute path to verify that also work (it should and third-party plugin are likely
            # use absolute paths)
            "/usr/share/initramfs-tools/hooks/"
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.triggers == []

    # However, it will if there is a file beneath the schemas dir
    fs_root = build_virtual_file_system(["./usr/share/initramfs-tools/hooks/some-hook"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    result = [t.serialized_format() for t in metadata.triggers]
    assert result == ["activate-noawait update-initramfs"]


def test_debputy_metadata_detector_systemd_tmpfiles():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    metadata_detector_id = "systemd-tmpfiles"

    # By default, the plugin will not add anything
    fs_root = build_virtual_file_system(["./bin/ls"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    # It only reacts to ".conf" files
    fs_root = build_virtual_file_system(["./usr/lib/tmpfiles.d/foo"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    fs_root = build_virtual_file_system(
        [
            "./usr/lib/tmpfiles.d/foo.conf",
            "./etc/tmpfiles.d/foo.conf",
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    snippets = metadata.maintscripts()
    assert len(snippets) == 1
    snippet = snippets[0]
    assert snippet.maintscript == "postinst"
    assert snippet.registration_method == "on_configure"
    # The snippet should use "systemd-tmpfiles [...] --create foo.conf ..."
    assert "--create foo.conf" in snippet.plugin_provided_script
    # The "foo.conf" should only be listed once
    assert snippet.plugin_provided_script.count("foo.conf") == 1


def test_debputy_metadata_detector_systemd_sysusers():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    metadata_detector_id = "systemd-sysusers"

    # By default, the plugin will not add anything
    fs_root = build_virtual_file_system(["./bin/ls"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    # It only reacts to ".conf" files
    fs_root = build_virtual_file_system(["./usr/lib/sysusers.d/foo"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    fs_root = build_virtual_file_system(["./usr/lib/sysusers.d/foo.conf"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    snippets = metadata.maintscripts()
    assert len(snippets) == 1
    snippet = snippets[0]
    assert snippet.maintscript == "postinst"
    assert snippet.registration_method == "on_configure"
    # The snippet should use "systemd-sysusers [...] foo.conf ..."
    assert "systemd-sysusers" in snippet.plugin_provided_script
    assert "foo.conf" in snippet.plugin_provided_script
    # The "foo.conf" should only be listed once
    assert snippet.plugin_provided_script.count("foo.conf") == 1


def test_debputy_metadata_detector_xfonts():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    metadata_detector_id = "xfonts"

    # By default, the plugin will not add anything
    fs_root = build_virtual_file_system(["./bin/ls"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []
    assert "misc:Depends" not in metadata.substvars

    # It ignores files in the X11 dir and directories starting with ".".
    fs_root = build_virtual_file_system(
        ["./usr/share/fonts/X11/foo", "./usr/share/fonts/X11/.a/"]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []
    assert "misc:Depends" not in metadata.substvars

    fs_root = build_virtual_file_system(
        [
            "./usr/share/fonts/X11/some-font-dir/",
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    snippets = metadata.maintscripts()
    assert metadata.substvars["misc:Depends"] == "xfonts-utils"
    assert len(snippets) == 2
    assert set(s.maintscript for s in snippets) == {"postinst", "postrm"}
    postinst_snippet = metadata.maintscripts(maintscript="postinst")[0]
    postrm_snippet = metadata.maintscripts(maintscript="postrm")[0]

    assert postinst_snippet.maintscript == "postinst"
    assert postinst_snippet.registration_method == "unconditionally_in_script"
    assert (
        "update-fonts-scale some-font-dir"
        not in postinst_snippet.plugin_provided_script
    )
    assert "--x11r7-layout some-font-dir" in postinst_snippet.plugin_provided_script
    assert (
        f"update-fonts-alias --include" not in postinst_snippet.plugin_provided_script
    )

    assert postrm_snippet.maintscript == "postrm"
    assert postrm_snippet.registration_method == "unconditionally_in_script"
    assert (
        "update-fonts-scale some-font-dir" not in postrm_snippet.plugin_provided_script
    )
    assert "--x11r7-layout some-font-dir" in postrm_snippet.plugin_provided_script
    assert f"update-fonts-alias --exclude" not in postrm_snippet.plugin_provided_script


def test_debputy_metadata_detector_xfonts_scale_and_alias():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )

    metadata_detector_id = "xfonts"
    package_name = "bar"
    fs_root = build_virtual_file_system(
        [
            "./usr/share/fonts/X11/some-font-dir/",
            f"./etc/X11/xfonts/some-font-dir/{package_name}.scale",
            f"./etc/X11/xfonts/some-font-dir/{package_name}.alias",
        ]
    )
    metadata = plugin.run_metadata_detector(
        metadata_detector_id,
        fs_root,
        package_metadata_context(
            package_fields={
                "Package": package_name,
            }
        ),
    )
    snippets = metadata.maintscripts()
    assert metadata.substvars["misc:Depends"] == "xfonts-utils"
    assert len(snippets) == 2
    assert set(s.maintscript for s in snippets) == {"postinst", "postrm"}
    postinst_snippet = metadata.maintscripts(maintscript="postinst")[0]
    postrm_snippet = metadata.maintscripts(maintscript="postrm")[0]

    assert postinst_snippet.maintscript == "postinst"
    assert postinst_snippet.registration_method == "unconditionally_in_script"
    assert "update-fonts-scale some-font-dir" in postinst_snippet.plugin_provided_script
    assert "--x11r7-layout some-font-dir" in postinst_snippet.plugin_provided_script
    assert (
        f"update-fonts-alias --include /etc/X11/xfonts/some-font-dir/{package_name}.alias some-font-dir"
        in postinst_snippet.plugin_provided_script
    )

    assert postrm_snippet.maintscript == "postrm"
    assert postrm_snippet.registration_method == "unconditionally_in_script"
    assert "update-fonts-scale some-font-dir" in postrm_snippet.plugin_provided_script
    assert "--x11r7-layout some-font-dir" in postrm_snippet.plugin_provided_script
    assert (
        f"update-fonts-alias --exclude /etc/X11/xfonts/some-font-dir/{package_name}.alias some-font-dir"
        in postrm_snippet.plugin_provided_script
    )


def test_debputy_metadata_detector_icon_cache():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    metadata_detector_id = "icon-cache"
    icon_dir = "usr/share/icons"

    # By default, the plugin will not add anything
    fs_root = build_virtual_file_system(["./bin/ls"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    fs_root = build_virtual_file_system(
        [
            # Ignored subdirs (dh_icons ignores them too)
            f"./{icon_dir}/gnome/foo.png",
            f"./{icon_dir}/hicolor/foo.png",
            # Unknown image format, so it does not trigger the update-icon-caches call
            f"./{icon_dir}/subdir-a/unknown-image-format.img",
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    fs_root = build_virtual_file_system(
        [
            f"./{icon_dir}/subdir-a/foo.png",
            f"./{icon_dir}/subdir-b/subsubdir/bar.svg",
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    snippets = metadata.maintscripts()
    assert len(snippets) == 2
    assert set(s.maintscript for s in snippets) == {"postinst", "postrm"}
    postinst_snippet = metadata.maintscripts(maintscript="postinst")[0]
    postrm_snippet = metadata.maintscripts(maintscript="postrm")[0]

    assert postinst_snippet.registration_method == "on_configure"
    assert postrm_snippet.registration_method == "unconditionally_in_script"

    # Directory order is stable according to the BinaryPackagePath API.
    assert (
        f"update-icon-caches /{icon_dir}/subdir-a /{icon_dir}/subdir-b"
        in postinst_snippet.plugin_provided_script
    )
    assert (
        f"update-icon-caches /{icon_dir}/subdir-a /{icon_dir}/subdir-b"
        in postrm_snippet.plugin_provided_script
    )


def test_debputy_metadata_detector_kernel_modules():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    metadata_detector_id = "kernel-modules"
    module_dir = "lib/modules"

    # By default, the plugin will not add anything
    fs_root = build_virtual_file_system(["./bin/ls"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    fs_root = build_virtual_file_system(
        [
            # Ignore files directly in the path or with wrong extension
            f"./{module_dir}/README",
            f"./{module_dir}/3.11/ignored-file.txt",
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    fs_root = build_virtual_file_system(
        [
            f"./{module_dir}/3.11/foo.ko",
            f"./usr/{module_dir}/3.12/bar.ko.xz",
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    snippets = metadata.maintscripts()
    assert len(snippets) == 4  # Two for each version
    assert set(s.maintscript for s in snippets) == {"postinst", "postrm"}
    postinst_snippets = metadata.maintscripts(maintscript="postinst")
    postrm_snippets = metadata.maintscripts(maintscript="postrm")

    assert len(postinst_snippets) == 2
    assert len(postrm_snippets) == 2
    assert {s.registration_method for s in postinst_snippets} == {"on_configure"}
    assert {s.registration_method for s in postrm_snippets} == {
        "unconditionally_in_script"
    }

    assert (
        "depmod -a -F /boot/System.map-3.11 3.11"
        in postinst_snippets[0].plugin_provided_script
    )
    assert (
        "depmod -a -F /boot/System.map-3.12 3.12"
        in postinst_snippets[1].plugin_provided_script
    )

    assert (
        "depmod -a -F /boot/System.map-3.11 3.11"
        in postrm_snippets[0].plugin_provided_script
    )
    assert (
        "depmod -a -F /boot/System.map-3.12 3.12"
        in postrm_snippets[1].plugin_provided_script
    )


def test_debputy_metadata_detector_dpkg_shlibdeps():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    metadata_detector_id = "dpkg-shlibdeps"
    skip_root_dir = "usr/lib/debug/"

    # By default, the plugin will not add anything
    fs_root = build_virtual_file_system(
        [
            "./usr/share/doc/foo/copyright",
            virtual_path_def("./usr/lib/debuty/test.py", fs_path=__file__),
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert "shlibs:Depends" not in metadata.substvars

    fs_root = build_virtual_file_system(
        [
            # Verify that certain directories are skipped as promised
            virtual_path_def(f"./{skip_root_dir}/bin/ls", fs_path="/bin/ls")
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert "shlibs:Depends" not in metadata.substvars

    # But we detect ELF binaries elsewhere
    fs_root = build_virtual_file_system(
        [virtual_path_def(f"./bin/ls", fs_path="/bin/ls")]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    # Do not make assertions about the content of `shlibs:Depends` as
    # package name and versions change over time.
    assert "shlibs:Depends" in metadata.substvars

    # Re-run to verify it runs for udebs as well
    metadata = plugin.run_metadata_detector(
        metadata_detector_id,
        fs_root,
        context=package_metadata_context(
            package_fields={"Package-Type": "udeb"},
        ),
    )
    assert "shlibs:Depends" in metadata.substvars


def test_debputy_metadata_detector_pycompile_files():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    metadata_detector_id = "pycompile-files"
    module_dir = "usr/lib/python3/dist-packages"

    # By default, the plugin will not add anything
    fs_root = build_virtual_file_system(["./bin/ls"])
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    fs_root = build_virtual_file_system(
        [
            # Ignore files in unknown directories by default
            "./random-dir/foo.py",
            # Must be in "dist-packages" to count
            "./usr/lib/python3/foo.py",
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    assert metadata.maintscripts() == []

    fs_root = build_virtual_file_system(
        [
            f"./{module_dir}/debputy/foo.py",
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    snippets = metadata.maintscripts()
    assert len(snippets) == 2
    assert set(s.maintscript for s in snippets) == {"postinst", "prerm"}
    postinst_snippets = metadata.maintscripts(maintscript="postinst")
    prerm_snippets = metadata.maintscripts(maintscript="prerm")

    assert len(postinst_snippets) == 1
    assert len(prerm_snippets) == 1
    assert {s.registration_method for s in postinst_snippets} == {"on_configure"}
    assert {s.registration_method for s in prerm_snippets} == {
        "unconditionally_in_script"
    }

    assert "py3compile -p foo" in postinst_snippets[0].plugin_provided_script

    assert "py3clean -p foo" in prerm_snippets[0].plugin_provided_script


def test_debputy_metadata_detector_pycompile_files_private_package_dir():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    metadata_detector_id = "pycompile-files"
    module_dir = "usr/share/foo"

    fs_root = build_virtual_file_system(
        [
            f"./{module_dir}/debputy/foo.py",
        ]
    )
    metadata = plugin.run_metadata_detector(metadata_detector_id, fs_root)
    snippets = metadata.maintscripts()
    assert len(snippets) == 2
    assert set(s.maintscript for s in snippets) == {"postinst", "prerm"}
    postinst_snippets = metadata.maintscripts(maintscript="postinst")
    prerm_snippets = metadata.maintscripts(maintscript="prerm")

    assert len(postinst_snippets) == 1
    assert len(prerm_snippets) == 1
    assert {s.registration_method for s in postinst_snippets} == {"on_configure"}
    assert {s.registration_method for s in prerm_snippets} == {
        "unconditionally_in_script"
    }

    assert (
        f"py3compile -p foo /{module_dir}"
        in postinst_snippets[0].plugin_provided_script
    )

    assert "py3clean -p foo" in prerm_snippets[0].plugin_provided_script


def _extract_service(
    services: Sequence[DetectedService[DSD]], name: str
) -> DetectedService[DSD]:
    v = [s for s in services if name in s.names]
    assert len(v) == 1
    return v[0]


def test_system_service_detection() -> None:
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    systemd_service_root_dir = "usr/lib/systemd"
    systemd_service_system_dir = f"{systemd_service_root_dir}/system"
    systemd_service_user_dir = f"{systemd_service_root_dir}/user"

    services, _ = plugin.run_service_detection_and_integrations(
        "systemd", build_virtual_file_system([])
    )
    assert not services

    services, _ = plugin.run_service_detection_and_integrations(
        "systemd",
        build_virtual_file_system(
            [f"{systemd_service_system_dir}/", f"{systemd_service_user_dir}/"]
        ),
    )
    assert not services

    fs_root = build_virtual_file_system(
        [
            virtual_path_def(
                f"{systemd_service_system_dir}/foo.service",
                content=textwrap.dedent(
                    """\
            Alias="myname.service"
            [Install]
            """
                ),
            ),
            virtual_path_def(
                f"{systemd_service_system_dir}/foo@.service",
                content=textwrap.dedent(
                    """\
            # dh_installsystemd ignores template services - we do for now as well.
            Alias="ignored.service"
            [Install]
            """
                ),
            ),
            virtual_path_def(
                f"{systemd_service_system_dir}/alias.service", link_target="foo.service"
            ),
            virtual_path_def(f"{systemd_service_system_dir}/bar.timer", content=""),
        ]
    )
    services, metadata = plugin.run_service_detection_and_integrations(
        "systemd",
        fs_root,
        service_context_type_hint=SystemdServiceContext,
    )
    assert len(services) == 2
    assert {s.names[0] for s in services} == {"foo.service", "bar.timer"}
    foo_service = _extract_service(services, "foo.service")
    assert set(foo_service.names) == {
        "foo.service",
        "foo",
        "alias",
        "alias.service",
        "myname.service",
        "myname",
    }
    assert foo_service.type_of_service == "service"
    assert foo_service.service_scope == "system"
    assert foo_service.enable_by_default
    assert foo_service.start_by_default
    assert foo_service.default_upgrade_rule == "restart"
    assert foo_service.service_context.had_install_section

    bar_timer = _extract_service(services, "bar.timer")
    assert set(bar_timer.names) == {"bar.timer"}
    assert bar_timer.type_of_service == "timer"
    assert bar_timer.service_scope == "system"
    assert not bar_timer.enable_by_default
    assert bar_timer.start_by_default
    assert bar_timer.default_upgrade_rule == "restart"
    assert not bar_timer.service_context.had_install_section

    snippets = metadata.maintscripts()
    assert len(snippets) == 4
    postinsts = metadata.maintscripts(maintscript="postinst")
    assert len(postinsts) == 2
    enable_postinst, start_postinst = postinsts
    assert (
        "deb-systemd-helper debian-installed foo.service"
        in enable_postinst.plugin_provided_script
    )
    assert (
        "deb-systemd-invoke start foo.service" in start_postinst.plugin_provided_script
    )
    assert (
        "deb-systemd-invoke restart foo.service"
        in start_postinst.plugin_provided_script
    )


def test_sysv_service_detection() -> None:
    plugin = initialize_plugin_under_test_preloaded(
        1,
        initialize_debputy_features,
        plugin_name="debputy",
        load_debputy_plugin=False,
    )
    init_dir = "etc/init.d"

    services, _ = plugin.run_service_detection_and_integrations(
        "sysvinit", build_virtual_file_system([])
    )
    assert not services

    services, _ = plugin.run_service_detection_and_integrations(
        "sysvinit",
        build_virtual_file_system(
            [
                f"{init_dir}/",
            ]
        ),
    )
    assert not services

    services, _ = plugin.run_service_detection_and_integrations(
        "sysvinit",
        build_virtual_file_system(
            [
                virtual_path_def(
                    f"{init_dir}/README",
                    mode=0o644,
                ),
            ]
        ),
    )
    assert not services

    fs_root = build_virtual_file_system(
        [
            virtual_path_def(
                f"{init_dir}/foo",
                mode=0o755,
            ),
        ]
    )
    services, metadata = plugin.run_service_detection_and_integrations(
        "sysvinit", fs_root
    )
    assert len(services) == 1
    assert {s.names[0] for s in services} == {"foo"}
    foo_service = _extract_service(services, "foo")
    assert set(foo_service.names) == {"foo"}
    assert foo_service.type_of_service == "service"
    assert foo_service.service_scope == "system"
    assert foo_service.enable_by_default
    assert foo_service.start_by_default
    assert foo_service.default_upgrade_rule == "restart"

    snippets = metadata.maintscripts()
    assert len(snippets) == 4
    postinsts = metadata.maintscripts(maintscript="postinst")
    assert len(postinsts) == 1
    postinst = postinsts[0]
    assert postinst.registration_method == "on_configure"
    assert "" in postinst.plugin_provided_script
    assert "update-rc.d foo defaults" in postinst.plugin_provided_script
    assert (
        "invoke-rc.d --skip-systemd-native foo start" in postinst.plugin_provided_script
    )
    assert (
        "invoke-rc.d --skip-systemd-native foo restart"
        in postinst.plugin_provided_script
    )
