diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 00714b45..6872957d 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to the IBM® CICS® Plug-in for Zowe CLI will be documented ## Recent Changes - Enhancement: Add optional query parameters on getResource SDK method. [#168](https://github.com/zowe/cics-for-zowe-client/issues/168) +- Enhancement: Add getCache method to SDK. [#169](https://github.com/zowe/cics-for-zowe-client/issues/169) ## `6.1.0` diff --git a/packages/sdk/__tests__/__unit__/cache/Cache.unit.test.ts b/packages/sdk/__tests__/__unit__/cache/Cache.unit.test.ts new file mode 100644 index 00000000..d9faaf38 --- /dev/null +++ b/packages/sdk/__tests__/__unit__/cache/Cache.unit.test.ts @@ -0,0 +1,189 @@ +/** + * 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, + getCache, + ICacheParms, + ICMCIApiResponse +} from "../../../src"; + +describe("CMCI - Get Cache", () => { + const content: ICMCIApiResponse = { + response: { + resultsummary: { + api_response1: "1024", + api_response2: "0", + api_response1_alt: "OK", + api_response2_alt: "", + recordcount: "1", + cachetoken: "E0252A3D2292C613", + displayed_recordcount: "1", + }, + records: [] + } + }; + const dummySession = new Session({ + user: "fake", + password: "fake", + hostname: "fake", + port: 1490 + }); + + let error: any; + let response: any; + let endPoint: string; + let cacheParms: ICacheParms; + + + describe("validation", () => { + beforeEach(() => { + response = undefined; + error = undefined; + }); + + it("should throw error if no parms are defined", async () => { + try { + response = await getCache(dummySession, undefined); + } catch (err) { + error = err; + } + + expect(response).toBeUndefined(); + expect(error).toBeDefined(); + expect(error.message).toMatch(/(Cannot read).*undefined/); + }); + + it("should throw error if cache token is not defined", async () => { + try { + response = await getCache(dummySession, { cacheToken: undefined }); + } catch (err) { + error = err; + } + + expect(response).toBeUndefined(); + expect(error).toBeDefined(); + expect(error.message).toContain("CICS Result Cache Token is required"); + }); + + it("should throw error if cache token is missing", async () => { + try { + response = await getCache(dummySession, { cacheToken: "" }); + } catch (err) { + error = err; + } + + expect(response).toBeUndefined(); + expect(error).toBeDefined(); + expect(error.message).toContain("Required parameter 'CICS Result Cache Token' must not be blank"); + }); + }); + + describe("success scenarios", () => { + + const cmciGetSpy = jest.spyOn(CicsCmciRestClient, "getExpectParsedXml").mockResolvedValue(content); + + beforeEach(() => { + response = undefined; + error = undefined; + cacheParms = { + cacheToken: "E0252A3D2292C613", + }; + cmciGetSpy.mockClear(); + cmciGetSpy.mockResolvedValue(content); + }); + + it("should be able to get a result cache", async () => { + try { + response = await getCache(dummySession, cacheParms); + } catch (err) { + error = err; + } + + endPoint = "/" + CicsCmciConstants.CICS_SYSTEM_MANAGEMENT + + "/" + CicsCmciConstants.CICS_RESULT_CACHE + + "/" + cacheParms.cacheToken + "?" + CicsCmciConstants.NO_DISCARD; + + expect(response).toEqual(content); + expect(cmciGetSpy).toHaveBeenCalledWith(dummySession, endPoint, []); + }); + + it("should be able to get a result cache with SUMMONLY", async () => { + try { + cacheParms.summonly = true; + response = await getCache(dummySession, cacheParms); + } catch (err) { + error = err; + } + + endPoint = "/" + CicsCmciConstants.CICS_SYSTEM_MANAGEMENT + + "/" + CicsCmciConstants.CICS_RESULT_CACHE + + "/" + cacheParms.cacheToken + "?" + CicsCmciConstants.NO_DISCARD + + "&" + CicsCmciConstants.SUMM_ONLY; + + expect(response).toEqual(content); + expect(cmciGetSpy).toHaveBeenCalledWith(dummySession, endPoint, []); + }); + + it("should be able to get a result cache with start index", async () => { + try { + cacheParms.startIndex = 10; + response = await getCache(dummySession, cacheParms); + } catch (err) { + error = err; + } + + endPoint = "/" + CicsCmciConstants.CICS_SYSTEM_MANAGEMENT + + "/" + CicsCmciConstants.CICS_RESULT_CACHE + + "/" + cacheParms.cacheToken + "/" + + "10?" + CicsCmciConstants.NO_DISCARD; + + expect(response).toEqual(content); + expect(cmciGetSpy).toHaveBeenCalledWith(dummySession, endPoint, []); + }); + + it("should be able to get a result cache with start index and count", async () => { + try { + cacheParms.startIndex = 15; + cacheParms.count = 5; + response = await getCache(dummySession, cacheParms); + } catch (err) { + error = err; + } + + endPoint = "/" + CicsCmciConstants.CICS_SYSTEM_MANAGEMENT + + "/" + CicsCmciConstants.CICS_RESULT_CACHE + + "/" + cacheParms.cacheToken + "/" + + "15/5?" + CicsCmciConstants.NO_DISCARD; + + expect(response).toEqual(content); + expect(cmciGetSpy).toHaveBeenCalledWith(dummySession, endPoint, []); + }); + + it("should be able to get a result cache without NODISCARD", async () => { + try { + cacheParms.nodiscard = false; + response = await getCache(dummySession, cacheParms); + } catch (err) { + error = err; + } + + endPoint = "/" + CicsCmciConstants.CICS_SYSTEM_MANAGEMENT + + "/" + CicsCmciConstants.CICS_RESULT_CACHE + + "/" + cacheParms.cacheToken; + + expect(response).toEqual(content); + expect(cmciGetSpy).toHaveBeenCalledWith(dummySession, endPoint, []); + }); + }); +}); diff --git a/packages/sdk/__tests__/__unit__/utils/Utils.unit.test.ts b/packages/sdk/__tests__/__unit__/utils/Utils.unit.test.ts index de9e9971..d615c193 100644 --- a/packages/sdk/__tests__/__unit__/utils/Utils.unit.test.ts +++ b/packages/sdk/__tests__/__unit__/utils/Utils.unit.test.ts @@ -9,8 +9,9 @@ * */ -import { Utils } from "../../../src/utils"; import { IGetResourceUriOptions } from "../../../src"; +import { IResultCacheParms } from "../../../src/doc/IResultCacheParms"; +import { Utils } from "../../../src/utils"; describe("Utils - getResourceUri", () => { @@ -415,3 +416,171 @@ describe('Utils - enforceParentheses', () => { expect(output).toEqual("((()))"); }); }); + +describe("Utils - getCacheUri", () => { + + let error: any; + let response: any; + + describe("validation", () => { + beforeEach(() => { + response = undefined; + error = undefined; + }); + + it("should throw error if cacheToken is empty", async () => { + try { + response = Utils.getCacheUri(""); + } catch (err) { + error = err; + } + + expect(response).toBeUndefined(); + expect(error).toBeDefined(); + expect(error.message).toEqual("Expect Error: Required parameter 'CICS Results Cache Token' must not be blank"); + }); + + it("should throw error if cacheToken is undefined", async () => { + try { + response = Utils.getCacheUri(undefined); + } catch (err) { + error = err; + } + + expect(response).toBeUndefined(); + expect(error).toBeDefined(); + expect(error.message).toEqual("Expect Error: CICS Results Cache Token is required"); + }); + + it("should throw error if cacheToken is null", async () => { + try { + response = Utils.getCacheUri(null); + } catch (err) { + error = err; + } + + expect(response).toBeUndefined(); + expect(error).toBeDefined(); + expect(error.message).toEqual("Expect Error: CICS Results Cache Token is required"); + }); + }); + + describe("success scenarios", () => { + + beforeEach(() => { + response = undefined; + error = undefined; + }); + + it("should be able to get a result cache uri with only the cache token specified", async () => { + try { + response = Utils.getCacheUri("abcdefg"); + } catch (err) { + error = err; + } + + expect(response).toBeDefined(); + expect(error).toBeUndefined(); + expect(response).toEqual("/CICSSystemManagement/CICSResultCache/abcdefg?NODISCARD"); + }); + + it("should be able to get a result cache with the index specified", async () => { + try { + + const options: IResultCacheParms = { + startIndex: 1 + }; + + response = Utils.getCacheUri("abcdefgh", options); + } catch (err) { + error = err; + } + + expect(response).toBeDefined(); + expect(error).toBeUndefined(); + expect(response).toEqual("/CICSSystemManagement/CICSResultCache/abcdefgh/1?NODISCARD"); + }); + + it("should be able to get a result cache with the count specified - ignored with no index", async () => { + try { + const options: IResultCacheParms = { + count: 20 + }; + + response = Utils.getCacheUri("cachetoken", options); + } catch (err) { + error = err; + } + + expect(response).toBeDefined(); + expect(error).toBeUndefined(); + expect(response).toEqual("/CICSSystemManagement/CICSResultCache/cachetoken?NODISCARD"); + }); + + it("should be able to get a result cache with the index and count specified", async () => { + try { + const options: IResultCacheParms = { + startIndex: 10, + count: 20 + }; + + response = Utils.getCacheUri("cachetoken", options); + } catch (err) { + error = err; + } + + expect(response).toBeDefined(); + expect(error).toBeUndefined(); + expect(response).toEqual("/CICSSystemManagement/CICSResultCache/cachetoken/10/20?NODISCARD"); + }); + + it("should be able to get a result cache with SUMMONLY", async () => { + try { + const options: IResultCacheParms = { + summonly: true, + }; + + response = Utils.getCacheUri("abcdef", options); + } catch (err) { + error = err; + } + + expect(response).toBeDefined(); + expect(error).toBeUndefined(); + expect(response).toEqual("/CICSSystemManagement/CICSResultCache/abcdef?NODISCARD&SUMMONLY"); + }); + + it("should be able to get a result cache and with false NODISCARD", async () => { + try { + const options: IResultCacheParms = { + nodiscard: false + }; + + response = Utils.getCacheUri("abcdef", options); + } catch (err) { + error = err; + } + + expect(response).toBeDefined(); + expect(error).toBeUndefined(); + expect(response).toEqual("/CICSSystemManagement/CICSResultCache/abcdef"); + }); + + it("should be able to get a result cache and with summonly but not nodiscard", async () => { + try { + const options: IResultCacheParms = { + summonly: true, + nodiscard: false, + }; + + response = Utils.getCacheUri("abcdef", options); + } catch (err) { + error = err; + } + + expect(response).toBeDefined(); + expect(error).toBeUndefined(); + expect(response).toEqual("/CICSSystemManagement/CICSResultCache/abcdef?SUMMONLY"); + }); + }); +}); diff --git a/packages/sdk/src/constants/CicsCmci.constants.ts b/packages/sdk/src/constants/CicsCmci.constants.ts index 2a18507d..791365ce 100644 --- a/packages/sdk/src/constants/CicsCmci.constants.ts +++ b/packages/sdk/src/constants/CicsCmci.constants.ts @@ -64,6 +64,11 @@ export const CicsCmciConstants = { */ CICS_CSDGROUP_IN_LIST: "CICSCSDGroupInList", + /** + * Specifies the Result Cache part of the URI + */ + CICS_RESULT_CACHE: "CICSResultCache", + /** * ORDERBY parameter */ diff --git a/packages/sdk/src/doc/ICacheParms.ts b/packages/sdk/src/doc/ICacheParms.ts new file mode 100644 index 00000000..9b8b7735 --- /dev/null +++ b/packages/sdk/src/doc/ICacheParms.ts @@ -0,0 +1,20 @@ +/** + * 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 { IResultCacheParms } from "./IResultCacheParms"; + + +export interface ICacheParms extends IResultCacheParms { + /** + * The cache token to be fetched + */ + cacheToken: string; +} diff --git a/packages/sdk/src/doc/IResultCacheParms.ts b/packages/sdk/src/doc/IResultCacheParms.ts new file mode 100644 index 00000000..181dbee2 --- /dev/null +++ b/packages/sdk/src/doc/IResultCacheParms.ts @@ -0,0 +1,24 @@ +/** + * 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 { IResourceQueryParams } from "./IResourceQueryParms"; + +export interface IResultCacheParms extends IResourceQueryParams { + /** + * Index of first record to collect from the results cache + */ + startIndex?: number; + + /** + * Number of records to fetch from the cache + */ + count?: number; +} diff --git a/packages/sdk/src/doc/index.ts b/packages/sdk/src/doc/index.ts index c418516a..f6275238 100644 --- a/packages/sdk/src/doc/index.ts +++ b/packages/sdk/src/doc/index.ts @@ -9,11 +9,14 @@ * */ +export * from "./ICacheParms"; export * from "./ICMCIApiResponse"; export * from "./ICMCIResponseResultSummary"; export * from "./ICSDGroupParms"; export * from "./IProgramParms"; export * from "./IResourceParms"; +export * from "./IResourceQueryParms"; +export * from "./IResultCacheParms"; export * from "./ITransactionParms"; export * from "./IURIMapParms"; export * from "./IWebServiceParms"; diff --git a/packages/sdk/src/methods/cache/Cache.ts b/packages/sdk/src/methods/cache/Cache.ts new file mode 100644 index 00000000..3f1a6363 --- /dev/null +++ b/packages/sdk/src/methods/cache/Cache.ts @@ -0,0 +1,32 @@ +/** + * 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, ImperativeExpect, Logger } from "@zowe/imperative"; +import { ICMCIApiResponse } from "../../doc"; +import { ICacheParms } from "../../doc/ICacheParms"; +import { IResultCacheParms } from "../../doc/IResultCacheParms"; +import { CicsCmciRestClient } from "../../rest"; +import { Utils } from "../../utils"; + +export async function getCache(session: AbstractSession, parms: ICacheParms): Promise { + ImperativeExpect.toBeDefinedAndNonBlank(parms.cacheToken, "CICS Result Cache Token", "CICS Result Cache Token is required"); + Logger.getAppLogger().debug("Attempting to get cache with the following parameters:\n%s", JSON.stringify(parms)); + + const options: IResultCacheParms = { + count: parms.count, + startIndex: parms.startIndex, + summonly: parms.summonly, + nodiscard: parms.nodiscard, + }; + const cmciResource = Utils.getCacheUri(parms.cacheToken, options); + + return CicsCmciRestClient.getExpectParsedXml(session, cmciResource, []); +} diff --git a/packages/sdk/src/methods/cache/index.ts b/packages/sdk/src/methods/cache/index.ts new file mode 100644 index 00000000..5b40ad6a --- /dev/null +++ b/packages/sdk/src/methods/cache/index.ts @@ -0,0 +1,12 @@ +/** + * 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. + * + */ + +export * from "./Cache"; diff --git a/packages/sdk/src/methods/index.ts b/packages/sdk/src/methods/index.ts index c2d6e387..16be9f5a 100644 --- a/packages/sdk/src/methods/index.ts +++ b/packages/sdk/src/methods/index.ts @@ -10,6 +10,7 @@ */ export * from "./add-to-list"; +export * from "./cache"; export * from "./define"; export * from "./delete"; export * from "./disable"; diff --git a/packages/sdk/src/utils/Utils.ts b/packages/sdk/src/utils/Utils.ts index 5135a789..df6ad2ab 100644 --- a/packages/sdk/src/utils/Utils.ts +++ b/packages/sdk/src/utils/Utils.ts @@ -12,6 +12,7 @@ import { ImperativeExpect } from "@zowe/imperative"; import { CicsCmciConstants } from "../constants"; import { IGetResourceUriOptions } from "../doc"; +import { IResultCacheParms } from "../doc/IResultCacheParms"; /** * Class for providing static utility methods @@ -63,6 +64,34 @@ export class Utils { return cmciResource; } + public static getCacheUri(cacheToken: string, options?: IResultCacheParms): string { + ImperativeExpect.toBeDefinedAndNonBlank(cacheToken, "CICS Results Cache Token", "CICS Results Cache Token is required"); + + let cmciResource = `/${CicsCmciConstants.CICS_SYSTEM_MANAGEMENT}/${CicsCmciConstants.CICS_RESULT_CACHE}/${cacheToken}`; + + if (options && options.startIndex) { + cmciResource += `/${options.startIndex}`; + + if (options.count) { + cmciResource += `/${options.count}`; + } + } + + let delimiter = "?"; + + // Add NODISCARD unless explicitally told not to + if (!options || options.nodiscard == null || options.nodiscard === true) { + cmciResource += `${delimiter}${CicsCmciConstants.NO_DISCARD}`; + delimiter = "&"; + } + + if (options && options.summonly) { + cmciResource += `${delimiter}${CicsCmciConstants.SUMM_ONLY}`; + } + + return cmciResource; + } + public static enforceParentheses(input: string): string { if (!input.startsWith('(') && !input.endsWith(')')) { return `(${input})`;