Skip to content

wait for notebook to complete #2190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 8, 2021
9 changes: 9 additions & 0 deletions services/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ services:
- default
- interactive_services_subnet
- computational_services_subnet
healthcheck:
test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice addition!

interval: 15s
retries: 5
# NOTES: this is not yet compatible with portainer deployment but could work also for other containers
# works with Docker 19.03 and not yet with Portainer 1.23.0 (see https://github.com/portainer/portainer/issues/3551)
# in the meantime postgres allows to set a configuration through CLI.
Expand Down Expand Up @@ -299,6 +303,11 @@ services:
networks:
- default
- computational_services_subnet
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 30s
retries: 50

traefik:
image: traefik:v2.2.1
Expand Down
74 changes: 44 additions & 30 deletions tests/e2e/tutorials/jupyters.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,43 +27,55 @@ async function runTutorial() {

const workbenchData = utils.extractWorkbenchData(studyData["data"]);
await tutorial.waitForServices(workbenchData["studyId"], [workbenchData["nodeIds"][1], workbenchData["nodeIds"][2]]);
await tutorial.waitFor(2000);

// open jupyterNB
await tutorial.openNode(1);

const iframeHandles = await tutorial.getIframe();
const iframes = [];
for (let i=0; i<iframeHandles.length; i++) {
for (let i = 0; i < iframeHandles.length; i++) {
const frame = await iframeHandles[i].contentFrame();
iframes.push(frame);
}
const nbIframe = iframes.find(iframe => iframe._url.endsWith("tree?"));

// inside the iFrame, open the first notebook
const notebookCBSelector = '#notebook_list > div:nth-child(2) > div > input[type=checkbox]';
await nbIframe.waitForSelector(notebookCBSelector);
await nbIframe.click(notebookCBSelector);
await tutorial.waitFor(2000);
await utils.waitAndClick(nbIframe, notebookCBSelector)
const notebookViewSelector = "#notebook_toolbar > div.col-sm-8.no-padding > div.dynamic-buttons > button.view-button.btn.btn-default.btn-xs"
await nbIframe.waitForSelector(notebookViewSelector);
await nbIframe.click(notebookViewSelector);
await tutorial.waitFor(2000);
await tutorial.takeScreenshot("openNotebook");

// inside the first notebook, click Run button 5 times
const runNBBtnSelector = '#run_int > button:nth-child(1)';
const runNotebookTimes = 5;
for (let i = 0; i < runNotebookTimes; i++) {
await nbIframe.waitForSelector(runNBBtnSelector);
await nbIframe.click(runNBBtnSelector);
await tutorial.waitFor(3000);
await tutorial.takeScreenshot("pressRunNB_" + (i + 1));
await utils.waitAndClick(nbIframe, notebookViewSelector)


// inside the first notebook, click Run all button
const runAllButtonSelector = '#run_int > button:nth-child(4)';
await utils.waitAndClick(nbIframe, runAllButtonSelector);
await tutorial.takeScreenshot("pressRunAllButtonNotebook");

// inside the first notebook, click confirm run all (NOTE: this dialog does not appear in headless mode)
try {
const confirmRunAllButtonSelector = 'body > div.modal.fade.in > div > div > div.modal-footer > button.btn.btn-default.btn-sm.btn-danger';
await utils.waitAndClick(nbIframe, confirmRunAllButtonSelector, 10000);
await tutorial.takeScreenshot("pressRunNotebookAfterConfirmation");
} catch (err) {
console.log("The confirmation dialog appears only in --demo mode.");
}

// TODO: Better check that the kernel is finished
await tutorial.waitFor(3000);

console.log('Checking results for the notebook:');
// now check that the input contains [4]
console.log('Waiting for notebook results...');
const finishedRunningCheckboxSelector = '#notebook-container > div:nth-child(5) > div.input > div.prompt_container > div.prompt.input_prompt';
// the page scrolls down, so first wait so that it becomes visible
await nbIframe.waitForSelector(finishedRunningCheckboxSelector);
await nbIframe.waitForFunction('document.querySelector("' + finishedRunningCheckboxSelector + '").innerText.match(/\[[0-9]+\]/)');
await tutorial.takeScreenshot("notebookWaitingForNotebookCompleted");
console.log('...waiting completed');
const element = await nbIframe.$(finishedRunningCheckboxSelector);
const value = await nbIframe.evaluate(el => el.textContent, element);
console.log('Results for the notebook cell is:', value);
// NOTE: we need to wait here to get the results.
await tutorial.waitFor(10000);

await tutorial.openNodeFiles(1);
const outFiles = [
"TheNumberNumber.txt",
Expand All @@ -77,7 +89,7 @@ async function runTutorial() {

const iframeHandles2 = await tutorial.getIframe();
const iframes2 = [];
for (let i=0; i<iframeHandles2.length; i++) {
for (let i = 0; i < iframeHandles2.length; i++) {
const frame = await iframeHandles2[i].contentFrame();
iframes2.push(frame);
}
Expand All @@ -89,21 +101,23 @@ async function runTutorial() {
await jLabIframe.click(input2outputFileSelector, {
clickCount: 2
});
await tutorial.waitFor(2000);

// click Run Menu
const mainRunMenuBtnSelector = '#jp-MainMenu > ul > li:nth-child(4)';
await jLabIframe.waitForSelector(mainRunMenuBtnSelector);
await jLabIframe.click(mainRunMenuBtnSelector);
await tutorial.waitFor(1000);
await utils.waitAndClick(jLabIframe, mainRunMenuBtnSelector)

// click Run All Cells
const mainRunAllBtnSelector = ' body > div.lm-Widget.p-Widget.lm-Menu.p-Menu.lm-MenuBar-menu.p-MenuBar-menu > ul > li:nth-child(17)';
await jLabIframe.waitForSelector(mainRunAllBtnSelector);
await jLabIframe.click(mainRunAllBtnSelector);
await tutorial.waitFor(6000);
await utils.waitAndClick(jLabIframe, mainRunAllBtnSelector)

console.log('Waiting for jupyter lab results...');
const labCompletedInputSelector = 'div.lm-Widget.p-Widget.jp-MainAreaWidget.jp-NotebookPanel.jp-Document.jp-Activity > div:nth-child(2) > div:nth-child(3) > div.lm-Widget.p-Widget.lm-Panel.p-Panel.jp-Cell-inputWrapper > div.lm-Widget.p-Widget.jp-InputArea.jp-Cell-inputArea > div.lm-Widget.p-Widget.jp-InputPrompt.jp-InputArea-prompt';
await jLabIframe.waitForFunction('document.querySelector("' + labCompletedInputSelector + '").innerText.match(/\[[0-9]+\]/)');
const jLabElement = await jLabIframe.$(labCompletedInputSelector);
const jLabVvalue = await jLabIframe.evaluate(el => el.textContent, jLabElement);
console.log('Checking results for the jupyter lab cell:', jLabVvalue);
await tutorial.takeScreenshot("pressRunJLab");

// wait sufficiently before getting the results
await tutorial.waitFor(10000);
console.log('Checking results for the jupyter lab:');
await tutorial.openNodeFiles(2);
const outFiles2 = [
Expand Down
8 changes: 4 additions & 4 deletions tests/e2e/tutorials/tutorialBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class TutorialBase {
console.error(`"${this.__templateName}" template could not be started:\n`, err);
throw (err);
}
await this.__page.waitFor(waitFor);
await this.__page.waitForTimeout(waitFor);
await this.takeScreenshot("dashboardOpenFirstTemplate_after");
return resp;
}
Expand All @@ -197,7 +197,7 @@ class TutorialBase {
console.error(`"${this.__templateName}" service could not be started:\n`, err);
throw (err);
}
await this.__page.waitFor(waitFor);
await this.__page.waitForTimeout(waitFor);
await this.takeScreenshot("dashboardOpenFirstService_after");
return resp;
}
Expand Down Expand Up @@ -296,7 +296,7 @@ class TutorialBase {

async retrieve(waitAfterRetrieve = 5000) {
await auto.clickRetrieve(this.__page);
await this.__page.waitFor(waitAfterRetrieve);
await this.__page.waitForTimeout(waitAfterRetrieve);
}

async openNodeRetrieveAndRestart(nodePosInTree = 0) {
Expand Down Expand Up @@ -380,7 +380,7 @@ class TutorialBase {
}

async waitFor(waitFor) {
await this.__page.waitFor(waitFor);
await this.__page.waitForTimeout(waitFor);
}

async takeScreenshot(screenshotTitle) {
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/utils/auto.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ async function checkDataProducedByNode(page, nFiles = 1) {
let children = [];
const minTime = 1000; // wait a bit longer for fetching the files
for (let i = 0; i < tries && children.length === 0; i++) {
await page.waitFor(minTime * (i + 1));
await page.waitForTimeout(minTime * (i + 1));
await page.waitForSelector('[osparc-test-id="fileTreeItem_NodeFiles"]');
children = await utils.getFileTreeItemIDs(page, "NodeFiles");
console.log(i + 1, 'try: ', children);
Expand Down
8 changes: 4 additions & 4 deletions tests/e2e/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ async function isServiceConnected(page, studyId, nodeId) {
console.log("-- Is Service Connected", nodeId);
const serviceUrl = await getServiceUrl(page, studyId, nodeId);
const connected = await makePingRequest(page, serviceUrl);
console.log(connected, "--")
console.log(connected ? ("service " + nodeId + " connected") : ("service" + nodeId + " connecting..."), "--")
return connected;
}

Expand Down Expand Up @@ -300,10 +300,10 @@ async function waitForValidOutputFile(page) {
})
}

async function waitAndClick(page, id) {
async function waitAndClick(page, id, timeout) {
await page.waitForSelector(id, {
timeout: 30000 // default 30s
})
timeout: (timeout ? timeout : 30000) // default 30s
});
await page.click(id);
}

Expand Down