Skip to content

HelpersTask615_Come_up_with_a_testing_approach_for_release_flow #651

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

Merged
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
053175a
Merge remote-tracking branch 'origin/master' into HelpersTask615_Come…
sandeepthalapanane Apr 28, 2025
0193193
HelpersTask615: Add unittest for docker_build_local_image()
sandeepthalapanane Apr 29, 2025
7bb1e74
Merge remote-tracking branch 'origin/master' into HelpersTask615_Come…
sandeepthalapanane Apr 29, 2025
070c1c1
HelpersTask615: Modify comments and docstring
sandeepthalapanane Apr 29, 2025
62e1f7e
HelpersTask615: Move helper functions out of the class
sandeepthalapanane Apr 30, 2025
98ff6cc
Merge remote-tracking branch 'origin/master' into HelpersTask615_Come…
sandeepthalapanane Apr 30, 2025
bbc022b
HelpersTask615: Merge master
sandeepthalapanane Apr 30, 2025
3dc176b
HelpersTask615: Rename helper functions
sandeepthalapanane Apr 30, 2025
1d66e48
HelpersTask615: Merge master into HelpersTask615_Come_up_with_a_testi…
sandeepthalapanane Apr 30, 2025
0b78a4d
Merge branch 'master' into HelpersTask615_Come_up_with_a_testing_appr…
dremdem Apr 30, 2025
49c5841
HelpersTask615: Split the check into seperate checks
sandeepthalapanane Apr 30, 2025
aec4479
Merge remote-tracking branch 'origin/master' into HelpersTask615_Come…
sandeepthalapanane Apr 30, 2025
1da532a
HelpersTask615: Remove .body from function call
sandeepthalapanane May 1, 2025
c408886
Merge remote-tracking branch 'origin/master' into HelpersTask615_Come…
sandeepthalapanane May 1, 2025
e61b802
Update
gpsaggese May 1, 2025
1781088
HelpersTask615: Propogate changes from previous commit
sandeepthalapanane May 1, 2025
939dc32
Merge remote-tracking branch 'origin/master' into HelpersTask615_Come…
sandeepthalapanane May 1, 2025
aa08a68
HelpersTask615: Modify comments
sandeepthalapanane May 1, 2025
45a2113
Merge branch 'master' into HelpersTask615_Come_up_with_a_testing_appr…
gpsaggese May 2, 2025
3e9ac1d
Merge remote-tracking branch 'origin/master' into HelpersTask615_Come…
sandeepthalapanane May 2, 2025
e545fcc
HelpersTask615: Added tests for building prod_image
sandeepthalapanane May 2, 2025
649a946
Merge remote-tracking branch 'origin/master' into HelpersTask615_Come…
sandeepthalapanane May 2, 2025
a1b6fe2
Merge branch 'master' into HelpersTask615_Come_up_with_a_testing_appr…
dremdem May 5, 2025
60cf04b
Merge branch 'master' into HelpersTask615_Come_up_with_a_testing_appr…
dremdem May 5, 2025
fa46cc3
HelpersTask615: Add a helper test class to refactor common code
sandeepthalapanane May 5, 2025
816c2da
HelpersTask615: Move inputs into setUp
sandeepthalapanane May 5, 2025
6fdf6bf
HelpersTask615: Change setUp and tearDown
sandeepthalapanane May 5, 2025
6fc4738
Merge remote-tracking branch 'origin/master' into HelpersTask615_Come…
sandeepthalapanane May 5, 2025
457b863
Merge branch 'master' into HelpersTask615_Come_up_with_a_testing_appr…
sandeepthalapanane May 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 220 additions & 56 deletions helpers/test/test_lib_tasks_docker_release.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import logging
import unittest.mock as umock
from typing import List
from typing import Generator, List

import pytest

import helpers.hsystem as hsystem
import helpers.hunit_test as hunitest
import helpers.lib_tasks_docker_release as hltadore
import helpers.test.test_lib_tasks as httestlib
Expand Down Expand Up @@ -36,17 +37,23 @@ def _extract_commands_from_call(calls: List[umock._Call]) -> List[str]:


# #############################################################################
# TestDockerBuildLocalImage1
# _DockerFlowTestHelper
# #############################################################################


class TestDockerBuildLocalImage1(hunitest.TestCase):
class _DockerFlowTestHelper(hunitest.TestCase):
"""
Helper test class to perform common setup, teardown logic and assertion
checks for Docker flow tests.
"""

def setUp(self) -> None:
"""
Set up test environment and initialize all necessary mocks.
"""
super().setUp()
@pytest.fixture(autouse=True)
def setup_teardown_test(self) -> Generator:
self.set_up_test()
yield
self.tear_down_test()

def set_up_test(self) -> None:
# Mock system calls.
self.system_patcher = umock.patch("helpers.hsystem.system")
self.mock_system = self.system_patcher.start()
Expand All @@ -63,41 +70,78 @@ def setUp(self) -> None:
"helpers.lib_tasks_docker.docker_login"
)
self.mock_docker_login = self.docker_login_patcher.start()
# Mock environment variable.
self.env_patcher = umock.patch.dict(
"os.environ", {"CSFY_ECR_BASE_PATH": "test.ecr.path"}
)
self.env_patcher.start()
#
self.user = hsystem.get_user_name()
self.patchers = [
self.system_patcher,
self.run_patcher,
self.version_patcher,
self.docker_login_patcher,
self.env_patcher,
]
# Test inputs.
self.mock_ctx = httestlib._build_mock_context_returning_ok()
self.test_version = "1.0.0"
self.test_base_image = "test-registry.com/test-image"
self.test_multi_arch = "linux/amd64,linux/arm64"

def tearDown(self) -> None:
def tear_down_test(self) -> None:
"""
Clean up test environment by stopping all mocks after each test case.
"""
self.system_patcher.stop()
self.run_patcher.stop()
self.version_patcher.stop()
self.docker_login_patcher.stop()
super().tearDown()
for patcher in self.patchers:
patcher.stop()

def _check_docker_command_output(
self, exp: str, call_args_list: List[umock._Call]
) -> None:
"""
Check that the sequence of commands from mock calls matches the
expected string.

:param exp: expected command string
:param call_args_list: list of mock call objects
"""
actual_cmds = _extract_commands_from_call(call_args_list)
actual_cmds = "\n".join(actual_cmds)
self.assert_equal(
actual_cmds,
exp,
purify_text=True,
purify_expected_text=True,
fuzzy_match=True,
remove_lead_trail_empty_lines=True,
dedent=True,
)

def test_docker_build_single_arch(self) -> None:

# #############################################################################
# Test_docker_build_local_image1
# #############################################################################


class Test_docker_build_local_image1(_DockerFlowTestHelper):

def test_docker_build_local_image_single_arch(self) -> None:
"""
Test building a local Docker image with single architecture.

This test verifies that the correct sequence of commands is
generated for building a local Docker image with single
architecture.
"""
# Prepare inputs.
mock_ctx = httestlib._build_mock_context_returning_ok()
test_version = "1.0.0"
test_base_image = "test-registry.com/test-image"
# Call tested function.
hltadore.docker_build_local_image(
mock_ctx,
test_version,
self.mock_ctx,
self.test_version,
cache=False,
base_image=test_base_image,
base_image=self.test_base_image,
poetry_mode="update",
)
actual_cmds = _extract_commands_from_call(self.mock_run.call_args_list)
actual_cmds = "\n".join(actual_cmds)
# The output is a list of strings, each representing a command.
exp = r"""
cp -f devops/docker_build/dockerignore.dev .dockerignore
Expand All @@ -114,41 +158,25 @@ def test_docker_build_single_arch(self) -> None:
cp -f pip_list.txt ./devops/docker_build/pip_list.txt
docker image ls test-registry.com/test-image:local-$USER_NAME-1.0.0
"""
# Check output.
self.assert_equal(
actual_cmds,
exp,
purify_text=True,
fuzzy_match=True,
remove_lead_trail_empty_lines=True,
dedent=True,
)
self._check_docker_command_output(exp, self.mock_run.call_args_list)

def test_docker_build_multi_arch(self) -> None:
def test_docker_build_local_image_multi_arch(self) -> None:
"""
Test building a local Docker image with multiple architectures.

This test verifies that the correct sequence of commands is
generated for building a local Docker image with multiple
architectures.
"""
# Prepare inputs.
mock_ctx = httestlib._build_mock_context_returning_ok()
test_version = "1.0.0"
test_base_image = "test-registry.com/test-image"
test_multi_arch = "linux/amd64,linux/arm64"
# Call tested function.
hltadore.docker_build_local_image(
mock_ctx,
test_version,
self.mock_ctx,
self.test_version,
cache=False,
base_image=test_base_image,
base_image=self.test_base_image,
poetry_mode="update",
multi_arch=test_multi_arch,
multi_arch=self.test_multi_arch,
)
actual_cmds = _extract_commands_from_call(self.mock_run.call_args_list)
actual_cmds = "\n".join(actual_cmds)
# The output is a list of strings, each representing a command.
exp = r"""
cp -f devops/docker_build/dockerignore.dev .dockerignore
docker buildx create \
Expand All @@ -173,12 +201,148 @@ def test_docker_build_multi_arch(self) -> None:
cp -f pip_list.txt ./devops/docker_build/pip_list.txt
docker image ls test-registry.com/test-image:local-$USER_NAME-1.0.0
"""
# Check output.
self.assert_equal(
actual_cmds,
exp,
purify_text=True,
fuzzy_match=True,
remove_lead_trail_empty_lines=True,
dedent=True,
self._check_docker_command_output(exp, self.mock_run.call_args_list)


# #############################################################################
# Test_docker_build_prod_image1
# #############################################################################


class Test_docker_build_prod_image1(_DockerFlowTestHelper):

def test_docker_build_prod_image(self) -> None:
"""
Test building a prod Docker image with single architecture.

This test verifies that the correct sequence of commands is
generated for building a prod Docker image.
"""
# Call tested function.
hltadore.docker_build_prod_image(
self.mock_ctx,
self.test_version,
base_image=self.test_base_image,
cache=False,
)
exp = r"""
cp -f devops/docker_build/dockerignore.prod .dockerignore
DOCKER_BUILDKIT=0 \
time \
docker build \
--no-cache \
--tag test-registry.com/test-image:prod-1.0.0 \
--file /app/devops/docker_build/prod.Dockerfile \
--build-arg VERSION=1.0.0 \
--build-arg ECR_BASE_PATH=test.ecr.path \
.
docker tag test-registry.com/test-image:prod-1.0.0 test-registry.com/test-image:prod
docker image ls test-registry.com/test-image:prod
"""
self._check_docker_command_output(exp, self.mock_run.call_args_list)

def test_docker_build_multi_arch_prod_image(self) -> None:
"""
Test building a prod Docker image with multiple architectures.

This test verifies that the correct sequence of commands is
generated for building a multi-arch prod Docker image.
"""
# Call tested function.
hltadore.docker_build_multi_arch_prod_image(
self.mock_ctx,
self.test_version,
base_image=self.test_base_image,
cache=False,
multi_arch=self.test_multi_arch,
)
exp = r"""
cp -f devops/docker_build/dockerignore.prod .dockerignore
docker buildx create \
--name multiarch_builder \
--driver docker-container \
--bootstrap \
&& \
docker buildx use multiarch_builder
tar -czh . | DOCKER_BUILDKIT=0 \
time \
docker buildx build \
--no-cache \
--push \
--platform linux/amd64,linux/arm64 \
--build-arg VERSION=1.0.0 --build-arg ECR_BASE_PATH=test.ecr.path \
--tag test-registry.com/test-image:prod-1.0.0 \
--file devops/docker_build/prod.Dockerfile \
-
docker pull test-registry.com/test-image:prod-1.0.0
docker image ls test-registry.com/test-image:prod-1.0.0
"""
self._check_docker_command_output(exp, self.mock_run.call_args_list)

def test_docker_build_prod_image_with_candidate_tag(self) -> None:
"""
Test building a prod Docker image with candidate mode using tag.

This test verifies that the correct sequence of commands is
generated for building a prod image with candidate mode using
tag.
"""
test_tag = "test_tag"
# Call tested function.
hltadore.docker_build_prod_image(
self.mock_ctx,
self.test_version,
base_image=self.test_base_image,
cache=False,
candidate=True,
tag=test_tag,
)
exp = r"""
cp -f devops/docker_build/dockerignore.prod .dockerignore
DOCKER_BUILDKIT=0 \
time \
docker build \
--no-cache \
--tag test-registry.com/test-image:prod-test_tag \
--file /app/devops/docker_build/prod.Dockerfile \
--build-arg VERSION=1.0.0 \
--build-arg ECR_BASE_PATH=test.ecr.path \
.
docker image ls test-registry.com/test-image:prod-test_tag
"""
self._check_docker_command_output(exp, self.mock_run.call_args_list)

def test_docker_build_prod_image_with_candidate_user_tag(self) -> None:
"""
Test building a prod Docker image with candidate mode using user tag.

This test verifies that the correct sequence of commands is
generated for building a prod image with candidate mode using
user tag and tag.
"""
test_user_tag = "test_user"
test_tag = "test_tag"
# Call tested function.
hltadore.docker_build_prod_image(
self.mock_ctx,
self.test_version,
base_image=self.test_base_image,
cache=False,
candidate=True,
user_tag=test_user_tag,
tag=test_tag,
)
exp = r"""
cp -f devops/docker_build/dockerignore.prod .dockerignore
DOCKER_BUILDKIT=0 \
time \
docker build \
--no-cache \
--tag test-registry.com/test-image:prod-test_user-test_tag \
--file /app/devops/docker_build/prod.Dockerfile \
--build-arg VERSION=1.0.0 \
--build-arg ECR_BASE_PATH=test.ecr.path \
.
docker image ls test-registry.com/test-image:prod-test_user-test_tag
"""
self._check_docker_command_output(exp, self.mock_run.call_args_list)
Loading