Skip to content

Commit da00229

Browse files
Spec level retry for failing integration tests (#312)
1 parent f03f595 commit da00229

File tree

5 files changed

+167
-110
lines changed

5 files changed

+167
-110
lines changed

packages/databricks-vscode/src/test/e2e/configure.e2e.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ describe("Configure Databricks Extension", async function () {
4141
host = process.env.DATABRICKS_HOST;
4242

4343
workbench = await browser.getWorkbench();
44+
});
45+
46+
it("should install vscode python extension", async function () {
47+
this.retries(1);
4448
await waitForPythonExtension();
4549
});
4650

packages/databricks-vscode/src/test/e2e/run_job_on_cluster.e2e.ts

Lines changed: 13 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ import * as fs from "fs/promises";
33
import assert from "node:assert";
44
import {
55
getViewSection,
6-
getViewSubSection,
6+
startSyncIfStopped,
77
waitForPythonExtension,
8+
waitForSyncComplete,
89
waitForTreeItems,
910
} from "./utils";
10-
import {sleep, TreeItem} from "wdio-vscode-service";
11+
import {sleep} from "wdio-vscode-service";
1112

12-
describe("Run python on cluster", async function () {
13+
describe("Run job on cluster", async function () {
1314
let projectDir: string;
1415
this.timeout(2 * 60 * 1000);
1516

@@ -45,59 +46,17 @@ describe("Run python on cluster", async function () {
4546
const section = await getViewSection("CONFIGURATION");
4647
assert(section);
4748
await waitForTreeItems(section);
48-
await waitForPythonExtension();
4949
});
5050

51-
beforeEach(async () => {
52-
const section = await getViewSection("CLUSTERS");
53-
await section?.collapse();
54-
55-
const repoConfigItem = await getViewSubSection("CONFIGURATION", "Repo");
56-
assert(repoConfigItem);
57-
58-
let status: TreeItem | undefined = undefined;
59-
for (const i of await repoConfigItem.getChildren()) {
60-
if ((await i.getLabel()).includes("State:")) {
61-
status = i;
62-
break;
63-
}
64-
}
65-
assert(status);
66-
if ((await status.getDescription())?.includes("STOPPED")) {
67-
const buttons = await repoConfigItem.getActionButtons();
68-
await buttons[0].elem.click();
69-
}
70-
71-
await browser.waitUntil(
72-
async () => {
73-
const repoConfigItem = await getViewSubSection(
74-
"CONFIGURATION",
75-
"Repo"
76-
);
77-
assert(repoConfigItem);
78-
79-
status = undefined;
80-
for (const i of await repoConfigItem.getChildren()) {
81-
if ((await i.getLabel()).includes("State:")) {
82-
status = i;
83-
break;
84-
}
85-
}
86-
assert(status);
87-
const description = await status?.getDescription();
88-
return (
89-
description !== undefined &&
90-
description.includes("WATCHING_FOR_CHANGES")
91-
);
92-
},
93-
{
94-
timeout: 20000,
95-
timeoutMsg: "Couldn't finish sync in 20s",
96-
}
97-
);
51+
it("should install vscode python extension", async function () {
52+
this.retries(1);
53+
await waitForPythonExtension();
9854
});
9955

10056
it("should run a python notebook as a job on a cluster", async () => {
57+
await startSyncIfStopped();
58+
await waitForSyncComplete();
59+
10160
const workbench = await driver.getWorkbench();
10261
const editorView = workbench.getEditorView();
10362
await editorView.closeAllEditors();
@@ -161,6 +120,9 @@ describe("Run python on cluster", async function () {
161120
});
162121

163122
it("should run a python file as a job on a cluster", async () => {
123+
await startSyncIfStopped();
124+
await waitForSyncComplete();
125+
164126
const workbench = await driver.getWorkbench();
165127
const editorView = workbench.getEditorView();
166128
await editorView.closeAllEditors();

packages/databricks-vscode/src/test/e2e/run_on_cluster.e2e.ts

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import * as fs from "fs/promises";
33
import assert from "node:assert";
44
import {
55
getViewSection,
6-
getViewSubSection,
6+
startSyncIfStopped,
77
waitForPythonExtension,
8+
waitForSyncComplete,
89
waitForTreeItems,
910
} from "./utils";
1011
import {sleep} from "wdio-vscode-service";
@@ -36,6 +37,10 @@ describe("Run python on cluster", async function () {
3637
path.join(projectDir, "hello.py"),
3738
`spark.sql('SELECT "hello world"').show()`
3839
);
40+
});
41+
42+
it("should install vscode python extension", async function () {
43+
this.retries(1);
3944
await waitForPythonExtension();
4045
});
4146

@@ -46,25 +51,8 @@ describe("Run python on cluster", async function () {
4651
});
4752

4853
it("should start syncing", async () => {
49-
const section = await getViewSection("CLUSTERS");
50-
await section?.collapse();
51-
52-
const repoConfigItem = await getViewSubSection("CONFIGURATION", "Repo");
53-
assert(repoConfigItem);
54-
const buttons = await repoConfigItem.getActionButtons();
55-
await buttons[0].elem.click();
56-
57-
// wait for sync to finish
58-
const workbench = await driver.getWorkbench();
59-
const terminalView = await workbench.getBottomBar().openTerminalView();
60-
61-
while (true) {
62-
await sleep(500);
63-
const text = await terminalView.getText();
64-
if (text.includes("Sync Complete")) {
65-
break;
66-
}
67-
}
54+
await startSyncIfStopped();
55+
await waitForSyncComplete();
6856
});
6957

7058
it("should run a python file on a cluster", async () => {

packages/databricks-vscode/src/test/e2e/utils.ts

Lines changed: 137 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,45 @@ import {
33
CustomTreeSection,
44
sleep,
55
TreeItem,
6+
ViewControl,
67
ViewSection,
78
} from "wdio-vscode-service";
89

9-
export type ViewSectionType = "CLUSTERS" | "CONFIGURATION";
10-
export async function getViewSection(
11-
name: ViewSectionType
12-
): Promise<ViewSection | undefined> {
10+
// eslint-disable-next-line @typescript-eslint/naming-convention
11+
const ViewSectionTypes = ["CLUSTERS", "CONFIGURATION"] as const;
12+
export type ViewSectionType = typeof ViewSectionTypes[number];
13+
14+
export async function findViewSection(name: ViewSectionType) {
1315
const workbench = await browser.getWorkbench();
1416

15-
let control;
16-
for (let i = 0; i <= 10; i++) {
17-
if (i === 10) {
18-
assert.fail(`Can't find view control "${name}"`);
19-
}
20-
control = await workbench.getActivityBar().getViewControl("Databricks");
21-
if (control) {
22-
break;
17+
let control: ViewControl | undefined;
18+
await browser.waitUntil(
19+
async () => {
20+
control = await workbench
21+
.getActivityBar()
22+
.getViewControl("Databricks");
23+
if (!control) {
24+
return false;
25+
}
26+
return true;
27+
},
28+
{
29+
timeout: 10 * 1000,
30+
interval: 1 * 1000,
31+
timeoutMsg: `Can't find view control "${name}"`,
2332
}
24-
await sleep(500);
25-
}
26-
assert.ok(control);
27-
28-
const view = await control.openView();
29-
assert.ok(view);
30-
31-
const content = await view.getContent();
32-
assert.ok(content);
33+
);
34+
const view = await (await control?.openView())
35+
?.getContent()
36+
?.getSection(name);
37+
return view;
38+
}
3339

34-
const section = await content.getSection(name);
35-
assert.ok(section);
40+
export async function getViewSection(
41+
name: ViewSectionType
42+
): Promise<ViewSection | undefined> {
43+
const section = await findViewSection(name);
44+
assert(section);
3645

3746
await section.expand();
3847
await (await section.elem).click();
@@ -43,6 +52,11 @@ export async function getViewSubSection(
4352
section: ViewSectionType,
4453
subSection: string
4554
): Promise<TreeItem | undefined> {
55+
for (const s of ViewSectionTypes) {
56+
if (s !== section) {
57+
await (await findViewSection(s))?.collapse();
58+
}
59+
}
4660
const sectionView = await getViewSection(section);
4761

4862
if (!sectionView) {
@@ -87,18 +101,30 @@ export async function waitForPythonExtension() {
87101
assert(section);
88102
const welcome = await section.findWelcomeContent();
89103
assert(welcome);
90-
sleep(1000);
104+
sleep(5000);
105+
91106
const workbench = await browser.getWorkbench();
92-
const notifs = await workbench.getNotifications();
93-
for (const n of notifs) {
94-
if (
95-
(await n.getActions()).find(
96-
(btn) => btn.getTitle() === "Install and Reload"
97-
) !== undefined
98-
) {
99-
await n.takeAction("Install and Reload");
107+
browser.waitUntil(
108+
async () => {
109+
const notifs = await workbench.getNotifications();
110+
let found = false;
111+
for (const n of notifs) {
112+
if (
113+
(await n.getActions()).find(
114+
(btn) => btn.getTitle() === "Install and Reload"
115+
) !== undefined
116+
) {
117+
await n.takeAction("Install and Reload");
118+
found = true;
119+
}
120+
}
121+
122+
return found;
123+
},
124+
{
125+
timeout: 10 * 1000,
100126
}
101-
}
127+
);
102128

103129
await browser.waitUntil(
104130
async () =>
@@ -108,16 +134,92 @@ export async function waitForPythonExtension() {
108134
)?.getTitle()
109135
)?.includes("README.quickstart.md") === true,
110136
{
111-
timeout: 120000,
137+
timeout: 1.5 * 60 * 1000,
112138
timeoutMsg:
113139
"Timeout when installing python extension and reloading",
114140
}
115141
);
116142

117-
sleep(500);
143+
sleep(1000);
144+
const notifs = await workbench.getNotifications();
118145
try {
119146
for (const n of notifs) {
120147
await n.dismiss();
121148
}
122149
} catch {}
123150
}
151+
152+
export async function waitForSyncComplete() {
153+
await browser.waitUntil(
154+
async () => {
155+
const repoConfigItem = await getViewSubSection(
156+
"CONFIGURATION",
157+
"Repo"
158+
);
159+
if (repoConfigItem === undefined) {
160+
return false;
161+
}
162+
await repoConfigItem.expand();
163+
164+
let status: TreeItem | undefined = undefined;
165+
for (const i of await repoConfigItem.getChildren()) {
166+
if ((await i.getLabel()).includes("State:")) {
167+
status = i;
168+
break;
169+
}
170+
}
171+
if (status === undefined) {
172+
return false;
173+
}
174+
175+
const description = await status?.getDescription();
176+
return (
177+
description !== undefined &&
178+
description.includes("WATCHING_FOR_CHANGES")
179+
);
180+
},
181+
{
182+
timeout: 60000,
183+
interval: 2000,
184+
timeoutMsg: "Couldn't finish sync in 1m",
185+
}
186+
);
187+
}
188+
189+
export async function startSyncIfStopped() {
190+
browser.waitUntil(
191+
async () => {
192+
const repoConfigItem = await getViewSubSection(
193+
"CONFIGURATION",
194+
"Repo"
195+
);
196+
if (repoConfigItem === undefined) {
197+
return false;
198+
}
199+
await repoConfigItem.expand();
200+
201+
let status: TreeItem | undefined = undefined;
202+
for (const i of await repoConfigItem.getChildren()) {
203+
if ((await i.getLabel()).includes("State:")) {
204+
status = i;
205+
break;
206+
}
207+
}
208+
if (status === undefined) {
209+
return false;
210+
}
211+
212+
if ((await status.getDescription())?.includes("STOPPED")) {
213+
const buttons = await repoConfigItem.getActionButtons();
214+
if (buttons.length === 0) {
215+
return false;
216+
}
217+
await buttons[0].elem.click();
218+
}
219+
return true;
220+
},
221+
{
222+
timeout: 20000,
223+
}
224+
);
225+
}

0 commit comments

Comments
 (0)