diff --git a/samples/delete_by_id_sample.py b/samples/delete_sample.py similarity index 94% rename from samples/delete_by_id_sample.py rename to samples/delete_sample.py index 8846c50..85137e6 100644 --- a/samples/delete_by_id_sample.py +++ b/samples/delete_sample.py @@ -34,7 +34,7 @@ def token_provider(): } ]} - response = client.delete_by_id(data,options=options) + response = client.delete(data,options=options) print('Response:', response) except SkyflowError as e: print('Error Occurred:', e) diff --git a/skyflow/_utils.py b/skyflow/_utils.py index c53d1f9..301e013 100644 --- a/skyflow/_utils.py +++ b/skyflow/_utils.py @@ -75,7 +75,7 @@ class InfoMessages(Enum): UPDATE_DATA_SUCCESS = "Data has been updated successfully" GET_TRIGGERED = "Get triggered." GET_SUCCESS = "Data fetched successfully." - DELETE_BY_ID_TRIGGERED = "Delete by ID triggered." + DELETE_TRIGGERED = "Delete triggered." DELETE_DATA_SUCCESS = "Data has been deleted successfully." @@ -91,7 +91,7 @@ class InterfaceName(Enum): IS_TOKEN_VALID = "service_account.isTokenValid" IS_EXPIRED = "service_account.is_expired" - DELETE_BY_ID = "client.delete_by_id" + DELETE = "client.delete" def http_build_query(data): diff --git a/skyflow/errors/_skyflow_errors.py b/skyflow/errors/_skyflow_errors.py index 414d91f..60f6c74 100644 --- a/skyflow/errors/_skyflow_errors.py +++ b/skyflow/errors/_skyflow_errors.py @@ -51,10 +51,9 @@ class SkyflowErrorMessages(Enum): INVALID_REDACTION_TYPE = "Redaction key has value of type %s, expected Skyflow.Redaction" INVALID_COLUMN_NAME = "Column name has value of type %s, expected string" INVALID_COLUMN_VALUE = "Column values has value of type %s, expected list" - INVALID_RECORDS_IN_DELETE = "Invalid records. records object should be an array" EMPTY_RECORDS_IN_DELETE = "records array cannot be empty" - EMPTY_ID_IN_DELETE = "Id cannot be empty in records array at index %s" - EMPTY_TABLE_IN_DELETE = "Table cannot be empty in records array at index %s" + EMPTY_ID_IN_DELETE = "Id cannot be empty in records array" + EMPTY_TABLE_IN_DELETE = "Table cannot be empty in records array" RECORDS_KEY_NOT_FOUND_DELETE = "records object is required" INVALID_REQUEST_BODY = "Given request body is not valid" diff --git a/skyflow/vault/_client.py b/skyflow/vault/_client.py index 303a4cf..4e0699a 100644 --- a/skyflow/vault/_client.py +++ b/skyflow/vault/_client.py @@ -5,7 +5,7 @@ import types import requests -from ._delete_by_id import deleteProcessResponse +from ._delete import deleteProcessResponse from ._insert import getInsertRequestBody, processResponse, convertResponse from ._update import sendUpdateRequests, createUpdateResponseBody from ._config import Configuration, DeleteOptions @@ -176,9 +176,9 @@ def update(self, updateInput, options: UpdateOptions = UpdateOptions()): log_info(InfoMessages.UPDATE_DATA_SUCCESS.value, interface) return result - def delete_by_id(self, records: dict,options: DeleteOptions = DeleteOptions()): - interface = InterfaceName.DELETE_BY_ID.value - log_info(InfoMessages.DELETE_BY_ID_TRIGGERED.value, interface=interface) + def delete(self, records: dict, options: DeleteOptions = DeleteOptions()): + interface = InterfaceName.DELETE.value + log_info(InfoMessages.DELETE_TRIGGERED.value, interface=interface) self._checkConfig(interface) @@ -192,58 +192,53 @@ def delete_by_id(self, records: dict,options: DeleteOptions = DeleteOptions()): result_list = [] errors = {} result = {} - error = {} try: - if not isinstance(records, dict) or "records" not in records: - error = {"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.RECORDS_KEY_NOT_FOUND_DELETE.value}} - return error - records_list = records["records"] - if not isinstance(records_list, list): - error.update({"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.INVALID_RECORDS_IN_DELETE.value}}) - return error - elif len(records_list) == 0: - error = {"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.EMPTY_RECORDS_IN_DELETE.value}} - return error + record = records["records"] + if not isinstance(record, list): + recordsType = str(type(record)) + raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT, SkyflowErrorMessages.INVALID_RECORDS_TYPE.value % ( + recordsType), interface=interface) + if len(record) == 0: + raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT, + SkyflowErrorMessages.EMPTY_RECORDS_IN_DELETE, interface=interface) + except KeyError: raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT, SkyflowErrorMessages.RECORDS_KEY_ERROR, interface=interface) try: - for index,record in enumerate(records["records"]): - record_list = record["id"] - if not isinstance(record_list, str): - error.update({"error": {"code": SkyflowErrorCodes.INVALID_INDEX.value, - "description": SkyflowErrorMessages.INVALID_ID_TYPE_DELETE.value % (index)}}) - return error - elif record_list == "": - error.update({"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.EMPTY_ID_IN_DELETE.value % (index)}}) - return error + for record in records["records"]: + id = record["id"] + if not isinstance(id, str): + idType = str(type(id)) + raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT, + SkyflowErrorMessages.INVALID_ID_TYPE.value % (idType), interface=interface) + if id == "": + raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT, + SkyflowErrorMessages.EMPTY_ID_IN_DELETE, interface=interface) except KeyError: - error.update({"error": {"code": SkyflowErrorCodes.INVALID_INDEX.value, - "description": SkyflowErrorMessages.IDS_KEY_ERROR.value}}) - return error + raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT, + SkyflowErrorMessages.IDS_KEY_ERROR, interface=interface) try: - for index,record in enumerate(records["records"]): - record_table = record["table"] - if not isinstance(record_table, str): - error.update({"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.INVALID_TABLE_TYPE_DELETE.value % (index)}}) - return error - elif record_table == "": - error.update({"error": {"code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.EMPTY_TABLE_IN_DELETE.value % (index)}}) - return error + for record in records["records"]: + table = record["table"] + if not isinstance(table, str): + tableType = str(type(table)) + raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT, + SkyflowErrorMessages.INVALID_TABLE_TYPE.value % ( + tableType), interface=interface) + if table == "": + raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT, + SkyflowErrorMessages.EMPTY_TABLE_IN_DELETE, interface=interface) except KeyError: - error.update({"error": {"code": SkyflowErrorCodes.INVALID_INDEX.value, - "description": SkyflowErrorMessages.TABLE_KEY_ERROR.value}}) - return error + raise SkyflowError(SkyflowErrorCodes.INVALID_INPUT, + SkyflowErrorMessages.TABLE_KEY_ERROR, interface=interface) + + partial=None + for record in records["records"]: request_url = self._get_complete_vault_url() + "/" + record["table"] + "/" + record["id"] response = requests.delete(request_url, headers=headers) - processed_response = deleteProcessResponse(response, records) + partial,processed_response = deleteProcessResponse(response, records) if processed_response is not None and processed_response.get('code') == 404: errors.update({'id': record["id"], 'error': processed_response}) error_list.append(errors) @@ -254,5 +249,10 @@ def delete_by_id(self, records: dict,options: DeleteOptions = DeleteOptions()): if errors: result.update({'errors': error_list}) - log_info(InfoMessages.DELETE_DATA_SUCCESS.value, interface) - return result + if partial: + raise SkyflowError(SkyflowErrorCodes.PARTIAL_SUCCESS, + SkyflowErrorMessages.PARTIAL_SUCCESS, result, interface=interface) + + else: + log_info(InfoMessages.DELETE_DATA_SUCCESS.value, interface) + return result diff --git a/skyflow/vault/_delete_by_id.py b/skyflow/vault/_delete.py similarity index 89% rename from skyflow/vault/_delete_by_id.py rename to skyflow/vault/_delete.py index f275c93..9faa882 100644 --- a/skyflow/vault/_delete_by_id.py +++ b/skyflow/vault/_delete.py @@ -8,18 +8,19 @@ from skyflow.errors._skyflow_errors import SkyflowError, SkyflowErrorCodes, SkyflowErrorMessages from skyflow._utils import InterfaceName -interface = InterfaceName.DELETE_BY_ID.value +interface = InterfaceName.DELETE.value def deleteProcessResponse(response: requests.Response, interface=interface): statusCode = response.status_code content = response.content + partial = False try: response.raise_for_status() if statusCode == 204: return None try: - return json.loads(content) + return partial,json.loads(content) except: raise SkyflowError( statusCode, SkyflowErrorMessages.RESPONSE_NOT_JSON.value % content, interface=interface) @@ -31,11 +32,12 @@ def deleteProcessResponse(response: requests.Response, interface=interface): if 'error' in errorResponse and type(errorResponse['error']) == dict and 'message' in errorResponse[ 'error']: message = errorResponse['error']['message'] + partial=True except: message = SkyflowErrorMessages.RESPONSE_NOT_JSON.value % content error = {} if 'x-request-id' in response.headers: message += ' - request id: ' + response.headers['x-request-id'] error.update({"code": statusCode, "description": message}) - return error + return partial,error diff --git a/tests/vault/test_delete.py b/tests/vault/test_delete.py new file mode 100644 index 0000000..fd6e7c3 --- /dev/null +++ b/tests/vault/test_delete.py @@ -0,0 +1,235 @@ +import json +import unittest +import os + +import asyncio +import warnings +from unittest import mock +from unittest.mock import patch, MagicMock + +import requests +from requests import HTTPError +from requests.models import Response +from dotenv import dotenv_values + +from skyflow.errors import SkyflowError, SkyflowErrorCodes +from skyflow.errors._skyflow_errors import SkyflowErrorMessages +from skyflow.service_account import generate_bearer_token +from skyflow.vault._client import Client +from skyflow.vault._config import Configuration, DeleteOptions +from skyflow.vault._delete import deleteProcessResponse + + +class TestDelete(unittest.TestCase): + + def setUp(self) -> None: + self.envValues = dotenv_values(".env") + self.dataPath = os.path.join(os.getcwd(), 'tests/vault/data/') + self.event_loop = asyncio.new_event_loop() + self.mocked_futures = [] + + def tokenProvider(): + token, type = generate_bearer_token( + self.envValues["CREDENTIALS_FILE_PATH"]) + return token + + config = Configuration( + "12345", "demo", tokenProvider) + self.client = Client(config) + warnings.filterwarnings( + action="ignore", message="unclosed", category=ResourceWarning) + + self.record_id = "123" + + self.mockResponse = { + "responses": [ + { + "records": [ + { + "skyflow_id": self.record_id, + "deleted": True + } + ] + } + ] + } + self.DeleteOptions = DeleteOptions(tokens=False) + + return super().setUp() + + def getDataPath(self, file): + return self.dataPath + file + '.json' + + def testDeleteInvalidRecordsType(self): + invalidData = {"records": "invalid"} + try: + self.client.delete(invalidData) + self.fail('Should have thrown an error') + except SkyflowError as e: + self.assertEqual(e.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual( + e.message, SkyflowErrorMessages.INVALID_RECORDS_TYPE.value % (str)) + + def testDeleteMissingdata(self): + invalid_data = {} + with self.assertRaises(SkyflowError) as context: + self.client.delete(invalid_data) + self.assertEqual(context.exception.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual(context.exception.message, SkyflowErrorMessages.RECORDS_KEY_ERROR.value) + + def testDeleteEmptyRecords(self): + invalid_data = {"records": []} + with self.assertRaises(SkyflowError) as context: + self.client.delete(invalid_data) + self.assertEqual(context.exception.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual(context.exception.message, SkyflowErrorMessages.EMPTY_RECORDS_IN_DELETE.value) + + def testDeleteMissingRecordsKey(self): + invalid_data = {"some_other_key": "value"} + with self.assertRaises(SkyflowError) as context: + self.client.delete(invalid_data) + self.assertEqual(context.exception.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual(context.exception.message, SkyflowErrorMessages.RECORDS_KEY_ERROR.value) + + def testDeleteNoIds(self): + invalidData = {"records": [{"invalid": "invalid", "table": "stripe"}]} + try: + self.client.delete(invalidData) + self.fail('Should have thrown an error') + except SkyflowError as e: + self.assertEqual(e.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual( + e.message, SkyflowErrorMessages.IDS_KEY_ERROR.value) + + def testDeleteInvalidIdType(self): + invalidData = {"records": [{"id": ["invalid"], "table": "stripe"}]} + try: + self.client.delete(invalidData) + self.fail('Should have thrown an error') + except SkyflowError as e: + self.assertEqual(e.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual(e.message, SkyflowErrorMessages.INVALID_ID_TYPE.value % (list)) + + def testDeleteInvalidIdType2(self): + invalidData = {"records": [{"id": 123, "table": "stripe"}]} + try: + self.client.delete(invalidData) + self.fail('Should have thrown an error') + except SkyflowError as e: + self.assertEqual(e.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual( + e.message, SkyflowErrorMessages.INVALID_ID_TYPE.value % (int)) + + def testDeleteEmptyId(self): + invalidData = {"records": [{"id": "", "table": "stripe"}]} + try: + self.client.delete(invalidData) + self.fail('Should have thrown an error') + except SkyflowError as e: + self.assertEqual(e.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual(e.message, SkyflowErrorMessages.EMPTY_ID_IN_DELETE.value) + + def testDeleteNoTable(self): + invalidData = {"records": [{"id": "id1", "invalid": "invalid"}]} + try: + self.client.delete(invalidData) + self.fail('Should have thrown an error') + except SkyflowError as e: + self.assertEqual(e.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual( + e.message, SkyflowErrorMessages.TABLE_KEY_ERROR.value) + + def testDeleteInvalidTableType(self): + invalidData = {"records": [{"id": "id1", "table": ["invalid"]}]} + try: + self.client.delete(invalidData) + self.fail('Should have thrown an error') + except SkyflowError as e: + self.assertEqual(e.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual( + e.message, SkyflowErrorMessages.INVALID_TABLE_TYPE.value % (list)) + + def testDeleteEmptyTable(self): + invalidData = {"records": [{"id": "123", "table": ""}]} + try: + self.client.delete(invalidData) + self.fail('Should have thrown an error') + except SkyflowError as e: + self.assertEqual(e.code, SkyflowErrorCodes.INVALID_INPUT.value) + self.assertEqual(e.message, SkyflowErrorMessages.EMPTY_TABLE_IN_DELETE.value) + + def testDeleteProcessResponseWithSuccessfulResponse(self): + mock_response = requests.Response() + mock_response.status_code = 200 + mock_response._content = b'{"key": "value"}' + partial, result = deleteProcessResponse(mock_response) + self.assertFalse(partial) + self.assertIsInstance(result, dict) + self.assertEqual(result, {"key": "value"}) + + def testDeleteProcessResponseWithNoContentResponse(self): + mock_response = requests.Response() + mock_response.status_code = 204 + result = deleteProcessResponse(mock_response) + self.assertIsNone(result) + + def test_http_error_with_error_message(self): + error_response = { + 'code': 400, + 'description': 'Error occurred' + } + response = mock.Mock(spec=requests.Response, status_code=400, + content=json.dumps(error_response).encode()) + partial, error = deleteProcessResponse(response) + self.assertFalse(partial) + self.assertEqual(error, { + "code": 400, + "description": "Error occurred", + }) + + def test_delete_data_with_errors(self): + response = mock.Mock(spec=requests.Response) + response.status_code = 404 + response.content = b'{"code": 404, "description": "Not found"}' + with mock.patch('requests.delete', return_value=response): + records = {"records": [ + {"id": "id1", "table": "stripe"}, + ]} + result = self.client.delete(records) + + self.assertIn('errors', result) + error = result['errors'][0] + self.assertEqual(error['id'], "id1") + self.assertEqual(error['error'], {'code': 404, 'description': 'Not found'}) + + def testDeleteProcessInvalidResponse(self): + response = Response() + response.status_code = 500 + response._content = b"Invalid Request" + try: + deleteProcessResponse(response) + except SkyflowError as e: + self.assertEqual(e.code, 500) + self.assertEqual(e.message, SkyflowErrorMessages.RESPONSE_NOT_JSON.value % + response.content.decode('utf-8')) + + def test_delete_process_response_with_error(self): + mock_response = mock.Mock(spec=requests.Response) + mock_response.status_code = 404 + mock_response.content = b'{"error": {"message": "Not found"}}' + mock_response.headers = {'x-request-id': 'request-id-123'} + partial, error = deleteProcessResponse(mock_response) + self.assertFalse(partial) + self.assertEqual(error, {"error": {"message": "Not found"}}) + + def test_delete_process_response_response_not_json(self): + mock_response = mock.Mock(spec=requests.Response) + mock_response.status_code = 500 + mock_response.content = b'Not a valid JSON response' + + with self.assertRaises(SkyflowError) as cm: + deleteProcessResponse(mock_response) + + exception = cm.exception + self.assertEqual(exception.code, 500) + self.assertIn("Not a valid JSON response", str(exception)) diff --git a/tests/vault/test_delete_by_id.py b/tests/vault/test_delete_by_id.py deleted file mode 100644 index 9617ac4..0000000 --- a/tests/vault/test_delete_by_id.py +++ /dev/null @@ -1,217 +0,0 @@ -import json -import unittest -import os - -import asyncio -import warnings -from unittest import mock -from unittest.mock import patch, MagicMock - -import requests -from requests import HTTPError -from requests.models import Response -from dotenv import dotenv_values - -from skyflow.errors import SkyflowError, SkyflowErrorCodes -from skyflow.errors._skyflow_errors import SkyflowErrorMessages -from skyflow.service_account import generate_bearer_token -from skyflow.vault._client import Client -from skyflow.vault._config import Configuration,DeleteOptions -from skyflow.vault._delete_by_id import deleteProcessResponse - - -class TestDelete(unittest.TestCase): - - def setUp(self) -> None: - self.envValues = dotenv_values(".env") - self.dataPath = os.path.join(os.getcwd(), 'tests/vault/data/') - self.event_loop = asyncio.new_event_loop() - self.mocked_futures = [] - - def tokenProvider(): - token, type = generate_bearer_token( - self.envValues["CREDENTIALS_FILE_PATH"]) - return token - - config = Configuration( - "12345", "demo", tokenProvider) - self.client = Client(config) - warnings.filterwarnings( - action="ignore", message="unclosed", category=ResourceWarning) - - self.record_id = "123" - - self.mockResponse = { - "responses": [ - { - "records": [ - { - "skyflow_id": self.record_id, - "deleted": True - } - ] - } - ] - } - self.DeleteOptions = DeleteOptions(tokens=False) - - return super().setUp() - - def getDataPath(self, file): - return self.dataPath + file + '.json' - - def testDeleteByIdInvalidRecordsType(self): - invalidData = "invalid_data" - result = self.client.delete_by_id(invalidData) - self.assertEqual(result, { - "error": { - "code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.RECORDS_KEY_NOT_FOUND_DELETE.value - } - }) - - def testDeleteByIdMissingRecordsKey(self): - invalidData = {"some_other_key": "value"} - result = self.client.delete_by_id(invalidData) - self.assertEqual(result, { - "error": { - "code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.RECORDS_KEY_NOT_FOUND_DELETE.value - } - }) - - def testDeleteByIdInvalidRecordsListType(self): - invalidData = {"records": "invalid_data"} - result = self.client.delete_by_id(invalidData) - self.assertEqual(result, { - "error": { - "code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.INVALID_RECORDS_IN_DELETE.value - } - }) - - def testDeleteByIdEmptyRecordsListType(self): - invalidData = {"records": []} - result = self.client.delete_by_id(invalidData) - # Assert the error response for an empty "records_list". - self.assertEqual(result, { - "error": { - "code": SkyflowErrorCodes.INVALID_INPUT.value, - "description": SkyflowErrorMessages.EMPTY_RECORDS_IN_DELETE.value - } - }) - - def testDeleteByIdEmptyTable(self): - invalidData = {"records": [{"id": "id1", "table": ""}]} - response = self.client.delete_by_id(invalidData) - self.assertIn("error", response) - error = response["error"] - self.assertEqual(error["code"], SkyflowErrorCodes.INVALID_INPUT.value) - self.assertEqual(error["description"], SkyflowErrorMessages.EMPTY_TABLE_IN_DELETE.value % (0)) - - def testDeleteByIdEmptyId(self): - invalidData = {"records": [{"id": "", "table": "stripe"}]} - response = self.client.delete_by_id(invalidData) - self.assertIn("error", response) - error = response["error"] - self.assertEqual(error["code"], SkyflowErrorCodes.INVALID_INPUT.value) - self.assertEqual(error["description"], SkyflowErrorMessages.EMPTY_ID_IN_DELETE.value % (0)) - - def testDeleteByIdInvalidIdType(self): - invalidData = {"records": [ - {"id": ["invalid"], "table": "stripe"}]} - response = self.client.delete_by_id(invalidData) - self.assertIn("error", response) - error = response["error"] - self.assertEqual(error["code"], SkyflowErrorCodes.INVALID_INDEX.value) - self.assertEqual(error["description"], SkyflowErrorMessages.INVALID_ID_TYPE_DELETE.value % (0)) - - def testDeleteByIdNoId(self): - invalidData = {"records": [{"invalid": "invalid", "table": "stripe"}]} - response = self.client.delete_by_id(invalidData) - self.assertIn("error", response) - error = response["error"] - self.assertEqual(error["code"], SkyflowErrorCodes.INVALID_INDEX.value) - self.assertEqual(error["description"], SkyflowErrorMessages.IDS_KEY_ERROR.value) - - def testDeleteByIdNoTable(self): - invalidData = {"records": [{"id": "id1", "invalid": "invalid"}]} - response = self.client.delete_by_id(invalidData) - self.assertIn("error", response) - error = response["error"] - self.assertEqual(error["code"], SkyflowErrorCodes.INVALID_INDEX.value) - self.assertEqual(error["description"], SkyflowErrorMessages.TABLE_KEY_ERROR.value) - - def testDeleteByIdInvalidTableType(self): - invalidData = {"records": [ - {"id": "id1", "table": ["invalid"]}]} - result = self.client.delete_by_id(invalidData) - self.assertIn("error", result) - error = result["error"] - self.assertEqual(error["code"], SkyflowErrorCodes.INVALID_INPUT.value) - self.assertEqual(error["description"], SkyflowErrorMessages.INVALID_TABLE_TYPE_DELETE.value % (0)) - - def testDeleteProcessResponseWithSuccessfulResponse(self): - mock_response = requests.Response() - mock_response.status_code = 200 - mock_response._content = b'{"key": "value"}' - result = deleteProcessResponse(mock_response) - self.assertIsInstance(result, dict) - self.assertEqual(result, {"key": "value"}) - - def testDeleteProcessResponseWithNoContentResponse(self): - mock_response = requests.Response() - mock_response.status_code = 204 - result = deleteProcessResponse(mock_response) - self.assertIsNone(result) - - def test_http_error_with_error_message(self): - error_response = { - 'code': 400, - 'description': 'Error occurred' - } - response = mock.Mock(spec=requests.Response) - response.status_code = 400 - response.content = json.dumps(error_response).encode() - error = deleteProcessResponse(response) - self.assertEqual(error, { - "code": 400, - "description": "Error occurred", - }) - - def test_delete_data_success(self): - records = {"records": [ - {"id": "id1", "table": "stripe"}]} - self.mock_response = mock.Mock(spec=requests.Response) - self.mock_response.status_code = 204 - self.mock_response.content = b'' - with mock.patch('requests.delete', return_value=self.mock_response): - result = self.client.delete_by_id(records) - self.assertIn('records', result) - self.assertEqual(result['records'], [None]) - - def test_delete_data_with_errors(self): - response = mock.Mock(spec=requests.Response) - response.status_code = 404 - response.content = b'{"code": 404, "description": "Not found"}' - with mock.patch('requests.delete', return_value=response): - records = {"records": [ - {"id": "id1", "table": "stripe"}, - ]} - result = self.client.delete_by_id(records) - - self.assertIn('errors', result) - error = result['errors'][0] - self.assertEqual(error['id'], "id1") - self.assertEqual(error['error'], {'code': 404, 'description': 'Not found'}) - - def testDeleteProcessInvalidResponse(self): - response = Response() - response.status_code = 500 - response._content = b"Invalid Request" - try: - deleteProcessResponse(response) - except SkyflowError as e: - self.assertEqual(e.code, 500) - self.assertEqual(e.message, SkyflowErrorMessages.RESPONSE_NOT_JSON.value % - response.content.decode('utf-8')) \ No newline at end of file