mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Code refactoring for extension testing (#10529)
* Setting up tests on import extension * -Added API wrappers for all the azdata and vscode APIs to make them easily mockable -Added some unit tests for the import extension -Some code logic separations * -added code report for the import extension in ci * Did some more code refractoring * -Added json report generation * updated vscodetestcoverage to latest version in import extension. * -remove duplicate codecoverageConfig.json
This commit is contained in:
@@ -5,13 +5,8 @@
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { ImportDataModel } from '../api/models';
|
||||
import { ImportPage } from '../api/importPage';
|
||||
import { FlatFileProvider } from '../../services/contracts';
|
||||
import { FlatFileWizard } from '../flatFileWizard';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
import * as constants from '../../common/constants';
|
||||
|
||||
export class FileConfigPage extends ImportPage {
|
||||
|
||||
@@ -28,10 +23,6 @@ export class FileConfigPage extends ImportPage {
|
||||
|
||||
private tableNames: string[] = [];
|
||||
|
||||
public constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider) {
|
||||
super(instance, wizardPage, model, view, provider);
|
||||
}
|
||||
|
||||
async start(): Promise<boolean> {
|
||||
let schemaComponent = await this.createSchemaDropdown();
|
||||
let tableNameComponent = await this.createTableNameBox();
|
||||
@@ -96,7 +87,7 @@ export class FileConfigPage extends ImportPage {
|
||||
|
||||
return {
|
||||
component: this.serverDropdown,
|
||||
title: localize('flatFileImport.serverDropdownTitle', "Server the database is in")
|
||||
title: constants.serverDropDownTitleText
|
||||
};
|
||||
}
|
||||
|
||||
@@ -124,8 +115,8 @@ export class FileConfigPage extends ImportPage {
|
||||
this.databaseDropdown.onValueChanged(async (db) => {
|
||||
this.model.database = (<azdata.CategoryValue>this.databaseDropdown.value).name;
|
||||
//this.populateTableNames();
|
||||
let connectionProvider = azdata.dataprotocol.getProvider<azdata.ConnectionProvider>(this.model.server.providerName, azdata.DataProviderType.ConnectionProvider);
|
||||
let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
|
||||
let connectionProvider = this._apiWrapper.getProvider<azdata.ConnectionProvider>(this.model.server.providerName, azdata.DataProviderType.ConnectionProvider);
|
||||
let connectionUri = await this._apiWrapper.getUriForConnection(this.model.server.connectionId);
|
||||
connectionProvider.changeDatabase(connectionUri, this.model.database);
|
||||
this.populateSchemaDropdown();
|
||||
});
|
||||
@@ -134,7 +125,7 @@ export class FileConfigPage extends ImportPage {
|
||||
|
||||
return {
|
||||
component: this.databaseLoader,
|
||||
title: localize('flatFileImport.databaseDropdownTitle', "Database the table is created in")
|
||||
title: constants.databaseDropdownTitleText
|
||||
};
|
||||
}
|
||||
|
||||
@@ -178,7 +169,7 @@ export class FileConfigPage extends ImportPage {
|
||||
required: true
|
||||
}).component();
|
||||
this.fileButton = this.view.modelBuilder.button().withProperties({
|
||||
label: localize('flatFileImport.browseFiles', "Browse"),
|
||||
label: constants.browseFilesText,
|
||||
}).component();
|
||||
|
||||
this.fileButton.onDidClick(async (click) => {
|
||||
@@ -187,7 +178,7 @@ export class FileConfigPage extends ImportPage {
|
||||
canSelectFiles: true,
|
||||
canSelectFolders: false,
|
||||
canSelectMany: false,
|
||||
openLabel: localize('flatFileImport.openFile', "Open"),
|
||||
openLabel: constants.openFileText,
|
||||
filters: {
|
||||
'CSV/TXT Files': ['csv', 'txt'],
|
||||
'All Files': ['*']
|
||||
@@ -227,7 +218,7 @@ export class FileConfigPage extends ImportPage {
|
||||
|
||||
return {
|
||||
component: this.fileTextBox,
|
||||
title: localize('flatFileImport.fileTextboxTitle', "Location of the file to be imported"),
|
||||
title: constants.fileTextboxTitleText,
|
||||
actions: [this.fileButton]
|
||||
};
|
||||
}
|
||||
@@ -256,7 +247,7 @@ export class FileConfigPage extends ImportPage {
|
||||
|
||||
return {
|
||||
component: this.tableNameTextBox,
|
||||
title: localize('flatFileImport.tableTextboxTitle', "New table name"),
|
||||
title: constants.tableTextboxTitleText,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -274,20 +265,31 @@ export class FileConfigPage extends ImportPage {
|
||||
|
||||
return {
|
||||
component: this.schemaLoader,
|
||||
title: localize('flatFileImport.schemaTextboxTitle', "Table schema"),
|
||||
title: constants.schemaTextboxTitleText,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private async populateSchemaDropdown(): Promise<boolean> {
|
||||
public async populateSchemaDropdown(): Promise<boolean> {
|
||||
this.schemaLoader.loading = true;
|
||||
|
||||
let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
|
||||
let queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(this.model.server.providerName, azdata.DataProviderType.QueryProvider);
|
||||
let values = await this.getSchemaValues();
|
||||
|
||||
const query = `SELECT name FROM sys.schemas`;
|
||||
this.model.schema = values[0].name;
|
||||
|
||||
let results = await queryProvider.runQueryAndReturn(connectionUri, query);
|
||||
this.schemaDropdown.updateProperties({
|
||||
values: values
|
||||
});
|
||||
|
||||
this.schemaLoader.loading = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public async getSchemaValues(): Promise<{ displayName: string, name: string }[]> {
|
||||
let connectionUri = await this._apiWrapper.getUriForConnection(this.model.server.connectionId);
|
||||
let queryProvider = this._apiWrapper.getProvider<azdata.QueryProvider>(this.model.server.providerName, azdata.DataProviderType.QueryProvider);
|
||||
|
||||
let results = await queryProvider.runQueryAndReturn(connectionUri, constants.selectSchemaQuery);
|
||||
|
||||
let idx = -1;
|
||||
let count = -1;
|
||||
@@ -311,15 +313,7 @@ export class FileConfigPage extends ImportPage {
|
||||
values[0] = values[idx];
|
||||
values[idx] = tmp;
|
||||
}
|
||||
|
||||
this.model.schema = values[0].name;
|
||||
|
||||
this.schemaDropdown.updateProperties({
|
||||
values: values
|
||||
});
|
||||
|
||||
this.schemaLoader.loading = false;
|
||||
return true;
|
||||
return values;
|
||||
}
|
||||
|
||||
protected deleteServerValues() {
|
||||
|
||||
@@ -4,13 +4,9 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { ColumnMetadata, ImportDataModel } from '../api/models';
|
||||
import { ColumnMetadata } from '../api/models';
|
||||
import { ImportPage } from '../api/importPage';
|
||||
import { FlatFileProvider } from '../../services/contracts';
|
||||
import { FlatFileWizard } from '../flatFileWizard';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
import * as constants from '../../common/constants';
|
||||
|
||||
export class ModifyColumnsPage extends ImportPage {
|
||||
private readonly categoryValues = [
|
||||
@@ -54,11 +50,6 @@ export class ModifyColumnsPage extends ImportPage {
|
||||
private text: azdata.TextComponent;
|
||||
private form: azdata.FormContainer;
|
||||
|
||||
public constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider) {
|
||||
super(instance, wizardPage, model, view, provider);
|
||||
}
|
||||
|
||||
|
||||
private static convertMetadata(column: ColumnMetadata): any[] {
|
||||
return [column.columnName, column.dataType, false, column.nullable];
|
||||
}
|
||||
@@ -105,20 +96,20 @@ export class ModifyColumnsPage extends ImportPage {
|
||||
async onPageEnter(): Promise<boolean> {
|
||||
this.loading.loading = true;
|
||||
await this.populateTable();
|
||||
this.instance.changeNextButtonLabel(localize('flatFileImport.importData', "Import Data"));
|
||||
this.instance.changeNextButtonLabel(constants.importDataText);
|
||||
this.loading.loading = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async onPageLeave(): Promise<boolean> {
|
||||
this.instance.changeNextButtonLabel(localize('flatFileImport.next', "Next"));
|
||||
this.instance.changeNextButtonLabel(constants.nextText);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async cleanup(): Promise<boolean> {
|
||||
delete this.model.proseColumns;
|
||||
this.instance.changeNextButtonLabel(localize('flatFileImport.next', "Next"));
|
||||
this.instance.changeNextButtonLabel(constants.nextText);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -139,23 +130,23 @@ export class ModifyColumnsPage extends ImportPage {
|
||||
this.table.updateProperties({
|
||||
height: 400,
|
||||
columns: [{
|
||||
displayName: localize('flatFileImport.columnName', "Column Name"),
|
||||
displayName: constants.columnNameText,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '150px',
|
||||
isReadOnly: false
|
||||
}, {
|
||||
displayName: localize('flatFileImport.dataType', "Data Type"),
|
||||
displayName: constants.dataTypeText,
|
||||
valueType: azdata.DeclarativeDataType.editableCategory,
|
||||
width: '150px',
|
||||
isReadOnly: false,
|
||||
categoryValues: this.categoryValues
|
||||
}, {
|
||||
displayName: localize('flatFileImport.primaryKey', "Primary Key"),
|
||||
displayName: constants.primaryKeyText,
|
||||
valueType: azdata.DeclarativeDataType.boolean,
|
||||
width: '100px',
|
||||
isReadOnly: false
|
||||
}, {
|
||||
displayName: localize('flatFileImport.allowNulls', "Allow Nulls"),
|
||||
displayName: constants.allowNullsText,
|
||||
valueType: azdata.DeclarativeDataType.boolean,
|
||||
isReadOnly: false,
|
||||
width: '100px'
|
||||
|
||||
@@ -4,19 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { ImportDataModel } from '../api/models';
|
||||
import { ImportPage } from '../api/importPage';
|
||||
import { FlatFileProvider } from '../../services/contracts';
|
||||
import { FlatFileWizard } from '../flatFileWizard';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
import * as constants from '../../common/constants';
|
||||
|
||||
export class ProsePreviewPage extends ImportPage {
|
||||
|
||||
private readonly successTitle: string = localize('flatFileImport.prosePreviewMessage', "This operation analyzed the input file structure to generate the preview below for up to the first 50 rows.");
|
||||
private readonly failureTitle: string = localize('flatFileImport.prosePreviewMessageFail', "This operation was unsuccessful. Please try a different input file.");
|
||||
|
||||
private table: azdata.TableComponent;
|
||||
private loading: azdata.LoadingComponent;
|
||||
private form: azdata.FormContainer;
|
||||
@@ -24,10 +16,6 @@ export class ProsePreviewPage extends ImportPage {
|
||||
private resultTextComponent: azdata.TextComponent;
|
||||
private isSuccess: boolean;
|
||||
|
||||
public constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider) {
|
||||
super(instance, wizardPage, model, view, provider);
|
||||
}
|
||||
|
||||
async start(): Promise<boolean> {
|
||||
this.table = this.view.modelBuilder.table().withProperties<azdata.TableComponentProperties>({
|
||||
data: undefined,
|
||||
@@ -35,7 +23,7 @@ export class ProsePreviewPage extends ImportPage {
|
||||
forceFitColumns: azdata.ColumnSizingMode.DataFit
|
||||
}).component();
|
||||
this.refresh = this.view.modelBuilder.button().withProperties({
|
||||
label: localize('flatFileImport.refresh', "Refresh"),
|
||||
label: constants.refreshText,
|
||||
isFile: false
|
||||
}).component();
|
||||
|
||||
@@ -47,7 +35,7 @@ export class ProsePreviewPage extends ImportPage {
|
||||
|
||||
this.resultTextComponent = this.view.modelBuilder.text()
|
||||
.withProperties({
|
||||
value: this.isSuccess ? this.successTitle : this.failureTitle
|
||||
value: this.isSuccess ? constants.successTitleText : constants.failureTitleText
|
||||
}).component();
|
||||
|
||||
this.form = this.view.modelBuilder.formContainer().withFormItems([
|
||||
@@ -84,14 +72,14 @@ export class ProsePreviewPage extends ImportPage {
|
||||
await this.populateTable(this.model.proseDataPreview, this.model.proseColumns.map(c => c.columnName));
|
||||
this.isSuccess = true;
|
||||
if (this.form) {
|
||||
this.resultTextComponent.value = this.successTitle;
|
||||
this.resultTextComponent.value = constants.successTitleText;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
await this.populateTable([], []);
|
||||
this.isSuccess = false;
|
||||
if (this.form) {
|
||||
this.resultTextComponent.value = this.failureTitle + '\n' + (error ?? '');
|
||||
this.resultTextComponent.value = constants.failureTitleText + '\n' + (error ?? '');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,15 +4,10 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
import { ImportDataModel } from '../api/models';
|
||||
import { ImportPage } from '../api/importPage';
|
||||
import { FlatFileProvider, InsertDataResponse } from '../../services/contracts';
|
||||
import { FlatFileWizard } from '../flatFileWizard';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
import { InsertDataResponse } from '../../services/contracts';
|
||||
import * as constants from '../../common/constants';
|
||||
|
||||
export class SummaryPage extends ImportPage {
|
||||
private table: azdata.TableComponent;
|
||||
@@ -20,10 +15,6 @@ export class SummaryPage extends ImportPage {
|
||||
private loading: azdata.LoadingComponent;
|
||||
private form: azdata.FormContainer;
|
||||
|
||||
public constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider) {
|
||||
super(instance, wizardPage, model, view, provider);
|
||||
}
|
||||
|
||||
async start(): Promise<boolean> {
|
||||
this.table = this.view.modelBuilder.table().component();
|
||||
this.statusText = this.view.modelBuilder.text().component();
|
||||
@@ -33,11 +24,11 @@ export class SummaryPage extends ImportPage {
|
||||
[
|
||||
{
|
||||
component: this.table,
|
||||
title: localize('flatFileImport.importInformation', "Import information")
|
||||
title: constants.importInformationText
|
||||
},
|
||||
{
|
||||
component: this.loading,
|
||||
title: localize('flatFileImport.importStatus', "Import status")
|
||||
title: constants.importStatusText
|
||||
}
|
||||
]
|
||||
).component();
|
||||
@@ -70,11 +61,11 @@ export class SummaryPage extends ImportPage {
|
||||
private populateTable() {
|
||||
this.table.updateProperties({
|
||||
data: [
|
||||
[localize('flatFileImport.serverName', "Server name"), this.model.server.providerName],
|
||||
[localize('flatFileImport.databaseName', "Database name"), this.model.database],
|
||||
[localize('flatFileImport.tableName', "Table name"), this.model.table],
|
||||
[localize('flatFileImport.tableSchema', "Table schema"), this.model.schema],
|
||||
[localize('flatFileImport.fileImport', "File to be imported"), this.model.filePath]],
|
||||
[constants.serverNameText, this.model.server.providerName],
|
||||
[constants.databaseText, this.model.database],
|
||||
[constants.tableNameText, this.model.table],
|
||||
[constants.tableSchemaText, this.model.schema],
|
||||
[constants.fileImportText, this.model.filePath]],
|
||||
columns: ['Object type', 'Name'],
|
||||
width: 600,
|
||||
height: 200
|
||||
@@ -96,9 +87,11 @@ export class SummaryPage extends ImportPage {
|
||||
|
||||
let result: InsertDataResponse;
|
||||
let err;
|
||||
let includePasswordInConnectionString = (this.model.server.options.connectionId === 'Integrated') ? false : true;
|
||||
|
||||
try {
|
||||
result = await this.provider.sendInsertDataRequest({
|
||||
connectionString: await this.getConnectionString(),
|
||||
connectionString: await this._apiWrapper.getConnectionString(this.model.server.connectionId, includePasswordInConnectionString),
|
||||
//TODO check what SSMS uses as batch size
|
||||
batchSize: 500
|
||||
});
|
||||
@@ -118,7 +111,7 @@ export class SummaryPage extends ImportPage {
|
||||
// TODO: When sql statements are in, implement this.
|
||||
//let rows = await this.getCountRowsInserted();
|
||||
//if (rows < 0) {
|
||||
updateText = localize('flatFileImport.success.norows', "✔ You have successfully inserted the data into a table.");
|
||||
updateText = constants.updateText;
|
||||
//} else {
|
||||
//updateText = localize('flatFileImport.success.rows', '✔ You have successfully inserted {0} rows.', rows);
|
||||
//}
|
||||
@@ -129,25 +122,6 @@ export class SummaryPage extends ImportPage {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the connection string to send to the middleware
|
||||
*/
|
||||
private async getConnectionString(): Promise<string> {
|
||||
let options = this.model.server.options;
|
||||
let connectionString: string;
|
||||
|
||||
if (options.authenticationType === 'Integrated') {
|
||||
connectionString = `Data Source=${options.server + (options.port ? `,${options.port}` : '')};Initial Catalog=${this.model.database};Integrated Security=True`;
|
||||
} else {
|
||||
let credentials = await azdata.connection.getCredentials(this.model.server.connectionId);
|
||||
connectionString = `Data Source=${options.server + (options.port ? `,${options.port}` : '')};Initial Catalog=${this.model.database};Integrated Security=False;User Id=${options.user};Password=${credentials.password}`;
|
||||
}
|
||||
|
||||
// TODO: Fix this, it's returning undefined string.
|
||||
//await azdata.connection.getConnectionString(this.model.server.connectionId, true);
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
// private async getCountRowsInserted(): Promise<Number> {
|
||||
// let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
|
||||
// let queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(this.model.server.providerName, azdata.DataProviderType.QueryProvider);
|
||||
|
||||
Reference in New Issue
Block a user