Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross-LPAR copy fails when copying a LARGE format dataset #2420

Merged
merged 19 commits into from
Feb 8, 2025
Merged
2 changes: 1 addition & 1 deletion packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Change Log
All notable changes to the Zowe CLI package will be documented in this file.


## Recent Changes

- Enhancement: Added the `--data-set-type` flag to create sequential data set command to allow for creating extended and large formatted sequential data sets. [#2141](https://github.com/zowe/zowe-cli/issues/2141)
- Enhancement: Added `--recordRange` flag to `zowe jobs download output` command to allow users to select a specific range of records to output from a spool file. [#2411](https://github.com/zowe/zowe-cli/pull/2411)
- BugFix: The `zowe zos-files copy data-set` command overwrites the contents of the target data set without user confirmation. A `--safe-replace` option was added which prompts the user to confirm before overwriting the contents of the target data set. [#2369] (https://github.com/zowe/zowe-cli/issues/2369)

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ describe("Create Partitioned Data Set", () => {
it("should fail creating a partitioned data set extended due to invalid data-set-type", () => {
const response = runCliScript(__dirname + "/__scripts__/command/command_create_pdse_fail_dsntype.sh",
TEST_ENVIRONMENT, [user]);
expect(response.stderr.toString()).toContain("Invalid zos-files create command 'dsntype' option: NONLIBRARY");
expect(response.stderr.toString()).toContain("Unable to perform this operation due to the following problem.");
expect(response.stderr.toString()).toContain("NONLIBRARY");
});

it("should fail creating a partitioned data set due to exceeding maximum value for size (primary space)", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ Array [
"name": "data-class",
"type": "string",
},
Object {
"aliases": Array [
"dst",
"dsntype",
],
"description": "The data set type (BASIC, EXTPREF, EXTREQ, HFS, LARGE, PDS, LIBRARY, PIPE)",
"name": "data-set-type",
"type": "string",
},
Object {
"aliases": Array [
"dt",
Expand Down Expand Up @@ -125,5 +134,9 @@ Array [
"description": "Create an empty physical sequential data set with default parameters",
"options": "NEW.PS.DATASET",
},
Object {
"description": "Create a LARGE format sequential data set with default parameters",
"options": "--data-set-type \`LARGE\`",
},
]
`;
3 changes: 2 additions & 1 deletion packages/cli/src/zosfiles/-strings-/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export default {
SUMMARY: "Create physical sequential data sets (PS)",
DESCRIPTION: "Create physical sequential data sets (PS).",
EXAMPLES: {
EX1: "Create an empty physical sequential data set with default parameters"
EX1: "Create an empty physical sequential data set with default parameters",
EX2: "Create a LARGE format sequential data set with default parameters"
}
},
VSAM: {
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/src/zosfiles/create/ps/Ps.definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,17 @@ export const PsDefinition: ICommandDefinition = {
ZosFilesCreateOptions.mgntclass,
ZosFilesCreateOptions.dataclass,
ZosFilesCreateOptions.unit,
ZosFilesCreateOptions.dsntype,
ZosFilesCreateExtraOptions.attributes
].sort((a, b) => a.name.localeCompare(b.name)),
examples: [
{
description: strings.ACTIONS.DATA_SET_SEQUENTIAL.EXAMPLES.EX1,
options: "NEW.PS.DATASET"
},
{
description: strings.ACTIONS.DATA_SET_SEQUENTIAL.EXAMPLES.EX2,
options: "--data-set-type `LARGE`"
}

]
Expand Down
1 change: 1 addition & 0 deletions packages/zosfiles/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ All notable changes to the Zowe z/OS files SDK package will be documented in thi

## Recent Changes

- BugFix: The `Create.dataSetValidateOptions()` function now correctly handles data set creation when the `dsorg` attribute is set to `PS-L` by automatically updating the `dsntype` attribute to `LARGE`. [#2141](https://github.com/zowe/zowe-cli/issues/2141)
- BugFix: Fixed an issue in the `Copy.dataSetCrossLPAR()` function where the `spacu` attribute of the copied data set was always set to `TRK`, regardless of the source data set's attributes. [#2412](https://github.com/zowe/zowe-cli/issues/2412)
- BugFix: The `Copy.data.set` function now prompts the user to confirm before overwriting the contents of the target data set with the addition of the `--safe-replace` option. [#2369] (https://github.com/zowe/zowe-cli/issues/2369)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { ITestEnvironment } from "../../../../../../__tests__/__src__/environmen
import { tmpdir } from "os";
import path = require("path");
import * as fs from "fs";
import { List } from "@zowe/zos-files-for-zowe-sdk";
import { ZosmfRestClient, List } from "@zowe/core-for-zowe-sdk";


let REAL_SESSION: Session;
let REAL_TARGET_SESSION: Session;
Expand Down Expand Up @@ -784,6 +785,47 @@ describe("Copy", () => {
expect(contents.toString().trim()).not.toContain("Member contents for test");
expect(contents.toString().trim()).toBe(readFileSync(fileLocation).toString());
});

it("should copy a large sequential data set cross LPAR (PS-L) - invoked w/ dsntype: `LARGE`", async() => {
const fromDataSetNameLrg = fromDataSetName += ".LRG";
const toDataSetNameLrg = toDataSetName += ".LRG";

let error: any;
let response: IZosFilesResponse | undefined = undefined;
const postExpectStringSpy = jest.spyOn(ZosmfRestClient, 'postExpectString');
const TEST_TARGET_SESSION = REAL_TARGET_SESSION;
const toDataset: IDataSet = { dsn: toDataSetNameLrg };
const fromOptions: IGetOptions = {
binary: false,
encoding: undefined,
record: false
};
const options: ICrossLparCopyDatasetOptions = {
"from-dataset": { dsn: fromDataSetNameLrg },
responseTimeout: 5,
replace: false
};
try {
await Create.dataSet(REAL_SESSION, CreateDataSetTypeEnum.DATA_SET_SEQUENTIAL, fromDataSetNameLrg, { dsorg: "PS-L"});
response = await Copy.dataSetCrossLPAR(REAL_SESSION, toDataset, options, fromOptions, TEST_TARGET_SESSION);
await Get.dataSet(TEST_TARGET_SESSION, toDataSetNameLrg);
await Delete.dataSet(REAL_SESSION, fromDataSetNameLrg);
await Delete.dataSet(REAL_SESSION, toDataSetNameLrg);
} catch (err) {
error = err;
}

expect(postExpectStringSpy).toHaveBeenCalledWith(
TEST_TARGET_SESSION,
expect.anything(),
expect.anything(),
expect.stringContaining("LARGE")
);
expect(response?.success).toBeTruthy();
expect(error).not.toBeDefined();
expect(response?.errorMessage).not.toBeDefined();
expect(response?.commandResponse).toContain("Data set copied successfully");
});
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { getUniqueDatasetName } from "../../../../../../__tests__/__src__/TestUt
import { ICreateZfsOptions } from "../../../../src/methods/create/doc/ICreateZfsOptions";
import { ITestEnvironment } from "../../../../../../__tests__/__src__/environment/ITestEnvironment";


let testEnvironment: ITestEnvironment<ITestPropertiesSchema>;
let defaultSystem: ITestPropertiesSchema;
let REAL_SESSION: Session;
Expand Down Expand Up @@ -136,6 +135,31 @@ describe("Create data set", () => {
expect(response.commandResponse).toContain(ZosFilesMessages.dataSetCreatedSuccessfully.message);
}, LONGER_TIMEOUT);

it("should create a large sequential data set (PS-L)", async () => {
let error;
let response;

try {
response = await Create.dataSet(
REAL_SESSION,
CreateDataSetTypeEnum.DATA_SET_SEQUENTIAL,
dsname,
{primary:1,recfm:"FB",blksize:6160,lrecl:80,dsntype:"LARGE",showAttributes:true}
);
Imperative.console.info("Response: " + inspect(response));
} catch (err) {
error = err;
Imperative.console.info("Error: " + inspect(error));
}

expect(error).toBeFalsy();
expect(response).toBeTruthy();

expect(response.success).toBe(true);
expect(response.commandResponse).toContain(ZosFilesMessages.dataSetCreatedSuccessfully.message);
expect(response.commandResponse).toContain("LARGE");
}, LONGER_TIMEOUT);

it("should create a sequential data set with response timeout", async () => {
let error;
let response;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,22 +127,16 @@ describe("Create data set", () => {
});

it("explicit testing of dsntype", async () => {
let success: boolean = false;
let success: boolean = true;
const dsntypes = ["BASIC", "EXTPREF", "EXTREQ", "HFS", "LARGE", "PDS", "LIBRARY", "PIPE"];
for (const type of dsntypes) {
dsOptions.dsntype = type;
try {
await Create.dataSetValidateOptions(dsOptions);
} catch (err) {
expect(success).toBe(true);
success = false;
}
}
try {
dsOptions.dsntype = "PDSE";
await Create.dataSetValidateOptions(dsOptions);
} catch (err) {
success = true;
}
expect(success).toBe(true);
});

Expand Down Expand Up @@ -292,6 +286,39 @@ describe("Create data set", () => {
);
});

it("should be able to create a large sequential data set using PS-L", async () => {
const custOptions = {
dsorg: "PS-L",
alcunit: "CYL",
primary: 20,
secondary: 10,
recfm: "FB",
blksize: 6160,
lrecl: 80
};
const response = await Create.dataSet(dummySession, CreateDataSetTypeEnum.DATA_SET_SEQUENTIAL, dataSetName, custOptions);

expect(response.success).toBe(true);
expect(response.commandResponse).toContain("created successfully");
expect(mySpy).toHaveBeenCalledWith(
dummySession,
endpoint,
[ZosmfHeaders.ACCEPT_ENCODING],
JSON.stringify({
...{
alcunit: "CYL",
dsorg: "PS",
primary: 20,
recfm: "FB",
blksize: 6160,
lrecl: 80,
secondary: 10,
dsntype: "LARGE"
}
})
);
});

it("should be able to create a variable block sequential data set using a block size that is too small", async () => {
const custOptions = {
dsorg: "PS",
Expand Down Expand Up @@ -1101,19 +1128,6 @@ describe("Create data set Validator", () => {
expect(error).toContain(`Invalid zos-files create command 'alcunit' option`);
});

it("should fail when dsntype specified with invalid value", async () => {
let error;
try {

const testOptions: any = {dsntype: "NOTLIBRARY"};
Create.dataSetValidateOptions(testOptions);
} catch (err) {
error = err.message;
}

expect(error).toContain(`Invalid zos-files create command 'dsntype' option`);
});

it("should fail when lrecl not specified", async () => {
let error;
try {
Expand Down
25 changes: 12 additions & 13 deletions packages/zosfiles/src/methods/create/Create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,35 +249,34 @@ export class Create {
break;

case "dirblk":
// Validate non-zero if dsorg is PS
if (tempOptions.dirblk !== 0 && tempOptions.dsorg === "PS") {
// Validate non-zero if dsorg starts with "PS"
if (tempOptions.dirblk !== 0 && tempOptions.dsorg.startsWith("PS")) {
throw new ImperativeError({ msg: ZosFilesMessages.invalidPSDsorgDirblkCombination.message });
}
// Validate non-zero if 'dsorg' is PO
if (tempOptions.dirblk === 0 && tempOptions.dsorg === "PO") {
// Validate non-zero if dsorg starts with "PO"
if (tempOptions.dirblk === 0 && tempOptions.dsorg.startsWith("PO")) {
throw new ImperativeError({ msg: ZosFilesMessages.invalidPODsorgDirblkCombination.message });
}

break;

case "dsntype": {
// Key to create a PDSE.
// Key to create a PDSE.
const type: string = tempOptions.dsntype.toUpperCase();
const availableTypes = ["BASIC", "EXTPREF", "EXTREQ", "HFS", "LARGE", "PDS", "LIBRARY", "PIPE"];
if (availableTypes.indexOf(type) === -1) {
throw new ImperativeError({ msg: ZosFilesMessages.invalidDsntypeOption.message + tempOptions.dsntype });
}
break;
}

case "dsorg":
// Only PO and PS valid
switch (tempOptions.dsorg.toUpperCase()) {
case "PO":
case "PS":
break;
// Check if dsorg is PS-L, if it is change it to "PS" and the dsntype to "LARGE".
// Since the create endpoint does not see "PS-L" as a valid creation option

default:
throw new ImperativeError({ msg: ZosFilesMessages.invalidDsorgOption.message + tempOptions.dsorg });
if(tempOptions.dsorg === "PS-L")
{
tempOptions.dsorg = "PS";
tempOptions.dsntype = "LARGE";
}

break;
Expand Down