Skip to content

Commit

Permalink
Merge pull request #2334 from zowe/encoding-ftu-fix
Browse files Browse the repository at this point in the history
fix encoding not being used on upload file to uss
  • Loading branch information
t1m0thyj authored Nov 4, 2024
2 parents 1d2cdc9 + 1d9a7bd commit 23b05f1
Show file tree
Hide file tree
Showing 12 changed files with 241 additions and 23 deletions.
6 changes: 6 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@

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.1`

- BugFix: Fixed an issue where the `zowe zos-logs list logs` command could fail or not return all logs if a start time was not supplied. [#2336](https://github.com/zowe/zowe-cli/pull/2336)


## `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,
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
Original file line number Diff line number Diff line change
Expand Up @@ -854,32 +854,31 @@ export class Upload {
};
}

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;

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

0 comments on commit 23b05f1

Please sign in to comment.