diff --git a/src/commands/serverCommand.ts b/src/commands/serverCommand.ts index ae6f237f..7a2f9538 100644 --- a/src/commands/serverCommand.ts +++ b/src/commands/serverCommand.ts @@ -135,7 +135,7 @@ export async function addAuthConnection( serverKey: string, username: string, password: string, -): void { +): Promise { const validUsername = validateServerUsername(username); if (validUsername) { window.showErrorMessage(validUsername); @@ -201,7 +201,7 @@ export async function enableTLS(serverKey: string): Promise { export async function addKdbConnection( kdbData: ServerDetails, isLocal?: boolean, -): void { +): Promise { const aliasValidation = validateServerAlias(kdbData.serverAlias, isLocal!); const hostnameValidation = validateServerName(kdbData.serverName); const portValidation = validateServerPort(kdbData.serverPort); diff --git a/src/validators/kdbValidator.ts b/src/validators/kdbValidator.ts index 01c0dfa2..6c2df662 100644 --- a/src/validators/kdbValidator.ts +++ b/src/validators/kdbValidator.ts @@ -33,7 +33,7 @@ export function validateServerAlias( return "Input value using restricted keywords of Insights Enterprise"; } - if (!isLocal && input === "Local") { + if (!isLocal && input.toLowerCase() === "local") { return "Input value using restricted keywords of Local for Bundle q Server"; } } diff --git a/test/suite/commands.test.ts b/test/suite/commands.test.ts index abe6722f..ee7e1e07 100644 --- a/test/suite/commands.test.ts +++ b/test/suite/commands.test.ts @@ -28,7 +28,7 @@ import { createDefaultDataSourceFile, } from "../../src/models/dataSource"; import { ExecutionTypes } from "../../src/models/execution"; -import { Insights } from "../../src/models/insights"; +import { InsightDetails, Insights } from "../../src/models/insights"; import { ScratchpadResult } from "../../src/models/scratchpadResult"; import { KdbDataSourceTreeItem } from "../../src/services/dataSourceTreeProvider"; import * as codeFlowLogin from "../../src/services/kdbInsights/codeFlowLogin"; @@ -44,7 +44,8 @@ import { ExecutionConsole } from "../../src/utils/executionConsole"; import * as queryUtils from "../../src/utils/queryUtils"; import { Connection } from "../../src/models/connection"; import { QueryHistory } from "../../src/models/queryHistory"; -import { ServerType } from "../../src/models/server"; +import { Server, ServerDetails, ServerType } from "../../src/models/server"; +import { NewConnectionPannel } from "../../src/panels/newConnection"; // eslint-disable-next-line @typescript-eslint/no-var-requires const dsCmd = require("../../src/commands/dataSourceCommand"); @@ -917,234 +918,162 @@ describe("serverCommand", () => { servers["testServer"], TreeItemCollapsibleState.None, ); - it("Should call new connection but not create kdb or insights", async () => { - const qpStub = sinon.stub(window, "showQuickPick").returns(undefined); - - const spy = sinon.spy(); - const kdbMock = sinon.mock(serverCommand); - kdbMock.expects("addKdbConnection").never(); - const insMock = sinon.mock(serverCommand); - insMock.expects("addInsightsConnection").never(); - - await serverCommand.addNewConnection(); - kdbMock.verify(); - insMock.verify(); - - assert(spy.notCalled); - - spy.resetHistory(); - insMock.restore(); - kdbMock.restore(); - qpStub.restore(); - }); - - it("Should add new kdb connection successfully", async () => { - const qpItem: QuickPickItem = { - label: "Enter a kdb endpoint", - detail: - "Enter the url, ip address, and port to connect to a kdb instance", - }; - - const qpStub = sinon.stub(window, "showQuickPick").resolves(qpItem); - const kdbStub = sinon - .stub(serverCommand, "addKdbConnection") - .returns(undefined); - - await serverCommand.addNewConnection(); - - assert(kdbStub.notCalled); - - kdbStub.restore(); - qpStub.restore(); - }); - - it("Should add new kdb connection without existing connection", async () => { - const qpItem: QuickPickItem = { - label: "Enter a kdb endpoint", - detail: - "Enter the url, ip address, and port to connect to a kdb instance", - }; - - const qpStub = sinon.stub(window, "showQuickPick").resolves(qpItem); - - await serverCommand.addKdbConnection(); - - assert.strictEqual(true, true); - - qpStub.restore(); - }); - - it("Should add new insights connection successfully", async () => { - const qpItem: QuickPickItem = { - label: "Connect to kdb Insights Enterprise", - detail: "Enter instance details", - }; - - const qpStub = sinon.stub(window, "showQuickPick").resolves(qpItem); - const insStub = sinon - .stub(serverCommand, "addInsightsConnection") - .returns(undefined); - - await serverCommand.addNewConnection(); - - assert(insStub.notCalled); - - insStub.restore(); - qpStub.restore(); - }); - - it("Should add new insights connection successfully", async () => { - const qpItem: QuickPickItem = { - label: "Connect to kdb Insights Enterprise", - detail: "Enter instance details", - }; - - const qpStub = sinon.stub(window, "showQuickPick").resolves(qpItem); - const inpStub = sinon - .stub(window, "showInputBox") - .onFirstCall() - .resolves(undefined) - .onSecondCall() - .resolves("https://insights.test"); - const insStub = sinon - .stub(serverCommand, "addInsightsConnection") - .returns(undefined); - - await serverCommand.addNewConnection(); - - assert(insStub.notCalled); + const insights = { + testInsight: { + alias: "testInsightsAlias", + server: "testInsightsName", + auth: false, + }, + }; + ext.serverProvider = new KdbTreeProvider(servers, insights); - insStub.restore(); - inpStub.restore(); - qpStub.restore(); + after(() => { + ext.serverProvider = undefined; }); - it("Should add new insights connection successfully", async () => { - const qpItem: QuickPickItem = { - label: "Connect to kdb Insights Enterprise", - detail: "Enter instance details", - }; - - const qpStub = sinon.stub(window, "showQuickPick").resolves(qpItem); - const inpStub = sinon - .stub(window, "showInputBox") - .onFirstCall() - .resolves("") - .onSecondCall() - .resolves("https://insights.test"); - const insStub = sinon - .stub(serverCommand, "addInsightsConnection") - .returns(undefined); - - await serverCommand.addNewConnection(); + it("should call the New Connection Panel Renderer", () => { + const newConnectionPanelStub = sinon.stub(NewConnectionPannel, "render"); - assert(insStub.notCalled); - - insStub.restore(); - inpStub.restore(); - qpStub.restore(); + serverCommand.addNewConnection(); + sinon.assert.calledOnce(newConnectionPanelStub); + sinon.restore(); }); - it("Should add new insights connection successfully", async () => { - const qpItem: QuickPickItem = { - label: "Connect to kdb Insights Enterprise", - detail: "Enter instance details", - }; - - const qpStub = sinon.stub(window, "showQuickPick").resolves(qpItem); - const inpStub = sinon - .stub(window, "showInputBox") - .onFirstCall() - .resolves("") - .onSecondCall() - .resolves("https://insights.test"); - const insStub = sinon - .stub(serverCommand, "addInsightsConnection") - .returns(undefined); - const getInsightsStub = sinon - .stub(insModule, "getInsights") - .returns(undefined); - - await serverCommand.addNewConnection(); - - assert(insStub.notCalled); - - getInsightsStub.restore(); - insStub.restore(); - inpStub.restore(); - qpStub.restore(); + describe("addInsightsConnection", () => { + let insightsData: InsightDetails; + let updateInsightsStub, getInsightsStub: sinon.SinonStub; + let windowMock: sinon.SinonMock; + beforeEach(() => { + insightsData = { + server: "https://insightsservername.com/", + alias: "insightsserveralias", + auth: true, + }; + windowMock = sinon.mock(vscode.window); + updateInsightsStub = sinon.stub(coreUtils, "updateInsights"); + getInsightsStub = sinon.stub(coreUtils, "getInsights"); + }); + afterEach(() => { + sinon.restore(); + windowMock.restore(); + }); + it("should add new Insights connection", async () => { + getInsightsStub.returns({}); + await serverCommand.addInsightsConnection(insightsData); + sinon.assert.calledOnce(updateInsightsStub); + windowMock + .expects("showInformationMessage") + .once() + .withArgs("Insights connection added successfully"); + }); + it("should show error message if Insights connection already exists", async () => { + getInsightsStub.returns(insights); + await serverCommand.addInsightsConnection(insightsData); + windowMock + .expects("showErrorMessage") + .once() + .withArgs("Insights connection already exists"); + }); + it("should show error message if Insights connection is invalid", async () => { + insightsData.server = "invalid"; + await serverCommand.addInsightsConnection(insightsData); + windowMock + .expects("showErrorMessage") + .once() + .withArgs("Invalid Insights connection"); + }); + it("should add connection where alias is not provided", async () => { + insightsData.alias = ""; + getInsightsStub.returns({}); + await serverCommand.addInsightsConnection(insightsData); + sinon.assert.calledOnce(updateInsightsStub); + windowMock + .expects("showInformationMessage") + .once() + .withArgs("Insights connection added successfully"); + }); }); - it("Should add new insights connection with no existing connection", async () => { - const qpItem: QuickPickItem = { - label: "Connect to kdb Insights Enterprise", - detail: "Enter instance details", - }; - - const insTest: Insights = { - test: { alias: "testalias", auth: false, server: "testserver" }, - }; - - const qpStub = sinon.stub(window, "showQuickPick").resolves(qpItem); - const inpStub = sinon - .stub(window, "showInputBox") - .onFirstCall() - .resolves("test") - .onSecondCall() - .resolves("https://insights.test"); - const insStub = sinon - .stub(serverCommand, "addInsightsConnection") - .returns(undefined); - const getInsightsStub = sinon - .stub(insModule, "getInsights") - .returns(insTest); - - await serverCommand.addNewConnection(); - - assert(insStub.notCalled); - - getInsightsStub.restore(); - insStub.restore(); - inpStub.restore(); - qpStub.restore(); - }); + describe("addKdbConnection", () => { + let kdbData: ServerDetails; + let windowMock: sinon.SinonMock; + let updateServersStub, getServersStub: sinon.SinonStub; + beforeEach(() => { + kdbData = { + serverName: "testServer", + serverAlias: "testServerAlias", + auth: false, + managed: false, + serverPort: "5001", + tls: false, + }; + windowMock = sinon.mock(vscode.window); + updateServersStub = sinon.stub(coreUtils, "updateServers"); + getServersStub = sinon.stub(coreUtils, "getServers"); + }); - it("Should add new insights connection with exiting connection", async () => { - const qpItem: QuickPickItem = { - label: "Connect to kdb Insights Enterprise", - detail: "Enter instance details", - }; + afterEach(() => { + sinon.restore(); + windowMock.restore(); + }); - const insTest: Insights = { - test: { - alias: "testalias", - auth: false, - server: "https://insights.test", - }, - }; + it("should add new Kdb connection", async () => { + getServersStub.returns({}); + await serverCommand.addKdbConnection(kdbData); + sinon.assert.calledOnce(updateServersStub); + windowMock + .expects("showInformationMessage") + .once() + .withArgs("Kdb connection added successfully"); + }); + it("should show error message if Kdb connection already exists", async () => { + getServersStub.returns(servers); + await serverCommand.addKdbConnection(kdbData); + windowMock + .expects("showErrorMessage") + .once() + .withArgs("Kdb connection already exists"); + }); + it("should show error message if Kdb connection is invalid", async () => { + kdbData.serverPort = "invalid"; + await serverCommand.addKdbConnection(kdbData); + windowMock + .expects("showErrorMessage") + .once() + .withArgs("Invalid Kdb connection"); + }); + it("should add connection where alias is not provided", async () => { + kdbData.serverAlias = ""; + getServersStub.returns({}); + await serverCommand.addKdbConnection(kdbData); + sinon.assert.calledOnce(updateServersStub); + windowMock + .expects("showInformationMessage") + .once() + .withArgs("Kdb connection added successfully"); + }); + it("should give error if alias is local and isLocal is false", async () => { + kdbData.serverAlias = "local"; + kdbData.managed = true; + await serverCommand.addKdbConnection(kdbData); + windowMock + .expects("showErrorMessage") + .once() + .withArgs("Invalid Kdb connection"); + }); - const qpStub = sinon.stub(window, "showQuickPick").resolves(qpItem); - const inpStub = sinon - .stub(window, "showInputBox") - .onFirstCall() - .resolves("test") - .onSecondCall() - .resolves("https://insights.test"); - const insStub = sinon - .stub(serverCommand, "addInsightsConnection") - .returns(undefined); - const getInsightsStub = sinon - .stub(insModule, "getInsights") - .returns(insTest); - - await serverCommand.addNewConnection(); - - assert(insStub.notCalled); - - getInsightsStub.restore(); - insStub.restore(); - inpStub.restore(); - qpStub.restore(); + it("should add authentication to the connection", async () => { + kdbData.auth = true; + kdbData.password = "password"; + kdbData.username = "username"; + getServersStub.returns({}); + await serverCommand.addKdbConnection(kdbData); + sinon.assert.calledOnce(updateServersStub); + windowMock + .expects("showInformationMessage") + .once() + .withArgs("Kdb connection added successfully"); + }); }); describe("writeQueryResultsToView", () => { diff --git a/test/suite/validators.test.ts b/test/suite/validators.test.ts index d0f908cf..0118b0f2 100644 --- a/test/suite/validators.test.ts +++ b/test/suite/validators.test.ts @@ -29,67 +29,86 @@ describe("Interface validation tests", () => { assert.strictEqual( result, undefined, - "Correct input value should return success." + "Correct input value should return success.", ); }); it("Should return failed validation with invalid scratchpad variable output name", () => { const result = validateScratchpadOutputVariableName( - "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt", ); assert.strictEqual( result, "Input value must be between 1 and 64 alphanumeric characters in length.", - "Invalid input value should return fail." + "Invalid input value should return fail.", ); }); }); describe("kdbValidator", () => { it("Should return fail for server alias that is blank or undefined", () => { - const result = validateServerAlias(undefined); + const result = validateServerAlias(undefined, false); assert.strictEqual( result, undefined, - "Server alias that is undefined should validate as undefined" + "Server alias that is undefined should validate as undefined", ); }); it("Should return fail for server alias that starts with a space", () => { - const result = validateServerAlias(" test"); + const result = validateServerAlias(" test", false); assert.strictEqual( result, "Input value cannot start with a space.", - "Input started with a space and should fail validation." + "Input started with a space and should fail validation.", ); }); it("Should return fail for server alias that is outside the size limits", () => { const result = validateServerAlias( - "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt", + false, ); assert.strictEqual( result, "Input value must be between 1 and 64 alphanumeric characters in length.", - "Input was outside the size limits." + "Input was outside the size limits.", ); }); it("Should return fail for server alias should not contain special chars", () => { - const result = validateServerAlias("test!"); + const result = validateServerAlias("test!", false); assert.strictEqual( result, "Input value must contain only alphanumeric characters and hypens only", - "Input contained special chars" + "Input contained special chars", ); }); it("Should return fail if using restricted keyword", () => { - const result = validateServerAlias("InsightsEnterprise"); + const result = validateServerAlias("InsightsEnterprise", false); assert.strictEqual( result, "Input value using restricted keywords of Insights Enterprise", - "Input contained restricted keyword." + "Input contained restricted keyword.", + ); + }); + + it("Should return fail if using restricted keyword", () => { + const result = validateServerAlias("local", false); + assert.strictEqual( + result, + "Input value using restricted keywords of Local for Bundle q Server", + "Input contained restricted keyword.", + ); + }); + + it("Should return fail if using restricted keyword", () => { + const result = validateServerAlias("local", false); + assert.strictEqual( + result, + "Input value using restricted keywords of Local for Bundle q Server", + "Input contained restricted keyword.", ); }); @@ -98,18 +117,18 @@ describe("kdbValidator", () => { assert.strictEqual( result, undefined, - "Server name that is undefined should validate as undefined" + "Server name that is undefined should validate as undefined", ); }); it("Should return fail for server name that is outside the size limits", () => { const result = validateServerName( - "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt", ); assert.strictEqual( result, "Input value must be between 1 and 64 alphanumeric characters in length.", - "Input was outside the size limits." + "Input was outside the size limits.", ); }); @@ -118,7 +137,7 @@ describe("kdbValidator", () => { assert.strictEqual( result, undefined, - "Server port that is undefined should validate as undefined" + "Server port that is undefined should validate as undefined", ); }); @@ -127,7 +146,7 @@ describe("kdbValidator", () => { assert.strictEqual( result, "Input value must be a number.", - "Input was not a number for server port." + "Input was not a number for server port.", ); }); @@ -136,7 +155,7 @@ describe("kdbValidator", () => { assert.strictEqual( result, "Invalid port number, valid range is 1-65536", - "input was not in valid port range" + "input was not in valid port range", ); }); @@ -150,18 +169,18 @@ describe("kdbValidator", () => { assert.strictEqual( result, undefined, - "Server username that is undefined should validate as undefined." + "Server username that is undefined should validate as undefined.", ); }); it("Should return fail for server username that is outside the size limits", () => { const result = validateServerUsername( - "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt", ); assert.strictEqual( result, "Input value must be between 1 and 64 alphanumeric characters in length.", - "Input was outside the size limits." + "Input was outside the size limits.", ); }); @@ -170,18 +189,18 @@ describe("kdbValidator", () => { assert.strictEqual( result, undefined, - "Server password that is undefined should validate as undefined." + "Server password that is undefined should validate as undefined.", ); }); it("Should return fail for server password that is outside the size limits", () => { const result = validateServerPassword( - "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt", ); assert.strictEqual( result, "Input value must be between 1 and 64 alphanumeric characters in length.", - "Input was outside the size limits." + "Input was outside the size limits.", ); }); @@ -190,7 +209,7 @@ describe("kdbValidator", () => { assert.strictEqual( result, undefined, - "Server tls that is undefined should validate as undefined." + "Server tls that is undefined should validate as undefined.", ); }); @@ -199,7 +218,7 @@ describe("kdbValidator", () => { assert.strictEqual( result, "Input value must be a boolean (true or false)", - "Server tls should be boolean" + "Server tls should be boolean", ); }); @@ -216,7 +235,7 @@ describe("Validation functions", () => { assert.strictEqual( result.getErrors(), "Value cannot be empty.", - "Empty value should return validation error" + "Empty value should return validation error", ); }); @@ -226,7 +245,7 @@ describe("Validation functions", () => { assert.strictEqual( result.getErrors(), null, - "String passed contains the special chars and didn't pass validation." + "String passed contains the special chars and didn't pass validation.", ); }); @@ -236,7 +255,7 @@ describe("Validation functions", () => { assert.strictEqual( result.getErrors(), "Password must have 1 special character.", - "String passed does not contain the special chars and should not pass." + "String passed does not contain the special chars and should not pass.", ); }); @@ -244,12 +263,12 @@ describe("Validation functions", () => { const vTest = new Validator("t*est"); const result = vTest.hasNoForbiddenChar( new RegExp("\\!"), - "Forbidden char found" + "Forbidden char found", ); assert.strictEqual( result.getErrors(), null, - "String passsed does not contain forbidden characters" + "String passsed does not contain forbidden characters", ); }); @@ -257,12 +276,12 @@ describe("Validation functions", () => { const vTest = new Validator("t*est"); const result = vTest.hasNoForbiddenChar( new RegExp("\\*"), - "Forbidden char found" + "Forbidden char found", ); assert.strictEqual( result.getErrors(), "Forbidden char found", - "String passsed does not contain forbidden characters" + "String passsed does not contain forbidden characters", ); }); @@ -272,7 +291,7 @@ describe("Validation functions", () => { assert.strictEqual( result.getErrors(), null, - "Length of string is in range" + "Length of string is in range", ); }); @@ -282,7 +301,7 @@ describe("Validation functions", () => { assert.strictEqual( result.getErrors(), "Length must be between 1 and 3 characters", - "Length of string is not in range" + "Length of string is not in range", ); }); @@ -292,7 +311,7 @@ describe("Validation functions", () => { assert.strictEqual( result.getErrors(), null, - `String contains at least one lower case char: ${result.getErrors()}` + `String contains at least one lower case char: ${result.getErrors()}`, ); }); @@ -302,7 +321,7 @@ describe("Validation functions", () => { assert.strictEqual( result.getErrors(), "Password should have at least one lowercase letter from a to z.", - "String contains both cases" + "String contains both cases", ); }); });