From bbfd32c9ff1802f490b170dbd42b71d1f678bfa2 Mon Sep 17 00:00:00 2001 From: ajaz Date: Fri, 11 Apr 2025 16:58:44 +0530 Subject: [PATCH 1/6] feat: added delete log forwarding command --- .../__tests__/delete-log-forwarding.test.js | 94 ++++++++++++++++ .../api-mesh/config/delete/log-forwarding.js | 80 ++++++++++++++ src/lib/smsClient.js | 104 ++++++++++++++++++ 3 files changed, 278 insertions(+) create mode 100644 src/commands/api-mesh/__tests__/delete-log-forwarding.test.js create mode 100644 src/commands/api-mesh/config/delete/log-forwarding.js diff --git a/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js b/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js new file mode 100644 index 00000000..45e25a5a --- /dev/null +++ b/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js @@ -0,0 +1,94 @@ +const DeleteLogForwardingCommand = require('../config/delete/log-forwarding'); +const { initSdk, promptConfirm } = require('../../../helpers'); +const { getMeshId, deleteLogForwarding } = require('../../../lib/smsClient'); + +jest.mock('../../../helpers', () => ({ + initSdk: jest.fn().mockResolvedValue({}), + initRequestId: jest.fn().mockResolvedValue({}), + promptConfirm: jest.fn().mockResolvedValue(true), +})); +jest.mock('../../../lib/smsClient'); + +let logSpy, errorLogSpy, parseSpy; + +describe('delete log forwarding command tests', () => { + beforeEach(() => { + initSdk.mockResolvedValue({ + imsOrgCode: 'mockOrgCode', + projectId: 'mockProjectId', + workspaceId: 'mockWorkspaceId', + workspaceName: 'mockWorkspaceName', + }); + + getMeshId.mockResolvedValue('mockMeshId'); + deleteLogForwarding.mockResolvedValue(); + + global.requestId = 'dummy_request_id'; + + logSpy = jest.spyOn(DeleteLogForwardingCommand.prototype, 'log'); + errorLogSpy = jest.spyOn(DeleteLogForwardingCommand.prototype, 'error'); + parseSpy = jest.spyOn(DeleteLogForwardingCommand.prototype, 'parse'); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('should fail if mesh ID is not found', async () => { + getMeshId.mockResolvedValueOnce(null); + + await expect(DeleteLogForwardingCommand.run()).rejects.toThrow( + 'Unable to delete log forwarding details. No mesh found for Org(mockOrgCode) -> Project(mockProjectId) -> Workspace(mockWorkspaceId). Check the details and try again.', + ); + + expect(logSpy).not.toHaveBeenCalled(); + expect(errorLogSpy).toHaveBeenCalledWith( + 'Unable to delete log forwarding details. No mesh found for Org(mockOrgCode) -> Project(mockProjectId) -> Workspace(mockWorkspaceId). Check the details and try again.', + ); + }); + + test('should skip confirmation if autoConfirmAction is set', async () => { + parseSpy.mockResolvedValueOnce({ + flags: { + ignoreCache: false, + autoConfirmAction: true, + }, + }); + + await DeleteLogForwardingCommand.run(); + + expect(promptConfirm).not.toHaveBeenCalled(); + expect(deleteLogForwarding).toHaveBeenCalledWith( + 'mockOrgCode', + 'mockProjectId', + 'mockWorkspaceId', + 'mockMeshId', + ); + expect(logSpy).toHaveBeenCalledWith('Successfully deleted log forwarding details'); + }); + + test('should fail if deleteLogForwarding throws an error', async () => { + deleteLogForwarding.mockRejectedValueOnce(new Error('Deletion failed')); + + await expect(DeleteLogForwardingCommand.run()).rejects.toThrow( + 'failed to delete log forwarding details. Try again. RequestId: dummy_request_id', + ); + + expect(logSpy).not.toHaveBeenCalledWith('Successfully deleted log forwarding details'); + expect(errorLogSpy).toHaveBeenCalledWith( + 'failed to delete log forwarding details. Try again. RequestId: dummy_request_id', + ); + }); + + test('should delete log forwarding details successfully', async () => { + await DeleteLogForwardingCommand.run(); + + expect(deleteLogForwarding).toHaveBeenCalledWith( + 'mockOrgCode', + 'mockProjectId', + 'mockWorkspaceId', + 'mockMeshId', + ); + expect(logSpy).toHaveBeenCalledWith('Successfully deleted log forwarding details'); + }); +}); diff --git a/src/commands/api-mesh/config/delete/log-forwarding.js b/src/commands/api-mesh/config/delete/log-forwarding.js new file mode 100644 index 00000000..f574416f --- /dev/null +++ b/src/commands/api-mesh/config/delete/log-forwarding.js @@ -0,0 +1,80 @@ +/* +Copyright 2021 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +const { Command } = require('@oclif/core'); +const logger = require('../../../../classes/logger'); +const { initSdk, promptConfirm } = require('../../../../helpers'); +const { ignoreCacheFlag, autoConfirmActionFlag } = require('../../../../utils'); +const { deleteLogForwarding, getMeshId } = require('../../../../lib/smsClient'); + +class DeleteLogForwardingCommand extends Command { + static flags = { + ignoreCache: ignoreCacheFlag, + autoConfirmAction: autoConfirmActionFlag, + }; + + async run() { + logger.info(`RequestId: ${global.requestId}`); + + const { flags } = await this.parse(DeleteLogForwardingCommand); + + const ignoreCache = await flags.ignoreCache; + const autoConfirmAction = await flags.autoConfirmAction; + + const { imsOrgCode, projectId, workspaceId, workspaceName } = await initSdk({ + ignoreCache, + }); + + let meshId = null; + + try { + meshId = await getMeshId(imsOrgCode, projectId, workspaceId, workspaceName); + } catch (err) { + this.error( + `Unable to get mesh ID. Please check the details and try again. RequestId: ${global.requestId}`, + ); + } + + // mesh could not be found + if (!meshId) { + this.error( + `Unable to delete log forwarding details. No mesh found for Org(${imsOrgCode}) -> Project(${projectId}) -> Workspace(${workspaceId}). Check the details and try again.`, + ); + } + + let shouldContinue = true; + + if (!autoConfirmAction) { + shouldContinue = await promptConfirm( + `Are you sure you want to delete the log forwarding details for mesh: ${meshId}?`, + ); + } + + if (shouldContinue) { + try { + await deleteLogForwarding(imsOrgCode, projectId, workspaceId, meshId); + this.log('Successfully deleted log forwarding details'); + } catch (error) { + this.log(error.message); + this.error( + `failed to delete log forwarding details. Try again. RequestId: ${global.requestId}`, + ); + } + } else { + this.log('delete log-forwarding cancelled'); + return 'delete log-forwarding cancelled'; + } + } +} + +DeleteLogForwardingCommand.description = 'Delete log forwarding details for a given mesh'; + +module.exports = DeleteLogForwardingCommand; diff --git a/src/lib/smsClient.js b/src/lib/smsClient.js index 83429bd0..d6018681 100644 --- a/src/lib/smsClient.js +++ b/src/lib/smsClient.js @@ -1397,6 +1397,109 @@ const getLogForwarding = async (organizationCode, projectId, workspaceId, meshId } }; +/** + * Deletes the log forwarding configuration for a given mesh. + * + * @param {string} organizationCode - The IMS org code + * @param {string} projectId - The project ID + * @param {string} workspaceId - The workspace ID + * @param {string} meshId - The mesh ID + */ +const deleteLogForwarding = async (organizationCode, projectId, workspaceId, meshId) => { + const { accessToken } = await getDevConsoleConfig(); + const config = { + method: 'DELETE', + url: `${SMS_BASE_URL}/organizations/${organizationCode}/projects/${projectId}/workspaces/${workspaceId}/meshes/${meshId}/log/forwarding`, + headers: { + 'Authorization': `Bearer ${accessToken}`, + 'x-request-id': global.requestId, + 'x-api-key': SMS_API_KEY, + }, + }; + + logger.info( + 'Initiating DELETE %s', + `${SMS_BASE_URL}/organizations/${organizationCode}/projects/${projectId}/workspaces/${workspaceId}/meshes/${meshId}/log/forwarding`, + ); + + try { + const response = await axios(config); + + logger.info('Response from DELETE %s', response.status); + + if (response && response?.status === 204) { + return response; + } else { + logger.error( + `Something went wrong: ${objToString( + response, + ['data'], + 'Unable to delete log forwarding details.', + )}. Received ${response.status}, expected 204`, + ); + throw new Error( + `something went wrong: ${objToString( + response, + ['data'], + 'Unable to delete log forwarding', + )}`, + ); + } + } catch (error) { + logger.info('Response from DELETE %s', error.response.status); + + if (error.response.status === 404) { + // The request was made and the server responded with a 404 status code + logger.error('log forwarding details not found'); + + throw new Error('log forwarding details not found'); + } else if (error.response && error.response.data) { + // The request was made and the server responded with an unsupported status code + logger.error( + 'Error while deleting log forwarding. Response: %s', + objToString(error, ['response', 'data'], 'Unable to delete log forwarding details'), + ); + + if (error.response.data.messages) { + const message = objToString( + error, + ['response', 'data', 'messages', '0', 'message'], + 'Unable to delete log forwarding details', + ); + + throw new Error(message); + } else if (error.response.data.message) { + const message = objToString( + error, + ['response', 'data', 'message'], + 'Unable to delete log forwarding details', + ); + + throw new Error(message); + } else { + const message = objToString( + error, + ['response', 'data'], + 'Unable to delete log forwarding details', + ); + + throw new Error(message); + } + } else { + // The request was made but no response was received + logger.error( + 'Error while deleting log forwarding details. No response received from the server: %s', + objToString(error, [], 'Unable to delete log forwarding details'), + ); + + throw new Error( + 'Unable to delete log forwarding details from Schema Management Service: %s', + error.message, + ); + } + } +}; + module.exports = { getApiKeyCredential, describeMesh, @@ -1420,4 +1523,5 @@ module.exports = { cachePurge, setLogForwarding, getLogForwarding, + deleteLogForwarding, }; From 7e1ac7e30e7ccac49742657cb954d145ff58c73f Mon Sep 17 00:00:00 2001 From: ajaz Date: Fri, 11 Apr 2025 18:57:45 +0530 Subject: [PATCH 2/6] chore: fix unit test file --- .../api-mesh/__tests__/delete-log-forwarding.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js b/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js index 45e25a5a..be874ff2 100644 --- a/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js +++ b/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js @@ -1,3 +1,15 @@ +/* +Copyright 2021 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + const DeleteLogForwardingCommand = require('../config/delete/log-forwarding'); const { initSdk, promptConfirm } = require('../../../helpers'); const { getMeshId, deleteLogForwarding } = require('../../../lib/smsClient'); From fdb709f147a4e388f41397e9ee0369613a11c133 Mon Sep 17 00:00:00 2001 From: ajaz Date: Mon, 14 Apr 2025 16:40:31 +0530 Subject: [PATCH 3/6] chore:address review comments --- src/lib/smsClient.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/smsClient.js b/src/lib/smsClient.js index d6018681..a794fb92 100644 --- a/src/lib/smsClient.js +++ b/src/lib/smsClient.js @@ -1431,10 +1431,10 @@ const deleteLogForwarding = async (organizationCode, projectId, workspaceId, mes return response; } else { logger.error( - `Something went wrong: ${objToString( + `Unable to delete log forwarding config: ${objToString( response, ['data'], - 'Unable to delete log forwarding details.', + 'Error', )}. Received ${response.status}, expected 204`, ); throw new Error( From 9bfc5c31fd4280db39782d682fef1a21a29228ef Mon Sep 17 00:00:00 2001 From: Sumaiya <108254100+AjazSumaiya@users.noreply.github.com> Date: Tue, 15 Apr 2025 14:46:56 +0530 Subject: [PATCH 4/6] Apply suggestions from code review Co-authored-by: Jared Hoover <98363870+jhadobe@users.noreply.github.com> --- src/commands/api-mesh/__tests__/delete-log-forwarding.test.js | 4 ++-- src/commands/api-mesh/config/delete/log-forwarding.js | 2 +- src/lib/smsClient.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js b/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js index be874ff2..fd4c05d9 100644 --- a/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js +++ b/src/commands/api-mesh/__tests__/delete-log-forwarding.test.js @@ -83,12 +83,12 @@ describe('delete log forwarding command tests', () => { deleteLogForwarding.mockRejectedValueOnce(new Error('Deletion failed')); await expect(DeleteLogForwardingCommand.run()).rejects.toThrow( - 'failed to delete log forwarding details. Try again. RequestId: dummy_request_id', + 'Unable to delete log forwarding details. Try again. RequestId: dummy_request_id', ); expect(logSpy).not.toHaveBeenCalledWith('Successfully deleted log forwarding details'); expect(errorLogSpy).toHaveBeenCalledWith( - 'failed to delete log forwarding details. Try again. RequestId: dummy_request_id', + 'Unable to delete log forwarding details. Try again. RequestId: dummy_request_id', ); }); diff --git a/src/commands/api-mesh/config/delete/log-forwarding.js b/src/commands/api-mesh/config/delete/log-forwarding.js index f574416f..2bfbe43a 100644 --- a/src/commands/api-mesh/config/delete/log-forwarding.js +++ b/src/commands/api-mesh/config/delete/log-forwarding.js @@ -65,7 +65,7 @@ class DeleteLogForwardingCommand extends Command { } catch (error) { this.log(error.message); this.error( - `failed to delete log forwarding details. Try again. RequestId: ${global.requestId}`, + `Unable to delete log forwarding details. Try again. RequestId: ${global.requestId}`, ); } } else { diff --git a/src/lib/smsClient.js b/src/lib/smsClient.js index a794fb92..18fe109b 100644 --- a/src/lib/smsClient.js +++ b/src/lib/smsClient.js @@ -1456,7 +1456,7 @@ const deleteLogForwarding = async (organizationCode, projectId, workspaceId, mes } else if (error.response && error.response.data) { // The request was made and the server responded with an unsupported status code logger.error( - 'Error while deleting log forwarding. Response: %s', + 'Error while deleting log forwarding details. Response: %s', objToString(error, ['response', 'data'], 'Unable to delete log forwarding details'), ); @@ -1493,7 +1493,7 @@ const deleteLogForwarding = async (organizationCode, projectId, workspaceId, mes ); throw new Error( - 'Unable to delete log forwarding details from Schema Management Service: %s', + 'Unable to delete log forwarding details: %s', error.message, ); } From 5f0f7719ba1131a9cc69a5eac3b02c7a75a4c3ed Mon Sep 17 00:00:00 2001 From: ajaz Date: Tue, 15 Apr 2025 14:57:27 +0530 Subject: [PATCH 5/6] fix: linting --- src/lib/smsClient.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib/smsClient.js b/src/lib/smsClient.js index 18fe109b..5ea90dbc 100644 --- a/src/lib/smsClient.js +++ b/src/lib/smsClient.js @@ -1492,10 +1492,7 @@ const deleteLogForwarding = async (organizationCode, projectId, workspaceId, mes objToString(error, [], 'Unable to delete log forwarding details'), ); - throw new Error( - 'Unable to delete log forwarding details: %s', - error.message, - ); + throw new Error('Unable to delete log forwarding details: %s', error.message); } } }; From 8fb85debd4f60709474e5494de0815cfaa902ceb Mon Sep 17 00:00:00 2001 From: ajaz Date: Tue, 15 Apr 2025 14:58:58 +0530 Subject: [PATCH 6/6] chore: bump up package version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 190c9255..572b498a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/aio-cli-plugin-api-mesh", - "version": "5.2.4-alpha.0", + "version": "5.2.4-alpha.1", "description": "Adobe I/O CLI plugin to develop and manage API mesh sources", "keywords": [ "oclif-plugin"