From 0731d40e3f6d0592b92ea9cff2458f21042f4533 Mon Sep 17 00:00:00 2001 From: Pedro Crespo <32402063+pcrespov@users.noreply.github.com> Date: Wed, 2 Dec 2020 17:09:55 +0100 Subject: [PATCH 1/6] Adding snapshot in graylog --- tests/e2e/utils/utils.js | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/e2e/utils/utils.js b/tests/e2e/utils/utils.js index aac8c9f2021b..5ace0c7078ff 100644 --- a/tests/e2e/utils/utils.js +++ b/tests/e2e/utils/utils.js @@ -295,6 +295,29 @@ function extractWorkbenchData(data) { return workbenchData; } +function getGrayLogSnapshotUrl(environment, since_secs=30){ + // WARNING: This list might change!! + const monitoring_base_url = { + "staging.osparc.io": "https://monitoring.staging.osparc.io/graylog/", + "osparc.io": "https://monitoring.osparc.io/graylog/", + "osparc-master.speag.com": "https://monitoring.osparc-master.speag.com/graylog/", + "osparc-staging.speag.com": "https://monitoring.osparc.speag.com/graylog/", + "osparc.speag.com": "https://monitoring.osparc.speag.com/graylog/", + }[environment]; + + if (monitoring_base_url != undefined) { + const now_millisecs = Date.now(); + const from = encodeURIComponent(new Date(now_millisecs - since_secs * 1000).toISOString()); + const to = encodeURIComponent(new Date(now_millisecs).toISOString()); + + search_query = "image_name%3Aitisfoundation%2A"; //image_name:itisfoundation* + url = `${monitoring_base_url}search?q=${search_query}&rangetype=absolute&from=${from}&to=${to}`; + } + + return url +} + + module.exports = { getUserAndPass, getDomain, @@ -316,5 +339,6 @@ module.exports = { createScreenshotsDir, takeScreenshot, extractWorkbenchData, - parseCommandLineArguments + parseCommandLineArguments, + getGrayLogSnapshotUrl } From e4964c1c459549987d789d0f7372cb9b61820bc7 Mon Sep 17 00:00:00 2001 From: Pedro Crespo <32402063+pcrespov@users.noreply.github.com> Date: Thu, 3 Dec 2020 09:53:06 +0100 Subject: [PATCH 2/6] Minimal doc --- tests/e2e/README.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 791947db33c5..3649e5392b95 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -1,3 +1,8 @@ +# end-to-end (e2e) testing + + +Presentation "[Understanding e2e testing](https://docs.google.com/presentation/d/1Kc2kz1e6Fl3XNDGXfPx_Aurqx29edGuke4rnIfHr5bI/edit?usp=sharing)" by @odeimaiz on Dec 2, 2020 + **WARNING**: Be aware that running these tests in your host might risk changing some configuration. @@ -49,8 +54,21 @@ Add the following configuration to your local ``launch.json``: ``` Now you can run the tests by clicking on the Play button, using that configuration. It should allow you to insert breakpoints and inspect variables. -## To run the tutorials -```bash + +## Run end-to-end + +```cmd +cd tests/e2e +npm install --save +node tutorials/{{test.js}} {{deployment}} ({{user}}) ({{password}}) (--demo) +node tutorials/sleepers.js https://osparc-master.speag.com/ puppeteer@itis.testing mypass --demo +``` +## Run portal-to-end + +```cmd cd tests/e2e -node tutorials/.js [ ] +npm install --save +node portal/{{test.js}} {{deployment}}/study/ {{published_template_uuid}} +# example +node portal/2D_Plot.js https://osparc-master.speag.com/study/ 003aaf4a-524a-11ea-b061-02420a00070b ``` From fdaffe0a1a5888f693fe469f34c7ce08d84b7b1e Mon Sep 17 00:00:00 2001 From: Pedro Crespo <32402063+pcrespov@users.noreply.github.com> Date: Thu, 3 Dec 2020 09:54:32 +0100 Subject: [PATCH 3/6] Util function to get snapshot url --- tests/e2e/utils/utils.js | 43 ++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/tests/e2e/utils/utils.js b/tests/e2e/utils/utils.js index 5ace0c7078ff..2784f8fed905 100644 --- a/tests/e2e/utils/utils.js +++ b/tests/e2e/utils/utils.js @@ -46,9 +46,9 @@ function getUserAndPass(args) { return userPass; } -function __getRandUserAndPass() { +function __getRandUserAndPass() { const randUser = Math.random().toString(36).substring(7); - const user = 'puppeteer_'+randUser+'@itis.testing'; + const user = 'puppeteer_' + randUser + '@itis.testing'; const pass = Math.random().toString(36).substring(7); return { user, @@ -69,7 +69,7 @@ async function getNodeTreeItemIDs(page) { const treeRoot = document.querySelector(selector); if (treeRoot.parentElement) { const tree = treeRoot.parentElement; - for (let i=1; i { - const response = await fetch(url+apiVersion+endpoint); + const response = await fetch(url + apiVersion + endpoint); return await response.json(); }, url, apiVersion, endpoint); return responseEnv; @@ -136,7 +136,7 @@ async function makeRequest(page, endpoint, apiVersion = "v0") { // https://github.com/Netflix/pollyjs/issues/149#issuecomment-481108446 await page.setBypassCSP(true); const resp = await page.evaluate(async (host, endpoint, apiVersion) => { - const url = host+apiVersion+endpoint; + const url = host + apiVersion + endpoint; console.log("makeRequest", url); const resp = await fetch(url); const jsonResp = await resp.json(); @@ -169,7 +169,7 @@ async function waitForResponse(page, url) { } async function isServiceReady(page, studyId, nodeId) { - const endPoint = "/projects/" + studyId +"/nodes/" + nodeId; + const endPoint = "/projects/" + studyId + "/nodes/" + nodeId; console.log("-- Is service ready", endPoint); const resp = await makeRequest(page, endPoint); @@ -184,7 +184,7 @@ async function isServiceReady(page, studyId, nodeId) { } async function isStudyDone(page, studyId) { - const endPoint = "/projects/" + studyId +"/state"; + const endPoint = "/projects/" + studyId + "/state"; console.log("-- Is study done", endPoint); const resp = await makeRequest(page, endPoint); @@ -198,7 +198,7 @@ async function isStudyDone(page, studyId) { } async function isStudyUnlocked(page, studyId) { - const endPoint = "/projects/" + studyId +"/state"; + const endPoint = "/projects/" + studyId + "/state"; console.log("-- Is study closed", endPoint); const resp = await makeRequest(page, endPoint); @@ -214,7 +214,7 @@ async function waitForValidOutputFile(page) { if (header['content-type'] === "binary/octet-stream") { resp.text().then( b => { - if (b>=0 && b<=10) { + if (b >= 0 && b <= 10) { page.removeListener("response", callback) resolve(b) } @@ -278,7 +278,7 @@ async function takeScreenshot(page, captureName = "") { quality: 15 }) } - catch(err) { + catch (err) { console.error("Error taking screenshot", err); } } @@ -295,15 +295,24 @@ function extractWorkbenchData(data) { return workbenchData; } -function getGrayLogSnapshotUrl(environment, since_secs=30){ - // WARNING: This list might change!! - const monitoring_base_url = { +function getGrayLogSnapshotUrl(target_url, since_secs = 30) { + let monitoring_base_url; + let snapshot_url; + + // WARNING: This mappings might change + const table = { "staging.osparc.io": "https://monitoring.staging.osparc.io/graylog/", "osparc.io": "https://monitoring.osparc.io/graylog/", "osparc-master.speag.com": "https://monitoring.osparc-master.speag.com/graylog/", "osparc-staging.speag.com": "https://monitoring.osparc.speag.com/graylog/", "osparc.speag.com": "https://monitoring.osparc.speag.com/graylog/", - }[environment]; + }; + for (var key in table) { + if (target_url.startsWith("https://" + key)) { + monitoring_base_url = table[key]; + break; + } + } if (monitoring_base_url != undefined) { const now_millisecs = Date.now(); @@ -311,10 +320,10 @@ function getGrayLogSnapshotUrl(environment, since_secs=30){ const to = encodeURIComponent(new Date(now_millisecs).toISOString()); search_query = "image_name%3Aitisfoundation%2A"; //image_name:itisfoundation* - url = `${monitoring_base_url}search?q=${search_query}&rangetype=absolute&from=${from}&to=${to}`; + snapshot_url = `${monitoring_base_url}search?q=${search_query}&rangetype=absolute&from=${from}&to=${to}`; } - return url + return snapshot_url } From 6ed257195144384abb56afd93cfc714b3510d6c8 Mon Sep 17 00:00:00 2001 From: Pedro Crespo <32402063+pcrespov@users.noreply.github.com> Date: Thu, 3 Dec 2020 10:10:13 +0100 Subject: [PATCH 4/6] Adds snapshot at the same time it takes a screenshot --- tests/e2e/tutorials/tutorialBase.js | 83 ++++++++++++++++------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/tests/e2e/tutorials/tutorialBase.js b/tests/e2e/tutorials/tutorialBase.js index 628dbb25b08a..8483e0470bb9 100644 --- a/tests/e2e/tutorials/tutorialBase.js +++ b/tests/e2e/tutorials/tutorialBase.js @@ -6,7 +6,7 @@ const utils = require('../utils/utils'); const responses = require('../utils/responsesQueue'); class TutorialBase { - constructor(url, templateName, user, pass, newUser, enableDemoMode=false) { + constructor(url, templateName, user, pass, newUser, enableDemoMode = false) { this.__demo = enableDemoMode; this.__templateName = templateName; @@ -28,12 +28,12 @@ class TutorialBase { try { utils.createScreenshotsDir(); } - catch(err) { + catch (err) { console.error("Error creating screenshots directory", err); - throw(err); + throw (err); } - this.__interval = setInterval(async() => { + this.__interval = setInterval(async () => { await this.takeScreenshot(); }, 2000); } @@ -55,9 +55,9 @@ class TutorialBase { try { await this.__page.goto(this.__url); } - catch(err) { + catch (err) { console.error(this.__url, "can't be reached", err); - throw(err); + throw (err); } const domain = utils.getDomain(this.__url); await this.takeScreenshot("landingPage_" + domain); @@ -73,9 +73,9 @@ class TutorialBase { await this.login(); } } - catch(err) { + catch (err) { console.error("Error starting", err); - throw(err); + throw (err); } } @@ -87,9 +87,9 @@ class TutorialBase { await this.__goTo(); resp = await this.__responsesQueue.waitUntilResponse("open", openStudyTimeout); } - catch(err) { + catch (err) { console.error(this.__templateName, "could not be started", err); - throw(err); + throw (err); } return resp; } @@ -109,9 +109,9 @@ class TutorialBase { try { await auto.logIn(this.__page, this.__user, this.__pass); } - catch(err) { + catch (err) { console.error("Failed logging in", err); - throw(err); + throw (err); } try { @@ -122,9 +122,9 @@ class TutorialBase { console.log(" - ", template.name); }); } - catch(err) { + catch (err) { console.error("Templates could not be fetched", err); - throw(err); + throw (err); } try { @@ -132,9 +132,9 @@ class TutorialBase { const services = resp["data"]; console.log("Services received:", services.length); } - catch(err) { + catch (err) { console.error("Services could not be fetched", err); - throw(err); + throw (err); } } @@ -144,7 +144,7 @@ class TutorialBase { try { resp = await this.__responsesQueue.waitUntilResponse("open"); } - catch(err) { + catch (err) { console.error(this.__templateName, "could not be started", err); } return resp; @@ -161,9 +161,9 @@ class TutorialBase { await this.__responsesQueue.waitUntilResponse("projects?from_template="); resp = await this.__responsesQueue.waitUntilResponse("open"); } - catch(err) { + catch (err) { console.error(`"${this.__templateName}" template could not be started:\n`, err); - throw(err); + throw (err); } await this.__page.waitFor(waitFor); await this.takeScreenshot("dashboardOpenFirstTemplate_after"); @@ -179,9 +179,9 @@ class TutorialBase { assert(serviceFound, "Expected service, got nothing. TIP: is it available??"); resp = await this.__responsesQueue.waitUntilResponse("open"); } - catch(err) { + catch (err) { console.error(`"${this.__templateName}" service could not be started:\n`, err); - throw(err); + throw (err); } await this.__page.waitFor(waitFor); await this.takeScreenshot("dashboardOpenFirstService_after"); @@ -194,8 +194,8 @@ class TutorialBase { } const start = new Date().getTime(); - while ((new Date().getTime())-start < timeout) { - for (let i = nodeIds.length-1; i>=0; i--) { + while ((new Date().getTime()) - start < timeout) { + for (let i = nodeIds.length - 1; i >= 0; i--) { const nodeId = nodeIds[i]; if (await utils.isServiceReady(this.__page, studyId, nodeId)) { nodeIds.splice(i, 1); @@ -203,37 +203,37 @@ class TutorialBase { } await utils.sleep(2500); if (nodeIds.length === 0) { - console.log("Services ready in", ((new Date().getTime())-start)/1000); + console.log("Services ready in", ((new Date().getTime()) - start) / 1000); // after the service is responsive we need to wait a bit until the iframe is rendered await utils.sleep(3000); return; } } - console.log("Timeout reached waiting for services", ((new Date().getTime())-start)/1000); + console.log("Timeout reached waiting for services", ((new Date().getTime()) - start) / 1000); return; } async waitForStudyRun(studyId, timeout = 60000) { const start = new Date().getTime(); - while ((new Date().getTime())-start < timeout) { + while ((new Date().getTime()) - start < timeout) { await utils.sleep(5000); if (await utils.isStudyDone(this.__page, studyId)) { return; } } - console.log("Timeout reached waiting for study run", ((new Date().getTime())-start)/1000); + console.log("Timeout reached waiting for study run", ((new Date().getTime()) - start) / 1000); return; } async waitForStudyUnlocked(studyId, timeout = 10000) { const start = new Date().getTime(); - while ((new Date().getTime())-start < timeout) { - await utils.sleep(timeout/10); + while ((new Date().getTime()) - start < timeout) { + await utils.sleep(timeout / 10); if (await utils.isStudyUnlocked(this.__page, studyId)) { return; } } - console.log("Timeout reached waiting for study unlock", ((new Date().getTime())-start)/1000); + console.log("Timeout reached waiting for study unlock", ((new Date().getTime()) - start) / 1000); return; } @@ -270,9 +270,9 @@ class TutorialBase { try { await this.__responsesQueue.waitUntilResponse("storage/locations/0/files/metadata?uuid_filter=" + nodeId); } - catch(err) { + catch (err) { console.error(err); - throw(err); + throw (err); } } @@ -294,9 +294,9 @@ class TutorialBase { try { await auto.checkDataProducedByNode(this.__page, expecedNFiles); } - catch(err) { + catch (err) { console.error("Failed checking Data Produced By Node", err); - throw(err); + throw (err); } await this.takeScreenshot("checkResults_after"); } @@ -312,9 +312,9 @@ class TutorialBase { await auto.toDashboard(this.__page); await this.__responsesQueue.waitUntilResponse(":close"); } - catch(err) { + catch (err) { console.error("Failed closing study", err); - throw(err); + throw (err); } await this.takeScreenshot("closeStudy_after"); } @@ -325,9 +325,9 @@ class TutorialBase { await this.waitForStudyUnlocked(studyId); await auto.deleteFirstStudy(this.__page, this.__templateName); } - catch(err) { + catch (err) { console.error("Failed deleting study", err); - throw(err); + throw (err); } await this.takeScreenshot("deleteFirstStudy_after"); } @@ -346,9 +346,16 @@ class TutorialBase { } async takeScreenshot(screenshotTitle) { + // Generates an URL that points to the backend logs at this time + const snapshot_url = utils.getGrayLogSnapshotUrl(this.__url, 30); + if (snapshot_url !== undefined) { + console.log("Backend Snapshot: ", snapshot_url) + } + if (this.__demo) { return; } + let title = this.__templateName; if (screenshotTitle) { title += '_' + screenshotTitle; From 5f24f89df93a91b9e587b08ea60532f49e040515 Mon Sep 17 00:00:00 2001 From: Pedro Crespo <32402063+pcrespov@users.noreply.github.com> Date: Thu, 3 Dec 2020 12:11:29 +0100 Subject: [PATCH 5/6] Update tests/e2e/README.md Co-authored-by: Odei Maiz <33152403+odeimaiz@users.noreply.github.com> --- tests/e2e/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 3649e5392b95..f0414176299e 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -61,7 +61,7 @@ Now you can run the tests by clicking on the Play button, using that configurati cd tests/e2e npm install --save node tutorials/{{test.js}} {{deployment}} ({{user}}) ({{password}}) (--demo) -node tutorials/sleepers.js https://osparc-master.speag.com/ puppeteer@itis.testing mypass --demo +node tutorials/sleepers.js https://osparc-master.speag.com/ user@domain mypass --demo ``` ## Run portal-to-end From 914ae101f47658f248609340aaa9d6a20282d720 Mon Sep 17 00:00:00 2001 From: Pedro Crespo <32402063+pcrespov@users.noreply.github.com> Date: Thu, 3 Dec 2020 12:24:53 +0100 Subject: [PATCH 6/6] Adds feedback from @ignapas --- tests/e2e/tutorials/tutorialBase.js | 6 +++--- tests/e2e/utils/utils.js | 22 +++++++++------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/tests/e2e/tutorials/tutorialBase.js b/tests/e2e/tutorials/tutorialBase.js index 8483e0470bb9..b4c50e596b6a 100644 --- a/tests/e2e/tutorials/tutorialBase.js +++ b/tests/e2e/tutorials/tutorialBase.js @@ -347,9 +347,9 @@ class TutorialBase { async takeScreenshot(screenshotTitle) { // Generates an URL that points to the backend logs at this time - const snapshot_url = utils.getGrayLogSnapshotUrl(this.__url, 30); - if (snapshot_url !== undefined) { - console.log("Backend Snapshot: ", snapshot_url) + const snapshotUrl = utils.getGrayLogSnapshotUrl(this.__url, 30); + if (snapshotUrl) { + console.log("Backend Snapshot: ", snapshotUrl) } if (this.__demo) { diff --git a/tests/e2e/utils/utils.js b/tests/e2e/utils/utils.js index 2784f8fed905..dd5e5785e4f2 100644 --- a/tests/e2e/utils/utils.js +++ b/tests/e2e/utils/utils.js @@ -295,9 +295,8 @@ function extractWorkbenchData(data) { return workbenchData; } -function getGrayLogSnapshotUrl(target_url, since_secs = 30) { - let monitoring_base_url; - let snapshot_url; +function getGrayLogSnapshotUrl(targetUrl, since_secs = 30) { + let snapshotUrl = null; // WARNING: This mappings might change const table = { @@ -307,23 +306,20 @@ function getGrayLogSnapshotUrl(target_url, since_secs = 30) { "osparc-staging.speag.com": "https://monitoring.osparc.speag.com/graylog/", "osparc.speag.com": "https://monitoring.osparc.speag.com/graylog/", }; - for (var key in table) { - if (target_url.startsWith("https://" + key)) { - monitoring_base_url = table[key]; - break; - } - } - if (monitoring_base_url != undefined) { + const { hostname } = new URL(targetUrl) + const monitoringBaseUrl = table[hostname] || null; + + if (monitoringBaseUrl) { const now_millisecs = Date.now(); const from = encodeURIComponent(new Date(now_millisecs - since_secs * 1000).toISOString()); const to = encodeURIComponent(new Date(now_millisecs).toISOString()); - search_query = "image_name%3Aitisfoundation%2A"; //image_name:itisfoundation* - snapshot_url = `${monitoring_base_url}search?q=${search_query}&rangetype=absolute&from=${from}&to=${to}`; + const searchQuery = "image_name%3Aitisfoundation%2A"; // image_name:itisfoundation* + snapshotUrl = `${monitoringBaseUrl}search?q=${searchQuery}&rangetype=absolute&from=${from}&to=${to}`; } - return snapshot_url + return snapshotUrl }