diff --git a/docs/developer-guide/unit-testing.md b/docs/developer-guide/unit-testing.md index 91aea0911d..c01c0a97fd 100644 --- a/docs/developer-guide/unit-testing.md +++ b/docs/developer-guide/unit-testing.md @@ -437,74 +437,97 @@ Please refer to the [AWS checks tests](./unit-testing.md#checks) for more inform For the GCP Provider we don't have any library to mock out the API calls we use. So in this scenario we inject the objects in the service client using [MagicMock](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock). -The following code shows how to use MagicMock to create the service objects for a GCP check test. +The following code shows how to use MagicMock to create the service objects for a GCP check test. It is a real example adapted for informative purposes. ```python -# We need to import the unittest.mock to allow us to patch some objects -# not to use shared ones between test, hence to isolate the test +from re import search from unittest import mock -# GCP Constants -GCP_PROJECT_ID = "123456789012" +# Import some constans values needed in every check +from tests.providers.gcp.gcp_fixtures import GCP_PROJECT_ID, set_mocked_gcp_provider -# We are going to create a test for the compute_firewall_rdp_access_from_the_internet_allowed check -class Test_compute_firewall_rdp_access_from_the_internet_allowed: +# We are going to create a test for the compute_project_os_login_enabled check +class Test_compute_project_os_login_enabled: - # We name the tests with test___ - def test_compute_compute_firewall_rdp_access_from_the_internet_allowed_one_compliant_rule_with_valid_port(self): + def test_one_compliant_project(self): + # Import the service resource model to create the mocked object + from prowler.providers.gcp.services.compute.compute_service import Project + # Create the custom Project object to be tested + project = Project( + id=GCP_PROJECT_ID, + enable_oslogin=True, + ) # Mocked client with MagicMock compute_client = mock.MagicMock - - # Assign GCP client configuration compute_client.project_ids = [GCP_PROJECT_ID] - compute_client.region = "global" + compute_client.projects = [project] - # Import the service resource model to create the mocked object - from prowler.providers.gcp.services.compute.compute_service import Firewall - - # Create the custom Firewall object to be tested - firewall = Firewall( - name="test", - id="1234567890", - source_ranges=["0.0.0.0/0"], - direction="INGRESS", - allowed_rules=[{"IPProtocol": "tcp", "ports": ["443"]}], - project_id=GCP_PROJECT_ID, + # In this scenario we have to mock the app_client from the check to enforce that the compute_client used is the one created above + # And also is mocked the return value of get_global_provider function to return our GCP mocked provider defined in fixtures + with mock.patch( + "prowler.providers.common.common.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.compute.compute_project_os_login_enabled.compute_project_os_login_enabled.compute_client", + new=compute_client, + ): + # We import the check within the two mocks + from prowler.providers.gcp.services.compute.compute_project_os_login_enabled.compute_project_os_login_enabled import ( + compute_project_os_login_enabled, + ) + # Once imported, we only need to instantiate the check's class + check = compute_project_os_login_enabled() + # And then, call the execute() function to run the check + # against the Compute client we've set up. + result = check.execute() + # Assert the expected results + assert len(result) == 1 + assert result[0].status == "PASS" + assert search( + f"Project {project.id} has OS Login enabled", + result[0].status_extended, + ) + assert result[0].resource_id == project.id + assert result[0].location == "global" + assert result[0].project_id == GCP_PROJECT_ID + + # Complementary test to make more coverage for different scenarios + def test_one_non_compliant_project(self): + from prowler.providers.gcp.services.compute.compute_service import Project + + project = Project( + id=GCP_PROJECT_ID, + enable_oslogin=False, ) - compute_client.firewalls = [firewall] - # In this scenario we have to mock also the Compute service and the compute_client from the check to enforce that the compute_client used is the one created within this check because patch != import, and if you execute tests in parallel some objects can be already initialised hence the check won't be isolated. - # In this case we don't use the Moto decorator, we use the mocked Compute client for both objects + compute_client = mock.MagicMock + compute_client.project_ids = [GCP_PROJECT_ID] + compute_client.projects = [project] + with mock.patch( - "prowler.providers.gcp.services.compute.compute_service.Compute", - new=defender_client, + "prowler.providers.common.common.get_global_provider", + return_value=set_mocked_gcp_provider(), ), mock.patch( - "prowler.providers.gcp.services.compute.compute_client.compute_client", - new=defender_client, + "prowler.providers.gcp.services.compute.compute_project_os_login_enabled.compute_project_os_login_enabled.compute_client", + new=compute_client, ): - - # We import the check within the two mocks not to initialise the iam_client with some shared information from - # the current_audit_info or the Compute service. - from prowler.providers.gcp.services.compute.compute_firewall_rdp_access_from_the_internet_allowed.compute_firewall_rdp_access_from_the_internet_allowed import ( - compute_firewall_rdp_access_from_the_internet_allowed, + from prowler.providers.gcp.services.compute.compute_project_os_login_enabled.compute_project_os_login_enabled import ( + compute_project_os_login_enabled, ) - # Once imported, we only need to instantiate the check's class - check = compute_firewall_rdp_access_from_the_internet_allowed() - - # And then, call the execute() function to run the check - # against the IAM client we've set up. + check = compute_project_os_login_enabled() result = check.execute() - # Last but not least, we need to assert all the fields - # from the check's results assert len(result) == 1 - assert result[0].status == "PASS" - assert result[0].status_extended == f"Firewall {firewall.name} does not expose port 3389 (RDP) to the internet." - assert result[0].resource_name = firewall.name - assert result[0].resource_id == firewall.id - assert result[0].project_id = GCP_PROJECT_ID - assert result[0].location = compute_client.region + assert result[0].status == "FAIL" + assert search( + f"Project {project.id} does not have OS Login enabled", + result[0].status_extended, + ) + assert result[0].resource_id == project.id + assert result[0].location == "global" + assert result[0].project_id == GCP_PROJECT_ID + ``` ### Services @@ -535,7 +558,7 @@ from tests.providers.azure.azure_fixtures import ( # We are going to create a test for the app_ensure_http_is_redirected_to_https check class Test_app_ensure_http_is_redirected_to_https: - # We name the tests with test__ + # We name the tests with test___ def test_app_http_to_https_disabled(self): resource_id = f"/subscriptions/{uuid4()}" # Mocked client with MagicMock