diff --git a/packages/zowe-explorer-api/src/profiles/AuthHandler.ts b/packages/zowe-explorer-api/src/profiles/AuthHandler.ts index 4b5e7e795..87804cbb6 100644 --- a/packages/zowe-explorer-api/src/profiles/AuthHandler.ts +++ b/packages/zowe-explorer-api/src/profiles/AuthHandler.ts @@ -32,7 +32,7 @@ export interface AuthPromptParams extends IAuthMethods { type ProfileLike = string | imperative.IProfileLoaded; export class AuthHandler { - private static lockedProfiles: Map = new Map(); + private static profileLocks: Map = new Map(); /** * Function that checks whether a profile is using token based authentication @@ -55,7 +55,8 @@ export class AuthHandler { */ public static unlockProfile(profile: ProfileLike, refreshResources?: boolean): void { const profileName = typeof profile === "string" ? profile : profile.name; - const mutex = this.lockedProfiles.get(profileName); + const mutex = this.profileLocks.get(profileName); + // If a mutex doesn't exist for this profile or the mutex is no longer locked, return if (mutex == null || !mutex.isLocked()) { return; } @@ -151,12 +152,12 @@ export class AuthHandler { 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()); + if (!this.profileLocks.has(profileName)) { + this.profileLocks.set(profileName, new Mutex()); } // Attempt to acquire the lock - const mutex = this.lockedProfiles.get(profileName); + const mutex = this.profileLocks.get(profileName); await mutex.acquire(); // Prompt the user to re-authenticate if an error and options were provided @@ -176,7 +177,7 @@ export class AuthHandler { * @returns {boolean} `true` if the given profile is locked, `false` otherwise */ public static isProfileLocked(profile: ProfileLike): boolean { - const mutex = this.lockedProfiles.get(typeof profile === "string" ? profile : profile.name); + const mutex = this.profileLocks.get(typeof profile === "string" ? profile : profile.name); if (mutex == null) { return false; } diff --git a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts index f341f66d0..e0a193643 100644 --- a/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/utils/ProfilesUtils.unit.test.ts @@ -13,8 +13,14 @@ import * as fs from "fs"; import * as path from "path"; import * as util from "util"; import * as vscode from "vscode"; -import { Gui, imperative, ProfilesCache, ZoweVsCodeExtension } from "@zowe/zowe-explorer-api"; -import { createAltTypeIProfile, createInstanceOfProfile, createValidIProfile } from "../../__mocks__/mockCreators/shared"; +import { AuthHandler, Gui, imperative, ProfilesCache, ZoweVsCodeExtension } from "@zowe/zowe-explorer-api"; +import { + createAltTypeIProfile, + createInstanceOfProfile, + createIProfile, + createISession, + createValidIProfile, +} from "../../__mocks__/mockCreators/shared"; import { MockedProperty } from "../../__mocks__/mockUtils"; import { Constants } from "../../../src/configuration/Constants"; import { ZoweLogger } from "../../../src/tools/ZoweLogger"; @@ -26,6 +32,7 @@ import { ProfilesConvertStatus, ProfilesUtils } from "../../../src/utils/Profile import { AuthUtils } from "../../../src/utils/AuthUtils"; import { ZoweLocalStorage } from "../../../src/tools/ZoweLocalStorage"; import { Definitions } from "../../../src/configuration/Definitions"; +import { createDatasetSessionNode } from "../../__mocks__/mockCreators/datasets"; jest.mock("../../../src/tools/ZoweLogger"); jest.mock("fs"); @@ -378,6 +385,25 @@ describe("ProfilesUtils unit tests", () => { expect(getProfileInfoSpy).toHaveBeenCalled(); }); + it("calls unlockProfile once credentials are provided", async () => { + const mockProfileInstance = new Profiles(imperative.Logger.getAppLogger()); + const promptCredentialsProfilesMock = jest.spyOn(mockProfileInstance, "promptCredentials").mockResolvedValueOnce(["someusername", "pw"]); + const updateCachedProfileMock = jest.spyOn(mockProfileInstance, "updateCachedProfile").mockResolvedValueOnce(undefined); + const profile = createIProfile(); + jest.spyOn(mockProfileInstance, "getLoadedProfConfig").mockResolvedValue(profile); + Object.defineProperty(Constants, "PROFILES_CACHE", { value: mockProfileInstance, configurable: true }); + jest.spyOn(ZoweVsCodeExtension as any, "promptUserPass").mockResolvedValue([]); + const unlockProfileSpy = jest.spyOn(AuthHandler, "unlockProfile"); + const mockNode = createDatasetSessionNode(createISession(), profile); + await ProfilesUtils.promptCredentials(mockNode); + expect(promptCredentialsProfilesMock).toHaveBeenCalledTimes(1); + expect(promptCredentialsProfilesMock).toHaveBeenCalledWith(profile, true); + expect(unlockProfileSpy).toHaveBeenCalledTimes(1); + expect(unlockProfileSpy).toHaveBeenCalledWith(profile); + expect(updateCachedProfileMock).toHaveBeenCalledTimes(1); + expect(updateCachedProfileMock).toHaveBeenCalledWith(profile, mockNode); + }); + it("shows an error message if the profile input is undefined", async () => { const mockProfileInstance = new Profiles(imperative.Logger.getAppLogger()); jest.spyOn(ProfilesCache.prototype, "getProfileInfo").mockResolvedValue(prof as unknown as imperative.ProfileInfo); diff --git a/packages/zowe-explorer/src/utils/ProfilesUtils.ts b/packages/zowe-explorer/src/utils/ProfilesUtils.ts index da4e75f1a..e0c366e1e 100644 --- a/packages/zowe-explorer/src/utils/ProfilesUtils.ts +++ b/packages/zowe-explorer/src/utils/ProfilesUtils.ts @@ -461,9 +461,7 @@ export class ProfilesUtils { args: [typeof profile === "string" ? profile : profile.name], comment: ["Profile name"], }); - if (AuthHandler.isProfileLocked(profile)) { - AuthHandler.unlockProfile(profile); - } + AuthHandler.unlockProfile(profile); if (typeof profile !== "string") { await Constants.PROFILES_CACHE.updateCachedProfile(profile, node); }