diff --git a/packages/cli/__tests__/__unit__/enable/Enable.definition.unit.test.ts b/packages/cli/__tests__/__unit__/enable/Enable.definition.unit.test.ts index ccd5717b..2034d166 100644 --- a/packages/cli/__tests__/__unit__/enable/Enable.definition.unit.test.ts +++ b/packages/cli/__tests__/__unit__/enable/Enable.definition.unit.test.ts @@ -12,7 +12,7 @@ import { ICommandDefinition } from "@zowe/imperative"; describe("cics enable urimap", () => { - const ENABLE_RESOURCES = 3; + const ENABLE_RESOURCES = 4; it("should not have changed", () => { const definition: ICommandDefinition = require("../../../src/enable/Enable.definition"); diff --git a/packages/cli/__tests__/__unit__/enable/localFile/LocalFile.definition.unit.test.ts b/packages/cli/__tests__/__unit__/enable/localFile/LocalFile.definition.unit.test.ts new file mode 100644 index 00000000..3f822a6b --- /dev/null +++ b/packages/cli/__tests__/__unit__/enable/localFile/LocalFile.definition.unit.test.ts @@ -0,0 +1,21 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { ICommandDefinition } from "@zowe/imperative"; + +describe("cics enable localFile", () => { + it("should not have changed", () => { + const definition: ICommandDefinition = require("../../../../src/enable/localFile/LocalFile.definition").LocalFileDefinition; + expect(definition).toBeDefined(); + delete definition.handler; + expect(definition).toMatchSnapshot(); + }); +}); diff --git a/packages/cli/__tests__/__unit__/enable/localFile/LocalFile.handler.unit.test.ts b/packages/cli/__tests__/__unit__/enable/localFile/LocalFile.handler.unit.test.ts new file mode 100644 index 00000000..05646966 --- /dev/null +++ b/packages/cli/__tests__/__unit__/enable/localFile/LocalFile.handler.unit.test.ts @@ -0,0 +1,102 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { mockHandlerParameters } from "@zowe/cli-test-utils"; +import { CommandProfiles, IHandlerParameters, IProfile, Session } from "@zowe/imperative"; +import { ICMCIApiResponse } from "../../../../src"; +import { LocalFileDefinition } from "../../../../src/enable/localFile/LocalFile.definition"; +import LocalFileHandler from "../../../../src/enable/localFile/LocalFile.handler"; + +jest.mock("@zowe/cics-for-zowe-sdk"); +const Enable = require("@zowe/cics-for-zowe-sdk"); + +const host = "somewhere.com"; +const port = "43443"; +const user = "someone"; +const password = "somesecret"; +const protocol = "http"; +const rejectUnauthorized = false; + +const PROFILE_MAP = new Map(); +PROFILE_MAP.set("cics", [ + { + name: "cics", + type: "cics", + host, + port, + user, + password, + protocol, + rejectUnauthorized, + }, +]); +const PROFILES: CommandProfiles = new CommandProfiles(PROFILE_MAP); +const DEFAULT_PARAMETERS: IHandlerParameters = mockHandlerParameters({ + positionals: ["cics", "enable", "localFile"], + definition: LocalFileDefinition, + profiles: PROFILES, +}); + +describe("enableLocalFileHandler", () => { + const localFileName = "testLocalFile"; + const regionName = "testRegion"; + + const defaultReturn: ICMCIApiResponse = { + response: { + resultsummary: { api_response1: "1024", api_response2: "0", recordcount: "0", displayed_recordcount: "0" }, + records: "testing", + }, + }; + + const functionSpy = jest.spyOn(Enable, "enableLocalFile"); + + beforeEach(() => { + functionSpy.mockClear(); + functionSpy.mockImplementation(async () => defaultReturn); + }); + + it("should call the enableLocalFile api", async () => { + const handler = new LocalFileHandler(); + + const commandParameters = { ...DEFAULT_PARAMETERS }; + commandParameters.arguments = { + ...commandParameters.arguments, + name: localFileName, + regionName, + host, + port, + user, + password, + protocol, + rejectUnauthorized, + }; + + await handler.process(commandParameters); + + expect(functionSpy).toHaveBeenCalledTimes(1); + const testProfile = PROFILE_MAP.get("cics")[0]; + expect(functionSpy).toHaveBeenCalledWith( + new Session({ + type: "basic", + hostname: testProfile.host, + port: testProfile.port, + user: testProfile.user, + password: testProfile.password, + rejectUnauthorized, + protocol, + }), + { + name: localFileName, + regionName, + } + ); + }); +}); diff --git a/packages/cli/__tests__/__unit__/enable/localFile/__snapshots__/LocalFile.definition.unit.test.ts.snap b/packages/cli/__tests__/__unit__/enable/localFile/__snapshots__/LocalFile.definition.unit.test.ts.snap new file mode 100644 index 00000000..2863fba2 --- /dev/null +++ b/packages/cli/__tests__/__unit__/enable/localFile/__snapshots__/LocalFile.definition.unit.test.ts.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`cics enable localFile should not have changed 1`] = ` +{ + "aliases": [ + "lf", + ], + "description": "Enable a local file from CICS.", + "examples": [ + { + "description": "Enable a local file named FILE from the region named MYREGION", + "options": "FILE --region-name MYREGION", + }, + ], + "name": "local-file", + "options": [ + { + "description": "The CICS region name in which to enable the local file", + "name": "region-name", + "type": "string", + }, + { + "description": "The name of the CICSPlex to which to enable the local file", + "name": "cics-plex", + "type": "string", + }, + ], + "positionals": [ + { + "description": "The name of the local file to enable.", + "name": "name", + "required": true, + "type": "string", + }, + ], + "profile": { + "optional": [ + "cics", + ], + }, + "type": "command", +} +`; diff --git a/packages/cli/__tests__/__unit__/enable/localFile/__snapshots__/LocalFile.handler.unit.test.ts.snap b/packages/cli/__tests__/__unit__/enable/localFile/__snapshots__/LocalFile.handler.unit.test.ts.snap new file mode 100644 index 00000000..a57ece2c --- /dev/null +++ b/packages/cli/__tests__/__unit__/enable/localFile/__snapshots__/LocalFile.handler.unit.test.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`enableLocalFileHandler should call the enableLocalFile api 1`] = `"The local file '%s' was enabled successfully."`; + +exports[`enableLocalFileHandler should call the enableLocalFile api 2`] = ` +{ + "response": { + "records": "testing", + "resultsummary": { + "api_response1": "1024", + "api_response2": "0", + "displayed_recordcount": "0", + "recordcount": "0", + }, + }, +} +`; diff --git a/packages/cli/__tests__/__unit__/enable/program/__snapshots__/Program.definition.unit.test.ts.snap b/packages/cli/__tests__/__unit__/enable/program/__snapshots__/Program.definition.unit.test.ts.snap index 28aa3f1e..b81b1bf6 100644 --- a/packages/cli/__tests__/__unit__/enable/program/__snapshots__/Program.definition.unit.test.ts.snap +++ b/packages/cli/__tests__/__unit__/enable/program/__snapshots__/Program.definition.unit.test.ts.snap @@ -41,45 +41,3 @@ exports[`cics enable program should not have changed 1`] = ` "type": "command", } `; - -exports[`cics enable urimap should not have changed 1`] = ` -{ - "aliases": [ - "prog", - ], - "description": "Enable a program from CICS.", - "examples": [ - { - "description": "Enable a program named PROGRAM1 from the region named MYREGION", - "options": "PROGRAM1 --region-name MYREGION", - }, - ], - "name": "program", - "options": [ - { - "description": "The CICS region name in which to enable the program", - "name": "region-name", - "type": "string", - }, - { - "description": "The name of the CICSPlex to which to enable the program", - "name": "cics-plex", - "type": "string", - }, - ], - "positionals": [ - { - "description": "The name of the program to enable. The maximum length is eight characters.", - "name": "name", - "required": true, - "type": "string", - }, - ], - "profile": { - "optional": [ - "cics", - ], - }, - "type": "command", -} -`; diff --git a/packages/cli/__tests__/__unit__/enable/transaction/__snapshots__/Transaction.definition.unit.test.ts.snap b/packages/cli/__tests__/__unit__/enable/transaction/__snapshots__/Transaction.definition.unit.test.ts.snap index b58e4a9d..0bb99b45 100644 --- a/packages/cli/__tests__/__unit__/enable/transaction/__snapshots__/Transaction.definition.unit.test.ts.snap +++ b/packages/cli/__tests__/__unit__/enable/transaction/__snapshots__/Transaction.definition.unit.test.ts.snap @@ -41,45 +41,3 @@ exports[`cics enable transaction should not have changed 1`] = ` "type": "command", } `; - -exports[`cics enable urimap should not have changed 1`] = ` -{ - "aliases": [ - "tran", - ], - "description": "Enable a transaction from CICS.", - "examples": [ - { - "description": "Enable a transaction named TRN1 from the region named MYREGION", - "options": "TRN1 --region-name MYREGION", - }, - ], - "name": "transaction", - "options": [ - { - "description": "The CICS region name in which to enable the transaction", - "name": "region-name", - "type": "string", - }, - { - "description": "The name of the CICSPlex to which to enable the transaction", - "name": "cics-plex", - "type": "string", - }, - ], - "positionals": [ - { - "description": "The name of the transaction to enable. The maximum length is four characters.", - "name": "name", - "required": true, - "type": "string", - }, - ], - "profile": { - "optional": [ - "cics", - ], - }, - "type": "command", -} -`; diff --git a/packages/cli/src/-strings-/en.ts b/packages/cli/src/-strings-/en.ts index 320fe560..0f3ba884 100644 --- a/packages/cli/src/-strings-/en.ts +++ b/packages/cli/src/-strings-/en.ts @@ -321,6 +321,22 @@ export default { SUMMARY: "Enable resources from CICS", DESCRIPTION: "Enable resources from CICS through IBM CMCI.", RESOURCES: { + LOCALFILE: { + DESCRIPTION: "Enable a local file from CICS.", + POSITIONALS: { + NAME: "The name of the local file to enable.", + }, + OPTIONS: { + REGIONNAME: "The CICS region name in which to enable the local file", + CICSPLEX: "The name of the CICSPlex to which to enable the local file", + }, + MESSAGES: { + SUCCESS: "The local file '%s' was enabled successfully.", + }, + EXAMPLES: { + EX1: "Enable a local file named FILE from the region named MYREGION", + }, + }, PROGRAM: { DESCRIPTION: "Enable a program from CICS.", POSITIONALS: { diff --git a/packages/cli/src/enable/Enable.definition.ts b/packages/cli/src/enable/Enable.definition.ts index 7edad098..38fe71cd 100644 --- a/packages/cli/src/enable/Enable.definition.ts +++ b/packages/cli/src/enable/Enable.definition.ts @@ -16,6 +16,7 @@ import i18nTypings from "../-strings-/en"; import { CicsSession } from "../CicsSession"; import { TransactionDefinition } from "./transaction/Transaction.definition"; import { ProgramDefinition } from "./program/Program.definition"; +import { LocalFileDefinition } from "./localFile/LocalFile.definition"; // Does not use the import in anticipation of some internationalization work to be done later. const strings = (require("../-strings-/en").default as typeof i18nTypings).ENABLE; @@ -29,7 +30,7 @@ const definition: ICommandDefinition = { summary: strings.SUMMARY, description: strings.DESCRIPTION, type: "group", - children: [ProgramDefinition, TransactionDefinition, UrimapDefinition], + children: [ProgramDefinition, LocalFileDefinition, TransactionDefinition, UrimapDefinition], passOn: [ { property: "options", diff --git a/packages/cli/src/enable/localFile/LocalFile.definition.ts b/packages/cli/src/enable/localFile/LocalFile.definition.ts new file mode 100644 index 00000000..cf63eaf3 --- /dev/null +++ b/packages/cli/src/enable/localFile/LocalFile.definition.ts @@ -0,0 +1,52 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { ICommandDefinition } from "@zowe/imperative"; + +import i18nTypings from "../../-strings-/en"; + +// Does not use the import in anticipation of some internationalization work to be done later. +const strings = (require("../../-strings-/en").default as typeof i18nTypings).ENABLE.RESOURCES.LOCALFILE; + +export const LocalFileDefinition: ICommandDefinition = { + name: "local-file", + aliases: ["lf"], + description: strings.DESCRIPTION, + handler: __dirname + "/LocalFile.handler", + type: "command", + positionals: [ + { + name: "name", + description: strings.POSITIONALS.NAME, + type: "string", + required: true, + }, + ], + options: [ + { + name: "region-name", + description: strings.OPTIONS.REGIONNAME, + type: "string", + }, + { + name: "cics-plex", + description: strings.OPTIONS.CICSPLEX, + type: "string", + }, + ], + profile: { optional: ["cics"] }, + examples: [ + { + description: strings.EXAMPLES.EX1, + options: "FILE --region-name MYREGION", + }, + ], +}; diff --git a/packages/cli/src/enable/localFile/LocalFile.handler.ts b/packages/cli/src/enable/localFile/LocalFile.handler.ts new file mode 100644 index 00000000..98355f4d --- /dev/null +++ b/packages/cli/src/enable/localFile/LocalFile.handler.ts @@ -0,0 +1,45 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { AbstractSession, IHandlerParameters, ITaskWithStatus, TaskStage } from "@zowe/imperative"; +import { ICMCIApiResponse, enableLocalFile } from "@zowe/cics-for-zowe-sdk"; +import { CicsBaseHandler } from "../../CicsBaseHandler"; + +import i18nTypings from "../../-strings-/en"; + +// Does not use the import in anticipation of some internationalization work to be done later. +const strings = (require("../../-strings-/en").default as typeof i18nTypings).ENABLE.RESOURCES.LOCALFILE; + +/** + * Command handler for enabling CICS LocalFiles via CMCI + * @export + * @class LocalFileHandler + * @implements {ICommandHandler} + */ +export default class LocalFileHandler extends CicsBaseHandler { + public async processWithSession(params: IHandlerParameters, session: AbstractSession): Promise { + const status: ITaskWithStatus = { + statusMessage: "Enabling LocalFile from CICS", + percentComplete: 0, + stageName: TaskStage.IN_PROGRESS, + }; + params.response.progress.startBar({ task: status }); + + const response = await enableLocalFile(session, { + name: params.arguments.name, + regionName: params.arguments.regionName, + cicsPlex: params.arguments.cicsPlex, + }); + + params.response.console.log(strings.MESSAGES.SUCCESS, params.arguments.name); + return response; + } +} diff --git a/packages/sdk/__tests__/__unit__/enable/Enable.localFile.unit.test.ts b/packages/sdk/__tests__/__unit__/enable/Enable.localFile.unit.test.ts new file mode 100644 index 00000000..93cd4647 --- /dev/null +++ b/packages/sdk/__tests__/__unit__/enable/Enable.localFile.unit.test.ts @@ -0,0 +1,106 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { Session } from "@zowe/imperative"; +import { CicsCmciConstants, CicsCmciRestClient, enableLocalFile, ICMCIApiResponse, IBaseParms } from "../../../src"; + +describe("CMCI - enable localFile", () => { + const localFile = "localFile"; + const region = "region"; + const content = "ThisIsATest" as unknown as ICMCIApiResponse; + + const enableParms: IBaseParms = { + regionName: region, + name: localFile, + }; + + const dummySession = new Session({ + user: "fake", + password: "fake", + hostname: "fake", + port: 1490, + }); + + let error: any; + let response: any; + let endPoint: any; + let requestBody: any; + + describe("validation", () => { + beforeEach(() => { + response = undefined; + error = undefined; + enableParms.regionName = region; + enableParms.name = localFile; + }); + + it("should throw an error if no region name is specified", async () => { + enableParms.regionName = undefined as any; + try { + response = await enableLocalFile(dummySession, enableParms); + } catch (err) { + error = err; + } + expect(response).toBeUndefined(); + expect(error).toBeDefined(); + expect(error.message).toContain("CICS region name is required"); + }); + + it("should throw an error if no localFile name is specified", async () => { + enableParms.name = undefined as any; + try { + response = await enableLocalFile(dummySession, enableParms); + } catch (err) { + error = err; + } + expect(response).toBeUndefined(); + expect(error).toBeDefined(); + expect(error.message).toContain("CICS LocalFile name is required"); + }); + }); + + describe("success scenarios", () => { + const enableSpy = jest.spyOn(CicsCmciRestClient, "putExpectParsedXml").mockResolvedValue(content); + + beforeEach(() => { + response = undefined; + error = undefined; + enableSpy.mockClear(); + enableSpy.mockResolvedValue(content); + enableParms.regionName = region; + enableParms.name = localFile; + }); + + it("should be able to enable a localFile", async () => { + endPoint = + "/" + + CicsCmciConstants.CICS_SYSTEM_MANAGEMENT + + "/" + + CicsCmciConstants.CICS_LOCAL_FILE + + "/" + + region + + `?CRITERIA=(FILE=${enableParms.name})`; + requestBody = { + request: { + action: { + $: { + name: "ENABLE", + }, + }, + }, + }; + + response = await enableLocalFile(dummySession, enableParms); + expect(response).toContain(content); + expect(enableSpy).toHaveBeenCalledWith(dummySession, endPoint, [], requestBody); + }); + }); +}); diff --git a/packages/sdk/src/constants/CicsCmci.constants.ts b/packages/sdk/src/constants/CicsCmci.constants.ts index ac8093eb..137de76c 100644 --- a/packages/sdk/src/constants/CicsCmci.constants.ts +++ b/packages/sdk/src/constants/CicsCmci.constants.ts @@ -88,9 +88,12 @@ export const CicsCmciConstants: { [key: string]: any } = { * PARAMETER parameter */ PARAMETER: "PARAMETER", - /** - * The CICS CMCI external resource names + * Specifies the required part of the REST interface URI to access local transactions definitions + */ + CICS_REMOTE_TRANSACTION: "CICSRemoteTransaction", + /** + * Specifies the required part of the REST interface URI to access local transactions definitions */ - CICS_CMCI_EXTERNAL_RESOURCES: ["CICSLocalTransaction", "CICSRemoteTransaction", "CICSDefinitionTransaction", "CICSLocalFile"], + CICS_LOCAL_FILE: "CICSLocalFile", }; diff --git a/packages/sdk/src/methods/enable/Enable.ts b/packages/sdk/src/methods/enable/Enable.ts index 3a13e01d..1369316b 100644 --- a/packages/sdk/src/methods/enable/Enable.ts +++ b/packages/sdk/src/methods/enable/Enable.ts @@ -130,3 +130,42 @@ export async function enableProgram(session: AbstractSession, parms: IProgramPar return await CicsCmciRestClient.putExpectParsedXml(session, cmciResource, [], requestBody); } + +/** + * Enable a local file installed in CICS through CMCI REST API + * @param {AbstractSession} session - the session to connect to CMCI with + * @param {IURIMapParms} parms - parameters for enabling your local file + * @returns {Promise} promise that resolves to the response (XML parsed into a javascript object) + * when the request is complete + * @throws {ImperativeError} CICS LocalFile name not defined or blank + * @throws {ImperativeError} CICS Region name not defined or blank + * @throws {ImperativeError} CicsCmciRestClient request fails + */ +export async function enableLocalFile(session: AbstractSession, parms: IBaseParms): Promise { + ImperativeExpect.toBeDefinedAndNonBlank(parms.name, "CICS LocalFile name", "CICS LocalFile name is required"); + ImperativeExpect.toBeDefinedAndNonBlank(parms.regionName, "CICS Region name", "CICS region name is required"); + const requestBody: any = { + request: { + action: { + $: { + name: "ENABLE", + }, + }, + }, + }; + + const cicsPlex = parms.cicsPlex === undefined ? "" : parms.cicsPlex + "/"; + const cmciResource = + "/" + + CicsCmciConstants.CICS_SYSTEM_MANAGEMENT + + "/" + + CicsCmciConstants.CICS_LOCAL_FILE + + "/" + + cicsPlex + + parms.regionName + + "?CRITERIA=(FILE=" + + parms.name + + ")"; + + return await CicsCmciRestClient.putExpectParsedXml(session, cmciResource, [], requestBody); +} diff --git a/packages/vsce/src/commands/enableCommands/enableLocalFileCommand.ts b/packages/vsce/src/commands/enableCommands/enableLocalFileCommand.ts index d614ca77..6ed62ff0 100644 --- a/packages/vsce/src/commands/enableCommands/enableLocalFileCommand.ts +++ b/packages/vsce/src/commands/enableCommands/enableLocalFileCommand.ts @@ -9,8 +9,6 @@ * */ -import { CicsCmciConstants, CicsCmciRestClient, ICMCIApiResponse } from "@zowe/cics-for-zowe-sdk"; -import { imperative } from "@zowe/zowe-explorer-api"; import { commands, ProgressLocation, TreeView, window } from "vscode"; import { CICSRegionTree } from "../../trees/CICSRegionTree"; import { CICSTree } from "../../trees/CICSTree"; @@ -19,6 +17,7 @@ import { CICSRegionsContainer } from "../../trees/CICSRegionsContainer"; import { CICSLocalFileTreeItem } from "../../trees/treeItems/CICSLocalFileTreeItem"; import { findSelectedNodes } from "../../utils/commandUtils"; import { CICSCombinedLocalFileTree } from "../../trees/CICSCombinedTrees/CICSCombinedLocalFileTree"; +import { enableLocalFile } from "@zowe/cics-for-zowe-sdk"; export function getEnableLocalFileCommand(tree: CICSTree, treeview: TreeView) { return commands.registerCommand("cics-extension-for-zowe.enableLocalFile", async (clickedNode) => { @@ -98,33 +97,3 @@ export function getEnableLocalFileCommand(tree: CICSTree, treeview: TreeView { - const requestBody: any = { - request: { - action: { - $: { - name: "ENABLE", - }, - }, - }, - }; - - const cicsPlex = parms.cicsPlex === undefined ? "" : parms.cicsPlex + "/"; - const cmciResource = - "/" + - CicsCmciConstants.CICS_SYSTEM_MANAGEMENT + - "/" + - "CICSLocalFile" + //CicsCmciConstants.CICS_CMCI_EXTERNAL_RESOURCES[3] - "/" + - cicsPlex + - parms.regionName + - "?CRITERIA=(FILE=" + - parms.name + - ")"; - - return await CicsCmciRestClient.putExpectParsedXml(session, cmciResource, [], requestBody); -}