Skip to content

Commit

Permalink
Merge pull request #2419 from zowe/copy-dsclp-spacu-track
Browse files Browse the repository at this point in the history
copy dsclp command resulting in spacu attribute always being TRACK
  • Loading branch information
zFernand0 authored Jan 29, 2025
2 parents c53ded5 + 2d40140 commit 68e0962
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 39 deletions.
4 changes: 4 additions & 0 deletions packages/zosfiles/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to the Zowe z/OS files SDK package will be documented in this file.

## Recent Changes

- 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)

## `8.12.0`

- Enhancement: The `Copy.dataset` function now creates a new data set if the entered target data set does not exist. [#2349](https://github.com/zowe/zowe-cli/issues/2349)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ 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";

let REAL_SESSION: Session;
let REAL_TARGET_SESSION: Session;
let testEnvironment: ITestEnvironment<ITestPropertiesSchema>;
let defaultSystem: ITestPropertiesSchema;
let defaultTargetSystem: ITestPropertiesSchema;
let fromDataSetName: string;
let fromDataSetNameTracks: string;
let fromDataSetNameCylinders: string;
let toDataSetName: string;

const file1 = "file1";
Expand All @@ -44,6 +47,8 @@ describe("Copy", () => {
REAL_SESSION = TestEnvironment.createZosmfSession(testEnvironment);
REAL_TARGET_SESSION = REAL_SESSION;
fromDataSetName = `${defaultSystem.zosmf.user.trim().toUpperCase()}.DATA.ORIGINAL`;
fromDataSetNameTracks = `${defaultSystem.zosmf.user.trim().toUpperCase()}.DATA.TRKORG`;
fromDataSetNameCylinders = `${defaultSystem.zosmf.user.trim().toUpperCase()}.DATA.CYLORG`;
toDataSetName = `${defaultSystem.zosmf.user.trim().toUpperCase()}.DATA.COPY`;
});

Expand Down Expand Up @@ -891,10 +896,18 @@ describe("Copy", () => {
});

describe("Success cases", () => {
it("should copy the source to the destination data set and allocate the dataset", async() => {
it("should copy the source to the destination data set and allocate the dataset - CYLINDERS", async() => {
try {
await Create.dataSet(REAL_SESSION, CreateDataSetTypeEnum.DATA_SET_SEQUENTIAL, fromDataSetNameCylinders, {alcunit: "CYL"});
await Upload.fileToDataset(REAL_SESSION, fileLocation, fromDataSetNameCylinders);
} catch (err) {
Imperative.console.info(`Error: ${inspect(err)}`);
}

let error: any;
let response: IZosFilesResponse | undefined = undefined;
let contents: Buffer;
let listAttributes;
const TEST_TARGET_SESSION = REAL_TARGET_SESSION;
const toDataset: IDataSet = { dsn: toDataSetName, member: file1 };
const fromOptions: IGetOptions = {
Expand All @@ -903,22 +916,82 @@ describe("Copy", () => {
record: false
};
const options: ICrossLparCopyDatasetOptions = {
"from-dataset": { dsn: fromDataSetName },
"from-dataset": { dsn: fromDataSetNameCylinders },
responseTimeout: 5,
replace: false
};
const toDataSetString = `${toDataset.dsn}(${toDataset.member})`;
try {
listAttributes = (await List.dataSet(REAL_SESSION, fromDataSetNameCylinders, {attributes: true})).apiResponse.items;
response = await Copy.dataSetCrossLPAR(REAL_SESSION, toDataset, options, fromOptions, TEST_TARGET_SESSION);
contents = await Get.dataSet(TEST_TARGET_SESSION, toDataSetString);
} catch (err) {
error = err;
}

expect(listAttributes[0].spacu).toEqual("CYLINDERS");
expect(response?.success).toBeTruthy();
expect(error).not.toBeDefined();
expect(response?.errorMessage).not.toBeDefined();
expect(response?.commandResponse).toContain("Data set copied successfully");
expect(contents.toString().trim()).toBe(readFileSync(fileLocation).toString());

try {
await Delete.dataSet(REAL_SESSION, fromDataSetNameCylinders);
await Delete.dataSet(REAL_SESSION, toDataSetName);
} catch (err) {
Imperative.console.info(`Error: ${inspect(err)}`);
}
});

it("should copy the source to the destination data set and allocate the dataset - TRACKS", async() => {
try {
await Create.dataSet(REAL_SESSION, CreateDataSetTypeEnum.DATA_SET_SEQUENTIAL, fromDataSetNameTracks, {alcunit: "TRK"});
await Upload.fileToDataset(REAL_SESSION, fileLocation, fromDataSetNameTracks);
} catch (err) {
Imperative.console.info(`Error: ${inspect(err)}`);
}

let error: any;
let response: IZosFilesResponse | undefined = undefined;
let contents: Buffer;
let listAttributes;
const TEST_TARGET_SESSION = REAL_TARGET_SESSION;

// Append "1" such that it is not an existing data set and thus will reach generateDatasetOptions() within Copy.ts
const toDataset: IDataSet = { dsn: toDataSetName, member: file1 };
const fromOptions: IGetOptions = {
binary: false,
encoding: undefined,
record: false
};
const options: ICrossLparCopyDatasetOptions = {
"from-dataset": { dsn: fromDataSetNameTracks },
responseTimeout: 5,
replace: false
};
const toDataSetString = `${toDataset.dsn}(${toDataset.member})`;
try {
listAttributes = (await List.dataSet(REAL_SESSION, fromDataSetNameTracks, {attributes: true})).apiResponse.items;
response = await Copy.dataSetCrossLPAR(REAL_SESSION, toDataset, options, fromOptions, TEST_TARGET_SESSION);
contents = await Get.dataSet(TEST_TARGET_SESSION, toDataSetString);
} catch (err) {
error = err;
}

expect(listAttributes[0].spacu).toEqual("TRACKS");
expect(response?.success).toBeTruthy();
expect(error).not.toBeDefined();
expect(response?.errorMessage).not.toBeDefined();
expect(response?.commandResponse).toContain("Data set copied successfully");
expect(contents.toString().trim()).toBe(readFileSync(fileLocation).toString());

try {
await Delete.dataSet(REAL_SESSION, fromDataSetNameTracks);
await Delete.dataSet(REAL_SESSION, toDataSetName);
} catch (err) {
Imperative.console.info(`Error: ${inspect(err)}`);
}
});

it("should overwrite the destination data set member", async() => {
Expand Down
134 changes: 105 additions & 29 deletions packages/zosfiles/__tests__/__unit__/methods/copy/Copy.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,7 @@ describe("Copy", () => {
const listAllMembersSpy = jest.spyOn(List, "allMembers");
const createDatasetSpy = jest.spyOn(Create, "dataSet");
const uploadDatasetSpy = jest.spyOn(Upload, "bufferToDataSet");

const psDataSetName = "TEST.PS.DATA.SET";
const memberName = "mem1";
const poDataSetName = "TEST.PO.DATA.SET";
Expand All @@ -826,6 +827,12 @@ describe("Copy", () => {
spacu: "TRK"
};

const dataSetPOCYL = {
dsname: poDataSetName,
dsorg: "PO",
spacu: "CYL"
};

beforeEach(() => {
getDatasetSpy.mockClear();
listDatasetSpy.mockClear();
Expand All @@ -842,9 +849,6 @@ describe("Copy", () => {
describe("Success Scenarios", () => {
describe("Sequential > Sequential", () => {
it("should send a request", async () => {
let response;
let caughtError;

listDatasetSpy.mockImplementation(async (): Promise<any> => {
return {
apiResponse: {
Expand All @@ -857,17 +861,14 @@ describe("Copy", () => {
return Buffer.from("123456789abcd");
});

try {
response = await Copy.dataSetCrossLPAR(
dummySession,
{ dsn: psDataSetName },
{ "from-dataset": { dsn: dataSetPS.dsname }, replace: true},
{ },
dummySession
);
} catch (e) {
caughtError = e;
}

const response = await Copy.dataSetCrossLPAR(
dummySession,
{ dsn: psDataSetName },
{ "from-dataset": { dsn: dataSetPS.dsname }, replace: true},
{ },
dummySession
);

expect(response).toEqual({
success: true,
Expand All @@ -882,9 +883,7 @@ describe("Copy", () => {

describe("Sequential > Sequential - no replace", () => {
it("should send a request", async () => {
let response;
let caughtError;

listDatasetSpy.mockImplementation(async (): Promise<any> => {
return {
apiResponse: {
Expand All @@ -898,7 +897,7 @@ describe("Copy", () => {
});

try {
response = await Copy.dataSetCrossLPAR(
await Copy.dataSetCrossLPAR(
dummySession,
{ dsn: psDataSetName },
{ "from-dataset": { dsn: dataSetPS.dsname }, replace: false},
Expand All @@ -909,6 +908,7 @@ describe("Copy", () => {
caughtError = e;
}

expect(caughtError).toBeDefined();
expect(listDatasetSpy).toHaveBeenCalledTimes(2);
expect(getDatasetSpy).toHaveBeenCalledTimes(1);
expect(uploadDatasetSpy).toHaveBeenCalledTimes(0);
Expand Down Expand Up @@ -959,9 +959,88 @@ describe("Copy", () => {
expect(uploadDatasetSpy).toHaveBeenCalledTimes(1);
});

it("should send a request - TRK and validate spacu", async () => {
listDatasetSpy.mockImplementation(async (): Promise<any> => {
return {
apiResponse: {
returnedRows: 1,
items: [dataSetPO],
}
};
});

listAllMembersSpy.mockImplementation(async (): Promise<any> => {
return {
apiResponse: {
returnedRows: 1
}
};
});

const response = await Copy.dataSetCrossLPAR(
dummySession,
{ dsn: poDataSetName, member: memberName },
{ "from-dataset": { dsn: poDataSetName, member: memberName }, replace: true },
{},
dummySession);

// Assertions
expect(response).toEqual({
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});

expect(listDatasetSpy).toHaveBeenCalledTimes(2);
expect(listAllMembersSpy).toHaveBeenCalledTimes(1);
expect(listAllMembersSpy.mock.calls[0][2].start).toBe(memberName);
expect(getDatasetSpy).toHaveBeenCalledTimes(1);
expect(uploadDatasetSpy).toHaveBeenCalledTimes(1);
expect(dataSetPO.spacu).toBe("TRK");
});

it("should send a request - CYL and validate spacu", async () => {
listDatasetSpy.mockImplementation(async (): Promise<any> => {
return {
apiResponse: {
returnedRows: 1,
items: [dataSetPOCYL],
}
};
});

listAllMembersSpy.mockImplementation(async (): Promise<any> => {
return {
apiResponse: {
returnedRows: 1
}
};
});


const response = await Copy.dataSetCrossLPAR(
dummySession,
{ dsn: poDataSetName, member: memberName },
{ "from-dataset": { dsn: poDataSetName, member: memberName }, replace: true },
{},
dummySession
);


expect(response).toEqual({
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});

expect(listDatasetSpy).toHaveBeenCalledTimes(2);
expect(listAllMembersSpy).toHaveBeenCalledTimes(1);
expect(listAllMembersSpy.mock.calls[0][2].start).toBe(memberName);
expect(getDatasetSpy).toHaveBeenCalledTimes(1);
expect(uploadDatasetSpy).toHaveBeenCalledTimes(1);
expect(dataSetPOCYL.spacu).toBe("CYL");
});

describe("Sequential > Member", () => {
it("should send a request", async () => {
let response;
let caughtError;

listDatasetSpy.mockReturnValueOnce({
Expand All @@ -983,17 +1062,14 @@ describe("Copy", () => {
};
});

try {
response = await Copy.dataSetCrossLPAR(
dummySession,
{ dsn: poDataSetName, member: memberName },
{ "from-dataset": { dsn: psDataSetName }, replace: true},
{ },
dummySession
);
} catch (e) {
caughtError = e;
}
const response = await Copy.dataSetCrossLPAR(
dummySession,
{ dsn: poDataSetName, member: memberName },
{ "from-dataset": { dsn: psDataSetName }, replace: true},
{ },
dummySession
);


expect(response).toEqual({
success: true,
Expand Down
Loading

0 comments on commit 68e0962

Please sign in to comment.