Skip to content

Commit 2d50158

Browse files
authored
Add e2e tests for running .py notebooks with dbconnect (#1626)
## Changes Tests + fix init-scripts cleanup login on windows (seems like it was always broken there). Partially addresses this bug #1624 ## Tests Tests
1 parent 4deef63 commit 2d50158

File tree

2 files changed

+79
-33
lines changed

2 files changed

+79
-33
lines changed

packages/databricks-vscode/src/language/notebooks/NotebookInitScriptManager.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,10 @@ export class NotebookInitScriptManager implements Disposable {
172172

173173
const sourceFiles = await this.sourceFiles;
174174
for (const file of await glob(
175-
path.join(startupDir, "00-databricks-init-*.py")
175+
path.join(startupDir, "00-databricks-init-*.py"),
176+
// path.join will use "\" separator on windows, wbut glob always expects "/", unless we specify windowsPathsNoEscape.
177+
// This means we can't use "\" to escape special chracters in the glob pattern, but we don't use any.
178+
{windowsPathsNoEscape: true}
176179
)) {
177180
if (!sourceFiles.includes(path.basename(file))) {
178181
await rm(file);

packages/databricks-vscode/src/test/e2e/run_dbconnect.ucws.e2e.ts

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ import {
1515
writeRootBundleConfig,
1616
} from "./utils/dabsFixtures.ts";
1717

18+
async function checkOutputFile(path: string, expectedContent: string) {
19+
await browser.waitUntil(
20+
async () => {
21+
const fileContent = await fs.readFile(path, "utf-8");
22+
console.log(`"${path}" contents: `, fileContent);
23+
return fileContent.includes(expectedContent);
24+
},
25+
{
26+
timeout: 60_000,
27+
interval: 2000,
28+
timeoutMsg: `Output file "${path}" did not contain "${expectedContent}"`,
29+
}
30+
);
31+
await fs.rm(path);
32+
}
33+
1834
describe("Run files on serverless compute", async function () {
1935
let projectDir: string;
2036
this.timeout(3 * 60 * 1000);
@@ -62,6 +78,13 @@ describe("Run files on serverless compute", async function () {
6278
`df.to_json(os.path.join(os.getcwd(), "notebook-output.json"))`,
6379
],
6480
},
81+
{
82+
cell_type: "code",
83+
execution_count: null,
84+
metadata: {},
85+
outputs: [],
86+
source: [`%run "./hello.py"`],
87+
},
6588
],
6689
metadata: {
6790
kernelspec: {
@@ -77,6 +100,24 @@ describe("Run files on serverless compute", async function () {
77100
})
78101
);
79102

103+
await fs.writeFile(
104+
path.join(nestedDir, "databricks-notebook.py"),
105+
[
106+
"# Databricks notebook source",
107+
`spark.sql('SELECT "hello world"').show()`,
108+
"# COMMAND ----------",
109+
"# DBTITLE 1,My cell title",
110+
"# MAGIC %sql",
111+
"# MAGIC select 1 + 1;",
112+
"# MAGIC select 'hello; world'",
113+
"# COMMAND ----------",
114+
`df = _sqldf.toPandas()`,
115+
`df.to_json(os.path.join(os.getcwd(), "databricks-notebook-output.json"))`,
116+
"# COMMAND ----------",
117+
"# MAGIC %run './hello.py'",
118+
].join("\n")
119+
);
120+
80121
await writeRootBundleConfig(
81122
getBasicBundleConfig({}, false),
82123
projectDir
@@ -202,21 +243,8 @@ describe("Run files on serverless compute", async function () {
202243
await executeCommandWhenAvailable(
203244
"Databricks: Run current file with Databricks Connect"
204245
);
205-
await browser.waitUntil(
206-
async () => {
207-
const fileOutput = await fs.readFile(
208-
path.join(projectDir, "file-output.json"),
209-
"utf-8"
210-
);
211-
console.log("File output: ", fileOutput);
212-
return fileOutput.includes("hello world");
213-
},
214-
{
215-
timeout: 60_000,
216-
interval: 2000,
217-
timeoutMsg: "Terminal output did not contain 'hello world'",
218-
}
219-
);
246+
const output = path.join(projectDir, "file-output.json");
247+
await checkOutputFile(output, "hello world");
220248
});
221249

222250
it("should run a notebook with dbconnect", async () => {
@@ -225,28 +253,43 @@ describe("Run files on serverless compute", async function () {
225253

226254
const kernelInput = await waitForInput();
227255
await kernelInput.selectQuickPick("Python Environments...");
228-
console.log(
229-
"Selected 'Python Environments...' option for kernel selection"
230-
);
256+
console.log("Selected 'Python Environments...' option");
231257

232258
const envInput = await waitForInput();
233259
await envInput.selectQuickPick(".venv");
234260
console.log("Selected .venv environment");
235261

236-
await browser.waitUntil(
237-
async () => {
238-
const notebookOutput = await fs.readFile(
239-
path.join(projectDir, "nested", "notebook-output.json"),
240-
"utf-8"
241-
);
242-
console.log("Notebook output: ", notebookOutput);
243-
return notebookOutput.includes("hello world");
244-
},
245-
{
246-
timeout: 60_000,
247-
interval: 2000,
248-
timeoutMsg: "Notebook execution did not complete successfully",
249-
}
262+
const firstCellOutput = path.join(
263+
projectDir,
264+
"nested",
265+
"notebook-output.json"
266+
);
267+
await checkOutputFile(firstCellOutput, "hello world");
268+
269+
const secondCellOutput = path.join(
270+
projectDir,
271+
"nested",
272+
"file-output.json"
273+
);
274+
await checkOutputFile(secondCellOutput, "hello world");
275+
});
276+
277+
it("should run a databricks notebook with dbconnect and handle magic comments", async () => {
278+
await openFile("databricks-notebook.py");
279+
await executeCommandWhenAvailable("Jupyter: Run All Cells");
280+
281+
const sqlOutputFile = path.join(
282+
projectDir,
283+
"nested",
284+
"databricks-notebook-output.json"
285+
);
286+
await checkOutputFile(sqlOutputFile, "hello; world");
287+
288+
const runOutputFile = path.join(
289+
projectDir,
290+
"nested",
291+
"file-output.json"
250292
);
293+
await checkOutputFile(runOutputFile, "hello world");
251294
});
252295
});

0 commit comments

Comments
 (0)