# Pylint doesn't play well with fixtures and dependency injection from pytest # pylint: disable=redefined-outer-name import os import pytest from buildstream import _yaml from buildstream.testing import create_repo from buildstream.testing import cli # pylint: disable=unused-import # Project directory TOP_DIR = os.path.dirname(os.path.realpath(__file__)) DATA_DIR = os.path.join(TOP_DIR, "project") def generate_element(output_file): element = { "kind": "import", "sources": [ { "kind": "fetch_source", "output-text": output_file, "urls": ["foo:repo1", "bar:repo2"], "fetch-succeeds": { "FOO/repo1": True, "BAR/repo2": False, "OOF/repo1": False, "RAB/repo2": True, "OFO/repo1": False, "RBA/repo2": False, "ooF/repo1": False, "raB/repo2": False, }, } ], } return element def generate_project(): project = { "name": "test", "min-version": "2.0", "element-path": "elements", "aliases": {"foo": "FOO/", "bar": "BAR/",}, "mirrors": [ {"name": "middle-earth", "aliases": {"foo": ["OOF/"], "bar": ["RAB/"],},}, {"name": "arrakis", "aliases": {"foo": ["OFO/"], "bar": ["RBA/"],},}, {"name": "oz", "aliases": {"foo": ["ooF/"], "bar": ["raB/"],}}, ], "plugins": [{"origin": "local", "path": "sources", "sources": ["fetch_source"]}], } return project @pytest.mark.datafiles(DATA_DIR) @pytest.mark.parametrize("ref_storage", [("inline"), ("project.refs")]) @pytest.mark.parametrize("mirror", [("no-mirror"), ("mirror"), ("unrelated-mirror")]) def test_mirror_fetch_ref_storage(cli, tmpdir, datafiles, ref_storage, mirror): bin_files_path = os.path.join(str(datafiles), "files", "bin-files", "usr") dev_files_path = os.path.join(str(datafiles), "files", "dev-files", "usr") upstream_repodir = os.path.join(str(tmpdir), "upstream") mirror_repodir = os.path.join(str(tmpdir), "mirror") project_dir = os.path.join(str(tmpdir), "project") os.makedirs(project_dir) element_dir = os.path.join(project_dir, "elements") # Create repo objects of the upstream and mirror upstream_repo = create_repo("tar", upstream_repodir) upstream_repo.create(bin_files_path) mirror_repo = upstream_repo.copy(mirror_repodir) upstream_ref = upstream_repo.create(dev_files_path) element = { "kind": "import", "sources": [upstream_repo.source_config(ref=upstream_ref if ref_storage == "inline" else None)], } element_name = "test.bst" element_path = os.path.join(element_dir, element_name) full_repo = element["sources"][0]["url"] upstream_map, repo_name = os.path.split(full_repo) alias = "foo" aliased_repo = alias + ":" + repo_name element["sources"][0]["url"] = aliased_repo full_mirror = mirror_repo.source_config()["url"] mirror_map, _ = os.path.split(full_mirror) os.makedirs(element_dir) _yaml.roundtrip_dump(element, element_path) if ref_storage == "project.refs": # Manually set project.refs to avoid caching the repo prematurely project_refs = {"projects": {"test": {element_name: [{"ref": upstream_ref}]}}} project_refs_path = os.path.join(project_dir, "project.refs") _yaml.roundtrip_dump(project_refs, project_refs_path) project = { "name": "test", "min-version": "2.0", "element-path": "elements", "aliases": {alias: upstream_map + "/"}, "ref-storage": ref_storage, } if mirror != "no-mirror": mirror_data = [{"name": "middle-earth", "aliases": {alias: [mirror_map + "/"]}}] if mirror == "unrelated-mirror": mirror_data.insert(0, {"name": "narnia", "aliases": {"frob": ["http://www.example.com/repo"]}}) project["mirrors"] = mirror_data project_file = os.path.join(project_dir, "project.conf") _yaml.roundtrip_dump(project, project_file) result = cli.run(project=project_dir, args=["source", "fetch", element_name]) result.assert_success() @pytest.mark.datafiles(DATA_DIR) @pytest.mark.usefixtures("datafiles") def test_mirror_fetch_multi(cli, tmpdir): output_file = os.path.join(str(tmpdir), "output.txt") project_dir = str(tmpdir) element_dir = os.path.join(project_dir, "elements") os.makedirs(element_dir, exist_ok=True) element_name = "test.bst" element_path = os.path.join(element_dir, element_name) element = generate_element(output_file) _yaml.roundtrip_dump(element, element_path) project_file = os.path.join(project_dir, "project.conf") project = generate_project() _yaml.roundtrip_dump(project, project_file) result = cli.run(project=project_dir, args=["source", "fetch", element_name]) result.assert_success() with open(output_file) as f: contents = f.read() assert "Fetch foo:repo1 succeeded from FOO/repo1" in contents assert "Fetch bar:repo2 succeeded from RAB/repo2" in contents @pytest.mark.datafiles(DATA_DIR) @pytest.mark.usefixtures("datafiles") def test_mirror_fetch_default_cmdline(cli, tmpdir): output_file = os.path.join(str(tmpdir), "output.txt") project_dir = str(tmpdir) element_dir = os.path.join(project_dir, "elements") os.makedirs(element_dir, exist_ok=True) element_name = "test.bst" element_path = os.path.join(element_dir, element_name) element = generate_element(output_file) _yaml.roundtrip_dump(element, element_path) project_file = os.path.join(project_dir, "project.conf") project = generate_project() _yaml.roundtrip_dump(project, project_file) result = cli.run(project=project_dir, args=["--default-mirror", "arrakis", "source", "fetch", element_name]) result.assert_success() with open(output_file) as f: contents = f.read() print(contents) # Success if fetching from arrakis' mirror happened before middle-earth's arrakis_str = "OFO/repo1" arrakis_pos = contents.find(arrakis_str) assert arrakis_pos != -1, "'{}' wasn't found".format(arrakis_str) me_str = "OOF/repo1" me_pos = contents.find(me_str) assert me_pos != -1, "'{}' wasn't found".format(me_str) assert arrakis_pos < me_pos, "'{}' wasn't found before '{}'".format(arrakis_str, me_str) @pytest.mark.datafiles(DATA_DIR) @pytest.mark.usefixtures("datafiles") def test_mirror_fetch_default_userconfig(cli, tmpdir): output_file = os.path.join(str(tmpdir), "output.txt") project_dir = str(tmpdir) element_dir = os.path.join(project_dir, "elements") os.makedirs(element_dir, exist_ok=True) element_name = "test.bst" element_path = os.path.join(element_dir, element_name) element = generate_element(output_file) _yaml.roundtrip_dump(element, element_path) project_file = os.path.join(project_dir, "project.conf") project = generate_project() _yaml.roundtrip_dump(project, project_file) userconfig = {"projects": {"test": {"default-mirror": "oz"}}} cli.configure(userconfig) result = cli.run(project=project_dir, args=["source", "fetch", element_name]) result.assert_success() with open(output_file) as f: contents = f.read() print(contents) # Success if fetching from Oz' mirror happened before middle-earth's oz_str = "ooF/repo1" oz_pos = contents.find(oz_str) assert oz_pos != -1, "'{}' wasn't found".format(oz_str) me_str = "OOF/repo1" me_pos = contents.find(me_str) assert me_pos != -1, "'{}' wasn't found".format(me_str) assert oz_pos < me_pos, "'{}' wasn't found before '{}'".format(oz_str, me_str) @pytest.mark.datafiles(DATA_DIR) @pytest.mark.usefixtures("datafiles") def test_mirror_fetch_default_cmdline_overrides_config(cli, tmpdir): output_file = os.path.join(str(tmpdir), "output.txt") project_dir = str(tmpdir) element_dir = os.path.join(project_dir, "elements") os.makedirs(element_dir, exist_ok=True) element_name = "test.bst" element_path = os.path.join(element_dir, element_name) element = generate_element(output_file) _yaml.roundtrip_dump(element, element_path) project_file = os.path.join(project_dir, "project.conf") project = generate_project() _yaml.roundtrip_dump(project, project_file) userconfig = {"projects": {"test": {"default-mirror": "oz"}}} cli.configure(userconfig) result = cli.run(project=project_dir, args=["--default-mirror", "arrakis", "source", "fetch", element_name]) result.assert_success() with open(output_file) as f: contents = f.read() print(contents) # Success if fetching from arrakis' mirror happened before middle-earth's arrakis_str = "OFO/repo1" arrakis_pos = contents.find(arrakis_str) assert arrakis_pos != -1, "'{}' wasn't found".format(arrakis_str) me_str = "OOF/repo1" me_pos = contents.find(me_str) assert me_pos != -1, "'{}' wasn't found".format(me_str) assert arrakis_pos < me_pos, "'{}' wasn't found before '{}'".format(arrakis_str, me_str) @pytest.mark.datafiles(DATA_DIR) def test_mirror_git_submodule_fetch(cli, tmpdir, datafiles): # Test that it behaves as expected with submodules, both defined in config # and discovered when fetching. foo_file = os.path.join(str(datafiles), "files", "foo") bar_file = os.path.join(str(datafiles), "files", "bar") bin_files_path = os.path.join(str(datafiles), "files", "bin-files", "usr") dev_files_path = os.path.join(str(datafiles), "files", "dev-files", "usr") mirror_dir = os.path.join(str(datafiles), "mirror") defined_subrepo = create_repo("git", str(tmpdir), "defined_subrepo") defined_subrepo.create(bin_files_path) defined_subrepo.copy(mirror_dir) defined_subrepo.add_file(foo_file) found_subrepo = create_repo("git", str(tmpdir), "found_subrepo") found_subrepo.create(dev_files_path) main_repo = create_repo("git", str(tmpdir)) main_mirror_ref = main_repo.create(bin_files_path) main_repo.add_submodule("defined", "file://" + defined_subrepo.repo) main_repo.add_submodule("found", "file://" + found_subrepo.repo) main_mirror = main_repo.copy(mirror_dir) main_repo.add_file(bar_file) project_dir = os.path.join(str(tmpdir), "project") os.makedirs(project_dir) element_dir = os.path.join(project_dir, "elements") os.makedirs(element_dir) element = {"kind": "import", "sources": [main_repo.source_config(ref=main_mirror_ref)]} element_name = "test.bst" element_path = os.path.join(element_dir, element_name) # Alias the main repo full_repo = element["sources"][0]["url"] _, repo_name = os.path.split(full_repo) alias = "foo" aliased_repo = alias + ":" + repo_name element["sources"][0]["url"] = aliased_repo # Hide the found subrepo del element["sources"][0]["submodules"]["found"] # Alias the defined subrepo subrepo = element["sources"][0]["submodules"]["defined"]["url"] _, repo_name = os.path.split(subrepo) aliased_repo = alias + ":" + repo_name element["sources"][0]["submodules"]["defined"]["url"] = aliased_repo _yaml.roundtrip_dump(element, element_path) full_mirror = main_mirror.source_config()["url"] mirror_map, _ = os.path.split(full_mirror) project = { "name": "test", "min-version": "2.0", "element-path": "elements", "aliases": {alias: "http://www.example.com/"}, "mirrors": [{"name": "middle-earth", "aliases": {alias: [mirror_map + "/"],},},], } project_file = os.path.join(project_dir, "project.conf") _yaml.roundtrip_dump(project, project_file) result = cli.run(project=project_dir, args=["source", "fetch", element_name]) result.assert_success() @pytest.mark.datafiles(DATA_DIR) def test_mirror_fallback_git_only_submodules(cli, tmpdir, datafiles): # Main repo has no mirror or alias. # One submodule is overridden to use a mirror. # There is another submodules not overriden. # Upstream for overriden submodule is down. # # We expect: # - overriden submodule is fetched from mirror. # - other submodule is fetched. bin_files_path = os.path.join(str(datafiles), "files", "bin-files", "usr") dev_files_path = os.path.join(str(datafiles), "files", "dev-files", "usr") upstream_bin_repodir = os.path.join(str(tmpdir), "bin-upstream") mirror_bin_repodir = os.path.join(str(tmpdir), "bin-mirror") upstream_bin_repo = create_repo("git", upstream_bin_repodir) upstream_bin_repo.create(bin_files_path) mirror_bin_repo = upstream_bin_repo.copy(mirror_bin_repodir) dev_repodir = os.path.join(str(tmpdir), "dev-upstream") dev_repo = create_repo("git", dev_repodir) dev_repo.create(dev_files_path) main_files = os.path.join(str(tmpdir), "main-files") os.makedirs(main_files) with open(os.path.join(main_files, "README"), "w") as f: f.write("TEST\n") main_repodir = os.path.join(str(tmpdir), "main-upstream") main_repo = create_repo("git", main_repodir) main_repo.create(main_files) upstream_url = "file://{}".format(upstream_bin_repo.repo) main_repo.add_submodule("bin", url=upstream_url) main_repo.add_submodule("dev", url="file://{}".format(dev_repo.repo)) # Unlist 'dev'. del main_repo.submodules["dev"] main_ref = main_repo.latest_commit() upstream_map, repo_name = os.path.split(upstream_url) alias = "foo" aliased_repo = "{}:{}".format(alias, repo_name) main_repo.submodules["bin"]["url"] = aliased_repo full_mirror = mirror_bin_repo.source_config()["url"] mirror_map, _ = os.path.split(full_mirror) project_dir = os.path.join(str(tmpdir), "project") os.makedirs(project_dir) element_dir = os.path.join(project_dir, "elements") element = {"kind": "import", "sources": [main_repo.source_config_extra(ref=main_ref, checkout_submodules=True)]} element_name = "test.bst" element_path = os.path.join(element_dir, element_name) os.makedirs(element_dir) _yaml.roundtrip_dump(element, element_path) project = { "name": "test", "min-version": "2.0", "element-path": "elements", "aliases": {alias: upstream_map + "/"}, "mirrors": [{"name": "middle-earth", "aliases": {alias: [mirror_map + "/"],}}], } project_file = os.path.join(project_dir, "project.conf") _yaml.roundtrip_dump(project, project_file) # Now make the upstream unavailable. os.rename(upstream_bin_repo.repo, "{}.bak".format(upstream_bin_repo.repo)) result = cli.run(project=project_dir, args=["source", "fetch", element_name]) result.assert_success() result = cli.run(project=project_dir, args=["build", element_name]) result.assert_success() checkout = os.path.join(str(tmpdir), "checkout") result = cli.run(project=project_dir, args=["artifact", "checkout", element_name, "--directory", checkout]) result.assert_success() assert os.path.exists(os.path.join(checkout, "bin", "bin", "hello")) assert os.path.exists(os.path.join(checkout, "dev", "include", "pony.h")) @pytest.mark.datafiles(DATA_DIR) def test_mirror_fallback_git_with_submodules(cli, tmpdir, datafiles): # Main repo has mirror. But does not list submodules. # # We expect: # - we will fetch submodules anyway bin_files_path = os.path.join(str(datafiles), "files", "bin-files", "usr") dev_files_path = os.path.join(str(datafiles), "files", "dev-files", "usr") bin_repodir = os.path.join(str(tmpdir), "bin-repo") bin_repo = create_repo("git", bin_repodir) bin_repo.create(bin_files_path) dev_repodir = os.path.join(str(tmpdir), "dev-repo") dev_repo = create_repo("git", dev_repodir) dev_repo.create(dev_files_path) main_files = os.path.join(str(tmpdir), "main-files") os.makedirs(main_files) with open(os.path.join(main_files, "README"), "w") as f: f.write("TEST\n") upstream_main_repodir = os.path.join(str(tmpdir), "main-upstream") upstream_main_repo = create_repo("git", upstream_main_repodir) upstream_main_repo.create(main_files) upstream_main_repo.add_submodule("bin", url="file://{}".format(bin_repo.repo)) upstream_main_repo.add_submodule("dev", url="file://{}".format(dev_repo.repo)) # Unlist submodules. del upstream_main_repo.submodules["bin"] del upstream_main_repo.submodules["dev"] upstream_main_ref = upstream_main_repo.latest_commit() mirror_main_repodir = os.path.join(str(tmpdir), "main-mirror") mirror_main_repo = upstream_main_repo.copy(mirror_main_repodir) upstream_url = mirror_main_repo.source_config()["url"] upstream_map, repo_name = os.path.split(upstream_url) alias = "foo" aliased_repo = "{}:{}".format(alias, repo_name) full_mirror = mirror_main_repo.source_config()["url"] mirror_map, _ = os.path.split(full_mirror) project_dir = os.path.join(str(tmpdir), "project") os.makedirs(project_dir) element_dir = os.path.join(project_dir, "elements") element = { "kind": "import", "sources": [upstream_main_repo.source_config_extra(ref=upstream_main_ref, checkout_submodules=True)], } element["sources"][0]["url"] = aliased_repo element_name = "test.bst" element_path = os.path.join(element_dir, element_name) os.makedirs(element_dir) _yaml.roundtrip_dump(element, element_path) project = { "name": "test", "min-version": "2.0", "element-path": "elements", "aliases": {alias: upstream_map + "/"}, "mirrors": [{"name": "middle-earth", "aliases": {alias: [mirror_map + "/"],}}], } project_file = os.path.join(project_dir, "project.conf") _yaml.roundtrip_dump(project, project_file) # Now make the upstream unavailable. os.rename(upstream_main_repo.repo, "{}.bak".format(upstream_main_repo.repo)) result = cli.run(project=project_dir, args=["source", "fetch", element_name]) result.assert_success() result = cli.run(project=project_dir, args=["build", element_name]) result.assert_success() checkout = os.path.join(str(tmpdir), "checkout") result = cli.run(project=project_dir, args=["artifact", "checkout", element_name, "--directory", checkout]) result.assert_success() assert os.path.exists(os.path.join(checkout, "bin", "bin", "hello")) assert os.path.exists(os.path.join(checkout, "dev", "include", "pony.h"))