Skip to content

Commit efa3c6b

Browse files
authored
Add e2e tests for bundle init flow (#1073)
Add smoke tests for bundle init and auth flows. Also fixes these problems: - DATABRICKS_CONFIG_FILE env var was not always respected (for example when creating a new profile) - bundle file watcher was broken on windows: we were using raw fsPath with backslashes, which doesn't work for globs - saveNewProfile was broken on windows: `toISOString` returns values with characters that aren't allowed in windows paths, resulting in `ENOENT` errors from `copyFile`
1 parent 65f03ee commit efa3c6b

22 files changed

+698
-478
lines changed

.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
},
2727
"overrides": [
2828
{
29-
"files": "**/*.test.ts",
29+
"files": ["**/*.test.ts", "**/test/**"],
3030
"rules": {
3131
"no-console": "off"
3232
}

.github/workflows/tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ jobs:
7676
run: yarn run test:cov
7777
working-directory: packages/databricks-vscode
7878

79-
# - name: Integration Tests
80-
# run: yarn run test:integ
81-
# working-directory: packages/databricks-vscode
79+
- name: Integration Tests
80+
run: yarn run test:integ
81+
working-directory: packages/databricks-vscode
8282

8383
- name: Integration Tests SDK wrappers
8484
run: yarn run test:integ:sdk

packages/databricks-vscode/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"license": "LicenseRef-LICENSE",
77
"version": "2.0.0",
88
"engines": {
9-
"vscode": "^1.83.0"
9+
"vscode": "^1.86.0"
1010
},
1111
"categories": [
1212
"Data Science",
@@ -844,8 +844,8 @@
844844
"ts-node": "^10.9.2",
845845
"typescript": "^5.3.3",
846846
"vsce": "^2.15.0",
847-
"wdio-video-reporter": "^4.0.5",
848-
"wdio-vscode-service": "^5.2.2",
847+
"wdio-video-reporter": "^5.1.4",
848+
"wdio-vscode-service": "^6.0.2",
849849
"yargs": "^17.7.2"
850850
},
851851
"nyc": {

packages/databricks-vscode/src/bundle/BundleFileSet.test.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Uri} from "vscode";
2-
import {BundleFileSet, getAbsolutePath} from "./BundleFileSet";
2+
import {BundleFileSet, getAbsoluteGlobPath} from "./BundleFileSet";
33
import {expect} from "chai";
44
import path from "path";
55
import * as tmp from "tmp-promise";
@@ -18,16 +18,18 @@ describe(__filename, async function () {
1818
await tmpdir.cleanup();
1919
});
2020

21-
it("should return the correct absolute path", () => {
21+
it("should return the correct absolute glob path", () => {
2222
const tmpdirUri = Uri.file(tmpdir.path);
23-
24-
expect(getAbsolutePath("test.txt", tmpdirUri).fsPath).to.equal(
25-
path.join(tmpdirUri.fsPath, "test.txt")
23+
let expectedGlob = path.join(tmpdirUri.fsPath, "test.txt");
24+
if (process.platform === "win32") {
25+
expectedGlob = expectedGlob.replace(/\\/g, "/");
26+
}
27+
expect(getAbsoluteGlobPath("test.txt", tmpdirUri)).to.equal(
28+
expectedGlob
29+
);
30+
expect(getAbsoluteGlobPath(Uri.file("test.txt"), tmpdirUri)).to.equal(
31+
expectedGlob
2632
);
27-
28-
expect(
29-
getAbsolutePath(Uri.file("test.txt"), tmpdirUri).fsPath
30-
).to.equal(path.join(tmpdirUri.fsPath, "test.txt"));
3133
});
3234

3335
it("should find the correct root bundle yaml", async () => {

packages/databricks-vscode/src/bundle/BundleFileSet.ts

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export async function writeBundleYaml(file: Uri, data: BundleSchema) {
2222

2323
export async function getSubProjects(root: Uri) {
2424
const subProjectRoots = await glob.glob(
25-
toGlobPath(getAbsolutePath(subProjectFilePattern, root).fsPath),
25+
getAbsoluteGlobPath(subProjectFilePattern, root),
2626
{nocase: process.platform === "win32"}
2727
);
2828
const normalizedRoot = path.normalize(root.fsPath);
@@ -40,11 +40,10 @@ export async function getSubProjects(root: Uri) {
4040
});
4141
}
4242

43-
export function getAbsolutePath(path: string | Uri, root: Uri) {
44-
if (typeof path === "string") {
45-
return Uri.joinPath(root, path);
46-
}
47-
return Uri.joinPath(root, path.fsPath);
43+
export function getAbsoluteGlobPath(path: string | Uri, root: Uri): string {
44+
path = typeof path === "string" ? path : path.fsPath;
45+
const uri = Uri.joinPath(root, path);
46+
return toGlobPath(uri.fsPath);
4847
}
4948

5049
function toGlobPath(path: string) {
@@ -68,9 +67,7 @@ export class BundleFileSet {
6867

6968
async getRootFile() {
7069
const rootFile = await glob.glob(
71-
toGlobPath(
72-
getAbsolutePath(rootFilePattern, this.workspaceRoot).fsPath
73-
),
70+
getAbsoluteGlobPath(rootFilePattern, this.workspaceRoot),
7471
{nocase: process.platform === "win32"}
7572
);
7673
if (rootFile.length !== 1) {
@@ -83,11 +80,9 @@ export class BundleFileSet {
8380
root?: Uri
8481
): Promise<{relative: Uri; absolute: Uri}[]> {
8582
const subProjectRoots = await glob.glob(
86-
toGlobPath(
87-
getAbsolutePath(
88-
subProjectFilePattern,
89-
root || this.workspaceRoot
90-
).fsPath
83+
getAbsoluteGlobPath(
84+
subProjectFilePattern,
85+
root || this.workspaceRoot
9186
),
9287
{nocase: process.platform === "win32"}
9388
);
@@ -167,9 +162,7 @@ export class BundleFileSet {
167162
isRootBundleFile(e: Uri) {
168163
return minimatch(
169164
e.fsPath,
170-
toGlobPath(
171-
getAbsolutePath(rootFilePattern, this.workspaceRoot).fsPath
172-
)
165+
getAbsoluteGlobPath(rootFilePattern, this.workspaceRoot)
173166
);
174167
}
175168

@@ -178,10 +171,10 @@ export class BundleFileSet {
178171
if (includedFilesGlob === undefined) {
179172
return false;
180173
}
181-
includedFilesGlob = getAbsolutePath(
174+
includedFilesGlob = getAbsoluteGlobPath(
182175
includedFilesGlob,
183176
this.workspaceRoot
184-
).fsPath;
177+
);
185178
return minimatch(e.fsPath, toGlobPath(includedFilesGlob));
186179
}
187180

packages/databricks-vscode/src/bundle/BundleWatcher.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Disposable, EventEmitter, Uri, workspace} from "vscode";
2-
import {BundleFileSet, getAbsolutePath} from "./BundleFileSet";
2+
import {BundleFileSet, getAbsoluteGlobPath} from "./BundleFileSet";
33
import {WithMutex} from "../locking";
44
import path from "path";
55

@@ -23,8 +23,7 @@ export class BundleWatcher implements Disposable {
2323
constructor(bundleFileSet: BundleFileSet, workspaceUri: Uri) {
2424
this.bundleFileSet = new WithMutex(bundleFileSet);
2525
const yamlWatcher = workspace.createFileSystemWatcher(
26-
getAbsolutePath(path.join("**", "*.{yaml,yml}"), workspaceUri)
27-
.fsPath
26+
getAbsoluteGlobPath(path.join("**", "*.{yaml,yml}"), workspaceUri)
2827
);
2928

3029
this.disposables.push(

packages/databricks-vscode/src/configuration/ConnectionCommands.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import {ConnectionManager} from "./ConnectionManager";
1212
import {UrlUtils} from "../utils";
1313
import {WorkspaceFsCommands} from "../workspace-fs";
1414
import {ConfigModel} from "./models/ConfigModel";
15+
import {saveNewProfile} from "./LoginWizard";
16+
import {PersonalAccessTokenAuthProvider} from "./auth/AuthProvider";
17+
import {normalizeHost} from "../utils/urlUtils";
1518

1619
function formatQuickPickClusterSize(sizeInMB: number): string {
1720
if (sizeInMB > 1024) {
@@ -73,6 +76,19 @@ export class ConnectionCommands implements Disposable {
7376
);
7477
}
7578

79+
// This command is not exposed to users.
80+
// We use it to test new profile flow in e2e tests.
81+
async saveNewProfileCommand(name: string) {
82+
const host = this.connectionManager.workspaceClient?.config.host;
83+
const token = this.connectionManager.workspaceClient?.config.token;
84+
if (!host || !token) {
85+
throw new Error("Must login first");
86+
}
87+
const hostUrl = normalizeHost(host);
88+
const provider = new PersonalAccessTokenAuthProvider(hostUrl, token);
89+
await saveNewProfile(name, provider);
90+
}
91+
7692
/**
7793
* Attach to cluster from settings. If attach fails or no cluster is configured
7894
* then show dialog to select (or create) a cluster. The selected cluster is saved

packages/databricks-vscode/src/configuration/LoginWizard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ export async function saveNewProfile(
387387
// Create a backup for .databrickscfg
388388
const backup = path.join(
389389
path.dirname(configFilePath),
390-
`.databrickscfg.${new Date().toISOString()}.bak`
390+
`.databrickscfg.${Date.now()}.bak`
391391
);
392392
await copyFile(configFilePath, backup);
393393
window.showInformationMessage(

packages/databricks-vscode/src/configuration/auth/AuthProvider.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,7 @@ export class ProfileAuthProvider extends AuthProvider {
204204
public static getSdkConfig(profile: string): Config {
205205
return new Config({
206206
profile: profile,
207-
configFile:
208-
workspaceConfigs.databrickscfgLocation ??
209-
process.env.DATABRICKS_CONFIG_FILE,
207+
configFile: workspaceConfigs.databrickscfgLocation,
210208
env: {},
211209
});
212210
}

packages/databricks-vscode/src/extension.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,11 @@ export async function activate(
486486
"databricks.connection.detachCluster",
487487
connectionCommands.detachClusterCommand(),
488488
connectionCommands
489+
),
490+
telemetry.registerCommand(
491+
"databricks.connection.saveNewProfile",
492+
connectionCommands.saveNewProfileCommand,
493+
connectionCommands
489494
)
490495
);
491496

0 commit comments

Comments
 (0)