Exemple #1
0
def test_for_git_failures(git_modules_dir, modules_repo):
    coroot = os.path.join(git_modules_dir, "testproject2")
    subprocess.check_output(
        [
            "git", "clone",
            os.path.join(git_modules_dir, "repos", "testproject"),
            "testproject2"
        ],
        cwd=git_modules_dir,
        stderr=subprocess.STDOUT,
    )
    os.chdir(coroot)
    Config.load_config()

    ProjectTool().execute("install", [])

    gp = module.gitprovider
    module.gitprovider = BadModProvider(gp,
                                        os.path.join(coroot, "libs", "mod6"))
    try:
        # test all tools, perhaps isolate to other test case
        ProjectTool().execute("install", [])
        ModuleTool().execute("list", [])
        ModuleTool().execute("update", [])
        ModuleTool().execute("status", [])
        ModuleTool().execute("push", [])
    finally:
        module.gitprovider = gp
Exemple #2
0
def test_complex_checkout(git_modules_dir, modules_repo):
    coroot = os.path.join(git_modules_dir, "testproject")
    subprocess.check_output([
        "git", "clone",
        os.path.join(git_modules_dir, "repos", "testproject")
    ],
                            cwd=git_modules_dir,
                            stderr=subprocess.STDOUT)
    os.chdir(coroot)
    Config.load_config()

    ProjectTool().execute("install", [])
    expected = ["mod1", "mod2", "mod3", "mod6", "mod7"]
    for i in expected:
        dirname = os.path.join(coroot, "libs", i)
        assert os.path.exists(os.path.join(dirname, "signal"))
        assert not os.path.exists(os.path.join(dirname, "badsignal"))

    assert not os.path.exists(os.path.join(coroot, "libs", "mod5"))

    # test all tools, perhaps isolate to other test case
    ModuleTool().execute("list", [])
    ModuleTool().execute("update", [])
    ModuleTool().execute("status", [])
    ModuleTool().execute("push", [])
Exemple #3
0
def test_module_update_dependencies(
    tmpdir: py.path.local,
    monkeypatch,
    snippetcompiler_clean,
    modules_dir: str,
) -> None:
    """
    Verify that `inmanta project update` correctly handles module's Python dependencies:
        - update should include install
        - update should update Python dependencies within module's constraints
        - update should update transitive Python dependencies
    """
    snippetcompiler_clean.setup_for_snippet(
        snippet="import my_mod",
        autostd=False,
        install_project=False,
        add_to_module_path=[str(tmpdir.join("modules"))],
    )

    # create index with multiple versions for packages a, b and c
    index: PipIndex = PipIndex(str(tmpdir.join("index")))
    create_python_package("a",
                          Version("1.0.0"),
                          str(tmpdir.join("a-1.0.0")),
                          publish_index=index)
    for v in ("1.0.0", "1.0.1", "2.0.0"):
        create_python_package("b",
                              Version(v),
                              str(tmpdir.join(f"b-{v}")),
                              requirements=[Requirement.parse("c")],
                              publish_index=index)
    for v in ("1.0.0", "2.0.0"):
        create_python_package("c",
                              Version(v),
                              str(tmpdir.join(f"c-{v}")),
                              publish_index=index)

    # install b-1.0.0 and c-1.0.0
    process_env.install_from_index(
        [Requirement.parse(req) for req in ("b==1.0.0", "c==1.0.0")],
        index_urls=[index.url])

    # create my_mod
    v1_module_from_template(
        source_dir=os.path.join(modules_dir, "minimalv1module"),
        dest_dir=str(tmpdir.join("modules", "my_mod")),
        new_name="my_mod",
        new_requirements=[Requirement.parse(req) for req in ("a", "b~=1.0.0")],
    )

    # run `inmanta project update` without running install first
    monkeypatch.setenv("PIP_INDEX_URL", index.url)
    ProjectTool().update()

    # Verify that:
    #   - direct dependency a has been installed
    #   - direct dependency b has been updated but not past the allowed constraint
    #   - transitive dependency c has been updated
    assert process_env.are_installed(("a==1.0.0", "b==1.0.1", "c==2.0.0"))
Exemple #4
0
def test_master_checkout(git_modules_dir, modules_repo):
    coroot = install_project(git_modules_dir, "masterproject")

    ProjectTool().execute("install", [])

    dirname = os.path.join(coroot, "libs", "mod8")
    assert os.path.exists(os.path.join(dirname, "devsignal"))
    assert os.path.exists(os.path.join(dirname, "mastersignal"))
Exemple #5
0
def test_project_install_preinstalled(
    local_module_package_index: str,
    snippetcompiler_clean,
    tmpdir: py.path.local,
    modules_v2_dir: str,
    editable: bool,
) -> None:
    """
    Verify that `inmanta project install` does not override preinstalled modules.
    """
    module_name: str = "minimalv2module"
    fq_mod_name: str = "inmanta_plugins.minimalv2module"

    assert env.process_env.get_module_file(fq_mod_name) is None

    # activate snippetcompiler venv
    snippetcompiler_clean.setup_for_snippet("")

    # preinstall older version of module
    module_path: str = os.path.join(str(tmpdir), module_name)
    new_version = version.Version("1.2.3.dev0")
    module_from_template(os.path.join(modules_v2_dir, module_name),
                         module_path,
                         new_version=new_version,
                         install=True,
                         editable=editable)

    def assert_module_install() -> None:
        module_info: Optional[Tuple[Optional[str],
                                    Loader]] = env.process_env.get_module_file(
                                        fq_mod_name)
        env_module_file, module_loader = module_info
        assert not isinstance(module_loader, loader.PluginModuleLoader)
        assert env_module_file is not None
        install_path: str = module_path if editable else env.process_env.site_packages_dir
        assert env_module_file == os.path.join(install_path,
                                               *fq_mod_name.split("."),
                                               "__init__.py")
        assert (env.process_env.get_installed_packages(
            only_editable=editable).get(
                f"{module.ModuleV2.PKG_NAME_PREFIX}{module_name}",
                None) == new_version)

    assert_module_install()

    # set up project and modules
    project: module.Project = snippetcompiler_clean.setup_for_snippet(
        f"import {module_name}",
        autostd=False,
        python_package_sources=[local_module_package_index])

    os.chdir(project.path)
    # autostd=True reports std as an import for any module, thus requiring it to be v2 because v2 can not depend on v1
    module.Project.get().autostd = False
    ProjectTool().execute("install", [])
    assert_module_install()
Exemple #6
0
def test_bad_checkout(git_modules_dir, modules_repo):
    coroot = os.path.join(git_modules_dir, "badproject")
    subprocess.check_output(
        ["git", "clone",
         os.path.join(git_modules_dir, "repos", "badproject")],
        cwd=git_modules_dir,
        stderr=subprocess.STDOUT)
    os.chdir(coroot)
    Config.load_config()

    with pytest.raises(ModuleLoadingException):
        ProjectTool().execute("install", [])
Exemple #7
0
def test_for_repo_without_versions(git_modules_dir, modules_repo):
    coroot = os.path.join(git_modules_dir, "noverproject")
    subprocess.check_output([
        "git", "clone",
        os.path.join(git_modules_dir, "repos", "noverproject")
    ],
                            cwd=git_modules_dir,
                            stderr=subprocess.STDOUT)
    os.chdir(coroot)
    Config.load_config()

    ProjectTool().execute("install", [])
Exemple #8
0
def test_bad_dep_checkout(git_modules_dir, modules_repo):
    coroot = os.path.join(git_modules_dir, "baddep")
    subprocess.check_output(
        ["git", "clone",
         os.path.join(git_modules_dir, "repos", "baddep")],
        cwd=git_modules_dir,
        stderr=subprocess.STDOUT)
    os.chdir(coroot)
    Config.load_config()

    with pytest.raises(CompilerException,
                       match="Not all module dependencies have been met"):
        ProjectTool().execute("install", [])
Exemple #9
0
def test_dev_checkout(git_modules_dir, modules_repo):
    coroot = os.path.join(git_modules_dir, "devproject")
    subprocess.check_output(
        ["git", "clone",
         os.path.join(git_modules_dir, "repos", "devproject")],
        cwd=git_modules_dir,
        stderr=subprocess.STDOUT)
    os.chdir(coroot)
    Config.load_config()

    ProjectTool().execute("install", [])

    dirname = os.path.join(coroot, "libs", "mod8")
    assert os.path.exists(os.path.join(dirname, "devsignal"))
    assert not os.path.exists(os.path.join(dirname, "mastersignal"))
Exemple #10
0
def test_project_install(
    local_module_package_index: str,
    snippetcompiler_clean,
    install_module_names: List[str],
    module_dependencies: List[str],
) -> None:
    """
    Install a simple inmanta project with `inmanta project install`. Make sure both v1 and v2 modules are installed
    as expected.
    """
    fq_mod_names: List[str] = [
        f"inmanta_plugins.{mod}"
        for mod in chain(install_module_names, module_dependencies)
    ]

    # set up project and modules
    project: module.Project = snippetcompiler_clean.setup_for_snippet(
        "\n".join(f"import {mod}" for mod in ["std", *install_module_names]),
        autostd=False,
        python_package_sources=[local_module_package_index],
        python_requires=[
            Requirement.parse(module.ModuleV2Source.get_package_name_for(mod))
            for mod in install_module_names
        ],
        install_project=False,
    )

    os.chdir(project.path)
    for fq_mod_name in fq_mod_names:
        assert env.process_env.get_module_file(fq_mod_name) is None
    # autostd=True reports std as an import for any module, thus requiring it to be v2 because v2 can not depend on v1
    module.Project.get().autostd = False
    ProjectTool().execute("install", [])
    for fq_mod_name in fq_mod_names:
        module_info: Optional[Tuple[Optional[str],
                                    Loader]] = env.process_env.get_module_file(
                                        fq_mod_name)
        env_module_file, module_loader = module_info
        assert not isinstance(module_loader, loader.PluginModuleLoader)
        assert env_module_file is not None
        assert env_module_file == os.path.join(
            env.process_env.site_packages_dir, *fq_mod_name.split("."),
            "__init__.py")
    v1_mod_dir: str = os.path.join(project.path, project.downloadpath)
    assert os.path.exists(v1_mod_dir)
    assert os.listdir(v1_mod_dir) == ["std"]
Exemple #11
0
def test_project_install_with_install_mode(
        tmpdir: py.path.local, modules_v2_dir: str, snippetcompiler_clean,
        install_mode: Optional[str]) -> None:
    """
    Test whether the `inmanta module install` command takes into account the `install_mode` configured on the inmanta project.
    """
    index: PipIndex = PipIndex(
        artifact_dir=os.path.join(str(tmpdir), ".custom-index"))

    module_template_path: str = os.path.join(modules_v2_dir,
                                             "elaboratev2module")
    module_name: str = "mod"
    package_name: str = module.ModuleV2Source.get_package_name_for(module_name)
    for module_version in ["1.0.0", "1.0.1.dev0"]:
        module_from_template(
            module_template_path,
            os.path.join(str(tmpdir), f"mod-{module_version}"),
            new_name=module_name,
            new_version=version.Version(module_version),
            publish_index=index,
        )

    # set up project
    snippetcompiler_clean.setup_for_snippet(
        f"import {module_name}",
        autostd=False,
        python_package_sources=[index.url],
        python_requires=[Requirement.parse(package_name)],
        install_mode=install_mode,
    )

    os.chdir(module.Project.get().path)
    ProjectTool().execute("install", [])

    if install_mode is None or install_mode == InstallMode.release:
        expected_version = version.Version("1.0.0")
    else:
        expected_version = version.Version("1.0.1.dev0")
    installed_packages: Dict[
        str, version.Version] = env.process_env.get_installed_packages()
    assert package_name in installed_packages
    assert installed_packages[package_name] == expected_version
Exemple #12
0
def test_install_for_git_failures(git_modules_dir, modules_repo):
    coroot = os.path.join(git_modules_dir, "testproject3")
    subprocess.check_output(
        [
            "git", "clone",
            os.path.join(git_modules_dir, "repos", "testproject"),
            "testproject3"
        ],
        cwd=git_modules_dir,
        stderr=subprocess.STDOUT,
    )
    os.chdir(coroot)
    Config.load_config()

    gp = module.gitprovider
    module.gitprovider = BadModProvider(gp,
                                        os.path.join(coroot, "libs", "mod6"))
    try:
        with pytest.raises(ModuleLoadingException):
            ProjectTool().execute("install", [])
    finally:
        module.gitprovider = gp
Exemple #13
0
def test_project_install_incompatible_dependencies(
    caplog,
    snippetcompiler_clean,
    tmpdir: py.path.local,
    modules_dir: str,
    modules_v2_dir: str,
) -> None:
    """
    Verify that introducing version incompatibilities in the Python environment results in the appropriate exception and
    warnings.
    """
    index: PipIndex = PipIndex(
        artifact_dir=os.path.join(str(tmpdir), ".custom-index"))

    # prepare v2 modules
    v2_template_path: str = os.path.join(modules_v2_dir, "minimalv2module")
    v2mod1: module.ModuleV2Metadata = module_from_template(
        v2_template_path,
        os.path.join(str(tmpdir), "v2mod1"),
        new_name="v2mod1",
        new_requirements=[Requirement.parse("more-itertools~=7.0")],
        publish_index=index,
    )
    v2mod2: module.ModuleV2Metadata = module_from_template(
        v2_template_path,
        os.path.join(str(tmpdir), "v2mod2"),
        new_name="v2mod2",
        new_requirements=[Requirement.parse("more-itertools~=8.0")],
        publish_index=index,
    )

    # set up project
    snippetcompiler_clean.setup_for_snippet(
        f"""
        import {module.ModuleV2.get_name_from_metadata(v2mod1)}
        import {module.ModuleV2.get_name_from_metadata(v2mod2)}
        """,
        autostd=False,
        install_project=False,
        python_package_sources=[index.url, "https://pypi.org/simple"],
        python_requires=[
            Requirement.parse(
                module.ModuleV2Source.get_package_name_for(
                    module.ModuleV2.get_name_from_metadata(metadata)))
            for metadata in [v2mod1, v2mod2]
        ],
    )

    # install project
    os.chdir(module.Project.get().path)
    with pytest.raises(
            CompilerException,
            match=
        ("Not all installed modules are compatible: requirements conflicts were found. Please resolve any conflicts before"
         " attempting another compile. Run `pip check` to check for any incompatibilities."
         ),
    ):
        ProjectTool().execute("install", [])

    assert any(
        re.match(
            "Incompatibility between constraint more-itertools~=[78].0 and installed version [78]\\..*",
            rec.message) is not None for rec in caplog.records)
Exemple #14
0
def test_project_install_incompatible_versions(
    caplog,
    snippetcompiler_clean,
    tmpdir: py.path.local,
    modules_dir: str,
    modules_v2_dir: str,
    autostd: bool,
) -> None:
    """
    Verify that introducing module version incompatibilities results in the appropriate exception and warnings.
    Make sure this works both for autostd (no explicit import) and for standard modules.
    """
    v2_mod_name: str = "std" if autostd else "v2mod"

    # declare conflicting module parameters
    current_version: version.Version = version.Version("1.0.0")
    req_v1_on_v1: module.InmantaModuleRequirement = module.InmantaModuleRequirement.parse(
        "v1mod1>42")
    req_v1_on_v2: module.InmantaModuleRequirement = module.InmantaModuleRequirement.parse(
        f"{v2_mod_name}>10000")

    # prepare v1 modules
    v1_modules_path: str = os.path.join(str(tmpdir), "libs")
    v1mod1_path: str = os.path.join(v1_modules_path, "v1mod1")
    shutil.copytree(os.path.join(modules_dir, "minimalv1module"), v1mod1_path)
    with open(os.path.join(v1mod1_path, module.ModuleV1.MODULE_FILE),
              "r+") as fh:
        config: Dict[str, object] = yaml.safe_load(fh)
        config["name"] = "v1mod1"
        config["version"] = str(current_version)
        fh.seek(0)
        yaml.dump(config, fh)
    v1mod2_path: str = os.path.join(v1_modules_path, "v1mod2")
    shutil.copytree(os.path.join(modules_dir, "minimalv1module"), v1mod2_path)
    with open(os.path.join(v1mod2_path, module.ModuleV1.MODULE_FILE),
              "r+") as fh:
        config: Dict[str, object] = yaml.safe_load(fh)
        config["name"] = "v1mod2"
        config["requires"] = [str(req_v1_on_v2), str(req_v1_on_v1)]
        fh.seek(0)
        yaml.dump(config, fh)

    # prepare v2 module
    index: PipIndex = PipIndex(
        artifact_dir=os.path.join(str(tmpdir), ".custom-index"))
    module_from_template(
        os.path.join(modules_v2_dir, "minimalv2module"),
        os.path.join(str(tmpdir), v2_mod_name),
        new_version=current_version,
        new_name=v2_mod_name,
        publish_index=index,
    )

    # set up project
    snippetcompiler_clean.setup_for_snippet(
        """
        import v1mod2
        import v1mod1
        %s
        """ % (f"import {v2_mod_name}" if not autostd else ""),
        autostd=autostd,
        install_project=False,
        add_to_module_path=[v1_modules_path],
        python_package_sources=[index.url],
        python_requires=[
            Requirement.parse(
                module.ModuleV2Source.get_package_name_for(v2_mod_name))
        ],
    )

    # install project
    os.chdir(module.Project.get().path)
    with pytest.raises(
            CompilerException,
            match=
            "Not all module dependencies have been met. Run `inmanta modules update` to resolve this."
    ):
        ProjectTool().execute("install", [])

    log_messages: Set[str] = {rec.message for rec in caplog.records}
    expected: Set[str] = {
        f"requirement {req_v1_on_v1} on module v1mod1 not fulfilled, now at version {current_version}",
        f"requirement {req_v1_on_v2} on module {v2_mod_name} not fulfilled, now at version {current_version}",
    }
    assert expected.issubset(log_messages)
Exemple #15
0
def test_project_install_modules_cache_invalid(
    caplog,
    local_module_package_index: str,
    snippetcompiler_clean,
    tmpdir: py.path.local,
    modules_dir: str,
    modules_v2_dir: str,
) -> None:
    """
    Verify that introducing invalidities in the modules cache results in the appropriate exception and warnings.

    - preinstall old (v1 or v2) version of {dependency_module}
    - install project with {main_module} that depends on {dependency_module}>={v2_version}
    """
    main_module: str = "main_module"
    dependency_module: str = "minimalv1module"
    fq_mod_name: str = "inmanta_plugins.minimalv1module"
    index: PipIndex = PipIndex(
        artifact_dir=os.path.join(str(tmpdir), ".custom-index"))
    libs_dir: str = os.path.join(str(tmpdir), "libs")
    os.makedirs(libs_dir)

    assert env.process_env.get_module_file(fq_mod_name) is None

    # prepare most recent v2 module
    v2_template_path: str = os.path.join(str(tmpdir), dependency_module)
    v1: module.ModuleV1 = module.ModuleV1(project=DummyProject(autostd=False),
                                          path=os.path.join(
                                              modules_dir, dependency_module))
    v2_version: version.Version = version.Version(
        str(v1.version.major + 1) + ".0.0")
    ModuleConverter(v1).convert(output_directory=v2_template_path)
    module_from_template(v2_template_path,
                         os.path.join(str(tmpdir), dependency_module,
                                      "stable"),
                         new_version=v2_version,
                         publish_index=index)

    # prepare main module that depends on stable v2 version of first module
    module_from_template(
        v2_template_path,
        os.path.join(str(tmpdir), main_module),
        new_name=main_module,
        new_content_init_cf=f"import {dependency_module}",
        # requires stable version, not currently installed dev version
        new_requirements=[
            module.InmantaModuleRequirement.parse(
                f"{dependency_module}>={v2_version}")
        ],
        install=False,
        publish_index=index,
    )

    # preinstall module
    # set up project, including activation of venv before installing the module
    snippetcompiler_clean.setup_for_snippet("", install_project=False)
    # install older v2 module
    module_from_template(
        v2_template_path,
        os.path.join(str(tmpdir), dependency_module, "dev"),
        new_version=version.Version(f"{v2_version}.dev0"),
        install=True,
    )

    # set up project for installation
    project: module.Project = snippetcompiler_clean.setup_for_snippet(
        f"import {main_module}",
        autostd=False,
        install_project=False,
        add_to_module_path=[libs_dir],
        python_package_sources=[index.url, local_module_package_index],
        # make sure main module gets installed, pulling in newest version of dependency module
        python_requires=[
            Requirement.parse(
                module.ModuleV2Source.get_package_name_for(main_module))
        ],
    )

    # populate project.modules[dependency_module] to force the error conditions in this simplified example
    project.get_module(dependency_module, allow_v1=True)

    os.chdir(project.path)
    with pytest.raises(
            CompilerException,
            match=
        ("Not all modules were loaded correctly as a result of transitive dependencies."
         " A recompile should load them correctly."),
    ):
        ProjectTool().execute("install", [])

    message: str = (
        f"Compiler has loaded module {dependency_module}=={v2_version}.dev0 but {dependency_module}=={v2_version} has"
        " later been installed as a side effect.")

    assert message in (rec.message for rec in caplog.records)