import unittest import json import pytest from unittest.mock import patch, MagicMock from ansible.module_utils.basic import AnsibleModule from ansible.module_utils import basic from ansible.module_utils.common.text.converters import to_bytes from ansible_collections.ednz_cloud.infomaniak.plugins.modules import ( public_cloud_config_info, ) def set_module_args(args): if "_ansible_remote_tmp" not in args: args["_ansible_remote_tmp"] = "/tmp" if "_ansible_keep_remote_files" not in args: args["_ansible_keep_remote_files"] = False args = json.dumps({"ANSIBLE_MODULE_ARGS": args}) basic._ANSIBLE_ARGS = to_bytes(args) class AnsibleExitJson(Exception): def __init__(self, kwargs): self.kwargs = kwargs def exit_json(*args, **kwargs): if "changed" not in kwargs: kwargs["changed"] = False raise AnsibleExitJson(kwargs) def fail_json(*args, **kwargs): raise SystemExit(json.dumps(kwargs)) class TestPublicCloudConfigInfoModule(unittest.TestCase): """ Unit tests for the public_cloud_config_info Ansible module. """ @patch( "ansible_collections.ednz_cloud.infomaniak.plugins.modules.public_cloud_config_info.AnsibleModule" ) @patch( "ansible_collections.ednz_cloud.infomaniak.plugins.modules.public_cloud_config_info.InfomaniakAPIClient" ) def test_successful_retrieval(self, mock_client_class, mock_ansible_module): """ Test a successful retrieval of public cloud configuration. """ api_response_data = { "result": "success", "data": { "free_tier": 300, "free_tier_used": 24.34, "account_resource_level": 2, "valid_from": 1707584356, "valid_to": 1717192799, "project_count": 2, }, } mock_client_instance = MagicMock() mock_client_instance.get.return_value = api_response_data mock_client_class.return_value = mock_client_instance mock_module_instance = MagicMock() mock_module_instance.params = { "api_token": "mock_api_token", "account_id": "mock_account_id", } mock_module_instance.check_mode = False mock_ansible_module.return_value = mock_module_instance mock_module_instance.exit_json = MagicMock() public_cloud_config_info.run_module() mock_client_class.assert_called_with( api_version="1", api_token="mock_api_token" ) mock_client_instance.get.assert_called_once_with( "/public_clouds/config", params={"account_id": "mock_account_id"} ) mock_module_instance.exit_json.assert_called_once_with( changed=False, config=api_response_data["data"] ) # def test_successful_retrieval(self): # """ # Test a successful retrieval of public cloud configuration. # """ # set_module_args( # { # "api_token": "mock_api_token", # "account_id": "mock_account_id", # } # ) # # api_response_data = { # "result": "success", # "data": { # "free_tier": 300, # "free_tier_used": 24.34, # "account_resource_level": 2, # "valid_from": 1707584356, # "valid_to": 1717192799, # "project_count": 2, # }, # } # # self.mock_client_instance.get.return_value = api_response_data # # with patch.object( # AnsibleModule, "exit_json", side_effect=exit_json # ) as mock_exit_json: # with patch.object( # AnsibleModule, "fail_json", side_effect=fail_json # ) as mock_fail_json: # with pytest.raises(AnsibleExitJson) as e: # public_cloud_config_info.main() # mock_fail_json.assert_not_called() # result = e.value.kwargs # assert result["changed"] is False # assert "config" in result # assert result["config"] == api_response_data["data"] # mock_exit_json.assert_called_once() # self.mock_client_class.assert_called_with( # api_version="1", api_token="mock_api_token" # ) # self.mock_client_instance.get.assert_called_once_with( # "/public_clouds/config", # params={"account_id": "mock_account_id"}, # ) def test_missing_required_params(self): """ Test behavior when required parameters are missing. """ set_module_args( { "api_token": "mock_api_token", # 'account_id' is missing } ) with patch.object(AnsibleModule, "fail_json", side_effect=fail_json): with pytest.raises(SystemExit) as e: public_cloud_config_info.main() captured_output = json.loads(e.value.args[0]) assert "msg" in captured_output assert "missing required arguments: account_id" in captured_output["msg"] def test_check_mode(self): """ Test the behavior in check mode, where no changes should be made. """ set_module_args( { "api_token": "mock_api_token", "account_id": "mock_account_id", "_ansible_check_mode": True, } ) with patch.object( AnsibleModule, "exit_json", side_effect=exit_json ) as mock_exit_json: with pytest.raises(AnsibleExitJson) as e: public_cloud_config_info.main() mock_exit_json.assert_called_once_with( changed=False, msg="Check mode: No changes made, would retrieve public cloud config.", ) @patch( "ansible_collections.ednz_cloud.infomaniak.plugins.modules.public_cloud_config_info.InfomaniakAPIClient" ) def test_network_timeout(self, mock_client_class): """ Test behavior when a network timeout occurs. """ # Simulate a network timeout error mock_client_instance = MagicMock() mock_client_instance.get.side_effect = Exception("Request timeout") mock_client_class.return_value = mock_client_instance set_module_args( { "api_token": "mock_api_token", "account_id": "mock_account_id", } ) with patch.object( AnsibleModule, "fail_json", side_effect=fail_json ) as mock_fail_json: with pytest.raises(SystemExit) as e: public_cloud_config_info.main() captured_output = json.loads(e.value.args[0]) assert "msg" in captured_output assert not captured_output["msg"] == "Request timeout" mock_fail_json.assert_called_once() @patch( "ansible_collections.ednz_cloud.infomaniak.plugins.modules.public_cloud_config_info.InfomaniakAPIClient" ) def test_invalid_json_response(self, mock_client_class): """ Test behavior when the API returns an invalid JSON response. """ mock_client_instance = MagicMock() mock_client_instance.get.side_effect = Exception("Invalid JSON response") mock_client_class.return_value = mock_client_instance # Set module args with the required parameters set_module_args( { "api_token": "mock_api_token", "account_id": "mock_account_id", } ) with patch.object( AnsibleModule, "fail_json", side_effect=fail_json ) as mock_fail_json: with pytest.raises(SystemExit) as e: public_cloud_config_info.main() captured_output = json.loads(e.value.args[0]) assert "msg" in captured_output assert captured_output["msg"] == "Invalid JSON response" mock_fail_json.assert_called_once()