generated from oracle/template-repo
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: fix the GitHub Actions workflow detection test (#591)
This PR fixes a bug in the GitHub Actions workflow detection test. The assertions in the test_get_workflows function were checking the return values of list.sort(), which is an in-place function and doesn't return anything. Instead we should compare the sorted lists. This PR also refactors the tests and removes MacaronTestCase, which is not necessary anymore. Signed-off-by: behnazh-w <behnaz.hassanshahi@oracle.com>
- Loading branch information
Showing
1 changed file
with
94 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,87 +1,105 @@ | ||
# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. | ||
# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. | ||
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. | ||
|
||
"""This module tests GitHub Actions CI service.""" | ||
|
||
import os | ||
from pathlib import Path | ||
|
||
import pytest | ||
|
||
from macaron import MACARON_PATH | ||
from macaron.code_analyzer.call_graph import CallGraph | ||
from macaron.parsers.actionparser import parse as parse_action | ||
from macaron.slsa_analyzer.ci_service.github_actions import GHWorkflowType, GitHubActions, GitHubNode | ||
|
||
from ...macaron_testcase import MacaronTestCase | ||
|
||
|
||
class TestGitHubActions(MacaronTestCase): | ||
"""Test the GitHub Actions CI service.""" | ||
|
||
github_actions = GitHubActions() | ||
mock_repos = Path(__file__).parent.joinpath("mock_repos") | ||
ga_has_build_kws = mock_repos.joinpath("has_build_gh_actions") | ||
jenkins_build = mock_repos.joinpath("has_build_jenkins") | ||
ga_no_build_kws = mock_repos.joinpath("no_build_gh_actions") | ||
|
||
def test_build_call_graph(self) -> None: | ||
"""Test building call graphs for GitHub Actions workflows.""" | ||
resources_dir = Path(__file__).parent.joinpath("resources", "github") | ||
|
||
# Test internal and reusable workflows. | ||
# Parse GitHub Actions workflows. | ||
root = GitHubNode(name="root", node_type=GHWorkflowType.NONE, source_path="", parsed_obj={}, caller_path="") | ||
gh_cg = CallGraph(root, "") | ||
workflow_path = os.path.join(resources_dir, "valid1.yaml") | ||
parsed_obj = parse_action(workflow_path, macaron_path=str(self.macaron_path)) | ||
|
||
callee = GitHubNode( | ||
name=os.path.basename(workflow_path), | ||
node_type=GHWorkflowType.INTERNAL, | ||
source_path=workflow_path, | ||
parsed_obj=parsed_obj, | ||
caller_path="", | ||
) | ||
root.add_callee(callee) | ||
self.github_actions.build_call_graph_from_node(callee) | ||
assert [ | ||
"GitHubNode(valid1.yaml,GHWorkflowType.INTERNAL)", | ||
"GitHubNode(apache/maven-gh-actions-shared/.github/workflows/maven-verify.yml@v2,GHWorkflowType.REUSABLE)", | ||
] == [str(node) for node in gh_cg.bfs()] | ||
|
||
# Test internal and external workflows. | ||
# Parse GitHub Actions workflows. | ||
root = GitHubNode(name="root", node_type=GHWorkflowType.NONE, source_path="", parsed_obj={}, caller_path="") | ||
gh_cg = CallGraph(root, "") | ||
workflow_path = os.path.join(resources_dir, "valid2.yaml") | ||
parsed_obj = parse_action(workflow_path, macaron_path=str(self.macaron_path)) | ||
|
||
callee = GitHubNode( | ||
name=os.path.basename(workflow_path), | ||
node_type=GHWorkflowType.INTERNAL, | ||
source_path=workflow_path, | ||
parsed_obj=parsed_obj, | ||
caller_path="", | ||
) | ||
root.add_callee(callee) | ||
self.github_actions.build_call_graph_from_node(callee) | ||
assert [ | ||
"GitHubNode(valid2.yaml,GHWorkflowType.INTERNAL)", | ||
"GitHubNode(actions/checkout@v3,GHWorkflowType.EXTERNAL)", | ||
"GitHubNode(actions/cache@v3,GHWorkflowType.EXTERNAL)", | ||
"GitHubNode(actions/setup-java@v3,GHWorkflowType.EXTERNAL)", | ||
] == [str(node) for node in gh_cg.bfs()] | ||
|
||
def test_is_detected(self) -> None: | ||
"""Test detecting GitHub Action config files.""" | ||
assert self.github_actions.is_detected(str(self.ga_has_build_kws)) | ||
assert self.github_actions.is_detected(str(self.ga_no_build_kws)) | ||
assert not self.github_actions.is_detected(str(self.jenkins_build)) | ||
|
||
def test_get_workflows(self) -> None: | ||
"""Test getting GitHub Actions workflows.""" | ||
expect = list(self.ga_has_build_kws.joinpath(".github", "workflows").glob("*")).sort() | ||
assert self.github_actions.get_workflows(str(self.ga_has_build_kws)).sort() == expect | ||
|
||
expect = list(self.ga_no_build_kws.joinpath(".github", "workflows").glob("*")).sort() | ||
assert self.github_actions.get_workflows(str(self.ga_no_build_kws)).sort() == expect | ||
|
||
assert not self.github_actions.get_workflows(str(self.jenkins_build)) | ||
mock_repos = Path(__file__).parent.joinpath("mock_repos") | ||
ga_has_build_kws = mock_repos.joinpath("has_build_gh_actions") | ||
jenkins_build = mock_repos.joinpath("has_build_jenkins") | ||
ga_no_build_kws = mock_repos.joinpath("no_build_gh_actions") | ||
|
||
|
||
@pytest.fixture(name="github_actions") | ||
def github_actions_() -> GitHubActions: | ||
"""Create a GitHubActions instance.""" | ||
return GitHubActions() | ||
|
||
|
||
@pytest.mark.parametrize( | ||
( | ||
"workflow_name", | ||
"expect", | ||
), | ||
[ | ||
( | ||
"valid1.yaml", | ||
[ | ||
"GitHubNode(valid1.yaml,GHWorkflowType.INTERNAL)", | ||
"GitHubNode(apache/maven-gh-actions-shared/.github/workflows/maven-verify.yml@v2,GHWorkflowType.REUSABLE)", | ||
], | ||
), | ||
( | ||
"valid2.yaml", | ||
[ | ||
"GitHubNode(valid2.yaml,GHWorkflowType.INTERNAL)", | ||
"GitHubNode(actions/checkout@v3,GHWorkflowType.EXTERNAL)", | ||
"GitHubNode(actions/cache@v3,GHWorkflowType.EXTERNAL)", | ||
"GitHubNode(actions/setup-java@v3,GHWorkflowType.EXTERNAL)", | ||
], | ||
), | ||
], | ||
ids=[ | ||
"Internal and reusable workflows", | ||
"Internal and external workflows", | ||
], | ||
) | ||
def test_build_call_graph(github_actions: GitHubActions, workflow_name: str, expect: list[str]) -> None: | ||
"""Test building call graphs for GitHub Actions workflows.""" | ||
resources_dir = Path(__file__).parent.joinpath("resources", "github") | ||
|
||
# Parse GitHub Actions workflows. | ||
root = GitHubNode(name="root", node_type=GHWorkflowType.NONE, source_path="", parsed_obj={}, caller_path="") | ||
gh_cg = CallGraph(root, "") | ||
workflow_path = os.path.join(resources_dir, workflow_name) | ||
parsed_obj = parse_action(workflow_path, macaron_path=MACARON_PATH) | ||
|
||
callee = GitHubNode( | ||
name=os.path.basename(workflow_path), | ||
node_type=GHWorkflowType.INTERNAL, | ||
source_path=workflow_path, | ||
parsed_obj=parsed_obj, | ||
caller_path="", | ||
) | ||
root.add_callee(callee) | ||
github_actions.build_call_graph_from_node(callee) | ||
assert [str(node) for node in gh_cg.bfs()] == expect | ||
|
||
|
||
def test_is_detected(github_actions: GitHubActions) -> None: | ||
"""Test detecting GitHub Action config files.""" | ||
assert github_actions.is_detected(str(ga_has_build_kws)) | ||
assert github_actions.is_detected(str(ga_no_build_kws)) | ||
assert not github_actions.is_detected(str(jenkins_build)) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"mock_repo", | ||
[ | ||
ga_has_build_kws, | ||
ga_no_build_kws, | ||
], | ||
ids=[ | ||
"GH Actions with build", | ||
"GH Actions with no build", | ||
], | ||
) | ||
def test_gh_get_workflows(github_actions: GitHubActions, mock_repo: Path) -> None: | ||
"""Test detection of reachable GitHub Actions workflows.""" | ||
expect = [str(path) for path in mock_repo.joinpath(".github", "workflows").glob("*")] | ||
workflows = github_actions.get_workflows(str(mock_repo)) | ||
assert sorted(workflows) == sorted(expect) | ||
|
||
|
||
def test_gh_get_workflows_fail_on_jenkins(github_actions: GitHubActions) -> None: | ||
"""Assert GitHubActions workflow detection not working on Jenkins CI configuration files.""" | ||
assert not github_actions.get_workflows(str(jenkins_build)) |