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

fix encoding not being used on upload file to uss #2334

Merged
merged 12 commits into from
Nov 4, 2024
4 changes: 4 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to the Zowe CLI package will be documented in this file.

## Recent Changes

- BugFix: Resolved issue where `zowe zos-files upload file-to-uss` was not properly handling command flags. [#2234](https://github.com/zowe/zowe-cli/pull/2334)

## `8.6.0`

- Enhancement: Added support for running applications on TSO/E address spaces. Start applications and receive/transmit messages using the new `tso start`, `tso receive` and `tso send` commands. [#2280](https://github.com/zowe/zowe-cli/pull/2280)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,5 +185,95 @@ describe("Upload file-to-uss handler", () => {
expect(apiMessage).toMatchSnapshot();
expect(logMessage).toMatchSnapshot();
});
it("should upload a file to a USS if requested - zosattributes file - binary", async () => {
// Require the handler and create a new instance
const handlerReq = require("../../../../../src/zosfiles/upload/ftu/FileToUSS.handler");
const handler = new handlerReq.default();
const inputfile = "test-file";
const USSFileName = "testing";
let zosAttributes: any;

let error;
let apiMessage = "";
let jsonObj;
let logMessage = "";
let fakeSession = null;

jest.spyOn(ZosFilesAttributes, "loadFromFile").mockImplementation(() => {
zosAttributes = Object.create(ZosFilesAttributes.prototype);
zosAttributes.attributes = new Map([
['*.json', { ignore: true }],
['*.bin', { ignore: false, localEncoding: 'binary', remoteEncoding: 'binary' }],
['*.jcl', { ignore: false, localEncoding: 'IBM-1047', remoteEncoding: 'IBM-1047' }],
['*.md', { ignore: false, localEncoding: 'UTF-8', remoteEncoding: 'UTF-8' }],
['*.txt', { ignore: false, localEncoding: 'binary', remoteEncoding: 'binary' }]
]);
zosAttributes.basePath = undefined;
return zosAttributes;
});
Upload.uploadFile = jest.fn(async (session, file, name, options = {}) => {
fakeSession = session;
return {
success: true,
commandResponse: "uploaded",
apiResponse: [
{ success: true, from: inputfile, to: USSFileName }
]
};
});
try {
await handler.process({
arguments: {
$0: "fake",
_: ["fake"],
inputfile,
USSFileName,
...UNIT_TEST_ZOSMF_PROF_OPTS
},
response: {
data: {
setMessage: jest.fn((setMsgArgs) => {
apiMessage = setMsgArgs;
}),
setObj: jest.fn((setObjArgs) => {
jsonObj = setObjArgs;
})
},
console: {
log: jest.fn((logArgs) => {
logMessage += "\n" + logArgs;
})
},
progress: {
startBar: jest.fn(() => {
// do nothing
}),
endBar: jest.fn(() => {
// do nothing
})
}
}
} as any);
} catch (e) {
error = e;
}
expect(error).toBeUndefined();
expect(Upload.uploadFile).toHaveBeenCalledTimes(1);
expect(Upload.uploadFile).toHaveBeenCalledWith(fakeSession, inputfile, USSFileName, {
attributes: zosAttributes,
binary: undefined,
includeHidden: undefined,
maxConcurrentRequests: undefined,
responseTimeout: undefined,
task: {
percentComplete: 0,
stageName: 0,
statusMessage: "Uploading USS file"
}
});
expect(jsonObj).toMatchSnapshot();
expect(apiMessage).toMatchSnapshot();
expect(logMessage).toMatchSnapshot();
});
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Upload file-to-uss handler process method should upload a file to a USS if requested - zosattributes file - binary 1`] = `
Object {
"apiResponse": Array [
Object {
"from": "test-file",
"success": true,
"to": "testing",
},
],
"commandResponse": "uploaded",
"success": true,
}
`;

exports[`Upload file-to-uss handler process method should upload a file to a USS if requested - zosattributes file - binary 2`] = `""`;

exports[`Upload file-to-uss handler process method should upload a file to a USS if requested - zosattributes file - binary 3`] = `
"
- 
success: true
from:  test-file
to:  testing


uploaded"
`;

exports[`Upload file-to-uss handler process method should upload a file to a USS if requested - zosattributes file 1`] = `
Object {
"apiResponse": Array [
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/zosfiles/upload/ftu/FileToUSS.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default class FileToUSSHandler extends ZosFilesBaseHandler {

const uploadOptions: IUploadOptions = {
binary: commandParameters.arguments.binary,
encoding: commandParameters.arguments.encoding,
jace-roell marked this conversation as resolved.
Show resolved Hide resolved
maxConcurrentRequests:
commandParameters.arguments.maxConcurrentRequests,
task: task,
Expand Down
5 changes: 5 additions & 0 deletions packages/zosfiles/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

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

## Recent Changes

- BugFix: Resolved issue where encoding argument was missing from `FileToUss.handler.ts` options object. [#2234](https://github.com/zowe/zowe-cli/pull/2334)
- BugFix: Resolved issue where `FileToUss.handler.ts` options object was not properly passed through subsequent command calls. [#2234](https://github.com/zowe/zowe-cli/pull/2334)

## `8.4.0`

- Enhancement: Added optional `--attributes` flag to `zowe zos-files upload file-to-uss` to allow passing a .zosattributes file path for upload encoding format. [#2319] (https://github.com/zowe/zowe-cli/pull/2319)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,7 @@ describe("Upload USS file", () => {
let readResponseGood: any;
let readResponseBad: any;
try {
// Upload file
response = runCliScript(__dirname + "/__resources__/upload_file_to_uss.sh", testEnvironment,[
defaultSystem.tso.account,
defaultSystem.zosmf.host,
Expand Down Expand Up @@ -900,6 +901,62 @@ describe("Upload USS file", () => {
// Compare file view with not matching upload and view encoding (1047 vs 1147).
expect(readResponseBad.stdout.toString()).not.toContain(fileContents);

// Compare file view with matching upload and view encoding (1047).
expect(readResponseGood.stdout.toString()).toContain(fileContents);
});
it("should upload local file to USS using .zosattributes file - binary", async () => {
let response: any;
let error;
let readResponseGood: any;
let readResponseBad: any;
try {
// Upload file
response = runCliScript(__dirname + "/__resources__/upload_file_to_uss.sh", testEnvironment,[
defaultSystem.tso.account,
defaultSystem.zosmf.host,
defaultSystem.zosmf.port,
defaultSystem.zosmf.user,
defaultSystem.zosmf.password,
defaultSystem.zosmf.rejectUnauthorized,
__dirname + "/testfiles/encodingCheckBinary.txt",
ussname,
__dirname + "/__resources__/.zosattributes-binary",
]);
// View file with .txt binary encoding in .zosattributes
readResponseGood = runCliScript(__dirname + "/__resources__/view_file_uss_binary.sh", testEnvironment,[
defaultSystem.tso.account,
defaultSystem.zosmf.host,
defaultSystem.zosmf.port,
defaultSystem.zosmf.user,
defaultSystem.zosmf.password,
defaultSystem.zosmf.rejectUnauthorized,
ussname,
true
]);
readResponseBad = runCliScript(__dirname + "/__resources__/view_file_uss.sh", testEnvironment,[
defaultSystem.tso.account,
defaultSystem.zosmf.host,
defaultSystem.zosmf.port,
defaultSystem.zosmf.user,
defaultSystem.zosmf.password,
defaultSystem.zosmf.rejectUnauthorized,
ussname,
"1047"
]);
}
catch (err) {
error = err;
Imperative.console.info("Error: " + inspect(error));
}
const fileContents = fs.readFileSync(__dirname + "/testfiles/encodingCheckBinary.txt").toString();

expect(response.stderr.toString()).toBe("");
expect(response.stdout.toString()).toBeDefined();
expect(response.stdout.toString()).toContain("USS file uploaded successfully.");

// Compare file view with not matching upload and view encoding (1047 vs 1147).
expect(readResponseBad.stdout.toString()).not.toContain(fileContents);

// Compare file view with matching upload and view encoding (1047).
expect(readResponseGood.stdout.toString()).toContain(fileContents);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.json -
*.bin binary binary
*.jcl IBM-1047 IBM-1047
*.md UTF-8 UTF-8
*.txt binary binary
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
account=$1
host=$2
port=$3
user=$4
password=$5
ru=$6
ussName=$7
encoding=$8

zowe zos-files view uf $ussName --binary $binary --host $host --port $port --user $user --password $password --ru $ru
exit $?
Original file line number Diff line number Diff line change
@@ -1 +1 @@
á é í ó ú ñ Ç ß 12345 !@#$% ^ [ ] $ £
á é í ó ú ñ Ç ß 12345 !@#$% ^ [ ] $ £
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[][][]
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ describe("z/OS Files - Upload", () => {
expect(error).toBeDefined();
expect(error.message).toContain(ZosFilesMessages.missingDatasetName.message);
});

it("should throw underlying fs error", async () => {
const rootError = {
code: "test",
Expand All @@ -226,6 +225,22 @@ describe("z/OS Files - Upload", () => {
expect(error.additionalDetails).toEqual(rootError.toString());
expect(error.causeErrors).toBe(rootError);
});
it("should throw error if error is null and stats.isFile() is true", async () => {
const testPath = "test/path";
lstatSpy.mockImplementationOnce((somePath, callback: any) => {
callback(null, {isFile: () => true});
});

try {
response = await Upload.dirToPds(dummySession, testPath, dsName);
} catch (err) {
error = err;
}

expect(response).toBeUndefined();
expect(error).toBeDefined();
expect(error.message).toContain(ZosFilesMessages.pathIsNotDirectory.message);
});

it("should return with proper message when path is pointing to a file", async () => {
lstatSpy.mockImplementationOnce((somePath, callback: any) => {
Expand Down Expand Up @@ -2475,7 +2490,7 @@ describe("z/OS Files - Upload", () => {
expect(fileToUssFileSpy).toHaveBeenCalledTimes(1);
expect(fileToUssFileSpy).toHaveBeenCalledWith(dummySession,
path.normalize(path.join(testPath, "uploadme")),
`${dsName}/uploadme`, { binary: true });
`${dsName}/uploadme`, { binary: true, attributes: attributesMock, recursive: false });
});

it("should not upload ignored directories", async () => {
Expand Down Expand Up @@ -2518,7 +2533,7 @@ describe("z/OS Files - Upload", () => {
expect(fileToUssFileSpy).toHaveBeenCalledTimes(1);
expect(fileToUssFileSpy).toHaveBeenCalledWith(dummySession,
path.normalize(path.join(testPath, "uploaddir", "uploadedfile")),
`${dsName}/uploaddir/uploadedfile`, { binary: true });
`${dsName}/uploaddir/uploadedfile`, { binary: true, attributes: attributesMock });
});
it("should upload files in text or binary according to attributes", async () => {
getFileListFromPathSpy.mockReturnValue(["textfile", "binaryfile"]);
Expand All @@ -2532,10 +2547,10 @@ describe("z/OS Files - Upload", () => {
expect(fileToUssFileSpy).toHaveBeenCalledWith(dummySession,
path.normalize(path.join(testPath, "textfile")),
`${dsName}/textfile`,
{ binary: false, encoding: "ISO8859-1", localEncoding: "ISO8859-1" });
{ binary: false, encoding: "ISO8859-1", localEncoding: "ISO8859-1", attributes: attributesMock, recursive: false });
expect(fileToUssFileSpy).toHaveBeenCalledWith(dummySession,
path.normalize(path.join(testPath, "binaryfile")),
`${dsName}/binaryfile`, { binary: true });
`${dsName}/binaryfile`, { binary: true, recursive: false, attributes: attributesMock });
});

it("should call API to tag files according to remote encoding", async () => {
Expand Down
33 changes: 16 additions & 17 deletions packages/zosfiles/src/methods/upload/Upload.ts
jace-roell marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -854,32 +854,31 @@
};
}

public static async uploadFile(session: AbstractSession, localPath: string, ussPath: string,
options: IUploadOptions): Promise<IZosFilesResponse> {
const tempOptions: Partial<IUploadOptions> = {};

public static async uploadFile(
session: AbstractSession,
localPath: string,
ussPath: string,
options: IUploadOptions
): Promise<IZosFilesResponse> {
const tempOptions: IUploadOptions = { ...options };
if (options.attributes) {
if (!options.attributes.fileShouldBeUploaded(localPath)) {
return;
}
tempOptions.binary = options.attributes.getFileTransferMode(localPath, options.binary) === TransferMode.BINARY;
const remoteEncoding = options.attributes.getRemoteEncoding(localPath);
if (remoteEncoding != null && remoteEncoding !== Tag.BINARY) {
tempOptions.encoding = remoteEncoding;
}

if(remoteEncoding === Tag.BINARY) tempOptions.encoding = undefined;
else if(remoteEncoding !== null) tempOptions.encoding = remoteEncoding;

if (!tempOptions.binary) {
tempOptions.localEncoding = options.attributes.getLocalEncoding(localPath);
}
} else {
if (options.filesMap) {
if (options.filesMap.fileNames.indexOf(path.basename(localPath)) > -1) {
tempOptions.binary = options.filesMap.binary;
} else {
tempOptions.binary = options.binary;
}
} else {
tempOptions.binary = options.binary;
}
} else if(options.filesMap?.fileNames.indexOf(path.basename(localPath)) > -1) {
tempOptions.binary = options.filesMap.binary;

Check warning on line 878 in packages/zosfiles/src/methods/upload/Upload.ts

View check run for this annotation

Codecov / codecov/patch

packages/zosfiles/src/methods/upload/Upload.ts#L878

Added line #L878 was not covered by tests

// Reset encoding to undefined if binary is true to avoid file tagging issues
if(tempOptions.binary) tempOptions.encoding = undefined;
}

return await this.fileToUssFile(session, localPath, ussPath, tempOptions);
Expand Down