-
Notifications
You must be signed in to change notification settings - Fork 122
HelpersTask629_Add_tests_for_dockerized_executable_sync_gh_issue_labels #649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
67e33e6
599a565
6729dfa
e5e758f
d5e7e33
a51629e
d927547
4a96eef
a3de9c5
605373c
e7c27e4
219fdc1
16fc945
fe9ecc7
a57d627
89278b2
47a234d
0f88027
aa5dd4b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Test labels for GitHub issue label synchronization. | ||
- name: bug | ||
description: Bug label | ||
color: "#d73a4a" | ||
- name: feature | ||
description: Feature request | ||
color: "#00FF00" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
import logging | ||
import os | ||
import unittest.mock as umock | ||
from typing import Dict, Generator, List, Optional | ||
|
||
import pytest | ||
|
||
import dev_scripts_helpers.github.dockerized_sync_gh_issue_labels as dshgdsgil | ||
import helpers.hio as hio | ||
import helpers.hunit_test as hunitest | ||
|
||
_LOG = logging.getLogger(__name__) | ||
|
||
|
||
def _get_label_data() -> Dict[str, str]: | ||
return {"name": "test", "description": "test label", "color": "FF0000"} | ||
|
||
|
||
def _make_mock_label(label_data: Dict[str, str]) -> umock.Mock: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add doc string |
||
label = umock.Mock() | ||
label.name = label_data["name"] | ||
label.color = label_data["color"] | ||
label.description = label_data["description"] | ||
return label | ||
|
||
|
||
# ############################################################################# | ||
# TestLabel1 | ||
# ############################################################################# | ||
|
||
|
||
class TestLabel1(hunitest.TestCase): | ||
|
||
def test_save_label(self) -> None: | ||
""" | ||
Test saving a label object to a file. | ||
""" | ||
# Prepare inputs. | ||
label_data = _get_label_data() | ||
input_label = dshgdsgil.Label( | ||
label_data["name"], label_data["description"], label_data["color"] | ||
) | ||
temp_dir = self.get_scratch_space() | ||
tmp_file_name = os.path.join(temp_dir, "test_labels.yaml") | ||
# Run. | ||
dshgdsgil.Label.save_labels([input_label], tmp_file_name) | ||
# Check the output. | ||
actual = hio.from_file(tmp_file_name) | ||
expected = f""" | ||
- name: {label_data["name"]} | ||
description: {label_data["description"]} | ||
color: {label_data["color"]} | ||
""" | ||
self.assert_equal(actual, expected, fuzzy_match=True) | ||
|
||
def test_load_label(self) -> None: | ||
""" | ||
Test loading a label object from a file. | ||
""" | ||
# Prepare inputs. | ||
label_data = _get_label_data() | ||
temp_dir = self.get_scratch_space() | ||
tmp_file_name = os.path.join(temp_dir, "test_labels.yaml") | ||
# Create a file with known content. | ||
txt = f""" | ||
- name: {label_data["name"]} | ||
description: {label_data["description"]} | ||
color: {label_data["color"]} | ||
""" | ||
hio.to_file(tmp_file_name, txt) | ||
# Load the label. | ||
output_labels = dshgdsgil.Label.load_labels(tmp_file_name) | ||
output_label = output_labels[0] | ||
# Check the output. | ||
actual = f""" | ||
name={output_label.name} | ||
description={output_label.description} | ||
color={output_label.color} | ||
""" | ||
expected = f""" | ||
name={label_data["name"]} | ||
description={label_data["description"]} | ||
color={label_data["color"]} | ||
""" | ||
self.assert_equal(actual, expected, fuzzy_match=True) | ||
|
||
|
||
# ############################################################################# | ||
# TestDockerizedSyncGitHubIssueLabels | ||
# ############################################################################# | ||
|
||
|
||
class TestDockerizedSyncGitHubIssueLabels(hunitest.TestCase): | ||
|
||
@pytest.fixture(autouse=True) | ||
def setup_teardown_test(self) -> Generator: | ||
# Run before each test. | ||
self.set_up_test() | ||
yield | ||
# Run after each test. | ||
self.tear_down_test() | ||
|
||
def set_up_test(self) -> None: | ||
self.setUp() | ||
# Prepare inputs. | ||
self.temp_dir = self.get_scratch_space() | ||
self.tmp_file_name = os.path.join(self.temp_dir, "test_labels.yaml") | ||
self.input_args = { | ||
"owner": "test-org", | ||
"repo": "test-repo", | ||
"token_env_var": "GITHUB_TOKEN", | ||
"input_file": self.tmp_file_name, | ||
"no_interactive": True, | ||
} | ||
# Mock the GitHub client. | ||
self.mock_repo = umock.Mock() | ||
self.mock_client = umock.Mock() | ||
self.mock_client.get_repo.return_value = self.mock_repo | ||
self.github_patch = umock.patch( | ||
"github.Github", return_value=self.mock_client | ||
) | ||
self.env_patch = umock.patch.dict( | ||
os.environ, {"GITHUB_TOKEN": "fake_token"} | ||
) | ||
self.github_patch.start() | ||
self.env_patch.start() | ||
|
||
def tear_down_test(self) -> None: | ||
# Stop the patches. | ||
self.github_patch.stop() | ||
self.env_patch.stop() | ||
|
||
def test_create_new_label(self) -> None: | ||
""" | ||
Test that a new label is created when it exists in yaml but not in | ||
repo. | ||
""" | ||
# Prepare inputs. | ||
self.mock_repo.get_labels.return_value = [] | ||
label_data = _get_label_data() | ||
input_label = self._save_label(label_data) | ||
# Run. | ||
self._run_with_args() | ||
# Check if the mock was called. | ||
self.mock_repo.create_label.assert_called_once_with( | ||
name=input_label.name, | ||
color=input_label.color, | ||
description=input_label.description, | ||
) | ||
|
||
def test_update_existing_label(self) -> None: | ||
""" | ||
Test that a label is updated when it exists in both yaml and repo with | ||
different properties. | ||
""" | ||
# Prepare inputs. | ||
repo_label_data = { | ||
"name": "test", | ||
"description": "old desc", | ||
"color": "00FF00", | ||
} | ||
yaml_label_data = { | ||
"name": "test", | ||
"description": "new desc", | ||
"color": "FF0000", | ||
} | ||
mock_label = _make_mock_label(repo_label_data) | ||
self.mock_repo.get_labels.return_value = [mock_label] | ||
input_label = self._save_label(yaml_label_data) | ||
# Run. | ||
self._run_with_args() | ||
# Check if the mock was called. | ||
mock_label.edit.assert_called_once_with( | ||
name=input_label.name, | ||
color=input_label.color, | ||
description=input_label.description, | ||
) | ||
|
||
def test_identical_label(self) -> None: | ||
""" | ||
Test that no changes are made when label exists and is identical. | ||
""" | ||
# Prepare inputs. | ||
label_data = _get_label_data() | ||
mock_label = _make_mock_label(label_data) | ||
self.mock_repo.get_labels.return_value = [mock_label] | ||
self._save_label(label_data) | ||
# Run. | ||
self._run_with_args() | ||
# Check if the mock was called. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we check if the create operation was called too? |
||
mock_label.edit.assert_not_called() | ||
mock_label.delete.assert_not_called() | ||
|
||
def test_prune_label(self) -> None: | ||
""" | ||
Test that labels that exist in repo but not in yaml are deleted when | ||
prune is enabled. | ||
""" | ||
# Prepare inputs. | ||
repo_label1 = { | ||
"name": "to_prune1", | ||
"description": "desc1", | ||
"color": "FF0000", | ||
} | ||
repo_label2 = { | ||
"name": "to_prune2", | ||
"description": "desc2", | ||
"color": "00FF00", | ||
} | ||
mock_label1 = _make_mock_label(repo_label1) | ||
mock_label2 = _make_mock_label(repo_label2) | ||
self.mock_repo.get_labels.return_value = [mock_label1, mock_label2] | ||
# Test with no labels in the YAML file. | ||
dshgdsgil.Label.save_labels([], self.tmp_file_name) | ||
# Run. | ||
self._run_with_args(extra_args=["--prune"]) | ||
# Check if the mock was called. | ||
mock_label1.delete.assert_called_once() | ||
mock_label2.delete.assert_called_once() | ||
|
||
def _run_with_args(self, *, extra_args: Optional[List[str]] = None) -> None: | ||
""" | ||
Run `dockerized_sync_gh_issue_labels.py` script with the given | ||
arguments. | ||
|
||
:param extra_args: additional arguments to pass to the script | ||
""" | ||
args = [ | ||
"--input_file", | ||
self.input_args["input_file"], | ||
"--owner", | ||
self.input_args["owner"], | ||
"--repo", | ||
self.input_args["repo"], | ||
"--token_env_var", | ||
self.input_args["token_env_var"], | ||
] | ||
if self.input_args.get("no_interactive", False): | ||
args.append("--no_interactive") | ||
if extra_args: | ||
args += extra_args | ||
with umock.patch("sys.argv", ["script"] + args): | ||
parser = dshgdsgil._parse() | ||
dshgdsgil._main(parser) | ||
|
||
def _save_label(self, label_data: Dict[str, str]) -> dshgdsgil.Label: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use the |
||
""" | ||
Create a Label from label_data and save it to a YAML file. | ||
|
||
:param label_data: the label data to save | ||
:return: the Label instance | ||
""" | ||
label = dshgdsgil.Label( | ||
label_data["name"], label_data["description"], label_data["color"] | ||
) | ||
dshgdsgil.Label.save_labels([label], self.tmp_file_name) | ||
return label |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import logging | ||
import os | ||
import unittest.mock as umock | ||
|
||
import pytest | ||
|
||
import dev_scripts_helpers.github.sync_gh_issue_labels as dshgsgila | ||
import helpers.hgit as hgit | ||
import helpers.hserver as hserver | ||
import helpers.hunit_test as hunitest | ||
|
||
_LOG = logging.getLogger(__name__) | ||
|
||
|
||
# ############################################################################# | ||
# Test_sync_gh_issue_labels1 | ||
sandeepthalapanane marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# ############################################################################# | ||
|
||
|
||
class Test_sync_gh_issue_labels1(hunitest.TestCase): | ||
|
||
@pytest.mark.skipif( | ||
hserver.is_inside_ci() or hserver.is_dev_csfy(), | ||
reason="Disabled because of CmampTask10710", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you able to run this test locally? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just upgraded to Ubuntu 24 and will be testing it out. I believe this test is important to ensure that the Docker container functions without any issues. Since we have already tested the functionalities in the dockerized test script, I want to verify that the Docker container operates smoothly as well. This way, we can ensure that everything runs smoothly and ticks all the boxes. |
||
) | ||
@umock.patch( | ||
"dev_scripts_helpers.github.dockerized_sync_gh_issue_labels.github.Github" | ||
) | ||
def test1(self, mock_github: umock.Mock) -> None: | ||
""" | ||
Test that the dockerized executable reads the input file, performs the | ||
necessary operations, and writes the backup file in the git root | ||
directory. | ||
sandeepthalapanane marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" | ||
# Set up mock labels. | ||
label_data = { | ||
"name": "bug", | ||
"color": "f29513", | ||
"description": "Something isn't working", | ||
} | ||
mock_label = umock.Mock() | ||
for k, v in label_data.items(): | ||
setattr(mock_label, k, v) | ||
Comment on lines
+36
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about creating a label object and mock it? |
||
# Set up mock GitHub repo. | ||
mock_repo = umock.Mock() | ||
mock_repo.get_labels.return_value = [mock_label] | ||
mock_client = umock.Mock() | ||
mock_client.get_repo.return_value = mock_repo | ||
mock_github.return_value = mock_client | ||
# Prepare input arguments. | ||
input_args = { | ||
"in_dir_name": self.get_input_dir(), | ||
"owner": "test-org", | ||
"repo": "test-repo", | ||
"token_env_var": "GITHUB_TEST_TOKEN", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the client running the tests might not have this var set |
||
} | ||
input_file_path = os.path.join( | ||
input_args["in_dir_name"], "test_gh_issues_labels.yml" | ||
) | ||
git_root_dir = hgit.get_client_root(False) | ||
backup_file_name = "tmp.labels.test-org.test-repo.yaml" | ||
backup_file_path = os.path.join(git_root_dir, backup_file_name) | ||
# Remove backup file if it exists. | ||
if os.path.exists(backup_file_path): | ||
os.remove(backup_file_path) | ||
# Run test. | ||
dshgsgila._run_dockerized_sync_gh_issue_labels( | ||
input_file_path, | ||
input_args["owner"], | ||
input_args["repo"], | ||
input_args["token_env_var"], | ||
dry_run=False, | ||
no_interactive=True, | ||
prune=False, | ||
backup=True, | ||
) | ||
# Check that the backup file exists. | ||
self.assertTrue( | ||
os.path.exists(backup_file_path), | ||
msg="Backup file was not created.", | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason why we don't use the Label object right away so there's no extra layer of conversion?