Aligns how Import and New project flows work (#11184)

* Slight import refactor

* Test updates

* Adds test, sets script name for File extractType to projectName

* generating correct folder list

* Correctly setting serverId for Imports started from Object Explorer

* Adding regression test

* uncommented test check
This commit is contained in:
Benjin Dubishar
2020-07-14 19:31:22 -07:00
committed by GitHub
parent 6147e1cba4
commit dc7e6f59bd
5 changed files with 165 additions and 167 deletions

View File

@@ -26,8 +26,7 @@ describe('Project: sqlproj content operations', function (): void {
});
it('Should read Project from sqlproj', async function (): Promise<void> {
const project: Project = new Project(projFilePath);
await project.readProjFile();
const project: Project = await Project.openProject(projFilePath);
// Files and folders
should(project.files.filter(f => f.type === EntryType.File).length).equal(4);
@@ -48,8 +47,7 @@ describe('Project: sqlproj content operations', function (): void {
});
it('Should add Folder and Build entries to sqlproj', async function (): Promise<void> {
const project: Project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
const folderPath = 'Stored Procedures';
const filePath = path.join(folderPath, 'Fake Stored Proc.sql');
@@ -58,8 +56,7 @@ describe('Project: sqlproj content operations', function (): void {
await project.addFolderItem(folderPath);
await project.addScriptItem(filePath, fileContents);
const newProject = new Project(projFilePath);
await newProject.readProjFile();
const newProject = await Project.openProject(projFilePath);
should(newProject.files.find(f => f.type === EntryType.Folder && f.relativePath === convertSlashesForSqlProj(folderPath))).not.equal(undefined);
should(newProject.files.find(f => f.type === EntryType.File && f.relativePath === convertSlashesForSqlProj(filePath))).not.equal(undefined);
@@ -71,8 +68,7 @@ describe('Project: sqlproj content operations', function (): void {
it('Should add Folder and Build entries to sqlproj with pre-existing scripts on disk', async function (): Promise<void> {
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
const project: Project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
let list: string[] = await testUtils.createListOfFiles(path.dirname(projFilePath));
@@ -84,8 +80,7 @@ describe('Project: sqlproj content operations', function (): void {
it('Should throw error while adding Folder and Build entries to sqlproj when a file/folder does not exist on disk', async function (): Promise<void> {
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
const project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
let list: string[] = [];
let testFolderPath: string = await testUtils.createDummyFileStructure(true, list, path.dirname(projFilePath));
@@ -98,8 +93,7 @@ describe('Project: sqlproj content operations', function (): void {
it('Should choose correct master dacpac', async function (): Promise<void> {
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
const project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
let uri = project.getSystemDacpacUri(constants.masterDacpac);
let ssdtUri = project.getSystemDacpacSsdtUri(constants.masterDacpac);
@@ -121,8 +115,7 @@ describe('Project: sqlproj content operations', function (): void {
it('Should choose correct msdb dacpac', async function (): Promise<void> {
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
const project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
let uri = project.getSystemDacpacUri(constants.msdbDacpac);
let ssdtUri = project.getSystemDacpacSsdtUri(constants.msdbDacpac);
@@ -144,8 +137,7 @@ describe('Project: sqlproj content operations', function (): void {
it('Should throw error when choosing correct master dacpac if invalid DSP', async function (): Promise<void> {
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
const project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
project.changeDSP('invalidPlatform');
await testUtils.shouldThrowSpecificError(async () => await project.getSystemDacpacUri(constants.masterDacpac), constants.invalidDataSchemaProvider);
@@ -153,8 +145,7 @@ describe('Project: sqlproj content operations', function (): void {
it('Should add database references correctly', async function (): Promise<void> {
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
const project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
should(project.databaseReferences.length).equal(0, 'There should be no datbase references to start with');
await project.addSystemDatabaseReference(SystemDatabase.master);
@@ -178,8 +169,7 @@ describe('Project: sqlproj content operations', function (): void {
it('Should not allow adding duplicate database references', async function (): Promise<void> {
projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
const project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
should(project.databaseReferences.length).equal(0, 'There should be no database references to start with');
await project.addSystemDatabaseReference(SystemDatabase.master);
@@ -220,8 +210,7 @@ describe('Project: round trip updates', function (): void {
async function testUpdateInRoundTrip(fileBeforeupdate: string, fileAfterUpdate: string, testTargets: boolean, testReferences: boolean): Promise<void> {
projFilePath = await testUtils.createTestSqlProjFile(fileBeforeupdate);
const project: Project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
if (testTargets) {
await testUpdateTargetsImportsRoundTrip(project);

View File

@@ -189,8 +189,7 @@ describe('ProjectsController: project controller operations', function (): void
await projController.delete(projTreeRoot.children.find(x => x.friendlyName === 'UpperFolder')!.children[0] /* LowerFolder */);
proj = new Project(proj.projectFilePath);
await proj.readProjFile(); // reload edited sqlproj from disk
proj = await Project.openProject(proj.projectFilePath); // reload edited sqlproj from disk
// confirm result
should(proj.files.length).equal(1, 'number of file/folder entries'); // lowerEntry and the contained scripts should be deleted
@@ -208,8 +207,7 @@ describe('ProjectsController: project controller operations', function (): void
await projController.exclude(<FolderNode>projTreeRoot.children.find(x => x.friendlyName === 'UpperFolder')!.children[0] /* LowerFolder */);
proj = new Project(proj.projectFilePath);
await proj.readProjFile(); // reload edited sqlproj from disk
proj = await Project.openProject(proj.projectFilePath); // reload edited sqlproj from disk
// confirm result
should(proj.files.length).equal(1, 'number of file/folder entries'); // LowerFolder and the contained scripts should be deleted
@@ -362,6 +360,7 @@ describe('ProjectsController: import operations', function (): void {
it('Should show error when no target information provided', async function (): Promise<void> {
testContext.apiWrapper.setup(x => x.showInputBox(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('MyProjectName'));
testContext.apiWrapper.setup(x => x.showOpenDialog(TypeMoq.It.isAny())).returns(() => Promise.resolve([vscode.Uri.file('fakePath')]));
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny())).returns(() => Promise.resolve(undefined));
testContext.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns((s) => { throw new Error(s); });
@@ -390,18 +389,55 @@ describe('ProjectsController: import operations', function (): void {
await testUtils.shouldThrowSpecificError(async () => await projController.importNewDatabaseProject({ connectionProfile: mockConnectionProfile }), constants.projectLocationRequired);
});
it('Should show error when selected folder is not empty', async function (): Promise<void> {
const testFolderPath = await testUtils.createDummyFileStructure();
it('Should set model filePath correctly for ExtractType = File and not-File.', async function (): Promise<void> {
const projectName = 'MyProjectName';
let folderPath = await testUtils.generateTestFolderPath();
testContext.apiWrapper.setup(x => x.showInputBox(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('MyProjectName'));
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: constants.objectType }));
testContext.apiWrapper.setup(x => x.showOpenDialog(TypeMoq.It.isAny())).returns(() => Promise.resolve([vscode.Uri.file(testFolderPath)]));
testContext.apiWrapper.setup(x => x.workspaceFolders()).returns(() => undefined);
testContext.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns((s) => { throw new Error(s); });
testContext.apiWrapper.setup(x => x.showInputBox(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(projectName));
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: constants.file }));
testContext.apiWrapper.setup(x => x.showOpenDialog(TypeMoq.It.isAny())).returns(() => Promise.resolve([vscode.Uri.file(folderPath)]));
const projController = new ProjectsController(testContext.apiWrapper.object, new SqlDatabaseProjectTreeViewProvider());
let importPath;
await testUtils.shouldThrowSpecificError(async () => await projController.importNewDatabaseProject({ connectionProfile: mockConnectionProfile }), constants.projectLocationNotEmpty);
let projController = TypeMoq.Mock.ofType(ProjectsController, undefined, undefined, testContext.apiWrapper.object, new SqlDatabaseProjectTreeViewProvider());
projController.callBase = true;
projController.setup(x => x.importApiCall(TypeMoq.It.isAny())).returns(async (model) => { importPath = model.filePath; });
await projController.object.importNewDatabaseProject({ connectionProfile: mockConnectionProfile });
should(importPath).equal(vscode.Uri.file(path.join(folderPath, projectName, projectName + '.sql')).fsPath, `model.filePath should be set to a specific file for ExtractTarget === file, but was ${importPath}`);
// reset for counter-test
importPath = undefined;
folderPath = await testUtils.generateTestFolderPath();
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: constants.schemaObjectType }));
await projController.object.importNewDatabaseProject({ connectionProfile: mockConnectionProfile });
should(importPath).equal(vscode.Uri.file(path.join(folderPath, projectName)).fsPath, `model.filePath should be set to a folder for ExtractTarget !== file, but was ${importPath}`);
});
it('Should establish Import context correctly for ObjectExplorer and palette launch points', async function (): Promise<void> {
// test welcome button and palette launch points (context-less)
let mockDbSelection = 'FakeDatabase';
testContext.apiWrapper.setup(x => x.listDatabases(TypeMoq.It.isAny())).returns(() => Promise.resolve([]));
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: mockDbSelection }));
testContext.apiWrapper.setup(x => x.openConnectionDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
providerName: 'MSSQL',
connectionId: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575',
options: {}
}));
let projController = new ProjectsController(testContext.apiWrapper.object, new SqlDatabaseProjectTreeViewProvider());
let result = await projController.getModelFromContext(undefined);
should(result).deepEqual({database: mockDbSelection, serverId: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575'});
// test launch via Object Explorer context
testContext.apiWrapper.reset();
result = await projController.getModelFromContext(mockConnectionProfile);
should(result).deepEqual({database: 'My Database', serverId: 'My Id'});
});
});
@@ -437,8 +473,7 @@ describe('ProjectsController: add database reference operations', function (): v
it('Should return the correct system database', async function (): Promise<void> {
const projController = new ProjectsController(testContext.apiWrapper.object, new SqlDatabaseProjectTreeViewProvider());
const projFilePath = await testUtils.createTestSqlProjFile(baselines.openProjectFileBaseline);
const project: Project = new Project(projFilePath);
await project.readProjFile();
const project = await Project.openProject(projFilePath);
testContext.apiWrapper.setup(x => x.showQuickPick(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ label: constants.master }));
let systemDb = await projController.getSystemDatabaseName(project);

View File

@@ -32,10 +32,7 @@ export async function createTestSqlProjFile(contents: string, folderPath?: strin
}
export async function createTestProject(contents: string, folderPath?: string): Promise<Project> {
const proj = new Project(await createTestSqlProjFile(contents, folderPath));
await proj.readProjFile();
return proj;
return await Project.openProject(await createTestSqlProjFile(contents, folderPath));
}
export async function createTestDataSources(contents: string, folderPath?: string): Promise<string> {