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

refactor: Lock profiles during async operations (phase 1: filesystem) #3370

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
acf538c
move DeferredPromise to API
traeok Dec 18, 2024
aa5251c
wip: AuthHandler
traeok Dec 18, 2024
43eba14
refactor: 'promptForAuthOnError' -> 'lockProfileOnAuthError'
traeok Dec 18, 2024
cea4f85
wip: reload workspaces once reauthenticated
traeok Dec 19, 2024
1216b03
wip: lock in other FS providers; fix update credentials logic
traeok Dec 19, 2024
b9ea559
wip(tests): resolve multiple failing tests
traeok Dec 19, 2024
aefbbb4
tests: resolve failing ProfilesUtils cases
traeok Dec 19, 2024
0dce568
wip: rename AuthUtils method, update FS providers
traeok Dec 20, 2024
167977a
refactor: Mutex class & use in AuthHandler; TSDoc
traeok Dec 20, 2024
18d485a
add reloadActiveEditorForProfile and related logic
traeok Dec 20, 2024
665c4a4
expose Mutex, fix failing tests
traeok Dec 20, 2024
8765304
chore: fix unused warnings in test code
traeok Dec 23, 2024
c597755
chore: fix lint and formatting errors
traeok Dec 23, 2024
929853b
tests: DeferredPromise, Mutex
traeok Dec 23, 2024
3c8bf4a
chore: rename test file in API to match source file
traeok Dec 23, 2024
49aee1d
remove unused import
traeok Dec 23, 2024
0507c3b
refactor: use async-mutex instead of homemade mutex
traeok Dec 23, 2024
d83c9ac
refactor: move fs helper fns, isLocked -> isProfileLocked
traeok Dec 23, 2024
5ca4607
wip: AuthHandler tests
traeok Dec 23, 2024
410755c
wip: patch coverage for AuthHandler, DeferredPromise
traeok Dec 23, 2024
00fe312
refactor: lockedProfiles -> profileLocks, patch cov in ProfilesUtils
traeok Dec 23, 2024
6dc0e01
tests: FileManagement functions
traeok Dec 23, 2024
ebc1f79
remove unused var 'credsEntered'
traeok Dec 23, 2024
5f35e85
refactor: save decorator for phase 2 (API changes)
traeok Dec 23, 2024
b1a6984
tests: AuthHandler SSO login during auth prompt
traeok Dec 23, 2024
f443bc6
add test for basic creds, move logic for updating trees
traeok Dec 23, 2024
d986e47
fix lint errors
traeok Dec 23, 2024
9264fde
tests: AuthHandler.updateTreeProvidersWithProfile
traeok Dec 24, 2024
4dcad76
chore: add changelogs
traeok Dec 24, 2024
3dc39b1
fix: refresh resources if updated in 'Manage Profile' option
traeok Dec 24, 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
2 changes: 1 addition & 1 deletion .eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ rules:
- warn
- "ignore": [-2, -1, 0, 1, 2, 4]
no-multiple-empty-lines: warn
no-return-await: warn
no-return-await: off
no-sequences: warn
no-shadow: off
no-sparse-arrays: warn
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ node_modules
pnpm-lock.yaml
**/bundle.l10n.json
**/.wdio-vscode-service
packages/zowe-explorer/__tests__/**/zowe.config.json
zedc/target
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { DeferredPromise } from "../../../src";

describe("DeferredPromise constructor", () => {
it("sets resolve and reject functions", () => {
const deferred = new DeferredPromise();
expect(deferred.promise).toBeInstanceOf(Promise);
expect(deferred.reject).toBeInstanceOf(Function);
expect(deferred.resolve).toBeInstanceOf(Function);
});
});

describe("DeferredPromise.status", () => {
it("returns pending when not yet resolved", () => {
const deferred = new DeferredPromise();
expect(deferred.status).toBe("pending");
});

it("returns fulfilled when resolved", () => {
const deferred = new DeferredPromise();
deferred.resolve(null);
expect(deferred.status).toBe("fulfilled");
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { DeferredPromise, Mutex } from "../../../src";
Fixed Show fixed Hide fixed

function getBlockMock(): Mutex {
return new Mutex();
}

describe("Mutex.tryLock", () => {
it("returns true if the lock was acquired", () => {
const mutex = getBlockMock();
expect(mutex.tryLock()).toBe(true);
});

it("returns false if the lock could not be acquired", async () => {
const mutex = getBlockMock();
await mutex.lock();
expect(mutex.tryLock()).toBe(false);
mutex.unlock();
});
});

describe("Mutex.lock", () => {
it("acquires the lock and returns once acquired", async () => {
const mutex = getBlockMock();
await mutex.lock();
expect(typeof true).toBe("boolean");
});
});

describe("Mutex.unlock", () => {
it("releases the lock and allows for continued execution", async () => {
const mutex = getBlockMock();
const callback = async () => {
await mutex.lock();
expect((mutex as any).mDeferred).not.toBe(null);
expect(typeof true).toBe("boolean");
mutex.unlock();
};
await mutex.lock();
mutex.unlock();
expect((mutex as any).mDeferred).toBe(null);
await callback();
});
});

describe("Mutex.isLocked", () => {
it("returns true when locked", async () => {
const m = new Mutex();
await m.lock();
expect(m.locked).toBe(true);
m.unlock();
});
it("returns false when unlocked", () => {
const m = new Mutex();
expect(m.locked).toBe(false);
});
});
228 changes: 228 additions & 0 deletions packages/zowe-explorer-api/src/profiles/AuthHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/**
* 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 { Gui } from "../globals";
import { CorrelatedError, reloadActiveEditorForProfile, reloadWorkspacesForProfile } from "../utils";
import * as imperative from "@zowe/imperative";
import { IZoweTree, IZoweTreeNode } from "../tree";
import { commands } from "vscode";
import { Mutex } from "../utils/Mutex";

export interface IAuthMethods {
/* Method for establishing SSO login with a given profile name */
ssoLogin: (node?: IZoweTreeNode, profileName?: string) => PromiseLike<boolean>;
/* Method that prompts the user for credentials, sets them on the profile and returns them to the caller if set */
promptCredentials: (profile: string | imperative.IProfileLoaded, rePrompt?: boolean) => PromiseLike<string[]>;
}

export interface AuthPromptParams extends IAuthMethods {
// Whether the profile is using token-based authentication
isUsingTokenAuth?: boolean;
// API-friendly error correlation for the "Invalid Credentials" scenario
errorCorrelation?: CorrelatedError;
}

type ProfileLike = string | imperative.IProfileLoaded;
export class AuthHandler {
private static lockedProfiles: Map<string, Mutex> = new Map();

/**
* Function that checks whether a profile is using token based authentication
* @param {string[]} secureProfileProps Secure properties for the service profile
* @param {string[]} baseSecureProfileProps Base profile's secure properties (optional)
* @returns {Promise<boolean>} a boolean representing whether token based auth is being used or not
*/
public static isUsingTokenAuth(secureProfileProps: string[], baseSecureProfileProps?: string[]): boolean {

Check warning on line 43 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L43

Added line #L43 was not covered by tests
const profileUsesBasicAuth = secureProfileProps.includes("user") && secureProfileProps.includes("password");
if (secureProfileProps.includes("tokenValue")) {
return secureProfileProps.includes("tokenValue") && !profileUsesBasicAuth;
}
return baseSecureProfileProps?.includes("tokenValue") && !profileUsesBasicAuth;
}

/**
* Unlocks the given profile so it can be used again.
* @param profile {ProfileLike} The profile (name or {@link imperative.IProfileLoaded} object) to unlock
* @param refreshResources {boolean} Whether to refresh high-priority resources (active editor & virtual workspace) after unlocking
*/
public static unlockProfile(profile: ProfileLike, refreshResources?: boolean): void {

Check warning on line 56 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L56

Added line #L56 was not covered by tests
const profileName = typeof profile === "string" ? profile : profile.name;
const deferred = this.lockedProfiles.get(profileName);

Check warning on line 58 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L58

Added line #L58 was not covered by tests
if (deferred) {
deferred.unlock();

Check warning on line 60 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L60

Added line #L60 was not covered by tests
if (refreshResources) {
// TODO: Log errors using ZoweLogger once available in ZE API
// refresh an active, unsaved editor if it uses the profile
reloadActiveEditorForProfile(profileName)

Check warning on line 64 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L64

Added line #L64 was not covered by tests
// eslint-disable-next-line no-console
.catch((err) => err instanceof Error && console.error(err.message));

// refresh virtual workspaces for the profile
reloadWorkspacesForProfile(profileName)

Check warning on line 69 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L69

Added line #L69 was not covered by tests
// eslint-disable-next-line no-console
.catch((err) => err instanceof Error && console.error(err.message));
}
}
}

/**
* Prompts the user to authenticate over SSO or a credential prompt in the event of an error.
* @param imperativeError The authentication error that was encountered
* @param profile The profile to authenticate
* @param opts {AuthPromptParams} Prompt parameters (login methods, using token auth, error correlation)
* @returns {boolean} Whether authentication was successful
*/
public static async promptForAuthentication(

Check warning on line 83 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L83

Added line #L83 was not covered by tests
imperativeError: imperative.ImperativeError,
profile: ProfileLike,
opts: AuthPromptParams

Check warning on line 86 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L86

Added line #L86 was not covered by tests
): Promise<boolean> {
const profileName = typeof profile === "string" ? profile : profile.name;
if (imperativeError.mDetails.additionalDetails) {
const tokenError: string = imperativeError.mDetails.additionalDetails;

Check warning on line 90 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L90

Added line #L90 was not covered by tests
if (tokenError.includes("Token is not valid or expired.") || opts.isUsingTokenAuth) {
// Handle token-based authentication error through the given `ssoLogin` method.
const message = "Log in to Authentication Service";

Check warning on line 93 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L93

Added line #L93 was not covered by tests
const userResp = await Gui.showMessage(opts.errorCorrelation?.message ?? imperativeError.message, {
items: [message],
vsCodeOpts: { modal: true },
});
if (userResp === message) {
if (await opts.ssoLogin(null, profileName)) {
// SSO login was successful, unlock profile so it can be used again
AuthHandler.unlockProfile(profileName, true);
return true;

Check warning on line 102 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L101-L102

Added lines #L101 - L102 were not covered by tests
}
}
return false;

Check warning on line 105 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L105

Added line #L105 was not covered by tests
}
}

// Prompt the user to update their credentials using the given `promptCredentials` method.
const checkCredsButton = "Update Credentials";

Check warning on line 110 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L110

Added line #L110 was not covered by tests
const creds = await Gui.errorMessage(opts.errorCorrelation?.message ?? imperativeError.message, {
items: [checkCredsButton],
vsCodeOpts: { modal: true },
}).then(async (selection) => {

Check warning on line 114 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L114

Added line #L114 was not covered by tests
if (selection !== checkCredsButton) {
return;

Check warning on line 116 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L116

Added line #L116 was not covered by tests
}
return opts.promptCredentials(profile, true);

Check warning on line 118 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L118

Added line #L118 was not covered by tests
});

if (creds != null) {
// New creds were set, directly propagate new profile to other tree providers.

// TODO: If we can access extender tree providers (e.g. CICS), it would help to propagate profile updates here.
// For now we will propagate profile changes to core providers (Data Sets, USS, Jobs)
const treeProviders = (await commands.executeCommand("zowe.getTreeProviders")) as any;
for (const provider of [treeProviders.ds, treeProviders.uss, treeProviders.job]) {
const node = (await (provider as IZoweTree<IZoweTreeNode>).getChildren()).find((n) => n.label === profileName);

Check warning on line 128 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L126-L128

Added lines #L126 - L128 were not covered by tests
if (node && typeof profile !== "string") {
node.setProfileToChoice(profile);

Check warning on line 130 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L130

Added line #L130 was not covered by tests
}
}
// Unlock profile so it can be used again
AuthHandler.unlockProfile(profileName, true);
return true;

Check warning on line 135 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L134-L135

Added lines #L134 - L135 were not covered by tests
}
return false;

Check warning on line 137 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L137

Added line #L137 was not covered by tests
}

/**
* Locks the given profile to prevent further use in asynchronous operations (at least where the lock is respected).
* Supports prompting for authentication if an Imperative error and prompt options are given.
* @param profile The profile to lock
* @param imperativeError The Imperative error that was encountered when using the profile
* @param opts Prompt parameters to use during authentication
* @returns Whether the profile was successfully locked
*/
public static async lockProfile(profile: ProfileLike, imperativeError?: imperative.ImperativeError, opts?: AuthPromptParams): Promise<boolean> {

Check warning on line 148 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L148

Added line #L148 was not covered by tests
const profileName = typeof profile === "string" ? profile : profile.name;

// If the mutex does not exist, make one for the profile and acquire the lock
if (!this.lockedProfiles.has(profileName)) {
this.lockedProfiles.set(profileName, new Mutex());

Check warning on line 153 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L153

Added line #L153 was not covered by tests
}

// Attempt to acquire the lock
const mutex = this.lockedProfiles.get(profileName);
await mutex.lock();

Check warning on line 158 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L157-L158

Added lines #L157 - L158 were not covered by tests

// Prompt the user to re-authenticate if an error and options were provided
if (imperativeError && opts) {
const credsEntered = await AuthHandler.promptForAuthentication(imperativeError, profile, opts);

Check warning on line 162 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L162

Added line #L162 was not covered by tests
Fixed Show fixed Hide fixed
if (!credsEntered) {
mutex.unlock();

Check warning on line 164 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L164

Added line #L164 was not covered by tests
}
// Return `true` as the mutex was still locked successfully.
return true;

Check warning on line 167 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L167

Added line #L167 was not covered by tests
}

return true;

Check warning on line 170 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L170

Added line #L170 was not covered by tests
}

/**
* Checks whether the given profile has its lock acquired.
* @param profile The profile to check
* @returns {boolean} `true` if the given profile is locked, `false` otherwise
*/
public static isLocked(profile: ProfileLike): boolean {

Check warning on line 178 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L178

Added line #L178 was not covered by tests
const mutex = this.lockedProfiles.get(typeof profile === "string" ? profile : profile.name);
if (mutex == null) {
return false;

Check warning on line 181 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L181

Added line #L181 was not covered by tests
}

return mutex.locked;

Check warning on line 184 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L184

Added line #L184 was not covered by tests
}

/**
* Non-blocking operation that attempts to acquire the lock for a profile if it can be acquired.
* @param profile The profile to acquire the lock for
* @returns {boolean} `true` if the lock was acquired, `false` otherwise
*/
public static tryToLockProfile(profile: ProfileLike): boolean {

Check warning on line 192 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L192

Added line #L192 was not covered by tests
const mutex = this.lockedProfiles.get(typeof profile === "string" ? profile : profile.name);
if (mutex) {
return mutex.tryLock();

Check warning on line 195 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L195

Added line #L195 was not covered by tests
}
return true;

Check warning on line 197 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L197

Added line #L197 was not covered by tests
}
}

export function withCredentialManagement<T extends (...args: any[]) => unknown | PromiseLike<unknown>>(
authMethods: IAuthMethods,
profile: ProfileLike,
apiMethod: T

Check warning on line 204 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L204

Added line #L204 was not covered by tests
): T {
return async function (...args: any[]) {
await AuthHandler.lockProfile(profile);
try {
const res = await apiMethod(...args);
AuthHandler.unlockProfile(profile);
return res;

Check warning on line 211 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L206-L211

Added lines #L206 - L211 were not covered by tests
} catch (error) {
if (error instanceof imperative.ImperativeError) {
const httpErrorCode = Number(error.mDetails.errorCode);

Check warning on line 214 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L214

Added line #L214 was not covered by tests
if (
httpErrorCode === imperative.RestConstants.HTTP_STATUS_401 ||
error.message.includes("All configured authentication methods failed")

Check warning on line 217 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L217

Added line #L217 was not covered by tests
) {
await AuthHandler.promptForAuthentication(error, profile, { ...authMethods });
return await apiMethod(...args);
} else {
throw error;

Check warning on line 222 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L219-L222

Added lines #L219 - L222 were not covered by tests
}
}
throw error;

Check warning on line 225 in packages/zowe-explorer-api/src/profiles/AuthHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/profiles/AuthHandler.ts#L225

Added line #L225 was not covered by tests
}
} as T;
}
2 changes: 1 addition & 1 deletion packages/zowe-explorer-api/src/profiles/ProfilesCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import * as imperative from "@zowe/imperative";
import type { IRegisterClient } from "../extend/IRegisterClient";
import { FileManagement } from "../utils";
import { FileManagement } from "../utils/FileManagement";
import { Validation } from "./Validation";
import { ZosmfProfile } from "@zowe/zosmf-for-zowe-sdk";
import { ZosTsoProfile } from "@zowe/zos-tso-for-zowe-sdk";
Expand Down
1 change: 1 addition & 0 deletions packages/zowe-explorer-api/src/profiles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*
*/

export * from "./AuthHandler";
export * from "./Validation";
export * from "./UserSettings";
export * from "./ProfilesCache";
Expand Down
49 changes: 49 additions & 0 deletions packages/zowe-explorer-api/src/utils/DeferredPromise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* 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.
*
*/

/* Status of the deferred promise */
export type DeferredPromiseStatus = "pending" | "fulfilled" | "rejected";

/**
* @brief Externally control the resolution and rejection of a promise.
*
* @details
* Creates a promise with accessible `resolve` and `reject` methods, enabling external entities to
* settle the promise based on custom logic or asynchronous events. This is particularly useful when
* the promise's outcome depends on factors outside the immediate context.
*/
export class DeferredPromise<T> {
private mStatus: DeferredPromiseStatus = "pending";

public promise: Promise<T>;
public resolve: (value: T | PromiseLike<T>) => void;
public reject: (reason?: any) => void;

public constructor() {
this.promise = new Promise<T>((resolve, reject) => {
this.resolve = (value): void => {
this.mStatus = "fulfilled";
resolve(value);
};
this.reject = (err): void => {
this.mStatus = "rejected";
reject(err);

Check warning on line 38 in packages/zowe-explorer-api/src/utils/DeferredPromise.ts

View check run for this annotation

Codecov / codecov/patch

packages/zowe-explorer-api/src/utils/DeferredPromise.ts#L37-L38

Added lines #L37 - L38 were not covered by tests
};
});
}

/**
* @returns {PromiseStatus} The status of the deferred promise
*/
public get status(): DeferredPromiseStatus {
return this.mStatus;
}
}
Loading
Loading