def test_gomod_vendor_without_flag(test_env): """ Validate failing of gomod vendor request without flag. Checks: * The request failed with expected error message """ env_data = utils.load_test_data( "gomod_packages.yaml")["vendored_without_flag"] client = utils.Client(test_env["api_url"], test_env["api_auth_type"], test_env.get("timeout")) initial_response = client.create_new_request(payload={ "repo": env_data["repo"], "ref": env_data["ref"], "pkg_managers": env_data["pkg_managers"], }, ) completed_response = client.wait_for_complete_request(initial_response) if test_env.get("strict_mode_enabled"): assert completed_response.status == 200 assert completed_response.data["state"] == "failed" error_msg = ( 'The "gomod-vendor" flag must be set when your repository has vendored dependencies' ) assert error_msg in completed_response.data["state_reason"], ( f"#{completed_response.id}: Request failed correctly, but with unexpected message: " f"{completed_response.data['state_reason']}. Expected message was: {error_msg}" ) else: utils.assert_properly_completed_response(completed_response)
def assert_successful_cached_request(response, env_data, tmpdir, client): """ Provide all verifications for Cachito request with cached dependencies. :param Response response: completed Cachito response :param dict env_data: the test data :param tmpdir: the path to directory with testing files :param Client client: the Cachito client to make requests """ utils.assert_properly_completed_response(response) response_data = response.data expected_response_data = env_data["response_expectations"] utils.assert_elements_from_response(response_data, expected_response_data) client.download_and_extract_archive(response.id, tmpdir) source_path = tmpdir.join(f"download_{str(response.id)}") expected_files = env_data["expected_files"] utils.assert_expected_files(source_path, expected_files, tmpdir) purl = env_data["purl"] deps_purls = [] source_purls = [] if "dep_purls" in env_data: deps_purls = [{"purl": x} for x in env_data["dep_purls"]] if "source_purls" in env_data: source_purls = [{"purl": x} for x in env_data["source_purls"]] image_contents = [{"dependencies": deps_purls, "purl": purl, "sources": source_purls}] utils.assert_content_manifest(client, response.id, image_contents)
def test_git_dir_not_included_by_default(test_env, default_requests, tmpdir): """ Check that the bundle does not include the .git file objects by default. Process: * Send new request to Cachito API * Send request to download appropriate bundle from Cachito Checks: * Check that response code is 200 * Check that state is "complete" * Check the downloaded data are in gzip format and valid * Check that downloaded data does not contain any .git files """ response = default_requests["gomod"].complete_response utils.assert_properly_completed_response(response) client = utils.Client(test_env["api_url"], test_env["api_auth_type"], test_env.get("timeout")) client.download_and_extract_archive(response.id, tmpdir) file_name_tar = tmpdir.join(f"download_{str(response.id)}.tar.gz") with tarfile.open(file_name_tar, mode="r:gz") as tar: git_files = { member.name for member in tar.getmembers() if path.basename(member.name) == ".git" } assert not git_files, ( f"#{response.id}: There are unexpected .git files in archive {file_name_tar}: " f"{git_files}" )
def test_run_app_from_bundle(test_env, default_requests, tmpdir): """ Check that downloaded bundle could be used to run the application. Process: * Send new request to Cachito API * Download a bundle from the request * Run go build * Run the application Checks: * Check that the state of request is complete * Check that the bundle is properly downloaded * Check that the application runs successfully """ response = default_requests["gomod"].complete_response utils.assert_properly_completed_response(response) client = utils.Client(test_env["api_url"], test_env["api_auth_type"], test_env.get("timeout")) client.download_and_extract_archive(response.id, tmpdir) bundle_dir = tmpdir.join(f"download_{str(response.id)}") app_name = test_env["run_app"]["app_name"] app_binary_file = str(tmpdir.join(app_name)) subprocess.run( [ "go", "build", "-o", app_binary_file, str(bundle_dir.join("app", "main.go")) ], env={ "GOPATH": str(bundle_dir.join("deps", "gomod")), "GOCACHE": str(bundle_dir.join("deps", "gomod")), "GOMODCACHE": "{}/pkg/mod".format(str(bundle_dir.join("deps", "gomod"))), }, cwd=str(bundle_dir.join("app")), check=True, ) assert path.exists( app_binary_file ), f"#{response.id}: Path for application binary file {app_binary_file} does not exist" sp = subprocess.run([app_binary_file, "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) assert sp.returncode == 0
def test_various_packages(test_env): client = utils.Client(test_env["api_url"], test_env["api_auth_type"], test_env.get("timeout")) for pkg_manager, package in test_env["various_packages"].items(): initial_response = client.create_new_request(payload={ "repo": package["repo"], "ref": package["ref"], "pkg_managers": [pkg_manager], }, ) completed_response = client.wait_for_complete_request(initial_response) utils.assert_properly_completed_response(completed_response) assert len(completed_response.data["dependencies"] ) == package["dependencies_count"]
def test_npm_basic(test_env, default_requests): """ A basic integration test for the npm package manager. Process: * Send new request to the Cachito API * Send request to check status of existing request Checks: * Verify that the request completes successfully * Verify that there is a correct package entry * Verify that there is a correct number of dependencies * Verify that the tslib dependency is not a dev dependency (dev key in the dependencies array) * Verify that the other dependencies are dev (dev key in the dependencies array) * Verify that the environment variables "CHROMEDRIVER_SKIP_DOWNLOAD": "true", "CYPRESS_INSTALL_BINARY": "0", "GECKODRIVER_SKIP_DOWNLOAD": "true", and "SKIP_SASS_BINARY_DOWNLOAD_FOR_CI": "true" are set. """ response = default_requests["npm"].complete_response utils.assert_properly_completed_response(response) response_packages = utils.make_list_of_packages_hashable( response.data["packages"]) expected_packages = test_env["get"]["npm"]["packages"] assert response_packages == expected_packages assert len(response.data["dependencies"] ) == test_env["get"]["npm"]["dependencies_count"] for item in response.data["dependencies"]: if item["name"] not in test_env["get"]["npm"]["non_dev_dependencies"]: assert item["dev"], ( f"dependency {item['name']} is not listed as non-dev in the test expectations," f"but is listed as non-dev in the response") else: assert not item["dev"], ( f"dependency {item['name']} is listed as non-dev in the test expectations," f"but is not listed as non-dev in the response") env_variables = response.data["environment_variables"] assert env_variables["CHROMEDRIVER_SKIP_DOWNLOAD"] == "true" assert env_variables["CYPRESS_INSTALL_BINARY"] == "0" assert env_variables["GECKODRIVER_SKIP_DOWNLOAD"] == "true" assert env_variables["SKIP_SASS_BINARY_DOWNLOAD_FOR_CI"] == "true"
def test_git_dir_included_by_flag(test_env, tmpdir): """ Check that the bundle includes the .git file objects when include-git-dir flag is used. Process: * Send new request to Cachito API * Send request to download appropriate bundle from Cachito Checks: * Check that response code is 200 * Check that state is "complete" * Check the downloaded data are in gzip format and valid * Check that downloaded data contains app/.git file object, directory """ package_info = test_env["packages"]["gomod"] client = utils.Client(test_env["api_url"], test_env["api_auth_type"], test_env.get("timeout")) initial_response = client.create_new_request(payload={ "repo": package_info["repo"], "ref": package_info["ref"], "pkg_managers": package_info["pkg_managers"], "flags": ["include-git-dir"], }, ) response = client.wait_for_complete_request(initial_response) utils.assert_properly_completed_response(response) client.download_and_extract_archive(response.id, tmpdir) file_name_tar = tmpdir.join(f"download_{str(response.id)}.tar.gz") with tarfile.open(file_name_tar, mode="r:gz") as tar: git_files = { member.name for member in tar.getmembers() if path.basename(member.name) == ".git" } assert git_files == { "app/.git" }, (f"#{response.id}: There are unexpected, or missing, .git files in archive {file_name_tar}: " f"{git_files}")
def test_using_cached_packages(self, tmpdir, test_env): """ Check that the cached packages are used instead of downloading them from repo again. Preconditions: * On git instance prepare an empty repository Process: * Clone the package from the upstream repository * Create empty commit on new test branch and push it to the prepared repository * Send new request to Cachito API which would fetch data from the prepared repository * Delete branch with the corresponding commit * Send the same request to Cachito API Checks: * Check that the state of the first request is complete * Check that the commit is not available in the repository after the branch is deleted * Check that the state of the second request is complete """ generated_suffix = "".join( random.choice(string.ascii_letters + string.digits) for x in range(10) ) branch_name = f"test-{generated_suffix}" repo = git.repo.Repo.clone_from(self.env_data["seed_repo"]["https_url"], tmpdir) remote = repo.create_remote("test", url=self.env_data["test_repo"]["ssh_url"]) assert remote.exists(), f"Remote {remote.name} does not exist" # set user configuration, if available if self.git_user: repo.config_writer().set_value("user", "name", self.git_user).release() if self.git_email: repo.config_writer().set_value("user", "email", self.git_email).release() try: repo.create_head(branch_name).checkout() repo.git.commit("--allow-empty", m="Commit created in integration test for Cachito") repo.git.push("-u", remote.name, branch_name) commit = repo.head.commit.hexsha client = utils.Client( test_env["api_url"], test_env["api_auth_type"], test_env.get("timeout"), ) response = client.create_new_request( payload={ "repo": self.env_data["test_repo"]["https_url"], "ref": commit, "pkg_managers": self.env_data["test_repo"]["pkg_managers"], }, ) first_response = client.wait_for_complete_request(response) utils.assert_properly_completed_response(first_response) assert repo.git.branch( "-a", "--contains", commit ), f"Commit {commit} is not in branches (it should be there)." finally: delete_branch_and_check(branch_name, repo, remote, [commit]) response = client.create_new_request( payload={ "repo": self.env_data["test_repo"]["https_url"], "ref": commit, "pkg_managers": self.env_data["test_repo"]["pkg_managers"], }, ) second_response = client.wait_for_complete_request(response) utils.assert_properly_completed_response(second_response) assert first_response.data["ref"] == second_response.data["ref"] assert first_response.data["repo"] == second_response.data["repo"] assert set(first_response.data["pkg_managers"]) == set(second_response.data["pkg_managers"]) first_pkgs = utils.make_list_of_packages_hashable(first_response.data["packages"]) second_pkgs = utils.make_list_of_packages_hashable(second_response.data["packages"]) assert first_pkgs == second_pkgs first_deps = utils.make_list_of_packages_hashable(first_response.data["dependencies"]) second_deps = utils.make_list_of_packages_hashable(second_response.data["dependencies"]) assert first_deps == second_deps
def test_check_downloaded_output(test_env, default_requests, tmpdir): """ Check that the bundle has all the necessities. Process: * Send new request to Cachito API * Send request to download appropriate bundle from Cachito Checks: * Check that response code is 200 * Check that state is "complete" * Check the downloaded data are in gzip format and valid * Check that dir deps/gomod/… contains cached dependencies * Check that dir app/ contains application source code * Check that the same full path filename is not duplicated """ response = default_requests["gomod"].complete_response utils.assert_properly_completed_response(response) client = utils.Client(test_env["api_url"], test_env["api_auth_type"], test_env.get("timeout")) file_name = tmpdir.join(f"download_{str(response.id)}") client.download_and_extract_archive(response.id, tmpdir) pkg_managers = test_env["downloaded_output"]["pkg_managers"] dependencies_path = path.join("deps", "gomod", "pkg", "mod", "cache", "download") names = [i["name"] for i in response.data["dependencies"] if i["type"] in pkg_managers] for dependency in names: package_name = utils.escape_path_go(dependency) dependency_path = path.join(file_name, dependencies_path, package_name) assert path.exists( dependency_path ), f"#{response.id}: Dependency path does not exist: {dependency_path}" go_mod_path = path.join(file_name, "app", "go.mod") assert path.exists( go_mod_path ), f"#{response.id}: File go.mod does not exist in location: {go_mod_path}" with open(go_mod_path, "r") as file: module_names = [] for line in file: if line.startswith("module "): module_names.append(line.split()[-1]) break expected_packages = [ i["name"] for i in response.data["packages"] if i["type"] in pkg_managers ] assert set(module_names) == set(expected_packages) list_go_files = [] for app_path in Path(path.join(file_name, "app")).rglob("*.go"): list_go_files.append(app_path) assert len(list_go_files) > 0 file_name_tar = tmpdir.join(f"download_{str(response.id)}.tar.gz") with tarfile.open(file_name_tar, mode="r:gz") as tar: members = tar.getmembers() path_names = set() for dependency in members: assert dependency.name not in path_names, ( f"#{response.id}: There is an unexpected duplicate {dependency.name} " f"in archive {file_name_tar}" ) path_names.add(dependency.name)
def test_dependency_replacement(test_env, tmpdir): """ Check that proper versions of dependencies were used. Process: * Send new request to Cachito API to fetch retrodep with another version of dependency package * Download a bundle archive Checks: * Check that the state of request is complete * Check that in the response there is a key "replaces" with dict values which was replaced * Check that dir deps/gomod/pkg/mod/cache/download/github.com/pkg/errors/@v/… contains only the required version * Check that app/go.mod file has replace directive for the specified package """ dependency_replacements = test_env["dep_replacement"][ "dependency_replacements"] client = utils.Client(test_env["api_url"], test_env["api_auth_type"], test_env.get("timeout")) response_created_req = client.create_new_request(payload={ "repo": test_env["packages"]["gomod"]["repo"], "ref": test_env["packages"]["gomod"]["ref"], "pkg_managers": test_env["packages"]["gomod"]["pkg_managers"], "dependency_replacements": dependency_replacements, }, ) response = client.wait_for_complete_request(response_created_req) utils.assert_properly_completed_response(response) names_replaced_dependencies = { i["replaces"]["name"] for i in response.data["dependencies"] if i["replaces"] is not None } supposed_replaced_dependencies = set(i["name"] for i in dependency_replacements) assert names_replaced_dependencies == supposed_replaced_dependencies bundle_dir_name = tmpdir.join(f"download_{str(response.id)}") client.download_and_extract_archive(response.id, tmpdir) for dependency in dependency_replacements: dep_name = utils.escape_path_go(dependency["name"]) dependency_version_file = path.join( bundle_dir_name, "deps", "gomod", "pkg", "mod", "cache", "download", dep_name, "@v", "list", ) assert path.exists(dependency_version_file), ( f"#{response.id}: Path for version of dependency " f"{dep_name} does not exist: {dependency_version_file}") with open(dependency_version_file, "r") as file: lines = {line.rstrip() for line in file.readlines()} assert dependency["version"] in lines, ( f"#{response.id}: File {dependency_version_file} does not contain" f" version {dependency['version']} that should have replaced the original one." ) go_mod_path = path.join(bundle_dir_name, "app", "go.mod") assert path.exists( go_mod_path ), f"#{response.id}: File go.mod does not exist in location: {go_mod_path}" with open(go_mod_path, "r") as file: go_mod_replace = [] for line in file: if line.startswith("replace "): go_mod_replace.append({ "name": line.split()[-2], "type": "gomod", "version": line.split()[-1] }) sorted_dep_replacements = utils.make_list_of_packages_hashable( dependency_replacements) sorted_go_mod_replace = utils.make_list_of_packages_hashable( go_mod_replace) assert sorted_go_mod_replace == sorted_dep_replacements