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

redo reprompt Cred #580

Merged
merged 11 commits into from
Mar 16, 2020
95 changes: 83 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,36 @@ describe("DatasetTree Unit Tests", () => {
expect(testTree.mFavorites[0].label).toBe(`[${sessionNode.label.trim()}]: ${newLabel}`);
});

it("Should rename a dataset", async () => {
stepanzharychevbroadcom marked this conversation as resolved.
Show resolved Hide resolved
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);

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);

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 +781,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 +970,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
26 changes: 25 additions & 1 deletion __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 @@ -281,6 +284,27 @@ describe("Profile class unit tests", () => {
(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[0]).toBe("fake");
stepanzharychevbroadcom marked this conversation as resolved.
Show resolved Hide resolved
expect(res[1]).toBe("fake");
expect(res[2]).toBe("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 @@ -633,7 +633,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 @@ -716,7 +716,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;
}