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

System tests should cleanup after themselves #2216

Open
wants to merge 58 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
d993866
keeping track of resources created during tests and adding cleanup
ATorrise Aug 6, 2024
3b01d28
tests that ive been preoccupied with
ATorrise Aug 14, 2024
fb156de
fixing these was hardgit add .
ATorrise Aug 15, 2024
960777b
ensuring more tests delete jobs from mf, also fixing delete operations
ATorrise Aug 15, 2024
68a7fdd
Merge remote-tracking branch 'origin/next' into system-test-cleanup
ATorrise Aug 15, 2024
4f059e6
finished zosjobs sdk tests and starting zosfiles sdk tests
ATorrise Aug 16, 2024
81048a7
modifying upload.system.test took the longest... removing some test f…
ATorrise Aug 21, 2024
a505c0d
took awhile to see the difference in regex between v1 and v2 that i w…
ATorrise Aug 22, 2024
56f0e9a
providing more clarity in a comment about calculating previous jobid
ATorrise Aug 22, 2024
c458433
fixing cli.zos-jobs.download and its accompanying scripts
ATorrise Aug 22, 2024
e356ac8
more cli sytem tests and ammended shell scripts
ATorrise Aug 22, 2024
123c7f9
finishin clizosjobslistspoolfiles
ATorrise Aug 22, 2024
d7b2840
fixing submit with a different, less intensive cleanup approach
ATorrise Aug 22, 2024
e1f2ca2
realizing need to keep createZosmfSession for uss files..
ATorrise Aug 23, 2024
4ccaad5
finishing cliZosjobsSubmit
ATorrise Aug 23, 2024
c5995dd
fixing error in variable name across files and finishing view spool t…
ATorrise Aug 23, 2024
a0fa936
unable to modify file like others
ATorrise Aug 26, 2024
f746a0b
deletes remaining ds from mf
ATorrise Aug 26, 2024
885a28a
Merge branch 'next' into system-test-cleanup
ATorrise Aug 26, 2024
f334c76
Update cli.zos-jobs.submit.stdin.system.test.ts to remove semicolon
ATorrise Aug 26, 2024
e11726f
Update cli.zos-jobs.submit.stdin.system.test.ts removing accidental line
ATorrise Aug 26, 2024
70cb522
whoops
ATorrise Aug 26, 2024
d87f789
Merge branch 'next' into system-test-cleanup
ATorrise Aug 26, 2024
0b475ac
changelog
ATorrise Aug 27, 2024
3853c8a
linting
ATorrise Aug 27, 2024
0159d2c
Merge branch 'next' into system-test-cleanup
ATorrise Aug 28, 2024
c7de80c
no circ dependency error?
ATorrise Aug 28, 2024
54baa2d
updating changelog
ATorrise Aug 28, 2024
ebe3570
moving things around with andrew's help
ATorrise Aug 28, 2024
663340f
moving around things in testEnv and ITestEnv
ATorrise Aug 28, 2024
9d59e1a
about to make a really big change
ATorrise Aug 29, 2024
fe2c72b
restoring clitestutils cleanup()
ATorrise Aug 29, 2024
46677f7
Merge branch 'next' into system-test-cleanup
ATorrise Aug 29, 2024
21bf9aa
fixing other testEnv
ATorrise Aug 29, 2024
a9d2865
updating imports
ATorrise Aug 29, 2024
52361c2
fixing imports
ATorrise Aug 29, 2024
309be62
hopefully not breaking
ATorrise Aug 29, 2024
585bb75
accidentally left 1 thing out of if statement
ATorrise Aug 29, 2024
a83444a
whoops
ATorrise Aug 29, 2024
bc1ffa2
making a wait util method and implementing it everywhere
ATorrise Aug 29, 2024
8ccb8f4
addressing one of fernandos comments
ATorrise Aug 30, 2024
842ee6b
timeout corrections
ATorrise Aug 30, 2024
9e8f22e
removing change to a unit test
ATorrise Aug 30, 2024
1c7a5b2
changing system test to work with 'any' job name
ATorrise Aug 30, 2024
83faac9
wiping testEnvironment.resources in cleanup
ATorrise Sep 4, 2024
6c7064b
changing the way the test works but need testing mini to be active an…
ATorrise Sep 4, 2024
deb5cfa
Merge branch 'next' into system-test-cleanup
ATorrise Sep 4, 2024
cefbff1
hopefully good to merge now
ATorrise Sep 4, 2024
aaa43b8
Merge branch 'system-test-cleanup' of https://github.com/zowe/zowe-cl…
ATorrise Sep 4, 2024
201ecc1
fixin - initializing resources
ATorrise Sep 4, 2024
4a37668
addressing timothy's requests
ATorrise Sep 19, 2024
36a19ca
Merge remote-tracking branch 'origin/next' into system-test-cleanup
ATorrise Sep 19, 2024
5e40b67
Merge branch 'master' of https://github.com/zowe/zowe-cli into system…
ATorrise Sep 19, 2024
2d1c9be
fixing runCliScrip import and TestEnvironment.cleanup
ATorrise Sep 19, 2024
d89d3b1
createSession() to createZosmfSession()
ATorrise Sep 19, 2024
ae20141
createsession to createzosmfsession
ATorrise Sep 19, 2024
54e8d99
adding import back into test
ATorrise Sep 20, 2024
9de05a2
getting things deleted
ATorrise Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions __tests__/__packages__/cli-test-utils/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 test utils package will be documented in this file.

## Recent Changes

- Updated `TestEnvironment`, `ITestEnvironment`, and `TestUtils` to simplify and automate the cleanup of test resources, such as datasets, USS files, jobs, and local files created during system tests.

## `8.0.0-next.202408271330`

- BugFix: Removed obsolete V1 `profiles` property from the parameters object returned by `mockHandlerParameters` method.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@

import * as fs from "fs";
import * as nodePath from "path";

import * as yaml from "js-yaml";
import { v4 as uuidv4 } from "uuid";
import { ImperativeError, ImperativeExpect, IO, Logger, LoggingConfigurer, TextUtils } from "@zowe/imperative";

import { AbstractSession, ImperativeError, ImperativeExpect,
IO, Logger, LoggingConfigurer, ProfileInfo, TextUtils } from "@zowe/imperative";
import { ISetupEnvironmentParms } from "./doc/parms/ISetupEnvironmentParms";
import { ITestEnvironment } from "./doc/response/ITestEnvironment";
import { TempTestProfiles } from "./TempTestProfiles";
Expand Down Expand Up @@ -43,7 +42,7 @@ export class TestEnvironment {
* @returns {Promise<ITestEnvironment>}
* @memberof TestEnvironment
*/
public static async setUp(params: ISetupEnvironmentParms): Promise<ITestEnvironment<any>> {
public static async setUp(params: ISetupEnvironmentParms, session?: AbstractSession): Promise<ITestEnvironment<any>> {
// Validate the input parameters
ImperativeExpect.toNotBeNullOrUndefined(params,
`${TestEnvironment.ERROR_TAG} createTestEnv(): No parameters supplied.`);
Expand Down Expand Up @@ -85,6 +84,24 @@ export class TestEnvironment {
return result;
}

/**
* Create a session using the default z/OSMF profile (if a session has not been added to test)
* @returns {Promise<ISession>} - A promise that resolves to the created session object
* @throws Will throw an error if reading profiles or creating the session fails
* @memberof TestEnvironment
*/
public static async createSession(): Promise<AbstractSession> {
// Load connection info from default z/OSMF profile
const profInfo = new ProfileInfo("zowe");
await profInfo.readProfilesFromDisk();
const zosmfProfAttrs = profInfo.getDefaultProfile("zosmf");
ATorrise marked this conversation as resolved.
Show resolved Hide resolved
if (!zosmfProfAttrs) {
throw new Error("Default z/OSMF profile not found.");
}
const zosmfMergedArgs = profInfo.mergeArgsForProfile(zosmfProfAttrs, { getSecureVals: true });
return ProfileInfo.createSession(zosmfMergedArgs.knownArgs);
}

/**
* Clean up your test environment.
* Deletes any temporary profiles that have been created
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
*/

export * from "./parms/ISetupEnvironmentParms";
export * from "./response/ITestEnvironment";
export * from "./response/ITestEnvironment";
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* @export
* @interface ITestEnvironment
*/
export interface ITestEnvironment<TestPropertiesSchema> {
export interface ITestEnvironment<ITestPropertiesSchema> {
/**
* The working directory for your test environment. It is a unique (uuid) area where your tests can create
* their home folders (for imperative, etc.) and you can use the area as scratch for any files, etc. that
Expand All @@ -29,10 +29,10 @@ export interface ITestEnvironment<TestPropertiesSchema> {
* in the case that no system test properties were configured or could be loaded.
*
* Not present if skipProperties is specified on ISetupEnvironmentParms
* @type {TestPropertiesSchema}
* @type {ITestPropertiesSchema}
* @memberof ITestEnvironment
*/
systemTestProperties: TestPropertiesSchema;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using generics, it's advisable to keep the name short, and ideally something different to an existing interface.

you could get the same benefits by doing <T extends ITestPropertiesSchema> and use the value of T as the desired type for this properti (e.g. systemTestProperties: T)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the value before was TestPropertiesSchema, do we need to make that change? I am also a bit confused with the difference between generics and interfaces in this particular context.

This comment was marked as resolved.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, these are Typescript generics which do not have any impact on users.

Having the ITestPropertiesSchema will cause confusion as we might expect the interface to be taking effect when it won't.

The reason why TestPropertiesSchema never caused problems was because it was just the name that we gave it (which is equivalent to using a single letter, like T)

Hence the suggestion of T extends ITestPropertiesSchema to get the benefits of the interface 😋

Feel free to ignore this comment if you feel I'm completely off base here (because, honestly, I might be) 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok i just reverted changes to the file... is that alright? commit: 2d1c9be
@zFernand0 @t1m0thyj

systemTestProperties: ITestPropertiesSchema;

/**
* Set of environmental variables (such as profile/logging home directory)
Expand Down
143 changes: 136 additions & 7 deletions __tests__/__src__/TestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,83 @@
*/

import { randomBytes } from "crypto";
import { ZosFilesConstants } from "../../packages/zosfiles/src";
import { Imperative, Headers, AbstractSession } from "@zowe/imperative";
import * as fs from "fs";
import { Imperative, Headers, AbstractSession, IO } from "@zowe/imperative";
import { ZosmfRestClient } from "../../packages/core/src";
import { ZosFilesConstants, Delete } from "../../packages/zosfiles/src";
import { DeleteJobs, ICommonJobParms, IDeleteJobParms, IJob } from "../../packages/zosjobs/src";
import { posix } from "path";
import { spawnSync, SpawnSyncReturns, ExecFileException } from "child_process";
import { ITestEnvironment } from "./environment/ITestEnvironment";
import { promisify } from "util";

/**
* Delete a local testing file after use
* @param {string} filePath - File path of temporary file
*/
export function deleteLocalFile(filePath: string): void {
try {
fs.unlinkSync(filePath);
} catch {
// If fs.unlinkSync fails, try to delete it with IO.deleteFile
try {
IO.deleteFile(posix.basename(filePath));
} catch {
throw new Error(`Error deleting local file: ${filePath}`);
}
}
}

/**
* Delete local directories after use
* @param {string[]} directories - Array of directories to delete
*/
export function deleteLocalDirectories(directories: string[]): void {
directories.forEach((dir) => {
try {
if (fs.existsSync(dir)) {
fs.rmdirSync(dir, { recursive: true });
}
} catch (err) {
throw new Error(`Error deleting directory: ${dir}`);
}
});
}
/**
* Delete a uss file from the mainframe
* @param {AbstractSession} session - z/OSMF connection info
* @param {string} fileName - The name of the USS file
*/
export function deleteFiles(session: AbstractSession, fileName: string): void {
Delete.ussFile(session, fileName);
}
ATorrise marked this conversation as resolved.
Show resolved Hide resolved

/**
* Delete a dataset from the mainframe
* @param {AbstractSession} session - z/OSMF connection info
* @param {string} datasetName - The name of the dataset
*/
export function deleteDataset(session: AbstractSession, dataSetName: string): void {
Delete.dataSet(session, dataSetName);
}

/**
* Delete a job from the mainframe using Zowe SDKs - IJob
* @param {AbstractSession} session - z/OSMF connection info
* @param {IJob} job - the job that you want to delete
*/
export function deleteJob(session: AbstractSession, job: IJob): void {
DeleteJobs.deleteJobForJob(session, job);
}

/**
* Delete a job from the mainframe using Zowe SDKs - jobid, jobname
* @param {AbstractSession} session - z/OSMF connection info
* @param {params} ICommonJobParms - constains jobname and jobid for job to delete
*/
export function deleteJobCommon(session: AbstractSession, params: ICommonJobParms): void {
DeleteJobs.deleteJobCommon(session, params as IDeleteJobParms);
}

/**
* This function strips any new lines out of the string passed.
Expand Down Expand Up @@ -100,11 +174,13 @@ export async function getTag(session: AbstractSession, ussPath: string) {
return response.stdout[0];
}

export function delay(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms) );
}

export const delTime = 500;
/**
* Pauses execution for a given number of milliseconds.
* @param {number} ms - Number of milliseconds to wait
* @returns {Promise<void>} - Resolves after the specified time has passed
*/
export const wait = promisify(setTimeout);
export const waitTime = 2000; //wait 2 seconds

/**
* Use instead of `util.inspect` to get consistently formatted output that can be used in snapshots.
Expand All @@ -114,3 +190,56 @@ export const delTime = 500;
export function inspect(obj: any) : string {
return JSON.stringify(Object.keys(obj).reduce((newObj, key) => ({...newObj, [key]: obj[key]}), {}));
}

/**
* Execute a CLI script
* @export
* @param scriptPath - the path to the script
* @param testEnvironment - the test environment with env
* @param [args=[]] - set of script args (optional)
* @returns node.js details about the results of
* executing the script, including exit code and output
*/
export function runCliScript(scriptPath: string, testEnvironment: ITestEnvironment<any>, args: any[] = []): SpawnSyncReturns<Buffer> {
ATorrise marked this conversation as resolved.
Show resolved Hide resolved
if (fs.existsSync(scriptPath)) {

// We force the color off to prevent any oddities in the snapshots or expected values
// Color can vary OS/terminal
const childEnv = JSON.parse(JSON.stringify(process.env));
childEnv.FORCE_COLOR = "0";
for (const key of Object.keys(testEnvironment.env)) {
// copy the values from the env
childEnv[key] = testEnvironment.env[key];
}

if (process.platform === "win32") {
// Execute the command synchronously
const response = spawnSync("sh", [scriptPath].concat(args), {
cwd: testEnvironment.workingDir,
encoding: "buffer",
env: childEnv
});
if ((response.error as ExecFileException)?.code === "ENOENT") {
throw new Error(`"sh" is missing from your PATH. Check that Git Bash is installed with the option to ` +
`"Use Git and Unix Tools from Windows Command Prompt".`);
}
return response;
}

// Check to see if the file is executable
try {
fs.accessSync(scriptPath, fs.constants.X_OK);
} catch {
fs.chmodSync(scriptPath, "755");
}
return spawnSync(scriptPath, args, {
cwd: testEnvironment.workingDir,
env: childEnv,
encoding: "buffer"
});

} else {
throw new Error(`The script file ${scriptPath} doesn't exist`);

}
}
27 changes: 27 additions & 0 deletions __tests__/__src__/environment/ITestEnvironment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/

import { ITestEnvironment as IBaseTestEnvironment } from "../../__packages__/cli-test-utils/src/environment/doc/response/ITestEnvironment";
import { ITestEnvironmentResources } from "./ITestEnvironmentResources";

/**
* The test environment for your test.
* @export
* @interface ITestEnvironment
*/
export interface ITestEnvironment<ITestPropertiesSchema> extends IBaseTestEnvironment<ITestPropertiesSchema>{
/**
* A collection of resources used within the test environment that need to be cleaned up once test finishes.
* @type {ITestEnvironmentResources}
* @memberof ITestEnvironment
*/
resources?: ITestEnvironmentResources;
}
56 changes: 56 additions & 0 deletions __tests__/__src__/environment/ITestEnvironmentResources.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/

import { AbstractSession } from "@zowe/imperative";
import { ICommonJobParms, IJob } from "../../../packages/zosjobs";

/**
* Represents the resources used within the test environment.
* @export
* @interface ITestEnvironmentResources
*/
export interface ITestEnvironmentResources {
/**
* Array of local file paths used within the test environment.
* @type {string[]}
*/
localFiles: string[];

/**
* Array of mainframe uss files used within the test environment.
* @type {string[]}
*/
files: string[];

/**
* Array of job objects representing jobs submitted to the mainframe during the test.
* @type {IJob[]}
*/
jobs: IJob[];

/**
* Array of job data containing jobname and jobid, used to track jobs within the test environment.
* @type {ICommonJobParms[]}
*/
jobData: ICommonJobParms[]; // Contains jobname and jobid

/**
* Array of dataset names used within the test environment.
* @type {string[]}
*/
datasets: string[];

/**
* The session used for interacting with z/OS systems during the test, if applicable.
* @type {AbstractSession}
*/
session?: AbstractSession;
}
Loading