Skip to content

Commit

Permalink
Merge pull request #580 from zowe/Issue-370
Browse files Browse the repository at this point in the history
redo reprompt Cred
  • Loading branch information
jellypuno authored Mar 16, 2020
2 parents 62dd30a + bd36d22 commit e0bf66a
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 35 deletions.
112 changes: 100 additions & 12 deletions __tests__/__unit__/DatasetTree.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,6 @@ describe("DatasetTree Unit Tests", () => {
failNotFound: false
};
mockLoadNamedProfile.mockReturnValue(profileOne);
Object.defineProperty(Profiles, "getInstance", {
value: jest.fn(() => {
return {
allProfiles: [{name: "firstName"}, {name: "secondName"}],
defaultProfile: {name: "firstName"},
loadNamedProfile: mockLoadNamedProfile
};
})
});
const testTree = new DatasetTree();
testTree.mSessionNodes.push(new ZoweDatasetNode("testSess", vscode.TreeItemCollapsibleState.Collapsed,
null, session, undefined, undefined, profileOne));
Expand All @@ -135,6 +126,17 @@ describe("DatasetTree Unit Tests", () => {
withProgress.mockImplementation((progLocation, callback) => {
return callback();
});
Object.defineProperty(Profiles, "getInstance", {
value: jest.fn(() => {
return {
allProfiles: [{name: "firstName"}, {name: "secondName"}],
defaultProfile: {name: "firstName"},
loadNamedProfile: mockLoadNamedProfile,
promptCredentials: jest.fn(),
updateProfile: jest.fn()
};
})
});
});

afterAll(() => {
Expand Down Expand Up @@ -459,7 +461,7 @@ describe("DatasetTree Unit Tests", () => {
defaultProfile: {name: "firstName"},
loadNamedProfile: mockLoadNamedProfile,
promptCredentials: jest.fn(()=> {
return [{values: "fake"}, {values: "fake"}, {values: "fake"}];
return ["fake", "fake", "fake"];
}),
};
})
Expand Down Expand Up @@ -489,7 +491,7 @@ describe("DatasetTree Unit Tests", () => {
defaultProfile: {name: "firstName"},
loadNamedProfile: mockLoadNamedProfile,
promptCredentials: jest.fn(()=> {
return [{values: "fake"}, {values: "fake"}, {values: "fake"}];
return ["fake", "fake", "fake"];
}),
};
})
Expand Down Expand Up @@ -717,6 +719,53 @@ describe("DatasetTree Unit Tests", () => {
expect(testTree.mFavorites[0].label).toBe(`[${sessionNode.label.trim()}]: ${newLabel}`);
});

it("Should rename a PDS dataset", async () => {
const sessionNode = testTree.mSessionNodes[1];
const newLabel = "USER.NEW.LABEL";
testTree.mFavorites = [];
const node = new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.Collapsed, sessionNode, null);
const checkSession = jest.spyOn(testTree, "rename");
node.label = `[${sessionNode.label.trim()}]: ${node.label}`;
testTree.rename(node);
expect(checkSession).toHaveBeenCalledTimes(1);
});

it("Should rename a DS and DS_FAV dataset", async () => {
const sessionNode = testTree.mSessionNodes[1];
const newLabel = "USER.NEW.LABEL";
testTree.mFavorites = [];
const node = new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.Collapsed, sessionNode, null);
const checkSession = jest.spyOn(testTree, "rename");
node.label = `[${sessionNode.label.trim()}]: ${node.label}`;
node.contextValue = "ds";
testTree.rename(node);
expect(checkSession).toHaveBeenCalledTimes(2);

node.contextValue = "ds_fav";
testTree.rename(node);
// tslint:disable-next-line: no-magic-numbers
expect(checkSession).toHaveBeenCalledTimes(3);

});

it("Should rename a Member and Member_FAV dataset", async () => {
const sessionNode = testTree.mSessionNodes[1];
const newLabel = "USER.NEW.LABEL";
testTree.mFavorites = [];
const node = new ZoweDatasetNode("node", vscode.TreeItemCollapsibleState.Collapsed, sessionNode, null);
const checkSession = jest.spyOn(testTree, "rename");
node.label = `[${sessionNode.label.trim()}]: ${node.label}`;
node.contextValue = "member";
testTree.rename(node);
// tslint:disable-next-line: no-magic-numbers
expect(checkSession).toHaveBeenCalledTimes(4);

node.contextValue = "member_fav";
testTree.rename(node);
// tslint:disable-next-line: no-magic-numbers
expect(checkSession).toHaveBeenCalledTimes(5);
});

it("Should rename a node", async () => {
const sessionNode = testTree.mSessionNodes[1];
const newLabel = "USER.NEW.LABEL";
Expand Down Expand Up @@ -749,7 +798,7 @@ describe("DatasetTree Unit Tests", () => {
allProfiles: [{name: "firstName", profile: {user:undefined, password: undefined}}, {name: "secondName"}],
defaultProfile: {name: "firstName"},
promptCredentials: jest.fn(()=> {
return [{values: "fake"}, {values: "fake"}, {values: "fake"}];
return ["fake", "fake", "fake"];
}),
};
})
Expand Down Expand Up @@ -938,6 +987,45 @@ describe("DatasetTree Unit Tests", () => {
showQuickPick.mockReset();
showInputBox.mockReset();
showErrorMessage.mockReset();
showErrorMessage.mockResolvedValueOnce("Check Credentials");

const label = "invalidCred";
// tslint:disable-next-line: object-literal-key-quotes
const error = {"mDetails": {"errorCode": 401}};
await utils.errorHandling(error, label);

expect(showErrorMessage.mock.calls.length).toEqual(1);
expect(showErrorMessage.mock.calls[0][0]).toEqual("Invalid Credentials. Please ensure the username and password for " +
`\n${label}\n` +
" are valid or this may lead to a lock-out.");
});

it("tests utils error handling USS", async () => {
showQuickPick.mockReset();
showInputBox.mockReset();
showErrorMessage.mockReset();
showErrorMessage.mockResolvedValueOnce("Check Credentials");

const label = "invalidCred [/tmp]";
// tslint:disable-next-line: object-literal-key-quotes
const error = {"mDetails": {"errorCode": 401}};
await utils.errorHandling(error, label);

expect(showErrorMessage.mock.calls.length).toEqual(1);
expect(showErrorMessage.mock.calls[0][0]).toEqual("Invalid Credentials. Please ensure the username and password for " +
`\n${label}\n` +
" are valid or this may lead to a lock-out.");
});

it("tests utils error handling: Theia", async () => {
showQuickPick.mockReset();
showInputBox.mockReset();
showErrorMessage.mockReset();

showErrorMessage.mockResolvedValueOnce("Check Credentials");

const theia = true;
Object.defineProperty(extension, "ISTHEIA", { get: () => theia });

const label = "invalidCred";
// tslint:disable-next-line: object-literal-key-quotes
Expand Down
28 changes: 24 additions & 4 deletions __tests__/__unit__/Profiles.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import * as path from "path";
import * as os from "os";
import * as vscode from "vscode";
import * as child_process from "child_process";
import { Logger, ISession } from "@zowe/imperative";
import { Logger, ISession, CliProfileManager } from "@zowe/imperative";
import { Profiles } from "../../src/Profiles";
import { ZosmfSession } from "@zowe/cli";

Expand Down Expand Up @@ -132,6 +132,9 @@ describe("Profile class unit tests", () => {
validateAndParseUrl: jest.fn(()=>{
return {};
}),
updateProfile: jest.fn(()=>{
return {};
}),
};
})
});
Expand Down Expand Up @@ -275,12 +278,29 @@ describe("Profile class unit tests", () => {
showInputBox.mockResolvedValueOnce("fake");
showInputBox.mockResolvedValueOnce("fake");
const res = await profiles.promptCredentials(promptProfile.name);
expect(res[0]).toBe("fake");
expect(res[1]).toBe("fake");
expect(res[2]).toBe("fake");
expect(res).toEqual(["fake", "fake", "fake"]);
(profiles.loadNamedProfile as any).mockReset();
});

it("should rePrompt credentials", async () => {
const promptProfile = {name: "profile1", profile: {user: "oldfake", password: "oldfake"}};
profiles.loadNamedProfile = jest.fn(() => {
return promptProfile as any;
});

Object.defineProperty(ZosmfSession, "createBasicZosmfSession", {
value: jest.fn(() => {
return { ISession: {user: "fake", password: "fake", base64EncodedAuth: "fake"} };
})
});

showInputBox.mockResolvedValueOnce("fake");
showInputBox.mockResolvedValueOnce("fake");
const res = await profiles.promptCredentials(promptProfile.name, true);
expect(res).toEqual(["fake", "fake", "fake"]);
(profiles.loadNamedProfile as any).mockReset();
});

it("should prompt credentials: username invalid", async () => {
const promptProfile = {name: "profile1", profile: {user: undefined, password: undefined}};
profiles.loadNamedProfile = jest.fn(() => {
Expand Down
5 changes: 2 additions & 3 deletions i18n/sample/src/utils.i18n.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"zosJobsProvider.option.prompt.createOwner": "Owner/Prefix Job Search",
"zosJobsProvider.option.prompt.createId": "Job Id search",
"errorHandling.invalid.credentials": "Invalid Credentials. ",
"errorHandling.invalid.credentials2": "Please ensure the username and password for ",
"errorHandling.invalid.credentials3": " are valid or this may lead to a lock-out."
"errorHandling.invalid.credentials": "Invalid Credentials. Please ensure the username and password for ",
"errorHandling.invalid.credentials2": " are valid or this may lead to a lock-out."
}
50 changes: 45 additions & 5 deletions src/Profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* *
*/

import { IProfileLoaded, Logger, CliProfileManager, IProfile, ISession, ImperativeConfig } from "@zowe/imperative";
import { IProfileLoaded, Logger, CliProfileManager, IProfile, ISession, IUpdateProfile } from "@zowe/imperative";
import * as nls from "vscode-nls";
import * as path from "path";
import { URL } from "url";
Expand Down Expand Up @@ -49,7 +49,7 @@ export class Profiles {
private static loader: Profiles;

public allProfiles: IProfileLoaded[] = [];

public loadedProfile: IProfileLoaded;
private profilesByType = new Map<string, IProfileLoaded[]>();
private defaultProfileByType = new Map<string, IProfileLoaded>();
private profileManagerByType= new Map<string, CliProfileManager>();
Expand Down Expand Up @@ -242,15 +242,20 @@ export class Profiles {
return profileName;
}

public async promptCredentials(sessName) {
public async promptCredentials(sessName, rePrompt?: boolean) {
let userName: string;
let passWord: string;
let options: vscode.InputBoxOptions;

const loadProfile = this.loadNamedProfile(sessName.trim());
const loadSession = loadProfile.profile as ISession;

if (!loadSession.user) {
if (rePrompt) {
userName = loadSession.user;
passWord = loadSession.password;
}

if (!loadSession.user || rePrompt) {

options = {
placeHolder: localize("promptcredentials.option.prompt.username.placeholder", "User Name"),
Expand All @@ -268,7 +273,7 @@ export class Profiles {
}
}

if (!loadSession.password) {
if (!loadSession.password || rePrompt) {
passWord = loadSession.password;

options = {
Expand All @@ -288,9 +293,44 @@ export class Profiles {
}
}
const updSession = await zowe.ZosmfSession.createBasicZosmfSession(loadSession as IProfile);
if (rePrompt) {
await this.updateProfile(loadProfile);
}
return [updSession.ISession.user, updSession.ISession.password, updSession.ISession.base64EncodedAuth];
}

private async updateProfile(ProfileInfo) {

for (const type of ZoweExplorerApiRegister.getInstance().registeredApiTypes()) {
const profileManager = await this.getCliProfileManager(type);
this.loadedProfile = (await profileManager.load({ name: ProfileInfo.name }));
}


const OrigProfileInfo = this.loadedProfile.profile as ISession;
const NewProfileInfo = ProfileInfo.profile;

if (OrigProfileInfo.user) {
OrigProfileInfo.user = NewProfileInfo.user;
}

if (OrigProfileInfo.password) {
OrigProfileInfo.password = NewProfileInfo.password;
}

const updateParms: IUpdateProfile = {
name: this.loadedProfile.name,
merge: true,
profile: OrigProfileInfo as IProfile
};

try {
(await this.getCliProfileManager(this.loadedProfile.type)).update(updateParms);
} catch (error) {
vscode.window.showErrorMessage(error.message);
}
}

private async saveProfile(ProfileInfo, ProfileName, ProfileType) {
let zosmfProfile: IProfile;
try {
Expand Down
4 changes: 0 additions & 4 deletions src/dataset/dsNodeActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,8 @@ import * as nls from "vscode-nls";
const localize = nls.config({messageFormat: nls.MessageFormat.file})();
import * as extension from "../extension";
import { Profiles } from "../Profiles";
import { ISession, Logger } from "@zowe/imperative";
import { DatasetTree } from "../DatasetTree";
import { IZoweTree } from "../api/IZoweTree";
import { IZoweDatasetTreeNode } from "../api/IZoweTreeNode";
// tslint:disable-next-line: prefer-const
let log: Logger;
/**
* Refreshes treeView
*
Expand Down
4 changes: 2 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ export async function addZoweSession(zoweFileProvider: IZoweTree<IZoweDatasetTre

const allProfiles = (await Profiles.getInstance()).allProfiles;
const createNewProfile = "Create a New Connection to z/OS";
let chosenProfile: string;
let chosenProfile: string = "";

// Get all profiles
let profileNamesList = allProfiles.map((profile) => {
Expand Down Expand Up @@ -717,7 +717,7 @@ export async function addZoweSession(zoweFileProvider: IZoweTree<IZoweDatasetTre
"Profile Name was not supplied. Operation Cancelled"));
return;
}
chosenProfile = profileName;
chosenProfile = profileName.trim();
log.debug(localize("addSession.log.debug.createNewProfile", "User created a new profile"));
try {
newprofile = await Profiles.getInstance().createNewConnection(chosenProfile);
Expand Down
24 changes: 19 additions & 5 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
* *
*/

import { TreeItem, QuickPickItem, QuickPick, window } from "vscode";
import { TreeItem, QuickPickItem, QuickPick, window, TreeItemCollapsibleState } from "vscode";
import * as extension from "../src/extension";
import { ISession } from "@zowe/imperative";
import { Profiles } from "./Profiles";
import * as nls from "vscode-nls";
Expand Down Expand Up @@ -104,6 +105,8 @@ export function getAppName(isTheia: boolean) {
*************************************************************************************************************/
export function errorHandling(errorDetails: any, label?: string, moreInfo?: string) {
let httpErrCode = null;
const errMsg = localize("errorHandling.invalid.credentials", "Invalid Credentials. Please ensure the username and password for ") +
`\n${label}\n` + localize("errorHandling.invalid.credentials2"," are valid or this may lead to a lock-out.");

if (errorDetails.mDetails !== undefined) {
httpErrCode = errorDetails.mDetails.errorCode;
Expand All @@ -112,10 +115,20 @@ export function errorHandling(errorDetails: any, label?: string, moreInfo?: stri
switch(httpErrCode) {
// tslint:disable-next-line: no-magic-numbers
case 401 : {
window.showErrorMessage(localize("errorHandling.invalid.credentials", "Invalid Credentials. ") +
localize("errorHandling.invalid.credentials2","Please ensure the username and password for ") +
`\n${label}\n` +
localize("errorHandling.invalid.credentials3", " are valid or this may lead to a lock-out."));
if (label.includes("[")) {
label = label.substring(0, label.indexOf(" ["));
}

if (extension.ISTHEIA) {
window.showErrorMessage(errMsg);
Profiles.getInstance().promptCredentials(label.trim());
} else {
window.showErrorMessage(errMsg, "Check Credentials").then((selection) => {
if (selection) {
Profiles.getInstance().promptCredentials(label.trim(), true);
}
});
}
break;
}
default: {
Expand Down Expand Up @@ -147,4 +160,5 @@ export function refreshTree(sessNode: IZoweTreeNode) {
}
}
}
sessNode.collapsibleState = TreeItemCollapsibleState.Collapsed;
}

0 comments on commit e0bf66a

Please sign in to comment.