Skip to content

Commit

Permalink
WIP Port fixes for credentials not refreshed in ds tree
Browse files Browse the repository at this point in the history
Signed-off-by: Timothy Johnson <[email protected]>
  • Loading branch information
t1m0thyj committed Dec 2, 2024
1 parent 4e42361 commit 2a1ba18
Show file tree
Hide file tree
Showing 17 changed files with 325 additions and 250 deletions.
1 change: 1 addition & 0 deletions packages/zowe-explorer-api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t
### Bug fixes

- Fixed an issue where the `responseTimeout` profile property was ignored for z/OSMF MVS and USS API calls. [#3225](https://github.com/zowe/zowe-explorer-vscode/issues/3225)
- Deprecated the method `ProfilesCache.updateProfilesArrays`. Use `ProfilesCache.updateCachedProfile` instead, which handles updating credentials cached in memory when `autoStore` is false. [#3120](https://github.com/zowe/zowe-explorer-vscode/issues/3120)

## `2.18.0`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,35 @@ describe("ProfilesCache", () => {
expect((profCache as any).defaultProfileByType.get("zosmf").profile).toMatchObject(lpar2Profile.profile);
});

it("updateCachedProfile should refresh all profiles when autoStore is true", async () => {
const profCache = new ProfilesCache(fakeLogger as unknown as zowe.imperative.Logger);
jest.spyOn(profCache, "getProfileInfo").mockResolvedValueOnce({
getTeamConfig: jest.fn().mockReturnValue({ properties: { autoStore: true } }),
} as unknown as zowe.imperative.ProfileInfo);
const refreshSpy = jest.spyOn(profCache, "refresh").mockImplementation();
await profCache.updateCachedProfile({
...lpar1Profile,
profile: lpar2Profile.profile,
} as zowe.imperative.IProfileLoaded);
expect(refreshSpy).toHaveBeenCalledTimes(1);
});

it("updateCachedProfile should update cached profile when autoStore is false", async () => {
const profCache = new ProfilesCache(fakeLogger as unknown as zowe.imperative.Logger);
profCache.allProfiles = [lpar1Profile as zowe.imperative.IProfileLoaded];
(profCache as any).defaultProfileByType = new Map([["zosmf", { ...profCache.allProfiles[0] }]]);
expect(profCache.allProfiles[0].profile).toMatchObject(lpar1Profile.profile);
jest.spyOn(profCache, "getProfileInfo").mockResolvedValueOnce({
getTeamConfig: jest.fn().mockReturnValue({ properties: { autoStore: false } }),
} as unknown as zowe.imperative.ProfileInfo);
await profCache.updateCachedProfile({
...lpar1Profile,
profile: lpar2Profile.profile,
} as zowe.imperative.IProfileLoaded);
expect(profCache.allProfiles[0].profile).toMatchObject(lpar2Profile.profile);
expect((profCache as any).defaultProfileByType.get("zosmf").profile).toMatchObject(lpar2Profile.profile);
});

it("getDefaultProfile should find default profile given type", () => {
const profCache = new ProfilesCache(fakeLogger as unknown as zowe.imperative.Logger);
(profCache as any).defaultProfileByType = new Map([["zosmf", lpar1Profile]]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ import * as vscode from "vscode";
import { ZoweTreeNode } from "../../../src/tree/ZoweTreeNode";
import { IZoweTreeNode } from "../../../src/tree/IZoweTreeNode";
import { imperative } from "@zowe/cli";

describe("ZoweTreeNode", () => {
const innerProfile = { user: "apple", password: "banana" };
const fakeProfile: imperative.IProfileLoaded = {
name: "amazingProfile",
profile: innerProfile,
message: "",
type: "zosmf",
failNotFound: true,
};

const makeNode = (
name: string,
collapseState: vscode.TreeItemCollapsibleState,
Expand Down Expand Up @@ -46,8 +56,8 @@ describe("ZoweTreeNode", () => {

it("getProfile should return profile of current node", () => {
const node = makeNode("test", vscode.TreeItemCollapsibleState.None, undefined);
node.setProfileToChoice("myProfile" as unknown as imperative.IProfileLoaded);
expect(node.getProfile()).toBe("myProfile");
node.setProfileToChoice(fakeProfile);
expect(node.getProfile().name).toBe("amazingProfile");
});

it("getProfile should return profile of parent node", () => {
Expand Down Expand Up @@ -78,4 +88,28 @@ describe("ZoweTreeNode", () => {
expect(node.getProfile()).toBeUndefined();
expect(node.getProfileName()).toBeUndefined();
});

it("setProfileToChoice should update properties on existing profile object", () => {
const node = makeNode("test", vscode.TreeItemCollapsibleState.None, undefined, undefined, {
...fakeProfile,
});
node.setProfileToChoice({ ...fakeProfile, profile: { host: "example.com", port: 443 } });
expect(node.getProfile().profile?.port).toBeDefined();
});

it("setProfileToChoice should update child nodes with the new profile", () => {
const node = makeNode("test", vscode.TreeItemCollapsibleState.Expanded, undefined);
node.setProfileToChoice({ ...fakeProfile, profile: { ...fakeProfile.profile, user: "banana" } });
const nodeChild = makeNode("child", vscode.TreeItemCollapsibleState.None, undefined);
nodeChild.setProfileToChoice(node.getProfile());
node.children = [nodeChild as any];
const fsEntry = {
metadata: {
profile: node.getProfile(),
},
};
expect(node.getProfile().profile?.user).toBe("banana");
expect(nodeChild.getProfile().profile?.user).toBe("banana");
expect(fsEntry.metadata.profile.profile?.user).toBe("banana");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ describe("ZoweVsCodeExtension", () => {
mergeArgsForProfile: jest.fn().mockReturnValue({ knownArgs: [] }),
}),
refresh: jest.fn(),
updateCachedProfile: jest.fn(),
};

beforeEach(() => {
Expand Down Expand Up @@ -460,6 +461,7 @@ describe("ZoweVsCodeExtension", () => {
updateProperty: mockUpdateProperty,
}),
refresh: jest.fn(),
updateCachedProfile: jest.fn(),
});
const showInputBoxSpy = jest.spyOn(Gui, "showInputBox").mockResolvedValueOnce("fakeUser").mockResolvedValueOnce("fakePassword");
const saveCredentialsSpy = jest.spyOn(ZoweVsCodeExtension as any, "saveCredentials");
Expand All @@ -485,6 +487,7 @@ describe("ZoweVsCodeExtension", () => {
updateProperty: mockUpdateProperty,
}),
refresh: jest.fn(),
updateCachedProfile: jest.fn(),
});
const showInputBoxSpy = jest.spyOn(Gui, "showInputBox").mockResolvedValueOnce("fakeUser").mockResolvedValueOnce("fakePassword");
const saveCredentialsSpy = jest.spyOn(ZoweVsCodeExtension as any, "saveCredentials");
Expand Down Expand Up @@ -513,6 +516,7 @@ describe("ZoweVsCodeExtension", () => {
updateProperty: mockUpdateProperty,
}),
refresh: jest.fn(),
updateCachedProfile: jest.fn(),
});
const showInputBoxSpy = jest.spyOn(Gui, "showInputBox").mockResolvedValueOnce("fakeUser").mockResolvedValueOnce("fakePassword");
jest.spyOn(Gui, "showMessage").mockResolvedValueOnce("yes");
Expand All @@ -539,6 +543,7 @@ describe("ZoweVsCodeExtension", () => {
updateProperty: mockUpdateProperty,
}),
refresh: jest.fn(),
updateCachedProfile: jest.fn(),
});
const showInputBoxSpy = jest.spyOn(Gui, "showInputBox").mockResolvedValueOnce("fakeUser").mockResolvedValueOnce("fakePassword");
jest.spyOn(Gui, "showMessage").mockResolvedValueOnce(undefined);
Expand Down
23 changes: 21 additions & 2 deletions packages/zowe-explorer-api/src/profiles/ProfilesCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { URL } from "url";

import * as zowe from "@zowe/cli";
import { ZoweExplorerApi } from "./ZoweExplorerApi";
import { IZoweNodeType } from "../tree";

// TODO: find a home for constants
export const CONTEXT_PREFIX = "_";
Expand Down Expand Up @@ -127,9 +128,8 @@ export class ProfilesCache {

/**
* Updates profile in allProfiles array and if default updates defaultProfileByType
*
* @deprecated Use `updateCachedProfile` instead
* @param {string} profileLoaded
*
* @returns {void}
*/
public updateProfilesArrays(profileLoaded: zowe.imperative.IProfileLoaded): void {
Expand All @@ -145,6 +145,25 @@ export class ProfilesCache {
}
}

public async updateCachedProfile(
profileLoaded: zowe.imperative.IProfileLoaded,
profileNode?: IZoweNodeType,
zeRegister?: ZoweExplorerApi.IApiRegisterClient
): Promise<void> {
if ((await this.getProfileInfo()).getTeamConfig().properties.autoStore) {
await this.refresh(zeRegister);
} else {
// Note: When autoStore is disabled, nested profiles within this service profile may not have their credentials updated.
const profIndex = this.allProfiles.findIndex((profile) => profile.type === profileLoaded.type && profile.name === profileLoaded.name);
this.allProfiles[profIndex].profile = profileLoaded.profile;
const defaultProf = this.defaultProfileByType.get(profileLoaded.type);
if (defaultProf != null && defaultProf.name === profileLoaded.name) {
this.defaultProfileByType.set(profileLoaded.type, profileLoaded);
}
}
profileNode?.setProfileToChoice(profileLoaded);
}

/**
* This returns default profile by type from defaultProfileByType
*
Expand Down
3 changes: 2 additions & 1 deletion packages/zowe-explorer-api/src/tree/ZoweTreeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ export class ZoweTreeNode extends vscode.TreeItem {
* @param {imperative.IProfileLoaded} The profile you will set the node to use
*/
public setProfileToChoice(aProfile: imperative.IProfileLoaded): void {
this.profile = aProfile;
// Don't reassign profile if its already defined, as we want to keep the reference valid for other nodes
this.profile = Object.assign(this.profile ?? {}, aProfile);
}
/**
* Sets the session for this node to the one chosen in parameters.
Expand Down
30 changes: 8 additions & 22 deletions packages/zowe-explorer-api/src/vscode/ZoweVsCodeExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class ZoweVsCodeExtension {
options: IPromptCredentialsOptions,
apiRegister: ZoweExplorerApi.IApiRegisterClient
): Promise<imperative.IProfileLoaded> {
const cache = ZoweVsCodeExtension.profilesCache;
const cache = options.zeProfiles ?? ZoweVsCodeExtension.profilesCache;
const profInfo = await cache.getProfileInfo();
const setSecure = options.secure ?? profInfo.isSecured();

Expand Down Expand Up @@ -143,7 +143,7 @@ export class ZoweVsCodeExtension {
await profInfo.updateProperty({ ...upd, property: "user", value: creds[0], setSecure });
await profInfo.updateProperty({ ...upd, property: "password", value: creds[1], setSecure });
}
await cache.refresh(apiRegister);
await cache.updateCachedProfile(loadProfile, undefined, apiRegister);

return loadProfile;
}
Expand Down Expand Up @@ -228,23 +228,11 @@ export class ZoweVsCodeExtension {
// If base profile already has a token type stored, then we check whether or not the connection details are the same
(serviceProfile.profile.host === baseProfile.profile.host && serviceProfile.profile.port === baseProfile.profile.port);
// If the connection details do not match, then we MUST forcefully store the token in the service profile
let profileToUpdate: imperative.IProfileLoaded;
if (connOk) {
profileToUpdate = baseProfile;
} else {
profileToUpdate = serviceProfile;
}
const profileToUpdate = connOk ? baseProfile : serviceProfile;

await cache.updateBaseProfileFileLogin(profileToUpdate, updBaseProfile, !connOk);
const baseIndex = cache.allProfiles.findIndex((profile) => profile.name === profileToUpdate.name);
cache.allProfiles[baseIndex] = { ...profileToUpdate, profile: { ...profileToUpdate.profile, ...updBaseProfile } };

if (node) {
node.setProfileToChoice({
...node.getProfile(),
profile: { ...node.getProfile().profile, ...updBaseProfile },
});
}
serviceProfile.profile = { ...serviceProfile.profile, ...updBaseProfile };
await cache.updateCachedProfile(serviceProfile, node);
return true;
}

Expand Down Expand Up @@ -283,11 +271,9 @@ export class ZoweVsCodeExtension {
await (zeRegister?.getCommonApi(serviceProfile).logout ?? Logout.apimlLogout)(updSession);

const connOk = serviceProfile.profile.host === baseProfile.profile.host && serviceProfile.profile.port === baseProfile.profile.port;
if (connOk) {
await cache.updateBaseProfileFileLogout(baseProfile);
} else {
await cache.updateBaseProfileFileLogout(serviceProfile);
}
await cache.updateBaseProfileFileLogout(connOk ? baseProfile : serviceProfile);
serviceProfile.profile = { ...serviceProfile.profile, tokenType: undefined, tokenValue: undefined };
await cache.updateCachedProfile(serviceProfile);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import { imperative } from "@zowe/cli";
import { InputBoxOptions, OpenDialogOptions } from "vscode";
import { ProfilesCache } from "../../profiles";

export interface IPromptCredentialsCommonOptions {
rePrompt?: boolean;
Expand All @@ -23,6 +24,7 @@ export interface IPromptCredentialsOptions extends IPromptCredentialsCommonOptio
sessionName?: string;
sessionType?: string;
secure?: boolean;
zeProfiles?: ProfilesCache;
}

export interface IPromptUserPassOptions extends IPromptCredentialsCommonOptions {
Expand Down
2 changes: 2 additions & 0 deletions packages/zowe-explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen
- Fixed an issue where a migrated data set is unusable after it is recalled through Zowe Explorer. [#3294](https://github.com/zowe/zowe-explorer-vscode/issues/3294)
- Fixed an issue where a recalled PDS is expandable after it is migrated through Zowe Explorer. [#3294](https://github.com/zowe/zowe-explorer-vscode/issues/3294)
- Fixed an issue where data set nodes did not update if migrated or recalled outside of Zowe Explorer. [#3294](https://github.com/zowe/zowe-explorer-vscode/issues/3294)
- Fixed issue where Search operation did not prompt for credentials if profile contains expired token. [#2259](https://github.com/zowe/zowe-explorer-vscode/issues/2259)
- Fixed issue where inactive status was not displayed for profiles loaded from Global Config. [#3134](https://github.com/zowe/zowe-explorer-vscode/issues/3134)

## `2.18.0`

Expand Down
25 changes: 25 additions & 0 deletions packages/zowe-explorer/__mocks__/vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,31 @@
*
*/

/**
* A location in the editor at which progress information can be shown. It depends on the
* location how progress is visually represented.
*/
export enum ProgressLocation {
/**
* Show progress for the source control viewlet, as overlay for the icon and as progress bar
* inside the viewlet (when visible). Neither supports cancellation nor discrete progress nor
* a label to describe the operation.
*/
SourceControl = 1,

/**
* Show progress in the status bar of the editor. Neither supports cancellation nor discrete progress.
* Supports rendering of {@link ThemeIcon theme icons} via the `$(<name>)`-syntax in the progress label.
*/
Window = 10,

/**
* Show progress as notification with an optional cancel button. Supports to show infinite and discrete
* progress but does not support rendering of icons.
*/
Notification = 15,
}

export enum ViewColumn {
/**
* A *symbolic* editor column representing the currently active column. This value
Expand Down
Loading

0 comments on commit 2a1ba18

Please sign in to comment.