Skip to content

Commit

Permalink
Merge pull request #2402 from zowe/fix-dataset-copy
Browse files Browse the repository at this point in the history
Implement fix for data set copy regression
  • Loading branch information
awharn authored Jan 3, 2025
2 parents e8939d8 + 2e8a27a commit 38b6ef8
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 18 deletions.
4 changes: 4 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Change Log
All notable changes to the Zowe CLI package will be documented in this file.

## Recent Changes

- BugFix: The `zowe files copy data-set` command no longer copies all partitioned data set members if a member is specified. [#2402](https://github.com/zowe/zowe-cli/pull/2402)

## `8.10.0`
-Enhancement: The `zowe zos-files copy data-set` command now copies members from a source partitioned data set to an existing target partitioned data set.[#2386](https://github.com/zowe/zowe-cli/pull/2386)

Expand Down
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

- BugFix: The `Copy.dataset` method no longer copies all partitioned data set members if a member is passed to the function. [#2402](https://github.com/zowe/zowe-cli/pull/2402)

## `8.10.0`
- Enhancement: The `Copy.dataset` method now recognizes partitioned data sets and can copy members of a source PDS into an existing target PDS. [#2386](https://github.com/zowe/zowe-cli/pull/2386)

Expand Down
77 changes: 63 additions & 14 deletions packages/zosfiles/__tests__/__unit__/methods/copy/Copy.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,17 @@ describe("Copy", () => {

describe("Data Set", () => {
const copyExpectStringSpy = jest.spyOn(ZosmfRestClient, "putExpectString");
const copyPDSSpy = jest.spyOn(Copy, "copyPDS");
const fromDataSetName = "USER.DATA.FROM";
const fromMemberName = "mem1";
const toDataSetName = "USER.DATA.TO";
const toMemberName = "mem2";
let isPDSSpy: jest.SpyInstance;
const isPDSSpy = jest.spyOn(Copy as any, "isPDS");

beforeEach(() => {
copyExpectStringSpy.mockClear();
copyExpectStringSpy.mockImplementation(async () => {
return "";
});
isPDSSpy = jest.spyOn(Copy as any, "isPDS").mockResolvedValue(false);
copyPDSSpy.mockClear();
copyExpectStringSpy.mockClear().mockImplementation(async () => { return ""; });
isPDSSpy.mockClear().mockResolvedValue(false);
});
afterAll(() => {
isPDSSpy.mockRestore();
Expand Down Expand Up @@ -75,6 +74,7 @@ describe("Copy", () => {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
expect(copyExpectStringSpy).toHaveBeenLastCalledWith(
dummySession,
Expand Down Expand Up @@ -113,6 +113,7 @@ describe("Copy", () => {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
expect(copyExpectStringSpy).toHaveBeenLastCalledWith(
dummySession,
Expand Down Expand Up @@ -152,6 +153,7 @@ describe("Copy", () => {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
expect(copyExpectStringSpy).toHaveBeenLastCalledWith(
dummySession,
Expand Down Expand Up @@ -191,6 +193,7 @@ describe("Copy", () => {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
expect(copyExpectStringSpy).toHaveBeenLastCalledWith(
dummySession,
Expand Down Expand Up @@ -229,6 +232,7 @@ describe("Copy", () => {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
expect(copyExpectStringSpy).toHaveBeenLastCalledWith(
dummySession,
Expand Down Expand Up @@ -267,6 +271,7 @@ describe("Copy", () => {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
expect(copyExpectStringSpy).toHaveBeenLastCalledWith(
dummySession,
Expand Down Expand Up @@ -306,6 +311,7 @@ describe("Copy", () => {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
expect(copyExpectStringSpy).toHaveBeenLastCalledWith(
dummySession,
Expand Down Expand Up @@ -345,6 +351,7 @@ describe("Copy", () => {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
expect(copyExpectStringSpy).toHaveBeenLastCalledWith(
dummySession,
Expand All @@ -366,6 +373,7 @@ describe("Copy", () => {
const argumentsOfCall = copyExpectStringSpy.mock.calls[0];
const lastArgumentOfCall = argumentsOfCall[argumentsOfCall.length - 1];
expect(lastArgumentOfCall).not.toHaveProperty("enq");
expect(copyPDSSpy).not.toHaveBeenCalled();
});
it("should contain valid enq value in payload", async () => {
await Copy.dataSet(
Expand All @@ -380,6 +388,7 @@ describe("Copy", () => {
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
const argumentsOfCall = copyExpectStringSpy.mock.calls[0];
const lastArgumentOfCall = argumentsOfCall[argumentsOfCall.length - 1];
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(lastArgumentOfCall).toHaveProperty("enq", "SHR");
});
it("should contain invalid enq value in payload", async () => {
Expand All @@ -395,6 +404,7 @@ describe("Copy", () => {
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
const argumentsOfCall = copyExpectStringSpy.mock.calls[0];
const lastArgumentOfCall = argumentsOfCall[argumentsOfCall.length - 1];
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(lastArgumentOfCall).toHaveProperty("enq", "AnyThing");
});
});
Expand All @@ -409,6 +419,7 @@ describe("Copy", () => {
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
const argumentsOfCall = copyExpectStringSpy.mock.calls[0];
const lastArgumentOfCall = argumentsOfCall[argumentsOfCall.length - 1];
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(lastArgumentOfCall).not.toHaveProperty("replace");
});
it("should contain replace with value true in payload", async () => {
Expand All @@ -424,6 +435,7 @@ describe("Copy", () => {
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
const argumentsOfCall = copyExpectStringSpy.mock.calls[0];
const lastArgumentOfCall = argumentsOfCall[argumentsOfCall.length - 1];
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(lastArgumentOfCall).toHaveProperty("replace", true);
});
it("should contain replace with value false in payload", async () => {
Expand All @@ -439,22 +451,17 @@ describe("Copy", () => {
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
const argumentsOfCall = copyExpectStringSpy.mock.calls[0];
const lastArgumentOfCall = argumentsOfCall[argumentsOfCall.length - 1];
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(lastArgumentOfCall).toHaveProperty("replace", false);
});
});
describe("Partitioned > Partitioned", () => {
let copyPDSSpy = jest.spyOn(Copy, "copyPDS");
beforeEach(() => {
copyPDSSpy.mockClear();
copyPDSSpy = jest.spyOn(Copy, "copyPDS").mockResolvedValue({
success:true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message,
});
isPDSSpy = jest.spyOn(Copy as any, "isPDS").mockResolvedValue(true);
isPDSSpy.mockClear().mockResolvedValue(true);
copyPDSSpy.mockClear().mockResolvedValue({success: true, commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message});
});
afterAll(() => {
copyPDSSpy.mockRestore();
isPDSSpy.mockRestore();
});
it("should call copyPDS to copy members of source PDS to target PDS", async () => {
const response = await Copy.dataSet(
Expand All @@ -475,6 +482,48 @@ describe("Copy", () => {
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
});
it("should not call copyPDS to copy members of source PDS to target PDS if member is specified", async() => {
const expectedPayload = {
"request": "copy",
"from-dataset": {
dsn: fromDataSetName,
member: fromMemberName
}
};
const expectedEndpoint = posix.join(
ZosFilesConstants.RESOURCE,
ZosFilesConstants.RES_DS_FILES,
`${toDataSetName}(${toMemberName})`
);
const expectedHeaders = [
{ "Content-Type": "application/json" },
{ "Content-Length": JSON.stringify(expectedPayload).length.toString() },
ZosmfHeaders.ACCEPT_ENCODING
];

const response = await Copy.dataSet(
dummySession,
{dsn: toDataSetName, member: toMemberName},
{"from-dataset": {
dsn: fromDataSetName,
member: fromMemberName
}}
);

expect(isPDSSpy).not.toHaveBeenCalled();
expect(copyPDSSpy).not.toHaveBeenCalled();
expect(response).toEqual({
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message
});
expect(copyExpectStringSpy).toHaveBeenCalledTimes(1);
expect(copyExpectStringSpy).toHaveBeenLastCalledWith(
dummySession,
expectedEndpoint,
expectedHeaders,
expectedPayload
);
});
});
});
describe("Failure Scenarios", () => {
Expand Down
10 changes: 6 additions & 4 deletions packages/zosfiles/src/methods/copy/Copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ export class Copy {
ImperativeExpect.toBeDefinedAndNonBlank(options["from-dataset"].dsn, "fromDataSetName");
ImperativeExpect.toBeDefinedAndNonBlank(toDataSetName, "toDataSetName");

const sourceIsPds = await this.isPDS(session, options["from-dataset"].dsn);
const targetIsPds = await this.isPDS(session, toDataSetName);
if (sourceIsPds && targetIsPds) {
return await this.copyPDS(session, options["from-dataset"].dsn, toDataSetName);
if(!toMemberName && !options["from-dataset"].member) {
const sourceIsPds = await this.isPDS(session, options["from-dataset"].dsn);
const targetIsPds = await this.isPDS(session, toDataSetName);
if (sourceIsPds && targetIsPds) {
return await this.copyPDS(session, options["from-dataset"].dsn, toDataSetName);
}
}

const endpoint: string = posix.join(
Expand Down

0 comments on commit 38b6ef8

Please sign in to comment.