Skip to content

Commit

Permalink
Merge branch 'master' into fix/jest-stare-config
Browse files Browse the repository at this point in the history
  • Loading branch information
awharn authored Nov 5, 2024
2 parents 2743305 + 142cff2 commit c9043d4
Show file tree
Hide file tree
Showing 31 changed files with 639 additions and 50 deletions.
4 changes: 3 additions & 1 deletion packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

All notable changes to the Zowe CLI package will be documented in this file.

## Recent Changes

- Enhancement: Added --wait-for-active and --wait-for-output to download options on zosjobs. [#2328](https://github.com/zowe/zowe-cli/pull/2328)

## `8.6.2`

Expand All @@ -11,7 +14,6 @@ All notable changes to the Zowe CLI package will be documented in this file.

- BugFix: Fixed an issue where the `zowe zos-logs list logs` command could fail or not return all logs if a start time was not supplied. [#2336](https://github.com/zowe/zowe-cli/pull/2336)


## `8.6.0`

- Enhancement: Added support for running applications on TSO/E address spaces. Start applications and receive/transmit messages using the new `tso start`, `tso receive` and `tso send` commands. [#2280](https://github.com/zowe/zowe-cli/pull/2280)
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
JOBID=$(zowe jobs submit ds "$1" --rff jobid --rft string)

zowe zos-jobs download output $JOBID --wfa
exit $?
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
JOBID=$(zowe jobs submit ds "$1" --rff jobid --rft string)

zowe zos-jobs download output $JOBID --wfo
exit $?
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { ITestEnvironment } from "../../../../../../__tests__/__src__/environmen
import { runCliScript } from "@zowe/cli-test-utils";
import { ITestPropertiesSchema } from "../../../../../../__tests__/__src__/properties/ITestPropertiesSchema";
import * as fs from "fs";
import { Session } from "@zowe/imperative";
import { GetJobs } from "@zowe/zos-jobs-for-zowe-sdk";

// Test Environment populated in the beforeAll();
let TEST_ENVIRONMENT: ITestEnvironment<ITestPropertiesSchema>;
Expand Down Expand Up @@ -43,12 +45,25 @@ describe("zos-jobs download output command", () => {
});
});

describe("Live system tests", () => {
it("should download a job and wait for it to reach output status", async () => {
const response = runCliScript(__dirname + "/__scripts__/download-output/download_job_wait_for_output.sh",
TEST_ENVIRONMENT, [IEFBR14_JCL]);
expect(response.stderr.toString()).toBe("");
expect(response.status).toBe(0);
});
it("should download a job and wait for it to reach active status", async () => {
const response = runCliScript(__dirname + "/__scripts__/download-output/download_job_wait_for_active.sh",
TEST_ENVIRONMENT, [IEFBR14_JCL]);
expect(response.stderr.toString()).toBe("");
expect(response.status).toBe(0);
});
});
describe("output", () => {
it("should download all spool files of a job", () => {
const outdir: string = TEST_ENVIRONMENT.workingDir + "/output/JES2";
const response = runCliScript(__dirname + "/__scripts__/download-output/download.sh",
TEST_ENVIRONMENT, [IEFBR14_JCL]);

// Extract the JOBID from the response output
const jobidRegex = /Submitted job ID: (JOB\d+)/;
const match = response.stdout.toString().match(jobidRegex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,66 @@ describe("download output handler tests", () => {
expect(error instanceof ImperativeError).toBe(true);
expect(error.message).toMatchSnapshot();
});

it("should download a job output using wfa", async () => {
let passedSession: Session = null;
GetJobs.getJob = jest.fn(async (session, jobid) => {
passedSession = session;
return GetJobsData.SAMPLE_COMPLETE_JOB;
});
DownloadJobs.downloadAllSpoolContentCommon = jest.fn(
async (session, options) => {
return;
}
);
const handler = new OutputHandler.default();
const params = Object.assign({}, ...[DEFAULT_PARAMETERS]);
params.arguments = Object.assign({}, ...[DEFAULT_PARAMETERS.arguments]);
params.arguments.jobid = GetJobsData.SAMPLE_COMPLETE_JOB.jobid;
params.arguments.wfa = true;
const opts: IDownloadAllSpoolContentParms = {
jobname: GetJobsData.SAMPLE_COMPLETE_JOB.jobname,
jobid: GetJobsData.SAMPLE_COMPLETE_JOB.jobid,
outDir: DownloadJobs.DEFAULT_JOBS_OUTPUT_DIR,
omitJobidDirectory: false,
waitForActive: params.arguments.waitForActive
};
await handler.process(params);
expect(GetJobs.getJob).toHaveBeenCalledTimes(1);
expect(DownloadJobs.downloadAllSpoolContentCommon).toHaveBeenCalledWith(
passedSession,
opts
);
});

it("should download a job output using wfo", async () => {
let passedSession: Session = null;
GetJobs.getJob = jest.fn(async (session, jobid) => {
passedSession = session;
return GetJobsData.SAMPLE_COMPLETE_JOB;
});
DownloadJobs.downloadAllSpoolContentCommon = jest.fn(
async (session, options) => {
return;
}
);
const handler = new OutputHandler.default();
const params = Object.assign({}, ...[DEFAULT_PARAMETERS]);
params.arguments = Object.assign({}, ...[DEFAULT_PARAMETERS.arguments]);
params.arguments.jobid = GetJobsData.SAMPLE_COMPLETE_JOB.jobid;
params.arguments.wfo = true;
const opts: IDownloadAllSpoolContentParms = {
jobname: GetJobsData.SAMPLE_COMPLETE_JOB.jobname,
jobid: GetJobsData.SAMPLE_COMPLETE_JOB.jobid,
outDir: DownloadJobs.DEFAULT_JOBS_OUTPUT_DIR,
omitJobidDirectory: false,
waitForOutput: params.arguments.waitForOutput
};
await handler.process(params);
expect(GetJobs.getJob).toHaveBeenCalledTimes(1);
expect(DownloadJobs.downloadAllSpoolContentCommon).toHaveBeenCalledWith(
passedSession,
opts
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ Object {
"name": "encoding",
"type": "string",
},
Object {
"aliases": Array [
"wfa",
],
"conflictsWith": Array [
"wait-for-output",
],
"description": "Wait for the job to enter ACTIVE status before completing the command.",
"name": "wait-for-active",
"type": "boolean",
},
Object {
"aliases": Array [
"wfo",
],
"conflictsWith": Array [
"wait-for-active",
],
"description": "Wait for the job to enter OUTPUT status before completing the command.",
"name": "wait-for-output",
"type": "boolean",
},
],
"positionals": Array [
Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ Destination: ./output"

exports[`download output handler tests should download a job output using defaults 2`] = `Object {}`;

exports[`download output handler tests should download a job output using wfa 1`] = `
"Successfully downloaded the job output
Destination: ./output"
`;

exports[`download output handler tests should download a job output using wfa 2`] = `Object {}`;

exports[`download output handler tests should download a job output using wfo 1`] = `
"Successfully downloaded the job output
Destination: ./output"
`;

exports[`download output handler tests should download a job output using wfo 2`] = `Object {}`;

exports[`download output handler tests should download a job output with a specific extension 1`] = `
"Successfully downloaded the job output
Destination: ./output"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,19 @@ export const OutputDefinition: ICommandDefinition = {
"data conversion is performed using the file encoding specified.",
type: "string",
conflictsWith: ["binary", "record"]
}
},
{
name: "wait-for-active", aliases: ["wfa"],
description: "Wait for the job to enter ACTIVE status before completing the command.",
type: "boolean",
conflictsWith: ["wait-for-output"]
},
{
name: "wait-for-output", aliases: ["wfo"],
description: "Wait for the job to enter OUTPUT status before completing the command.",
type: "boolean",
conflictsWith: ["wait-for-active"]
},
] as ICommandOptionDefinition[]),
examples: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export default class OutputHandler extends ZosmfBaseHandler {
const binary: boolean = this.mArguments.binary;
const record: boolean = this.mArguments.record;
const encoding: string = this.mArguments.encoding;
const waitForActive: boolean = this.mArguments.waitForActive;
const waitForOutput: boolean = this.mArguments.waitForOutput;
// Get the job details
const job: IJob = await GetJobs.getJob(this.mSession, jobid);
const options: IDownloadAllSpoolContentParms = {
Expand All @@ -45,7 +47,9 @@ export default class OutputHandler extends ZosmfBaseHandler {
extension,
binary,
record,
encoding
encoding,
waitForActive,
waitForOutput
};
// Download 'em all
await DownloadJobs.downloadAllSpoolContentCommon(this.mSession, options);
Expand Down
4 changes: 4 additions & 0 deletions packages/imperative/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to the Imperative package will be documented in this file.

## Recent Changes

- Enhancement: Added optional `proxy` object to ISession interface for extenders to pass a ProxyVariables object that would override the environment variables if in place. [#2330](https://github.com/zowe/zowe-cli/pull/2330)

## `8.6.1`

- BugFix: Handled an HTTP 1.1 race condition where an SDK user may experience an ECONNRESET error if a session was reused on Node 20 and above due to HTTP Keep-Alive. [#2339](https://github.com/zowe/zowe-cli/pull/2339)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1472,14 +1472,13 @@ describe("AbstractRestClient tests", () => {
});

describe('buildOptions', () => {
const privateRestClient = new RestClient(
new Session({
hostname: "FakeHostName",
type: AUTH_TYPE_CERT_PEM,
cert: "FakePemCert",
certKey: "FakePemCertKey"
})
) as any;
const restSession = new Session({
hostname: "FakeHostName",
type: AUTH_TYPE_CERT_PEM,
cert: "FakePemCert",
certKey: "FakePemCertKey"
});
const privateRestClient = new RestClient(restSession) as any;
let getSystemProxyUrlSpy: jest.SpyInstance;
let getProxyAgentSpy: jest.SpyInstance;
let setCertPemAuthSpy: jest.SpyInstance;
Expand All @@ -1503,6 +1502,22 @@ describe("AbstractRestClient tests", () => {
const result = privateRestClient.buildOptions(resource, request, reqHeaders);
expect(Object.keys(result)).toContain('agent');
});

it('Should use session proxy options over env vars for proxy agent', () => {
restSession.ISession.proxy = { proxy_authorization: 'proxy_auth_string'};
const resource = '/resource';
const request = '';
const reqHeaders: any[] = [];
const url = new URL('https://www.zowe.com');
const proxyAgent = new HttpsProxyAgent(url, { rejectUnauthorized: true });
getSystemProxyUrlSpy.mockReturnValue(url);
getProxyAgentSpy.mockReturnValue(proxyAgent);
setCertPemAuthSpy.mockReturnValue(true);
const headerSpy = jest.spyOn(privateRestClient, "appendHeaders");
const result = privateRestClient.buildOptions(resource, request, reqHeaders);
expect(Object.keys(result)).toContain('agent');
expect(headerSpy).toHaveBeenCalledWith([{'Proxy-Authorization': restSession.ISession.proxy.proxy_authorization}]);
})
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,50 @@ describe("Proxy tests", () => {
const httpUrl = "http://www.zowe.com";
const httpsUrl = "https://www.zowe.com";
const noProxyList = "www.zowe.com, fake.com,ibm.com,broadcom.com ";
const passedUrl = "passedurl.com";
let getProxySettingsSpy: jest.SpyInstance;
let checkUrlSpy: jest.SpyInstance;

describe("recognise passed proxy values in session", () => {
const noProxySpy = jest.spyOn(privateProxy, "matchesNoProxySettings");
const httpEnvVarSpy = jest.spyOn(privateProxy, "getHttpEnvVariables");
const httpsEnvVarSpy = jest.spyOn(privateProxy, "getHttpsEnvVariables");
checkUrlSpy = jest.spyOn(privateProxy, "checkUrl");
const expected = {
proxyUrl: passedUrl,
protocol: HTTPS_PROTOCOL
}

beforeEach(() => {
jest.clearAllMocks();
checkUrlSpy.mockClear();
});
it("Should use the HTTP proxy agent passed with session", () => {
expected.protocol = HTTP_PROTOCOL;
session.proxy = { http_proxy: passedUrl };
session.protocol = HTTP_PROTOCOL;
noProxySpy.mockReturnValueOnce(false);
expect(httpEnvVarSpy).not.toHaveBeenCalled();
expect(httpsEnvVarSpy).not.toHaveBeenCalled();
checkUrlSpy.mockReturnValueOnce(passedUrl);
expect(JSON.stringify(ProxySettings["getProxySettings"](session))).toEqual(JSON.stringify(expected));
noProxySpy.mockClear();
checkUrlSpy.mockClear();
});
it("Should use the HTTPS proxy agent passed with session", () => {
expected.protocol = HTTPS_PROTOCOL;
session.proxy = { https_proxy: passedUrl };
session.protocol = HTTPS_PROTOCOL;
noProxySpy.mockReturnValueOnce(false);
expect(httpEnvVarSpy).not.toHaveBeenCalled();
expect(httpsEnvVarSpy).not.toHaveBeenCalled();
checkUrlSpy.mockReturnValueOnce(passedUrl);
expect(JSON.stringify(ProxySettings["getProxySettings"](session))).toEqual(JSON.stringify(expected));
noProxySpy.mockClear();
checkUrlSpy.mockClear();
});
});

describe("getProxyAgent", () => {
beforeEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -108,13 +149,22 @@ describe("Proxy tests", () => {
expect(ProxySettings["matchesNoProxySettings"](session)).toEqual(expected);
process.env["NO_PROXY"] = undefined;
});

it("Should return true for match with no_proxy passed with session proxy", () => {
session.proxy = { http_proxy: passedUrl, no_proxy: ["fake.com"] };
session.protocol = HTTP_PROTOCOL;
expect(ProxySettings["matchesNoProxySettings"](session)).toEqual(true);
});
it("Should not match session hostname with no_proxy", () => {
const expected = false;
process.env["NO_PROXY"] = noProxyList;
session.hostname = "microsoft.com";
expect(ProxySettings["matchesNoProxySettings"](session)).toEqual(expected);
process.env["NO_PROXY"] = undefined;
});
it("Should return false for match with no_proxy passed with session proxy", () => {
session.proxy = { http_proxy: passedUrl, no_proxy: ["false.com", "blah.com"] };
session.protocol = HTTP_PROTOCOL;
expect(ProxySettings["matchesNoProxySettings"](session)).toEqual(false);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,27 @@ describe("Session tests", () => {
expect(session.ISession).toMatchSnapshot();
});

it("should build a session with passed proxy settings updating http_proxy and session's strictSSL", () => {
let error;
let session;
let mySettings;
try {
mySettings = {
http_proxy: "example.com",
https_proxy: undefined,
no_proxy: undefined,
proxy_authorization: undefined,
proxy_strict_ssl: false
};
session = new Session({hostname: "localhost", type: "bearer", tokenValue: "blahblahblah", proxy: mySettings});
} catch (thrownError) {
error = thrownError;
}
expect(error).toBeUndefined();
expect(session.ISession.proxy).toEqual(mySettings);
expect(session.ISession.strictSSL).toEqual(false);
});

it("should require proper type", () => {
let error;
try {
Expand Down
1 change: 1 addition & 0 deletions packages/imperative/src/rest/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export * as SessConstants from "./src/session/SessConstants";
export * from "./src/session/doc/ISession";
export * from "./src/session/doc/IOptionsForAddConnProps";
export * from "./src/session/doc/IOverridePromptConnProps";
export * from "./src/session/doc/ProxyVariables";
export * from "./src/session/AbstractSession";
export * from "./src/session/ConnectionPropsForSessCfg";
export * from "./src/session/Session";
Loading

0 comments on commit c9043d4

Please sign in to comment.