Skip to content

Commit

Permalink
truncate lrecl functionality
Browse files Browse the repository at this point in the history
Signed-off-by: Pujal <[email protected]>
  • Loading branch information
pujal0909 committed Feb 9, 2025
1 parent 059e305 commit 2016201
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { tmpdir } from "os";
import path = require("path");
import * as fs from "fs";
import { List } from "@zowe/zos-files-for-zowe-sdk";
import * as util from "util";

let REAL_SESSION: Session;
let REAL_TARGET_SESSION: Session;
Expand Down Expand Up @@ -157,6 +158,40 @@ describe("Copy", () => {
expect(contents2).toBeTruthy();
expect(contents1.toString()).toEqual(contents2.toString());
});
it("Should handle truncation errors and log them to a file", async () => {
let error;
let response;

const uploadFileToDatasetSpy = jest.spyOn(Upload, 'fileToDataset').mockImplementation(async (session, filePath, dsn) => {
if (filePath === fileLocation) {
throw new Error("Truncation of a record occurred during an I/O operation");
}
return Promise.resolve() as any;
});
const copyDataSetSpy = jest.spyOn(Copy, 'dataSet').mockImplementation(async () => {
return {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message + " " + util.format(ZosFilesMessages.membersContentTruncated.message)
};
});
try {
response = await Copy.dataSet(
REAL_SESSION,
{dsn: toDataSetName},
{"from-dataset": {
dsn:fromDataSetName
}}
);
} catch (err) {
error = err;
Imperative.console.info(`Error: ${inspect(err)}`);
}
expect(response).toBeTruthy();
expect(response.success).toBe(true);
expect(response.commandResponse).toContain(ZosFilesMessages.datasetCopiedSuccessfully.message + " " + util.format(ZosFilesMessages.membersContentTruncated.message));
uploadFileToDatasetSpy.mockRestore();
copyDataSetSpy.mockRestore();
});
afterEach(() => {
fs.rmSync(downloadDir, { recursive: true, force: true });
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { error } from "console";
import * as util from "util";
import { Copy, Create, Get, List, Upload, ZosFilesConstants, ZosFilesMessages, IZosFilesResponse, Download, ZosFilesUtils } from "../../../../src";
import { ZosmfHeaders, ZosmfRestClient } from "@zowe/core-for-zowe-sdk";
import path = require("path");
import { tmpdir } from "os";

describe("Copy", () => {
const dummySession = new Session({
Expand Down Expand Up @@ -770,6 +772,7 @@ describe("Copy", () => {
const rmSync = jest.spyOn(fs, "rmSync");
const listDatasetSpy = jest.spyOn(List, "dataSet");
const hasIdenticalMemberNames = jest.spyOn(Copy as any, "hasIdenticalMemberNames");
const writeFileSync = jest.spyOn(fs, "writeFileSync");

beforeEach(() => {
hasIdenticalMemberNames.mockRestore();
Expand Down Expand Up @@ -901,6 +904,38 @@ describe("Copy", () => {
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message,
});
});
it("should handle truncation errors and log them to a file", async () => {
const truncatedMembersFilePath = path.join(tmpdir(), "errorMembers.txt");
let caughtError;
let response;
const sourceResponse = {
apiResponse: {
items: [
{ member: "mem1" },
{ member: "mem2" },
]
}
};
const fileList = ["mem1", "mem2"];
listAllMembersSpy.mockImplementation(async (): Promise<any> => sourceResponse);
downloadAllMembersSpy.mockImplementation(async (): Promise<any> => undefined);
fileListPathSpy.mockReturnValue(fileList);
generateMemName.mockReturnValue("mem1");
readStream.mockReturnValue("test" as any);
uploadSpy.mockImplementation((dummySession, readStream, dsn) => {
if (dsn.includes("mem1")) {
return Promise.reject(new Error("Truncation of a record occurred during an I/O operation"));
}
return Promise.resolve() as any;
});
try{
response = await Copy.copyPDS(dummySession, fromDataSetName, toDataSetName);
}
catch(e) {
caughtError = e;
}
expect(response.commandResponse).toContain("Data set copied successfully. Member(s)' contents were truncated due to insufficient record lines. You can view the list of members here: " + truncatedMembersFilePath);
});

describe("hasIdenticalMemberNames", () => {
const listAllMembersSpy = jest.spyOn(List, "allMembers");
Expand All @@ -909,7 +944,7 @@ describe("Copy", () => {
jest.clearAllMocks();
});
it("should return true if the source and target have identical member names", async () => {
listAllMembersSpy.mockImplementation(async (session, dsName): Promise<any> => {
listAllMembersSpy.mockImplementation(async (_session, dsName): Promise<any> => {
if (dsName === fromDataSetName) {
return {
apiResponse: {
Expand Down Expand Up @@ -949,7 +984,7 @@ describe("Copy", () => {
]
}
};
listAllMembersSpy.mockImplementation(async (session, dsName): Promise<any> => {
listAllMembersSpy.mockImplementation(async (_session, dsName): Promise<any> => {
if (dsName === fromDataSetName) {
return sourceResponse;
} else if (dsName === toDataSetName) {
Expand Down
22 changes: 19 additions & 3 deletions packages/zosfiles/src/methods/copy/Copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@ export class Copy {
*
* @see https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.izua700/IZUHPINFO_API_PutDataSetMemberUtilities.htm
*/

public static async copyPDS (
session: AbstractSession, fromPds: string, toPds: string): Promise<IZosFilesResponse> {
try {
Expand All @@ -227,12 +226,29 @@ export class Copy {
const downloadDir = path.join(tmpdir(), fromPds);
await Download.allMembers(session, fromPds, {directory:downloadDir});
const uploadFileList: string[] = ZosFilesUtils.getFileListFromPath(downloadDir);
const truncatedMembers: string[] = [];

for (const file of uploadFileList) {
const memName = ZosFilesUtils.generateMemberName(file);
const uploadingDsn = `${toPds}(${memName})`;
const uploadStream = IO.createReadStream(file);
await Upload.streamToDataSet(session, uploadStream, uploadingDsn);
try {
const uploadStream = IO.createReadStream(file);
await Upload.streamToDataSet(session, uploadStream, uploadingDsn);
}
catch(error) {
if(error.message && error.message.includes("Truncation of a record occurred during an I/O operation")) {
truncatedMembers.push(memName);
}
continue;
}
}
if(truncatedMembers.length > 0) {
const errorMembersFile = path.join(tmpdir(), 'errorMembers.txt');
fs.writeFileSync(errorMembersFile, truncatedMembers.join('\n'));
return {
success: true,
commandResponse: ZosFilesMessages.datasetCopiedSuccessfully.message + " " + util.format(ZosFilesMessages.membersContentTruncated.message, errorMembersFile)
};
}
fs.rmSync(downloadDir, {recursive: true});
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export interface ICopyDatasetOptions extends IZosFilesOptions {

/**
* Prompt for duplicates
* @returns True if target data set members
* @returns `True` if the copy operation will overwrite an existing member; `false` otherwise
*/
promptForLikeNamedMembers?: () => Promise<boolean>;
}

0 comments on commit 2016201

Please sign in to comment.