From 10f651ed334cea168acc92dba01983adc09dcae2 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Thu, 21 Nov 2024 15:38:17 +0530 Subject: [PATCH 01/15] FT-778: Endpoint code added --- pyatlan/client/constants.py | 6 ++++++ pyatlan/client/credential.py | 30 +++++++++++++++++++++++++++++- pyatlan/model/credential.py | 12 +++++++++++- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/pyatlan/client/constants.py b/pyatlan/client/constants.py index 5edd57b46..b62c61d84 100644 --- a/pyatlan/client/constants.py +++ b/pyatlan/client/constants.py @@ -488,6 +488,12 @@ HTTPStatus.OK, endpoint=EndPoint.HERACLES, ) +GET_ALL_CREDENTIALS = API( + CREDENTIALS_API, + HTTPMethod.GET, + HTTPStatus.OK, + endpoint=EndPoint.HERACLES +) UPDATE_CREDENTIAL_BY_GUID = API( CREDENTIALS_API + "/{credential_guid}", HTTPMethod.POST, diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index 6b81fe0e7..ec91c4466 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -4,12 +4,14 @@ from pyatlan.client.constants import ( GET_CREDENTIAL_BY_GUID, TEST_CREDENTIAL, - UPDATE_CREDENTIAL_BY_GUID, + GET_ALL_CREDENTIALS, + UPDATE_CREDENTIAL_BY_GUID ) from pyatlan.errors import ErrorCode from pyatlan.model.credential import ( Credential, CredentialResponse, + CredentialResponseList, CredentialTestResponse, ) @@ -46,6 +48,32 @@ def get(self, guid: str) -> CredentialResponse: if not isinstance(raw_json, dict): return raw_json return CredentialResponse(**raw_json) + + @validate_arguments + def get_all(self, filter: dict, limit: int = None, offset: int = None) -> CredentialResponseList: + """ + Retrieves all credentials based on the provided filter and optional pagination parameters. + + :param filter: A dictionary specifying the filter criteria (required). + :param limit: Maximum number of credentials to retrieve (optional). + :param offset: Number of credentials to skip before starting retrieval (optional). + :returns: A CredentialResponseList instance. + :raises: AtlanError on any error during API invocation. + """ + params = {"filter": filter} + if limit is not None: + params["limit"] = limit + if offset is not None: + params["offset"] = offset + + raw_json = self._client._call_api(GET_ALL_CREDENTIALS, query_params=params) + + if not isinstance(raw_json, dict) or "records" not in raw_json: + raise ErrorCode.INVALID_RESPONSE.exception_with_parameters( + "Expected a dictionary containing 'records'" + ) + + return CredentialResponseList(**raw_json) @validate_arguments def test(self, credential: Credential) -> CredentialTestResponse: diff --git a/pyatlan/model/credential.py b/pyatlan/model/credential.py index cb677d8e3..ef1e013fa 100644 --- a/pyatlan/model/credential.py +++ b/pyatlan/model/credential.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional,List from pydantic.v1 import Field @@ -94,6 +94,16 @@ def to_credential(self) -> Credential: ) +class CredentialResponseList(AtlanObject): + """ + Model representing a response containing a list of CredentialResponse objects. + + Attributes: + records (List[CredentialResponse]): The list of credential records returned. + """ + + records: List[CredentialResponse] = Field(..., description="The list of credential records returned.") + class CredentialTestResponse(AtlanObject): code: Optional[int] error: Optional[str] From 4235b4eae27f916352be9f527ea896bf15677b2a Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Thu, 21 Nov 2024 17:53:25 +0530 Subject: [PATCH 02/15] Update pyatlan/client/credential.py Co-authored-by: Aryaman <56113566+Aryamanz29@users.noreply.github.com> --- pyatlan/client/credential.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index ec91c4466..2c7e3104e 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -50,7 +50,7 @@ def get(self, guid: str) -> CredentialResponse: return CredentialResponse(**raw_json) @validate_arguments - def get_all(self, filter: dict, limit: int = None, offset: int = None) -> CredentialResponseList: + def get_all(self, filter: Dict[str, Any], limit: int = None, offset: int = None) -> CredentialResponseList: """ Retrieves all credentials based on the provided filter and optional pagination parameters. From 74cca36c93f704387046179c559bb7c1b30a54e3 Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Thu, 21 Nov 2024 17:54:04 +0530 Subject: [PATCH 03/15] Update pyatlan/client/credential.py Co-authored-by: Aryaman <56113566+Aryamanz29@users.noreply.github.com> --- pyatlan/client/credential.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index 2c7e3104e..8dbe04a20 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -54,10 +54,10 @@ def get_all(self, filter: Dict[str, Any], limit: int = None, offset: int = None) """ Retrieves all credentials based on the provided filter and optional pagination parameters. - :param filter: A dictionary specifying the filter criteria (required). - :param limit: Maximum number of credentials to retrieve (optional). - :param offset: Number of credentials to skip before starting retrieval (optional). - :returns: A CredentialResponseList instance. + :param filter: dictionary specifying the filter criteria. + :param limit: (optional) maximum number of credentials to retrieve. + :param offset: (optional) number of credentials to skip before starting retrieval. + :returns: CredentialResponseList instance. :raises: AtlanError on any error during API invocation. """ params = {"filter": filter} From 328258df30babe30d63a65460135695720464290 Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Thu, 21 Nov 2024 18:08:44 +0530 Subject: [PATCH 04/15] Update pyatlan/client/credential.py Co-authored-by: Aryaman <56113566+Aryamanz29@users.noreply.github.com> --- pyatlan/client/credential.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index 8dbe04a20..eb01d34b2 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -60,7 +60,8 @@ def get_all(self, filter: Dict[str, Any], limit: int = None, offset: int = None) :returns: CredentialResponseList instance. :raises: AtlanError on any error during API invocation. """ - params = {"filter": filter} + if filter is not None: + params["filter"] = filter if limit is not None: params["limit"] = limit if offset is not None: From 6f9cc40967471e46e51b1f5412585fb2e7def901 Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Thu, 21 Nov 2024 18:09:04 +0530 Subject: [PATCH 05/15] Update pyatlan/model/credential.py Co-authored-by: Aryaman <56113566+Aryamanz29@users.noreply.github.com> --- pyatlan/model/credential.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyatlan/model/credential.py b/pyatlan/model/credential.py index ef1e013fa..f4c599a98 100644 --- a/pyatlan/model/credential.py +++ b/pyatlan/model/credential.py @@ -102,7 +102,7 @@ class CredentialResponseList(AtlanObject): records (List[CredentialResponse]): The list of credential records returned. """ - records: List[CredentialResponse] = Field(..., description="The list of credential records returned.") + records: Optional[List[CredentialResponse]] = Field(default=None, description="list of credential records returned.") class CredentialTestResponse(AtlanObject): code: Optional[int] From bc6e271444189b199dcde088ed902c597f3677f4 Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Thu, 21 Nov 2024 18:09:13 +0530 Subject: [PATCH 06/15] Update pyatlan/model/credential.py Co-authored-by: Aryaman <56113566+Aryamanz29@users.noreply.github.com> --- pyatlan/model/credential.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyatlan/model/credential.py b/pyatlan/model/credential.py index f4c599a98..f78bf1677 100644 --- a/pyatlan/model/credential.py +++ b/pyatlan/model/credential.py @@ -97,9 +97,6 @@ def to_credential(self) -> Credential: class CredentialResponseList(AtlanObject): """ Model representing a response containing a list of CredentialResponse objects. - - Attributes: - records (List[CredentialResponse]): The list of credential records returned. """ records: Optional[List[CredentialResponse]] = Field(default=None, description="list of credential records returned.") From 97d636a41b1b223f35e964455443262a7cedd178 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 22 Nov 2024 10:33:42 +0530 Subject: [PATCH 07/15] FT-778: Added typing lib and defined params as dict --- pyatlan/client/credential.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index eb01d34b2..3089a0b49 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -1,11 +1,13 @@ +from typing import Any, Dict, Optional + from pydantic.v1 import validate_arguments from pyatlan.client.common import ApiCaller from pyatlan.client.constants import ( + GET_ALL_CREDENTIALS, GET_CREDENTIAL_BY_GUID, TEST_CREDENTIAL, - GET_ALL_CREDENTIALS, - UPDATE_CREDENTIAL_BY_GUID + UPDATE_CREDENTIAL_BY_GUID, ) from pyatlan.errors import ErrorCode from pyatlan.model.credential import ( @@ -48,19 +50,25 @@ def get(self, guid: str) -> CredentialResponse: if not isinstance(raw_json, dict): return raw_json return CredentialResponse(**raw_json) - + @validate_arguments - def get_all(self, filter: Dict[str, Any], limit: int = None, offset: int = None) -> CredentialResponseList: + def get_all( + self, + filter: Optional[Dict[str, Any]] = None, + limit: Optional[int] = None, + offset: Optional[int] = None, + ) -> CredentialResponseList: """ Retrieves all credentials based on the provided filter and optional pagination parameters. - :param filter: dictionary specifying the filter criteria. + :param filter: dictionary specifying the filter criteria. :param limit: (optional) maximum number of credentials to retrieve. :param offset: (optional) number of credentials to skip before starting retrieval. :returns: CredentialResponseList instance. :raises: AtlanError on any error during API invocation. - """ - if filter is not None: + """ + params = {} + if filter is not None: params["filter"] = filter if limit is not None: params["limit"] = limit From 15d7d2cbd73dd43601dd0304c62b3b8df5a36160 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 22 Nov 2024 10:52:30 +0530 Subject: [PATCH 08/15] FT-778: Added typing lib and defined params --- pyatlan/client/constants.py | 5 +---- pyatlan/client/credential.py | 2 +- pyatlan/model/credential.py | 9 ++++++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pyatlan/client/constants.py b/pyatlan/client/constants.py index b62c61d84..e1e2009b1 100644 --- a/pyatlan/client/constants.py +++ b/pyatlan/client/constants.py @@ -489,10 +489,7 @@ endpoint=EndPoint.HERACLES, ) GET_ALL_CREDENTIALS = API( - CREDENTIALS_API, - HTTPMethod.GET, - HTTPStatus.OK, - endpoint=EndPoint.HERACLES + CREDENTIALS_API, HTTPMethod.GET, HTTPStatus.OK, endpoint=EndPoint.HERACLES ) UPDATE_CREDENTIAL_BY_GUID = API( CREDENTIALS_API + "/{credential_guid}", diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index 3089a0b49..71ca5a437 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -67,7 +67,7 @@ def get_all( :returns: CredentialResponseList instance. :raises: AtlanError on any error during API invocation. """ - params = {} + params: Dict[str, Any] = {} if filter is not None: params["filter"] = filter if limit is not None: diff --git a/pyatlan/model/credential.py b/pyatlan/model/credential.py index f78bf1677..e2d50ecf5 100644 --- a/pyatlan/model/credential.py +++ b/pyatlan/model/credential.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional,List +from typing import Any, Dict, Optional, List from pydantic.v1 import Field @@ -98,8 +98,11 @@ class CredentialResponseList(AtlanObject): """ Model representing a response containing a list of CredentialResponse objects. """ - - records: Optional[List[CredentialResponse]] = Field(default=None, description="list of credential records returned.") + + records: Optional[List[CredentialResponse]] = Field( + default=None, description="list of credential records returned." + ) + class CredentialTestResponse(AtlanObject): code: Optional[int] From d489a9ee06da9b193905088e94cffa51ab4064e1 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 22 Nov 2024 11:37:44 +0530 Subject: [PATCH 09/15] Corrected the error code. --- pyatlan/client/credential.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index 71ca5a437..b307f3ce4 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -78,9 +78,7 @@ def get_all( raw_json = self._client._call_api(GET_ALL_CREDENTIALS, query_params=params) if not isinstance(raw_json, dict) or "records" not in raw_json: - raise ErrorCode.INVALID_RESPONSE.exception_with_parameters( - "Expected a dictionary containing 'records'" - ) + raise ErrorCode.JSON_ERROR.exception_with_parameters("No records found in response", 400, "API response did not contain the expected 'records' key") return CredentialResponseList(**raw_json) From dc05a1f6703aceb4a6ca229aa5d2ec1005c80a59 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 22 Nov 2024 11:40:11 +0530 Subject: [PATCH 10/15] Corrected the error code and did qa check --- pyatlan/client/credential.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index b307f3ce4..c39eb98bf 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -78,7 +78,11 @@ def get_all( raw_json = self._client._call_api(GET_ALL_CREDENTIALS, query_params=params) if not isinstance(raw_json, dict) or "records" not in raw_json: - raise ErrorCode.JSON_ERROR.exception_with_parameters("No records found in response", 400, "API response did not contain the expected 'records' key") + raise ErrorCode.JSON_ERROR.exception_with_parameters( + "No records found in response", + 400, + "API response did not contain the expected 'records' key", + ) return CredentialResponseList(**raw_json) From 847247cc3050de61994836cec45b56e33dd4d5a0 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 22 Nov 2024 16:40:44 +0530 Subject: [PATCH 11/15] Made all fields in the CredentialResponse model optional to improve flexibility, as some fields were observed to have null values. Updated the filter query parameter to use json.dumps to ensure it is properly stringified as required by the API. Utilized format_path_with_params for consistent query parameter alignment across API request. --- pyatlan/client/credential.py | 9 ++++++--- pyatlan/model/credential.py | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index c39eb98bf..b0a520d6b 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -1,3 +1,4 @@ +from json import dumps from typing import Any, Dict, Optional from pydantic.v1 import validate_arguments @@ -61,7 +62,7 @@ def get_all( """ Retrieves all credentials based on the provided filter and optional pagination parameters. - :param filter: dictionary specifying the filter criteria. + :param filter: (optional) dictionary specifying the filter criteria. :param limit: (optional) maximum number of credentials to retrieve. :param offset: (optional) number of credentials to skip before starting retrieval. :returns: CredentialResponseList instance. @@ -69,13 +70,15 @@ def get_all( """ params: Dict[str, Any] = {} if filter is not None: - params["filter"] = filter + params["filter"] = dumps(filter) if limit is not None: params["limit"] = limit if offset is not None: params["offset"] = offset - raw_json = self._client._call_api(GET_ALL_CREDENTIALS, query_params=params) + raw_json = self._client._call_api( + GET_ALL_CREDENTIALS.format_path_with_params(), query_params=params + ) if not isinstance(raw_json, dict) or "records" not in raw_json: raise ErrorCode.JSON_ERROR.exception_with_parameters( diff --git a/pyatlan/model/credential.py b/pyatlan/model/credential.py index e2d50ecf5..0e329c136 100644 --- a/pyatlan/model/credential.py +++ b/pyatlan/model/credential.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional, List +from typing import Any, Dict, List, Optional from pydantic.v1 import Field @@ -54,20 +54,20 @@ class Credential(AtlanObject): class CredentialResponse(AtlanObject): - id: str - version: str - is_active: bool - created_at: int - updated_at: int - created_by: str - tenant_id: str - name: str + id: Optional[str] + version: Optional[str] + is_active: Optional[bool] + created_at: Optional[int] + updated_at: Optional[int] + created_by: Optional[str] + tenant_id: Optional[str] + name: Optional[str] description: Optional[str] - connector_config_name: str - connector: str - connector_type: str - auth_type: str - host: str + connector_config_name: Optional[str] + connector: Optional[str] + connector_type: Optional[str] + auth_type: Optional[str] + host: Optional[str] port: Optional[int] metadata: Optional[Dict[str, Any]] level: Optional[Dict[str, Any]] From 8624f59bd3480a357e9c8cc6742b95ca5f8668d7 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 22 Nov 2024 17:48:55 +0530 Subject: [PATCH 12/15] Add Unit Test for get_all() --- tests/unit/test_credential_client.py | 95 ++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/tests/unit/test_credential_client.py b/tests/unit/test_credential_client.py index 2cfacf59e..00961cf16 100644 --- a/tests/unit/test_credential_client.py +++ b/tests/unit/test_credential_client.py @@ -11,6 +11,7 @@ from pyatlan.model.credential import ( Credential, CredentialResponse, + CredentialResponseList, CredentialTestResponse, ) @@ -189,3 +190,97 @@ def test_cred_test_update_when_given_cred( assert isinstance(cred_response, CredentialResponse) cred = cred_response.to_credential() _assert_cred_response(cred, credential_response) + + +@pytest.mark.parametrize( + "test_filter, test_limit, test_offset, test_response", + [ + (None, None, None, {"records": [{"id": "cred1"}, {"id": "cred2"}]}), + ({"name": "test"}, 5, 0, {"records": [{"id": "cred3"}]}), + ({"invalid": "field"}, 10, 0, {"records": []}), + ], +) +def test_cred_get_all_success( + test_filter, test_limit, test_offset, test_response, mock_api_caller +): + mock_api_caller._call_api.return_value = test_response + client = CredentialClient(mock_api_caller) + + result = client.get_all(filter=test_filter, limit=test_limit, offset=test_offset) + + assert isinstance(result, CredentialResponseList) + assert len(result.records) == len(test_response["records"]) + for record, expected in zip(result.records, test_response["records"]): + assert record.id == expected["id"] + + +def test_cred_get_all_empty_response(mock_api_caller): + mock_api_caller._call_api.return_value = {"records": []} + client = CredentialClient(mock_api_caller) + + result = client.get_all() + + assert isinstance(result, CredentialResponseList) + assert len(result.records) == 0 + + +def test_cred_get_all_invalid_response(mock_api_caller): + mock_api_caller._call_api.return_value = {} + client = CredentialClient(mock_api_caller) + + with pytest.raises(Exception, match="No records found in response"): + client.get_all() + + +@pytest.mark.parametrize( + "test_filter, test_limit, test_offset", + [ + ("invalid_filter", None, None), + (None, "invalid_limit", None), + (None, None, "invalid_offset"), + ], +) +def test_cred_get_all_invalid_params_raises_validation_error( + test_filter, test_limit, test_offset, client: CredentialClient +): + with pytest.raises(ValidationError): + client.get_all(filter=test_filter, limit=test_limit, offset=test_offset) + + +def test_cred_get_all_timeout(mock_api_caller): + mock_api_caller._call_api.side_effect = TimeoutError("Request timed out") + client = CredentialClient(mock_api_caller) + + with pytest.raises(TimeoutError, match="Request timed out"): + client.get_all() + + +def test_cred_get_all_partial_response(mock_api_caller): + mock_api_caller._call_api.return_value = { + "records": [{"id": "cred1", "name": "Test Credential"}] + } + client = CredentialClient(mock_api_caller) + + result = client.get_all() + + assert isinstance(result, CredentialResponseList) + assert result.records[0].id == "cred1" + assert result.records[0].name == "Test Credential" + assert result.records[0].host is None + + +def test_cred_get_all_invalid_filter_type(mock_api_caller): + client = CredentialClient(mock_api_caller) + + with pytest.raises(ValidationError, match="value is not a valid dict"): + client.get_all(filter="invalid_filter") + + +def test_cred_get_all_no_results(mock_api_caller): + mock_api_caller._call_api.return_value = {"records": []} + client = CredentialClient(mock_api_caller) + + result = client.get_all(filter={"name": "nonexistent"}) + + assert isinstance(result, CredentialResponseList) + assert len(result.records) == 0 From 970c4525520bdfe56d485e00425cb9403ec80551 Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 22 Nov 2024 19:33:39 +0530 Subject: [PATCH 13/15] Add all the required Integration Tests --- tests/integration/test_workflow_client.py | 74 +++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/integration/test_workflow_client.py b/tests/integration/test_workflow_client.py index bb09e098a..3b35aaa8a 100644 --- a/tests/integration/test_workflow_client.py +++ b/tests/integration/test_workflow_client.py @@ -13,6 +13,7 @@ from pyatlan.model.workflow import WorkflowResponse, WorkflowSchedule from tests.integration.client import TestId, delete_asset from tests.integration.connection_test import create_connection +from pyatlan.client.atlan import AtlanClient MODULE_NAME = TestId.make_unique("WorfklowClient") WORKFLOW_TEMPLATE_REF = "workflowTemplateRef" @@ -269,3 +270,76 @@ def test_workflow_add_remove_schedule(client: AtlanClient, workflow: WorkflowRes # Now remove the scheduled run response = client.workflow.remove_schedule(workflow) _assert_remove_schedule(response, workflow) + +def test_get_all_credentials(client: AtlanClient): + + credentials = client.credentials.get_all() + assert credentials, "Expected credentials but found None" + assert credentials.records is not None, "Expected records but found None" + assert len(credentials.records) > 0, "Expected at least one record but found none" + + +def test_get_all_credentials_with_limit_and_offset(client: AtlanClient): + limit = 5 + offset = 2 + credentials = client.credentials.get_all(limit=limit, offset=offset) + assert credentials.records is not None, "Expected records but found None" + assert len(credentials.records) <= limit, ( + f"Expected at most {limit} records, got {len(credentials.records)}" + ) + + +def test_get_all_credentials_with_filter_limit_offset(client: AtlanClient): + filter_criteria = {"connectorType": "rest"} + limit = 1 + offset = 1 + credentials = client.credentials.get_all(filter=filter_criteria, limit=limit, offset=offset) + assert len(credentials.records) <= limit, "Exceeded limit in results" + for cred in credentials.records: + assert cred.connector_type == "rest" + +def test_get_all_credentials_with_multiple_filters(client: AtlanClient): + filter_criteria = { + "connectorType": "jdbc", + "isActive": True + } + + credentials = client.credentials.get_all(filter=filter_criteria) + assert credentials, "Expected credentials but found None" + assert credentials.records is not None, "Expected records but found None" + assert len(credentials.records) > 0, "Expected at least one record but found none" + + for record in credentials.records: + assert record.connector_type == "jdbc", f"Expected 'jdbc', got {record.connectorType}" + assert record.is_active, f"Expected active record, but got inactive: {record}" + +def test_get_all_credentials_with_invalid_filter_key(client: AtlanClient): + filter_criteria = { + "invalidKey": "someValue" + } + try: + credentials = client.credentials.get_all(filter=filter_criteria) + pytest.fail("Expected an error due to invalid filter key, but none occurred.") + except Exception as e: + assert "400" in str(e), f"Expected a 400 error, but got: {e}" + +def test_get_all_credentials_with_invalid_filter_value(client: AtlanClient): + + filter_criteria = { + "connectorType": 123 # Invalid type (should be a string) + } + + try: + credentials = client.credentials.get_all(filter=filter_criteria) + pytest.fail("Expected an error due to invalid filter value, but none occurred.") + except Exception as e: + assert "400" in str(e), f"Expected a 400 error, but got: {e}" + +def test_get_all_credentials_with_large_limit(client: AtlanClient): + + limit = 100 # Larger than the total number of records + credentials = client.credentials.get_all(limit=limit) + + assert credentials, "Expected credentials but found None" + assert credentials.records is not None, "Expected records but found None" + assert len(credentials.records) <= limit, f"Expected at most {limit} records, but got {len(credentials.records)}" From 69a9c732dda351c4359a998120172b5e9c7255df Mon Sep 17 00:00:00 2001 From: vaibhavatlan Date: Fri, 22 Nov 2024 19:50:36 +0530 Subject: [PATCH 14/15] Final Integration Tests --- tests/integration/test_workflow_client.py | 65 ++++++++++++----------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/tests/integration/test_workflow_client.py b/tests/integration/test_workflow_client.py index 3b35aaa8a..8b1a68d7f 100644 --- a/tests/integration/test_workflow_client.py +++ b/tests/integration/test_workflow_client.py @@ -13,7 +13,6 @@ from pyatlan.model.workflow import WorkflowResponse, WorkflowSchedule from tests.integration.client import TestId, delete_asset from tests.integration.connection_test import create_connection -from pyatlan.client.atlan import AtlanClient MODULE_NAME = TestId.make_unique("WorfklowClient") WORKFLOW_TEMPLATE_REF = "workflowTemplateRef" @@ -271,12 +270,14 @@ def test_workflow_add_remove_schedule(client: AtlanClient, workflow: WorkflowRes response = client.workflow.remove_schedule(workflow) _assert_remove_schedule(response, workflow) + def test_get_all_credentials(client: AtlanClient): - credentials = client.credentials.get_all() assert credentials, "Expected credentials but found None" assert credentials.records is not None, "Expected records but found None" - assert len(credentials.records) > 0, "Expected at least one record but found none" + assert ( + len(credentials.records or []) > 0 + ), "Expected at least one record but found none" def test_get_all_credentials_with_limit_and_offset(client: AtlanClient): @@ -284,62 +285,66 @@ def test_get_all_credentials_with_limit_and_offset(client: AtlanClient): offset = 2 credentials = client.credentials.get_all(limit=limit, offset=offset) assert credentials.records is not None, "Expected records but found None" - assert len(credentials.records) <= limit, ( - f"Expected at most {limit} records, got {len(credentials.records)}" - ) + assert ( + len(credentials.records or []) <= limit + ), f"Expected at most {limit} records, got {len(credentials.records or [])}" def test_get_all_credentials_with_filter_limit_offset(client: AtlanClient): filter_criteria = {"connectorType": "rest"} limit = 1 offset = 1 - credentials = client.credentials.get_all(filter=filter_criteria, limit=limit, offset=offset) - assert len(credentials.records) <= limit, "Exceeded limit in results" - for cred in credentials.records: - assert cred.connector_type == "rest" + credentials = client.credentials.get_all( + filter=filter_criteria, limit=limit, offset=offset + ) + assert len(credentials.records or []) <= limit, "Exceeded limit in results" + for cred in credentials.records or []: + assert ( + cred.connector_type == "rest" + ), f"Expected 'rest', got {cred.connector_type}" + def test_get_all_credentials_with_multiple_filters(client: AtlanClient): - filter_criteria = { - "connectorType": "jdbc", - "isActive": True - } + filter_criteria = {"connectorType": "jdbc", "isActive": True} credentials = client.credentials.get_all(filter=filter_criteria) assert credentials, "Expected credentials but found None" assert credentials.records is not None, "Expected records but found None" - assert len(credentials.records) > 0, "Expected at least one record but found none" + assert ( + len(credentials.records or []) > 0 + ), "Expected at least one record but found none" - for record in credentials.records: - assert record.connector_type == "jdbc", f"Expected 'jdbc', got {record.connectorType}" + for record in credentials.records or []: + assert ( + record.connector_type == "jdbc" + ), f"Expected 'jdbc', got {record.connector_type}" assert record.is_active, f"Expected active record, but got inactive: {record}" + def test_get_all_credentials_with_invalid_filter_key(client: AtlanClient): - filter_criteria = { - "invalidKey": "someValue" - } + filter_criteria = {"invalidKey": "someValue"} try: - credentials = client.credentials.get_all(filter=filter_criteria) + client.credentials.get_all(filter=filter_criteria) pytest.fail("Expected an error due to invalid filter key, but none occurred.") except Exception as e: assert "400" in str(e), f"Expected a 400 error, but got: {e}" -def test_get_all_credentials_with_invalid_filter_value(client: AtlanClient): - filter_criteria = { - "connectorType": 123 # Invalid type (should be a string) - } +def test_get_all_credentials_with_invalid_filter_value(client: AtlanClient): + filter_criteria = {"connector_type": 123} try: - credentials = client.credentials.get_all(filter=filter_criteria) + client.credentials.get_all(filter=filter_criteria) pytest.fail("Expected an error due to invalid filter value, but none occurred.") except Exception as e: assert "400" in str(e), f"Expected a 400 error, but got: {e}" -def test_get_all_credentials_with_large_limit(client: AtlanClient): - limit = 100 # Larger than the total number of records +def test_get_all_credentials_with_large_limit(client: AtlanClient): + limit = 100 credentials = client.credentials.get_all(limit=limit) - assert credentials, "Expected credentials but found None" assert credentials.records is not None, "Expected records but found None" - assert len(credentials.records) <= limit, f"Expected at most {limit} records, but got {len(credentials.records)}" + assert ( + len(credentials.records or []) <= limit + ), f"Expected at most {limit} records, but got {len(credentials.records or [])}" From b95e4f4a18ca08daa023ddacce7c82a0929ccc2f Mon Sep 17 00:00:00 2001 From: Aryamanz29 Date: Mon, 25 Nov 2024 16:15:02 +0530 Subject: [PATCH 15/15] [change] Minor changes in docstrings and tests --- pyatlan/client/credential.py | 4 ++-- tests/integration/test_workflow_client.py | 16 +++------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/pyatlan/client/credential.py b/pyatlan/client/credential.py index b0a520d6b..ca9e7e464 100644 --- a/pyatlan/client/credential.py +++ b/pyatlan/client/credential.py @@ -60,11 +60,11 @@ def get_all( offset: Optional[int] = None, ) -> CredentialResponseList: """ - Retrieves all credentials based on the provided filter and optional pagination parameters. + Retrieves all credentials. :param filter: (optional) dictionary specifying the filter criteria. :param limit: (optional) maximum number of credentials to retrieve. - :param offset: (optional) number of credentials to skip before starting retrieval. + :param offset: (optional) number of credentials to skip before starting retrieval. :returns: CredentialResponseList instance. :raises: AtlanError on any error during API invocation. """ diff --git a/tests/integration/test_workflow_client.py b/tests/integration/test_workflow_client.py index 8b1a68d7f..61f6e5e6b 100644 --- a/tests/integration/test_workflow_client.py +++ b/tests/integration/test_workflow_client.py @@ -291,7 +291,7 @@ def test_get_all_credentials_with_limit_and_offset(client: AtlanClient): def test_get_all_credentials_with_filter_limit_offset(client: AtlanClient): - filter_criteria = {"connectorType": "rest"} + filter_criteria = {"connectorType": "jdbc"} limit = 1 offset = 1 credentials = client.credentials.get_all( @@ -300,8 +300,8 @@ def test_get_all_credentials_with_filter_limit_offset(client: AtlanClient): assert len(credentials.records or []) <= limit, "Exceeded limit in results" for cred in credentials.records or []: assert ( - cred.connector_type == "rest" - ), f"Expected 'rest', got {cred.connector_type}" + cred.connector_type == "jdbc" + ), f"Expected 'jdbc', got {cred.connector_type}" def test_get_all_credentials_with_multiple_filters(client: AtlanClient): @@ -338,13 +338,3 @@ def test_get_all_credentials_with_invalid_filter_value(client: AtlanClient): pytest.fail("Expected an error due to invalid filter value, but none occurred.") except Exception as e: assert "400" in str(e), f"Expected a 400 error, but got: {e}" - - -def test_get_all_credentials_with_large_limit(client: AtlanClient): - limit = 100 - credentials = client.credentials.get_all(limit=limit) - assert credentials, "Expected credentials but found None" - assert credentials.records is not None, "Expected records but found None" - assert ( - len(credentials.records or []) <= limit - ), f"Expected at most {limit} records, but got {len(credentials.records or [])}"