Skip to content

Commit aa043b4

Browse files
Merge pull request #276 from pcoop/branch1
.zosattributes for all
2 parents 0956de0 + d33d347 commit aa043b4

File tree

8 files changed

+249
-8
lines changed

8 files changed

+249
-8
lines changed

__tests__/api/BundleContent/BundleMocked.test.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,16 @@ describe("MockedFilesystemTests", () => {
2222

2323
it("should tolerate META-INF directory not existing", () => {
2424
// Mocks for the manifest - META-INF exists
25-
jest.spyOn(fs, "existsSync").mockImplementationOnce(() => ( false ));
25+
jest.spyOn(fs, "existsSync").mockImplementation((path: string) => {
26+
if (path.endsWith("META-INF")) {
27+
return false;
28+
}
29+
if (path.endsWith(".zosattributes")) {
30+
return false;
31+
}
32+
return true;
33+
});
34+
2635
// Mocks for the manifest - Bundle dir writable
2736
jest.spyOn(fs, "accessSync").mockImplementationOnce(() => ( true ));
2837

@@ -355,6 +364,9 @@ describe("MockedFilesystemTests", () => {
355364
}
356365
return true;
357366
});
367+
jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => {
368+
return true;
369+
});
358370

359371
jest.spyOn(fs, "mkdirSync").mockImplementationOnce(() => { throw new Error("InjectedError"); });
360372

@@ -383,7 +395,11 @@ describe("MockedFilesystemTests", () => {
383395
});
384396

385397
// Mocks for the manifest - manifest write
386-
jest.spyOn(fs, "writeFileSync").mockImplementationOnce(() => { throw new Error("InjectedError"); });
398+
jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => {
399+
if (path.endsWith("cics.xml")) {
400+
throw new Error("InjectedError");
401+
}
402+
});
387403

388404

389405
let err: Error;
@@ -408,6 +424,9 @@ describe("MockedFilesystemTests", () => {
408424
}
409425
return true;
410426
});
427+
jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => {
428+
return true;
429+
});
411430

412431
jest.spyOn(fs, "mkdirSync").mockImplementationOnce(() => { throw new Error("InjectedError"); });
413432

@@ -434,9 +453,11 @@ describe("MockedFilesystemTests", () => {
434453
}
435454
return true;
436455
});
437-
438-
// Mocks for the nodejsapp - write .nodejsapp file)
439-
jest.spyOn(fs, "writeFileSync").mockImplementationOnce(() => { throw new Error("InjectedError"); });
456+
jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => {
457+
if (path.endsWith(".nodejsapp")) {
458+
throw new Error("InjectedError");
459+
}
460+
});
440461

441462
let err: Error;
442463
try {

__tests__/api/BundleDeploy/BundleDeployer.test.ts

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ const DEFAULT_PARAMTERS: IHandlerParameters = {
2323
},
2424
profiles: {
2525
get: (type: string) => {
26+
if (profileError === true) {
27+
throw new Error("Profile Error");
28+
}
2629
return { host: "testname", user: "testuser", password: "testpwd" };
2730
}
2831
} as any,
@@ -57,14 +60,15 @@ const DEFAULT_PARAMTERS: IHandlerParameters = {
5760
let createSpy = jest.spyOn(ZosmfSession, "createBasicZosmfSession").mockImplementation(() => ({}));
5861
let listSpy = jest.spyOn(List, "allMembers").mockImplementation(() => ({}));
5962
let submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => ({}));
60-
63+
let profileError = false;
6164

6265
describe("BundleDeployer01", () => {
6366

6467
beforeEach(() => {
6568
createSpy = jest.spyOn(ZosmfSession, "createBasicZosmfSession").mockImplementation(() => ({}));
6669
listSpy = jest.spyOn(List, "allMembers").mockImplementation(() => ( { val: "DFHDPLOY EYU9ABSI" }));
6770
submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => ({}));
71+
profileError = false;
6872
});
6973
afterEach(() => {
7074
jest.restoreAllMocks();
@@ -78,6 +82,12 @@ describe("BundleDeployer01", () => {
7882

7983
expect(createSpy).toHaveBeenCalledTimes(1);
8084
});
85+
it("should complain with error during profile load for deploy", async () => {
86+
profileError = true;
87+
await runDeployTestWithError();
88+
89+
expect(createSpy).toHaveBeenCalledTimes(0);
90+
});
8191
it("should complain with missing zOSMF profile for undeploy", async () => {
8292
createSpy.mockImplementationOnce(() => { throw new Error( "Injected Create error" ); });
8393
await runUndeployTestWithError();
@@ -327,6 +337,60 @@ describe("BundleDeployer01", () => {
327337
expect(err).toBeDefined();
328338
expect(err.message).toMatchSnapshot();
329339
});
340+
it("tolerate embedded quote", async () => {
341+
342+
let parms: IHandlerParameters;
343+
parms = DEFAULT_PARAMTERS;
344+
setCommonParmsForDeployTests(parms);
345+
parms.arguments.resgroup = "12345678";
346+
parms.arguments.jobcard = '//DFHDPLOY JOB DFHDPLOY,"some text",CLASS=A,MSGCLASS=X,TIME=NOLIMIT';
347+
await testDeployJCL(parms);
348+
});
349+
it("tolerate embedded single quote", async () => {
350+
351+
let parms: IHandlerParameters;
352+
parms = DEFAULT_PARAMTERS;
353+
setCommonParmsForDeployTests(parms);
354+
parms.arguments.resgroup = "12345678";
355+
parms.arguments.jobcard = "//DFHDPLOY JOB DFHDPLOY,'some text',CLASS=A,MSGCLASS=X,TIME=NOLIMIT";
356+
await testDeployJCL(parms);
357+
});
358+
it("tolerate quotes around jobcard", async () => {
359+
360+
let parms: IHandlerParameters;
361+
parms = DEFAULT_PARAMTERS;
362+
setCommonParmsForDeployTests(parms);
363+
parms.arguments.resgroup = "12345678";
364+
parms.arguments.jobcard = '"//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT"';
365+
await testDeployJCL(parms);
366+
});
367+
it("tolerate single quotes around jobcard", async () => {
368+
369+
let parms: IHandlerParameters;
370+
parms = DEFAULT_PARAMTERS;
371+
setCommonParmsForDeployTests(parms);
372+
parms.arguments.resgroup = "12345678";
373+
parms.arguments.jobcard = "'//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT'";
374+
await testDeployJCL(parms);
375+
});
376+
it("tolerate quotes around jobcard with embedded quote", async () => {
377+
378+
let parms: IHandlerParameters;
379+
parms = DEFAULT_PARAMTERS;
380+
setCommonParmsForDeployTests(parms);
381+
parms.arguments.resgroup = "12345678";
382+
parms.arguments.jobcard = '"//DFHDPLOY JOB DFHDPLOY,"some text",CLASS=A,MSGCLASS=X,TIME=NOLIMIT"';
383+
await testDeployJCL(parms);
384+
});
385+
it("tolerate single quotes around jobcard with embedded single quote", async () => {
386+
387+
let parms: IHandlerParameters;
388+
parms = DEFAULT_PARAMTERS;
389+
setCommonParmsForDeployTests(parms);
390+
parms.arguments.resgroup = "12345678";
391+
parms.arguments.jobcard = "'//DFHDPLOY JOB DFHDPLOY,'some text',CLASS=A,MSGCLASS=X,TIME=NOLIMIT'";
392+
await testDeployJCL(parms);
393+
});
330394
it("should support long bundledir", async () => {
331395
let parms: IHandlerParameters;
332396
parms = DEFAULT_PARAMTERS;

__tests__/api/BundleDeploy/__snapshots__/BundleDeployer.test.ts.snap

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ exports[`BundleDeployer01 should complain if status can't be determined 1`] = `"
1818

1919
exports[`BundleDeployer01 should complain if status can't be determined 2`] = `"DFHDPLOY command completed for jobid UNKNOWN, but status cannot be determined."`;
2020

21+
exports[`BundleDeployer01 should complain with error during profile load for deploy 1`] = `"Required parameter --zosmf-host is not set."`;
22+
2123
exports[`BundleDeployer01 should complain with missing zOSMF profile for deploy 1`] = `"Injected Create error"`;
2224

2325
exports[`BundleDeployer01 should complain with missing zOSMF profile for undeploy 1`] = `"Injected Create error"`;
@@ -599,3 +601,117 @@ exports[`BundleDeployer01 should tolerate empty output from DFHDPLOY 1`] = `"DFH
599601
exports[`BundleDeployer01 should undeploy successfully 1`] = `"Bundle undeployment successful."`;
600602

601603
exports[`BundleDeployer01 should update the progress bar 1`] = `"spoolOutput is not iterable"`;
604+
605+
exports[`BundleDeployer01 tolerate embedded quote 1`] = `
606+
"//DFHDPLOY JOB DFHDPLOY,\\"some text\\",CLASS=A,MSGCLASS=X,TIME=NOLIMIT
607+
//DFHDPLOY EXEC PGM=DFHDPLOY,REGION=100M
608+
//STEPLIB DD DISP=SHR,DSN=12345678901234567890123456789012345.SDFHLOAD
609+
// DD DISP=SHR,DSN=abcde12345abcde12345abcde12345abcde.SEYUAUTH
610+
//SYSTSPRT DD SYSOUT=*
611+
//SYSIN DD *
612+
*
613+
SET CICSPLEX(12345678);
614+
*
615+
DEPLOY BUNDLE(12345678)
616+
BUNDLEDIR(1234567890)
617+
SCOPE(12345678)
618+
STATE(ENABLED)
619+
RESGROUP(12345678);
620+
/*
621+
"
622+
`;
623+
624+
exports[`BundleDeployer01 tolerate embedded single quote 1`] = `
625+
"//DFHDPLOY JOB DFHDPLOY,'some text',CLASS=A,MSGCLASS=X,TIME=NOLIMIT
626+
//DFHDPLOY EXEC PGM=DFHDPLOY,REGION=100M
627+
//STEPLIB DD DISP=SHR,DSN=12345678901234567890123456789012345.SDFHLOAD
628+
// DD DISP=SHR,DSN=abcde12345abcde12345abcde12345abcde.SEYUAUTH
629+
//SYSTSPRT DD SYSOUT=*
630+
//SYSIN DD *
631+
*
632+
SET CICSPLEX(12345678);
633+
*
634+
DEPLOY BUNDLE(12345678)
635+
BUNDLEDIR(1234567890)
636+
SCOPE(12345678)
637+
STATE(ENABLED)
638+
RESGROUP(12345678);
639+
/*
640+
"
641+
`;
642+
643+
exports[`BundleDeployer01 tolerate quotes around jobcard 1`] = `
644+
"//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT
645+
//DFHDPLOY EXEC PGM=DFHDPLOY,REGION=100M
646+
//STEPLIB DD DISP=SHR,DSN=12345678901234567890123456789012345.SDFHLOAD
647+
// DD DISP=SHR,DSN=abcde12345abcde12345abcde12345abcde.SEYUAUTH
648+
//SYSTSPRT DD SYSOUT=*
649+
//SYSIN DD *
650+
*
651+
SET CICSPLEX(12345678);
652+
*
653+
DEPLOY BUNDLE(12345678)
654+
BUNDLEDIR(1234567890)
655+
SCOPE(12345678)
656+
STATE(ENABLED)
657+
RESGROUP(12345678);
658+
/*
659+
"
660+
`;
661+
662+
exports[`BundleDeployer01 tolerate quotes around jobcard with embedded quote 1`] = `
663+
"//DFHDPLOY JOB DFHDPLOY,\\"some text\\",CLASS=A,MSGCLASS=X,TIME=NOLIMIT
664+
//DFHDPLOY EXEC PGM=DFHDPLOY,REGION=100M
665+
//STEPLIB DD DISP=SHR,DSN=12345678901234567890123456789012345.SDFHLOAD
666+
// DD DISP=SHR,DSN=abcde12345abcde12345abcde12345abcde.SEYUAUTH
667+
//SYSTSPRT DD SYSOUT=*
668+
//SYSIN DD *
669+
*
670+
SET CICSPLEX(12345678);
671+
*
672+
DEPLOY BUNDLE(12345678)
673+
BUNDLEDIR(1234567890)
674+
SCOPE(12345678)
675+
STATE(ENABLED)
676+
RESGROUP(12345678);
677+
/*
678+
"
679+
`;
680+
681+
exports[`BundleDeployer01 tolerate single quotes around jobcard 1`] = `
682+
"//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT
683+
//DFHDPLOY EXEC PGM=DFHDPLOY,REGION=100M
684+
//STEPLIB DD DISP=SHR,DSN=12345678901234567890123456789012345.SDFHLOAD
685+
// DD DISP=SHR,DSN=abcde12345abcde12345abcde12345abcde.SEYUAUTH
686+
//SYSTSPRT DD SYSOUT=*
687+
//SYSIN DD *
688+
*
689+
SET CICSPLEX(12345678);
690+
*
691+
DEPLOY BUNDLE(12345678)
692+
BUNDLEDIR(1234567890)
693+
SCOPE(12345678)
694+
STATE(ENABLED)
695+
RESGROUP(12345678);
696+
/*
697+
"
698+
`;
699+
700+
exports[`BundleDeployer01 tolerate single quotes around jobcard with embedded single quote 1`] = `
701+
"//DFHDPLOY JOB DFHDPLOY,'some text',CLASS=A,MSGCLASS=X,TIME=NOLIMIT
702+
//DFHDPLOY EXEC PGM=DFHDPLOY,REGION=100M
703+
//STEPLIB DD DISP=SHR,DSN=12345678901234567890123456789012345.SDFHLOAD
704+
// DD DISP=SHR,DSN=abcde12345abcde12345abcde12345abcde.SEYUAUTH
705+
//SYSTSPRT DD SYSOUT=*
706+
//SYSIN DD *
707+
*
708+
SET CICSPLEX(12345678);
709+
*
710+
DEPLOY BUNDLE(12345678)
711+
BUNDLEDIR(1234567890)
712+
SCOPE(12345678)
713+
STATE(ENABLED)
714+
RESGROUP(12345678);
715+
/*
716+
"
717+
`;

__tests__/api/BundlePush/BundlePusher.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ const DEFAULT_PARAMTERS: IHandlerParameters = {
2525
},
2626
profiles: {
2727
get: (type: string) => {
28+
29+
if (profileError === true) {
30+
throw new Error("Profile Error");
31+
}
32+
2833
if (type === "zosmf") {
2934
return zosmfProfile;
3035
}
@@ -73,6 +78,7 @@ let consoleText = "";
7378
let zosmfProfile = {};
7479
let sshProfile = {};
7580
let cicsProfile = {};
81+
let profileError = false;
7682

7783
let zosMFSpy = jest.spyOn(ZosmfSession, "createBasicZosmfSession").mockImplementation(() => ({}));
7884
let sshSpy = jest.spyOn(SshSession, "createBasicSshSession").mockImplementation(() => ({}));
@@ -114,6 +120,7 @@ describe("BundlePusher01", () => {
114120
zosmfProfile = { host: "wibble", user: "user", password: "thisIsntReal", port: 443, rejectUnauthorized: true };
115121
sshProfile = { host: "wibble", user: "user", password: "thisIsntReal", port: 22 };
116122
cicsProfile = undefined;
123+
profileError = false;
117124
});
118125
afterEach(() => {
119126
jest.restoreAllMocks();
@@ -199,6 +206,12 @@ describe("BundlePusher01", () => {
199206

200207
expect(zosMFSpy).toHaveBeenCalledTimes(1);
201208
});
209+
it("should complain with error during profile load for push", async () => {
210+
profileError = true;
211+
await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, "Required parameter --zosmf-host is not set.");
212+
213+
expect(zosMFSpy).toHaveBeenCalledTimes(0);
214+
});
202215
it("should implement --zosmf-* overrides" , async () => {
203216
const parms = getCommonParmsForPushTests();
204217
parms.arguments.zh = "overrideHost";

src/api/BundleContent/Bundle.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ node_modules -
8686
this.manifest = new Manifest(this.bundleDirectory, this.merge, this.overwrite, params);
8787
this.preparedToSave = false;
8888
this.zosAttribsFile = this.path.join(this.bundleDirectory, ".zosattributes");
89+
this.zosAttribsNeeded = true;
8990
}
9091

9192
/**

src/api/BundleDeploy/BundleDeployer.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,13 @@ export class BundleDeployer {
225225

226226
private async createZosMFSession(): Promise<AbstractSession> {
227227
// Create a zosMF session
228-
let zosmfProfile = this.params.profiles.get("zosmf");
228+
let zosmfProfile;
229+
try {
230+
zosmfProfile = this.params.profiles.get("zosmf");
231+
}
232+
catch (error) {
233+
// No-op, we can cope with there being no profile.
234+
}
229235

230236
if (zosmfProfile === undefined) {
231237
zosmfProfile = {};

src/api/BundleDeploy/ParmValidator.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ export class ParmValidator {
303303
// handle long jobcards
304304
ParmValidator.wrapJobcard(params);
305305

306+
// Strip leading and trailing quotes, if they're there
307+
params.arguments.jobcard = params.arguments.jobcard.replace(/^"(.*)"$/, "$1");
308+
params.arguments.jobcard = params.arguments.jobcard.replace(/^'(.*)'$/, "$1");
309+
306310
// split the jobcard into a comma separated list
307311
const jobcardParts = params.arguments.jobcard.split(",");
308312
const firstPart = jobcardParts[0].trim();

0 commit comments

Comments
 (0)