mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-23 01:25:38 -05:00
SQL Project - deploy to docker publish option (#17050)
SQL Project - deploy to docker publish option
This commit is contained in:
@@ -128,13 +128,13 @@ export const done = localize('done', "Done");
|
||||
export const nameMustNotBeEmpty = localize('nameMustNotBeEmpty', "Name must not be empty");
|
||||
|
||||
// Deploy
|
||||
export const selectDeployOption = localize('selectDeployOption', "Select where to deploy the project to");
|
||||
export const deployToExistingServer = localize('deployToExistingServer', "Deploy to existing server");
|
||||
export const deployToDockerContainer = localize('deployToDockerContainer', "Deploy to docker container");
|
||||
export const selectPublishOption = localize('selectPublishOption', "Select where to publish the project to");
|
||||
export const publishToExistingServer = localize('publishToExistingServer', "Publish to existing server");
|
||||
export const publishToDockerContainer = localize('publishToDockerContainer', "Publish to docker container");
|
||||
export const enterPortNumber = localize('enterPortNumber', "Enter port number or press enter to use the default value");
|
||||
export const enterConnectionStringEnvName = localize('enterConnectionStringEnvName', "Enter connection string environment variable name");
|
||||
export const enterConnectionStringTemplate = localize('enterConnectionStringTemplate', "Enter connection string template");
|
||||
export const enterPassword = localize('enterPassword', "Enter password or press enter to use the generated password");
|
||||
export const enterPassword = localize('enterPassword', "Enter password");
|
||||
export const portMustBeNumber = localize('portMustNotBeNumber', "Port must a be number");
|
||||
export const valueCannotBeEmpty = localize('valueCannotBeEmpty', "Value cannot be empty");
|
||||
export const dockerImageLabelPrefix = 'source=sqldbproject';
|
||||
|
||||
@@ -505,3 +505,15 @@ export async function getAllProjectsInFolder(folder: vscode.Uri, projectExtensio
|
||||
// glob will return an array of file paths with forward slashes, so they need to be converted back if on windows
|
||||
return (await glob(projFilter)).map(p => vscode.Uri.file(path.resolve(p)));
|
||||
}
|
||||
|
||||
export function validateSqlServerPortNumber(port: string | undefined): boolean {
|
||||
if (!port) {
|
||||
return false;
|
||||
}
|
||||
const valueAsNum = +port;
|
||||
return !isNaN(valueAsNum) && valueAsNum > 0 && valueAsNum < 65535;
|
||||
}
|
||||
|
||||
export function isEmptyString(password: string | undefined): boolean {
|
||||
return password === undefined || password === '';
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ export default class MainController implements vscode.Disposable {
|
||||
|
||||
vscode.commands.registerCommand('sqlDatabaseProjects.build', async (node: WorkspaceTreeItem) => { return this.projectsController.buildProject(node); });
|
||||
vscode.commands.registerCommand('sqlDatabaseProjects.publish', async (node: WorkspaceTreeItem) => { this.projectsController.publishProject(node); });
|
||||
vscode.commands.registerCommand('sqlDatabaseProjects.deployLocal', async (node: WorkspaceTreeItem) => { return this.projectsController.deployProject(node); });
|
||||
vscode.commands.registerCommand('sqlDatabaseProjects.schemaCompare', async (node: WorkspaceTreeItem) => { return this.projectsController.schemaCompare(node); });
|
||||
vscode.commands.registerCommand('sqlDatabaseProjects.createProjectFromDatabase', async (context: azdataType.IConnectionProfile | vscodeMssql.ITreeNodeInfo | undefined) => { return this.projectsController.createProjectFromDatabase(context); });
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/t
|
||||
import { IconPathHelper } from '../common/iconHelper';
|
||||
import { DashboardData, PublishData, Status } from '../models/dashboardData/dashboardData';
|
||||
import { launchPublishDatabaseQuickpick } from '../dialogs/publishDatabaseQuickpick';
|
||||
import { launchDeployDatabaseQuickpick } from '../dialogs/deployDatabaseQuickpick';
|
||||
import { launchPublishToDockerContainerQuickpick } from '../dialogs/deployDatabaseQuickpick';
|
||||
import { DeployService } from '../models/deploy/deployService';
|
||||
import { SqlTargetPlatform } from 'sqldbproj';
|
||||
import { createNewProjectFromDatabaseWithQuickpick } from '../dialogs/createProjectFromDatabaseQuickpick';
|
||||
@@ -256,13 +256,13 @@ export class ProjectsController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploys a project
|
||||
* Publishes a project to docker container
|
||||
* @param treeNode a treeItem in a project's hierarchy, to be used to obtain a Project
|
||||
*/
|
||||
public async deployProject(context: Project | dataworkspace.WorkspaceTreeItem): Promise<void> {
|
||||
public async publishToDockerContainer(context: Project | dataworkspace.WorkspaceTreeItem): Promise<void> {
|
||||
const project: Project = this.getProjectFromContext(context);
|
||||
try {
|
||||
let deployProfile = await launchDeployDatabaseQuickpick(project);
|
||||
let deployProfile = await launchPublishToDockerContainerQuickpick(project);
|
||||
if (deployProfile && deployProfile.deploySettings) {
|
||||
let connectionUri: string | undefined;
|
||||
if (deployProfile.localDbSetting) {
|
||||
@@ -274,10 +274,6 @@ export class ProjectsController {
|
||||
if (deployProfile.deploySettings.connectionUri) {
|
||||
const publishResult = await this.publishOrScriptProject(project, deployProfile.deploySettings, true);
|
||||
if (publishResult && publishResult.success) {
|
||||
|
||||
// Update app settings if requested by user
|
||||
//
|
||||
await this.deployService.updateAppSettings(deployProfile);
|
||||
if (deployProfile.localDbSetting) {
|
||||
await this.deployService.getConnection(deployProfile.localDbSetting, true, deployProfile.localDbSetting.dbName);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as constants from '../common/constants';
|
||||
import { AppSettingType, IDeployProfile, ILocalDbSetting } from '../models/deploy/deployProfile';
|
||||
import * as utils from '../common/utils';
|
||||
import { AppSettingType, IDeployAppIntegrationProfile, IDeployProfile, ILocalDbSetting } from '../models/deploy/deployProfile';
|
||||
import { Project } from '../models/project';
|
||||
import * as generator from 'generate-password';
|
||||
import { getPublishDatabaseSettings } from './publishDatabaseQuickpick';
|
||||
import * as path from 'path';
|
||||
import * as fse from 'fs-extra';
|
||||
@@ -15,73 +15,7 @@ import * as fse from 'fs-extra';
|
||||
/**
|
||||
* Create flow for Deploying a database using only VS Code-native APIs such as QuickPick
|
||||
*/
|
||||
export async function launchDeployDatabaseQuickpick(project: Project): Promise<IDeployProfile | undefined> {
|
||||
|
||||
// Show options to user for deploy to existing server or docker
|
||||
|
||||
const deployOption = await vscode.window.showQuickPick(
|
||||
[constants.deployToExistingServer, constants.deployToDockerContainer],
|
||||
{ title: constants.selectDeployOption, ignoreFocusOut: true });
|
||||
|
||||
// Return when user hits escape
|
||||
if (!deployOption) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let localDbSetting: ILocalDbSetting | undefined;
|
||||
// Deploy to docker selected
|
||||
if (deployOption === constants.deployToDockerContainer) {
|
||||
let portNumber = await vscode.window.showInputBox({
|
||||
title: constants.enterPortNumber,
|
||||
ignoreFocusOut: true,
|
||||
value: constants.defaultPortNumber,
|
||||
validateInput: input => isNaN(+input) ? constants.portMustBeNumber : undefined
|
||||
}
|
||||
);
|
||||
|
||||
// Return when user hits escape
|
||||
if (!portNumber) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let password: string | undefined = generator.generate({
|
||||
length: 10,
|
||||
numbers: true,
|
||||
symbols: true,
|
||||
lowercase: true,
|
||||
uppercase: true,
|
||||
exclude: '`"\'' // Exclude the chars that cannot be included in the password. Some chars can make the command fail in the terminal
|
||||
});
|
||||
password = await vscode.window.showInputBox({
|
||||
title: constants.enterPassword,
|
||||
ignoreFocusOut: true,
|
||||
value: password,
|
||||
password: true
|
||||
}
|
||||
);
|
||||
|
||||
// Return when user hits escape
|
||||
if (!password) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
localDbSetting = {
|
||||
serverName: 'localhost',
|
||||
userName: 'sa',
|
||||
dbName: project.projectFileName,
|
||||
password: password,
|
||||
port: +portNumber,
|
||||
};
|
||||
}
|
||||
let deploySettings = await getPublishDatabaseSettings(project, deployOption !== constants.deployToDockerContainer);
|
||||
|
||||
// Return when user hits escape
|
||||
if (!deploySettings) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// TODO: Ask for SQL CMD Variables or profile
|
||||
|
||||
export async function launchDeployAppIntegrationQuickpick(project: Project): Promise<IDeployAppIntegrationProfile | undefined> {
|
||||
let envVarName: string | undefined = '';
|
||||
const integrateWithAzureFunctions: boolean = true; //TODO: get value from settings or quickpick
|
||||
|
||||
@@ -116,7 +50,7 @@ export async function launchDeployDatabaseQuickpick(project: Project): Promise<I
|
||||
title: constants.enterConnectionStringEnvName,
|
||||
ignoreFocusOut: true,
|
||||
value: constants.defaultConnectionStringEnvVarName,
|
||||
validateInput: input => input === '' ? constants.valueCannotBeEmpty : undefined,
|
||||
validateInput: input => utils.isEmptyString(input) ? constants.valueCannotBeEmpty : undefined,
|
||||
placeHolder: constants.enterConnectionStringEnvNameDescription
|
||||
}
|
||||
);
|
||||
@@ -128,15 +62,70 @@ export async function launchDeployDatabaseQuickpick(project: Project): Promise<I
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
envVariableName: envVarName,
|
||||
appSettingFile: settingExist ? localSettings : undefined,
|
||||
appSettingType: settingExist ? AppSettingType.AzureFunction : AppSettingType.None
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create flow for publishing a database to docker container using only VS Code-native APIs such as QuickPick
|
||||
*/
|
||||
export async function launchPublishToDockerContainerQuickpick(project: Project): Promise<IDeployProfile | undefined> {
|
||||
|
||||
let localDbSetting: ILocalDbSetting | undefined;
|
||||
// Deploy to docker selected
|
||||
let portNumber = await vscode.window.showInputBox({
|
||||
title: constants.enterPortNumber,
|
||||
ignoreFocusOut: true,
|
||||
value: constants.defaultPortNumber,
|
||||
validateInput: input => !utils.validateSqlServerPortNumber(input) ? constants.portMustBeNumber : undefined
|
||||
}
|
||||
);
|
||||
|
||||
// Return when user hits escape
|
||||
if (!portNumber) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let password: string | undefined = '';
|
||||
password = await vscode.window.showInputBox({
|
||||
title: constants.enterPassword,
|
||||
ignoreFocusOut: true,
|
||||
value: password,
|
||||
validateInput: input => utils.isEmptyString(input) ? constants.valueCannotBeEmpty : undefined,
|
||||
password: true
|
||||
}
|
||||
);
|
||||
|
||||
// Return when user hits escape
|
||||
if (!password) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
localDbSetting = {
|
||||
serverName: 'localhost',
|
||||
userName: 'sa',
|
||||
dbName: project.projectFileName,
|
||||
password: password,
|
||||
port: +portNumber,
|
||||
};
|
||||
|
||||
let deploySettings = await getPublishDatabaseSettings(project, false);
|
||||
|
||||
// Return when user hits escape
|
||||
if (!deploySettings) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (localDbSetting && deploySettings) {
|
||||
deploySettings.serverName = localDbSetting.serverName;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
localDbSetting: localDbSetting,
|
||||
envVariableName: envVarName,
|
||||
appSettingFile: settingExist ? localSettings : undefined,
|
||||
deploySettings: deploySettings,
|
||||
appSettingType: settingExist ? AppSettingType.AzureFunction : AppSettingType.None
|
||||
};
|
||||
}
|
||||
|
||||
@@ -207,17 +207,37 @@ export async function getPublishDatabaseSettings(project: Project, promptForConn
|
||||
* Create flow for Publishing a database using only VS Code-native APIs such as QuickPick
|
||||
*/
|
||||
export async function launchPublishDatabaseQuickpick(project: Project, projectController: ProjectsController): Promise<void> {
|
||||
let settings: IDeploySettings | undefined = await getPublishDatabaseSettings(project);
|
||||
const publishTarget = await launchPublishTargetOption();
|
||||
if (publishTarget === constants.publishToDockerContainer) {
|
||||
await projectController.publishToDockerContainer(project);
|
||||
} else {
|
||||
let settings: IDeploySettings | undefined = await getPublishDatabaseSettings(project);
|
||||
|
||||
if (settings) {
|
||||
// 5. Select action to take
|
||||
const action = await vscode.window.showQuickPick(
|
||||
[constants.generateScriptButtonText, constants.publish],
|
||||
{ title: constants.chooseAction, ignoreFocusOut: true });
|
||||
if (!action) {
|
||||
return;
|
||||
if (settings) {
|
||||
// 5. Select action to take
|
||||
const action = await vscode.window.showQuickPick(
|
||||
[constants.generateScriptButtonText, constants.publish],
|
||||
{ title: constants.chooseAction, ignoreFocusOut: true });
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
await projectController.publishOrScriptProject(project, settings, action === constants.publish);
|
||||
}
|
||||
await projectController.publishOrScriptProject(project, settings, action === constants.publish);
|
||||
}
|
||||
}
|
||||
|
||||
async function launchPublishTargetOption(): Promise<string | undefined> {
|
||||
// Show options to user for deploy to existing server or docker
|
||||
|
||||
const publishOption = await vscode.window.showQuickPick(
|
||||
[constants.publishToExistingServer, constants.publishToDockerContainer],
|
||||
{ title: constants.selectPublishOption, ignoreFocusOut: true });
|
||||
|
||||
// Return when user hits escape
|
||||
if (!publishOption) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return publishOption;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ export enum AppSettingType {
|
||||
export interface IDeployProfile {
|
||||
localDbSetting?: ILocalDbSetting;
|
||||
deploySettings?: IDeploySettings;
|
||||
}
|
||||
|
||||
export interface IDeployAppIntegrationProfile {
|
||||
envVariableName?: string;
|
||||
appSettingFile?: string;
|
||||
appSettingType: AppSettingType;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AppSettingType, IDeployProfile, ILocalDbSetting } from './deployProfile';
|
||||
import { AppSettingType, IDeployAppIntegrationProfile, IDeployProfile, ILocalDbSetting } from './deployProfile';
|
||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||
import { Project } from '../project';
|
||||
import * as constants from '../../common/constants';
|
||||
@@ -32,7 +32,7 @@ export class DeployService {
|
||||
return '';
|
||||
}
|
||||
|
||||
private findAppRuntime(profile: IDeployProfile, appSettingContent: any): string | undefined {
|
||||
private findAppRuntime(profile: IDeployAppIntegrationProfile, appSettingContent: any): string | undefined {
|
||||
switch (profile.appSettingType) {
|
||||
case AppSettingType.AzureFunction:
|
||||
return <string>appSettingContent?.Values['FUNCTIONS_WORKER_RUNTIME'];
|
||||
@@ -41,7 +41,7 @@ export class DeployService {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async updateAppSettings(profile: IDeployProfile): Promise<void> {
|
||||
public async updateAppSettings(profile: IDeployAppIntegrationProfile, deployProfile: IDeployProfile | undefined): Promise<void> {
|
||||
// Update app settings
|
||||
//
|
||||
if (!profile.appSettingFile) {
|
||||
@@ -53,22 +53,22 @@ export class DeployService {
|
||||
let content = JSON.parse(fse.readFileSync(profile.appSettingFile, 'utf8'));
|
||||
if (content && content.Values) {
|
||||
let connectionString: string | undefined = '';
|
||||
if (profile.localDbSetting) {
|
||||
if (deployProfile && deployProfile.localDbSetting) {
|
||||
// Find the runtime and generate the connection string for the runtime
|
||||
//
|
||||
const runtime = this.findAppRuntime(profile, content);
|
||||
let connectionStringTemplate = this.createConnectionStringTemplate(runtime);
|
||||
const macroDict: Record<string, string> = {
|
||||
'SERVER': profile?.localDbSetting?.serverName || '',
|
||||
'PORT': profile?.localDbSetting?.port?.toString() || '',
|
||||
'USER': profile?.localDbSetting?.userName || '',
|
||||
'SA_PASSWORD': profile?.localDbSetting?.password || '',
|
||||
'DATABASE': profile?.localDbSetting?.dbName || '',
|
||||
'SERVER': deployProfile?.localDbSetting?.serverName || '',
|
||||
'PORT': deployProfile?.localDbSetting?.port?.toString() || '',
|
||||
'USER': deployProfile?.localDbSetting?.userName || '',
|
||||
'SA_PASSWORD': deployProfile?.localDbSetting?.password || '',
|
||||
'DATABASE': deployProfile?.localDbSetting?.dbName || '',
|
||||
};
|
||||
|
||||
connectionString = templates.macroExpansion(connectionStringTemplate, macroDict);
|
||||
} else if (profile.deploySettings?.connectionUri) {
|
||||
connectionString = await this.getConnectionString(profile.deploySettings?.connectionUri);
|
||||
} else if (deployProfile?.deploySettings?.connectionUri) {
|
||||
connectionString = await this.getConnectionString(deployProfile?.deploySettings?.connectionUri);
|
||||
}
|
||||
|
||||
if (connectionString && profile.envVariableName) {
|
||||
@@ -88,8 +88,8 @@ export class DeployService {
|
||||
return undefined;
|
||||
}
|
||||
const projectName = project.projectFileName;
|
||||
const imageLabel = `${constants.dockerImageLabelPrefix}_${projectName}`;
|
||||
const imageName = `${constants.dockerImageNamePrefix}-${projectName}-${UUID.generateUuid().toLowerCase()}`;
|
||||
const imageLabel = `${constants.dockerImageLabelPrefix}_${projectName}`.toLocaleLowerCase();
|
||||
const imageName = `${constants.dockerImageNamePrefix}-${projectName}-${UUID.generateUuid()}`.toLocaleLowerCase();
|
||||
const root = project.projectFolderPath;
|
||||
const mssqlFolderPath = path.join(root, constants.mssqlFolderName);
|
||||
const commandsFolderPath = path.join(mssqlFolderPath, constants.commandsFolderName);
|
||||
|
||||
@@ -66,10 +66,6 @@ describe('deploy service', function (): void {
|
||||
it('Should deploy a database to docker container successfully', async function (): Promise<void> {
|
||||
const testContext = createContext();
|
||||
const deployProfile: IDeployProfile = {
|
||||
appSettingType: AppSettingType.AzureFunction,
|
||||
appSettingFile: '',
|
||||
deploySettings: undefined,
|
||||
envVariableName: '',
|
||||
localDbSetting: {
|
||||
dbName: 'test',
|
||||
password: 'PLACEHOLDER',
|
||||
@@ -137,10 +133,6 @@ describe('deploy service', function (): void {
|
||||
await fse.writeFile(filePath, settingContent);
|
||||
|
||||
const deployProfile: IDeployProfile = {
|
||||
appSettingType: AppSettingType.AzureFunction,
|
||||
appSettingFile: filePath,
|
||||
deploySettings: undefined,
|
||||
envVariableName: 'SQLConnectionString',
|
||||
localDbSetting: {
|
||||
dbName: 'test',
|
||||
password: 'PLACEHOLDER',
|
||||
@@ -150,9 +142,14 @@ describe('deploy service', function (): void {
|
||||
}
|
||||
};
|
||||
|
||||
const appInteg = {appSettingType: AppSettingType.AzureFunction,
|
||||
appSettingFile: filePath,
|
||||
deploySettings: undefined,
|
||||
envVariableName: 'SQLConnectionString'};
|
||||
|
||||
const deployService = new DeployService(testContext.outputChannel);
|
||||
sandbox.stub(childProcess, 'exec').yields(undefined, 'id');
|
||||
await deployService.updateAppSettings(deployProfile);
|
||||
await deployService.updateAppSettings(appInteg, deployProfile);
|
||||
let newContent = JSON.parse(fse.readFileSync(filePath, 'utf8'));
|
||||
should(newContent).deepEqual(expected);
|
||||
|
||||
@@ -184,23 +181,26 @@ describe('deploy service', function (): void {
|
||||
await fse.writeFile(filePath, settingContent);
|
||||
|
||||
const deployProfile: IDeployProfile = {
|
||||
appSettingType: AppSettingType.AzureFunction,
|
||||
appSettingFile: filePath,
|
||||
|
||||
deploySettings: {
|
||||
connectionUri: 'connection',
|
||||
databaseName: 'test',
|
||||
serverName: 'test'
|
||||
},
|
||||
envVariableName: 'SQLConnectionString',
|
||||
localDbSetting: undefined
|
||||
};
|
||||
|
||||
const appInteg = {
|
||||
appSettingType: AppSettingType.AzureFunction,
|
||||
appSettingFile: filePath,
|
||||
envVariableName: 'SQLConnectionString',
|
||||
}
|
||||
const deployService = new DeployService(testContext.outputChannel);
|
||||
let connection = new azdata.connection.ConnectionProfile();
|
||||
sandbox.stub(azdata.connection, 'getConnection').returns(Promise.resolve(connection));
|
||||
sandbox.stub(childProcess, 'exec').yields(undefined, 'id');
|
||||
sandbox.stub(azdata.connection, 'getConnectionString').returns(Promise.resolve('connectionString'));
|
||||
await deployService.updateAppSettings(deployProfile);
|
||||
await deployService.updateAppSettings(appInteg, deployProfile);
|
||||
let newContent = JSON.parse(fse.readFileSync(filePath, 'utf8'));
|
||||
should(newContent).deepEqual(expected);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as should from 'should';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import { createDummyFileStructure } from './testUtils';
|
||||
import { exists, trimUri, removeSqlCmdVariableFormatting, formatSqlCmdVariable, isValidSqlCmdVariableName, timeConversion } from '../common/utils';
|
||||
import { exists, trimUri, removeSqlCmdVariableFormatting, formatSqlCmdVariable, isValidSqlCmdVariableName, timeConversion, validateSqlServerPortNumber, isEmptyString } from '../common/utils';
|
||||
import { Uri } from 'vscode';
|
||||
|
||||
describe('Tests to verify utils functions', function (): void {
|
||||
@@ -88,5 +88,22 @@ describe('Tests to verify utils functions', function (): void {
|
||||
should(timeConversion( (59 * 1000))).equal('59 sec');
|
||||
should(timeConversion( (59))).equal('59 msec');
|
||||
});
|
||||
|
||||
it('Should validate port number correctly', () => {
|
||||
should(validateSqlServerPortNumber('invalid')).equals(false);
|
||||
should(validateSqlServerPortNumber('')).equals(false);
|
||||
should(validateSqlServerPortNumber(undefined)).equals(false);
|
||||
should(validateSqlServerPortNumber('65536')).equals(false);
|
||||
should(validateSqlServerPortNumber('-1')).equals(false);
|
||||
should(validateSqlServerPortNumber('65530')).equals(true);
|
||||
should(validateSqlServerPortNumber('1533')).equals(true);
|
||||
});
|
||||
|
||||
it('Should validate empty string correctly', () => {
|
||||
should(isEmptyString('invalid')).equals(false);
|
||||
should(isEmptyString('')).equals(true);
|
||||
should(isEmptyString(undefined)).equals(true);
|
||||
should(isEmptyString('65536')).equals(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user