Skip to content

Commit

Permalink
issueTso unit testing
Browse files Browse the repository at this point in the history
Signed-off-by: jace-roell <[email protected]>
  • Loading branch information
jace-roell committed Sep 3, 2024
1 parent c91de9e commit 2bb090f
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/*
* 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.
*
*/
* 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.
*
*/

jest.mock("../../../../../../zostso/lib/IssueTso");
import { IssueTso } from "@zowe/zos-tso-for-zowe-sdk";
Expand All @@ -18,34 +18,39 @@ import { StartTsoData } from "../../../__resources__/StartTsoData";
import {
UNIT_TEST_ZOSMF_PROF_OPTS,
UNIT_TEST_PROFILES_ZOSMF_TSO,
UNIT_TEST_TSO_PROF_OPTS
UNIT_TEST_TSO_PROF_OPTS,
} from "../../../../../../../__tests__/__src__/mocks/ZosmfProfileMock";
import { mockHandlerParameters } from "@zowe/cli-test-utils";
import { ZosmfBaseHandler } from "@zowe/zosmf-for-zowe-sdk";

const DEFAULT_PARAMETERS: IHandlerParameters = mockHandlerParameters({
arguments: {
...UNIT_TEST_ZOSMF_PROF_OPTS,
...UNIT_TEST_TSO_PROF_OPTS
...UNIT_TEST_TSO_PROF_OPTS,
},
positionals: ["zos-tso", "issue", "address-space"],
definition: CommandDefinition,
profiles: UNIT_TEST_PROFILES_ZOSMF_TSO
profiles: UNIT_TEST_PROFILES_ZOSMF_TSO,
});
let PARAMS_NO_SSM_STATEFUL = DEFAULT_PARAMETERS;
PARAMS_NO_SSM_STATEFUL.positionals = ["zos-tso","issue","cmd","TIME","--sf","--no-ssm"];
PARAMS_NO_SSM_STATEFUL.positionals = [
"zos-tso",
"issue",
"cmd",
"TIME",
"--sf",
"--no-ssm",
];
PARAMS_NO_SSM_STATEFUL.arguments.stateful = false;
PARAMS_NO_SSM_STATEFUL.arguments.suppressStartupMessages = false;
PARAMS_NO_SSM_STATEFUL.arguments.commandText = "TIME";

describe("issue command handler tests", () => {

afterEach(() => {
jest.resetAllMocks();
});

it("should issue command", async () => {
IssueTso.issueTsoCommand = jest.fn((session, acc, cmd, prof) => {
IssueTso.issueTsoCmd = jest.fn((session, acc, cmd, prof) => {
expect(prof).toBeDefined();
expect(prof).toMatchSnapshot();
return StartTsoData.SAMPLE_ISSUE_RESPONSE_WITH_MSG;
Expand All @@ -55,15 +60,16 @@ describe("issue command handler tests", () => {
params.arguments.acc = "acc";
params.arguments.cmd = "time";
await handler.process(params);
expect(IssueTso.issueTsoCommand).toHaveBeenCalledTimes(1);
expect(IssueTso.issueTsoCmd).toHaveBeenCalledTimes(1);
});

it("should be able respond with error message", async () => {
const failMessage = "IZUG1126E: z/OSMF cannot correlate the request for key \"ZOSMFAD-SYS2-55-aaakaaac\"\n" +
const failMessage =
'IZUG1126E: z/OSMF cannot correlate the request for key "ZOSMFAD-SYS2-55-aaakaaac"\n' +
"with an active z/OS application session.";
let error;
IssueTso.issueTsoCommand = jest.fn((session, servletKey) => {
throw new ImperativeError({msg: failMessage});
IssueTso.issueTsoCmd = jest.fn((session, servletKey) => {
throw new ImperativeError({ msg: failMessage });
});
const handler = new Command.default();
const params = Object.assign({}, ...[DEFAULT_PARAMETERS]);
Expand All @@ -74,28 +80,30 @@ describe("issue command handler tests", () => {
} catch (thrownError) {
error = thrownError;
}
expect(IssueTso.issueTsoCommand).toHaveBeenCalledTimes(1);
expect(IssueTso.issueTsoCmd).toHaveBeenCalledTimes(1);
expect(error).toBeDefined();
expect(error instanceof ImperativeError).toBe(true);
expect(error.message).toMatchSnapshot();
});

it("should issue command with issueTsoCmd", async () => {
IssueTso.issueTsoCmd = jest.fn().mockReturnValue({
success: true,
startReady: true,
zosmfResponse: {
cmdResponse: [
success: true,
startReady: true,
zosmfResponse: {
cmdResponse: [
{
message: "IKJ56650I TIME-00:00:00 AM. CPU-00:00:00 SERVICE-554 SESSION-00:00:00 JANUARY 1,2024",
message:
"IKJ56650I TIME-00:00:00 AM. CPU-00:00:00 SERVICE-554 SESSION-00:00:00 JANUARY 1,2024",
},
{
message: "READY ",
message: "READY ",
},
],
tsoPromptReceived: "Y",
},
commandResponse: "IKJ56650I TIME-00:00:00 AM. CPU-00:00:00 SERVICE-554 SESSION-00:00:00 JANUARY 1,2024\nREADY ",
],
tsoPromptReceived: "Y",
},
commandResponse:
"IKJ56650I TIME-00:00:00 AM. CPU-00:00:00 SERVICE-554 SESSION-00:00:00 JANUARY 1,2024\nREADY ",
});
const handler = new Command.default();
const params = Object.assign({}, ...[PARAMS_NO_SSM_STATEFUL]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,7 @@ exports[`issue command handler tests should be able respond with error message 1
with an active z/OS application session."
`;

exports[`issue command handler tests should issue command 1`] = `
Object {
"account": "fake",
"characterSet": undefined,
"codePage": undefined,
"columns": undefined,
"logonProcedure": undefined,
"regionSize": undefined,
"rows": undefined,
}
`;
exports[`issue command handler tests should issue command 1`] = `false`;

exports[`issue command handler tests should issue command 2`] = `"messages from TSO"`;

Expand Down
42 changes: 27 additions & 15 deletions packages/cli/src/zostso/issue/command/Command.handler.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,47 @@
/*
* 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.
*
*/
* 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 { IHandlerParameters } from "@zowe/imperative";
import { IIssueResponse, IIssueTsoCmdResponse, IssueTso, ZosTsoBaseHandler } from "@zowe/zos-tso-for-zowe-sdk";

import {
IIssueResponse,
IssueTso,
ZosTsoBaseHandler,
} from "@zowe/zos-tso-for-zowe-sdk";
/**
* Handler to issue command to TSO address space
* @export
* @class Handler
* @implements {ICommandHandler}
*/
export default class Handler extends ZosTsoBaseHandler {

// Process the command and produce the TSO response
public async processCmd(params: IHandlerParameters) {

// Issue the TSO command
const response: IIssueResponse = await IssueTso.issueTsoCmd(this.mSession,params.arguments.commandText,undefined,params.arguments.stateful,params.arguments.suppressStartupMessages);
const response: IIssueResponse = await IssueTso.issueTsoCmd(
this.mSession,
params.arguments.commandText,
undefined,
params.arguments.stateful,
params.arguments.suppressStartupMessages
);

// If requested, suppress the startup
if (!params.arguments.suppressStartupMessages && response.startResponse != null) {
if (
!params.arguments.suppressStartupMessages &&
response.startResponse != null
) {
this.console.log(response.startResponse.messages);
}
this.console.log(response.commandResponse);

// Return as an object when using --response-format-json
this.data.setObj(response);
}
Expand Down
69 changes: 67 additions & 2 deletions packages/zostso/__tests__/__unit__/IssueTso.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
import { ImperativeError, Session } from "@zowe/imperative";
import { IIssueTsoParms, ISendResponse, IssueTso, IStartStopResponse, IStartTsoParms, IZosmfTsoResponse, SendTso,
StartTso, StopTso } from "../../src";
import { CheckStatus } from "@zowe/zosmf-for-zowe-sdk";

const PRETEND_SESSION = new Session({
user: "user",
password: "password",
hostname: "host.com",
port: 443,
type: "basic",
rejectUnauthorized: false
rejectUnauthorized: false,
});
const SEND_RESPONSE = {
success: true,
Expand Down Expand Up @@ -129,7 +130,7 @@ describe("TsoIssue issueTsoCommand - failing scenarios", () => {
});
});

describe("TsoIssue issueTsoCommand", () => {
describe("TsoIssue issueTsoCommand - Deprecated API", () => {
it("should succeed", async () => {
(StartTso.start as any) = jest.fn(() => {
return new Promise((resolve) => {
Expand Down Expand Up @@ -190,3 +191,67 @@ describe("TsoIssue issueTsoCommand", () => {
expect(response).toBeDefined();
});
});

describe("TsoIssue issueTsoCmd - Revised API", () => {
it("should succeed", async () => {
(StartTso.start as any) = jest.fn(() => {
return new Promise((resolve) => {
process.nextTick(() => {
resolve(START_RESPONSE);
});
});
});
(SendTso.getAllResponses as any) = jest.fn(() => {
return new Promise((resolve) => {
process.nextTick(() => {
resolve({});
});
});
});
(SendTso.sendDataToTSOCollect as any) = jest.fn(() => {
return new Promise((resolve) => {
process.nextTick(() => {
resolve(SEND_RESPONSE);
});
});
});
(StopTso.stop as any) = jest.fn(() => {
return new Promise((resolve) => {
process.nextTick(() => {
resolve(null);
});
});
});

let error: ImperativeError;
let response: ISendResponse;
jest.spyOn(CheckStatus, "isZosVersionGreaterThan").mockReturnValue(Promise.resolve(true));
try {
response = await IssueTso.issueTsoCmd(PRETEND_SESSION, "TEST", undefined, true, false);
} catch (thrownError) {
error = thrownError;
}
expect(error).not.toBeDefined();
expect(response).toBeDefined();
});

it("should succeed (with params)", async () => {
(IssueTso.issueTsoCmd as any) = jest.fn(() => {
return new Promise((resolve) => {
process.nextTick(() => {
resolve({});
});
});
});
let error: ImperativeError;
let response: ISendResponse;
jest.spyOn(CheckStatus, "isZosVersionGreaterThan").mockReturnValue(Promise.resolve(true));
try {
response = await IssueTso.issueTsoCmd(PRETEND_SESSION, "command", undefined, true, false);
} catch (thrownError) {
error = thrownError;
}
expect(error).not.toBeDefined();
expect(response).toBeDefined();
});
});
47 changes: 27 additions & 20 deletions packages/zostso/src/IssueTso.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,42 +34,49 @@ export class IssueTso {
commandInfo: string | IIssueTsoCmdParms,
addressSpaceOptions?: IStartTsoParms,
isStateful?: boolean,
suppressStartupMessage?: boolean,
suppressStartupMessage?: boolean
): Promise<IIssueResponse> {
let command: string | IIssueTsoCmdParms;
let version: string;
if(!isStateful) isStateful = false
if(!suppressStartupMessage) suppressStartupMessage = false;
if (!isStateful) isStateful = false;
if (!suppressStartupMessage) suppressStartupMessage = false;

let useNewApi =
addressSpaceOptions == null &&
await CheckStatus.isZosVersionGreaterThan(
(await CheckStatus.isZosVersionGreaterThan(
session,
ZosmfConstants.VERSIONS.V2R4
) && suppressStartupMessage === true;
)) &&
suppressStartupMessage === true;
if (useNewApi) {
command = commandInfo;
version = "v1";
try {
const endpoint = `${TsoConstants.RESOURCE}/${version}/${TsoConstants.RES_START_TSO}`;
const apiResponse = await ZosmfRestClient.putExpectJSON<IIssueTsoCmdResponse>(
session,
endpoint,
[Headers.APPLICATION_JSON],
{
tsoCmd: command,
cmdState: isStateful ? "stateful" : "stateless",
}
);
const apiResponse =
await ZosmfRestClient.putExpectJSON<IIssueTsoCmdResponse>(
session,
endpoint,
[Headers.APPLICATION_JSON],
{
tsoCmd: command,
cmdState: isStateful ? "stateful" : "stateless",
}
);
const response: IIssueResponse = {
success: true,
startReady: apiResponse.cmdResponse[apiResponse.cmdResponse.length - 1].message.trim() === 'READY',
startReady:
apiResponse.cmdResponse[
apiResponse.cmdResponse.length - 1
].message.trim() === "READY",
zosmfResponse: apiResponse as any,
commandResponse: apiResponse.cmdResponse.map(item => item.message).join('\n')
commandResponse: apiResponse.cmdResponse
.map((item) => item.message)
.join("\n"),
};
return response;
} catch(e) {
if(!e.mMessage.includes("status 404")) throw e;
} catch (e) {
if (!e.mMessage.includes("status 404")) throw e;
useNewApi = false;
}
}
Expand All @@ -78,8 +85,8 @@ export class IssueTso {
const profInfo = new ProfileInfo("zowe");
await profInfo.readProfilesFromDisk();
addressSpaceOptions = profInfo
.getTeamConfig()
.api.profiles.defaultGet("tso");
.getTeamConfig()
.api.profiles.defaultGet("tso");
command =
typeof commandInfo === "string"
? commandInfo
Expand Down

0 comments on commit 2bb090f

Please sign in to comment.