diff --git a/package-lock.json b/package-lock.json index 02938df125..17381c9863 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3898,6 +3898,11 @@ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true }, + "denque": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", + "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==" + }, "deprecation": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", @@ -4680,6 +4685,14 @@ } } }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, "genfun": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", @@ -5953,6 +5966,11 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, "is-regex": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", @@ -6687,6 +6705,11 @@ } } }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -7210,6 +7233,44 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, + "mysql2": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", + "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", + "requires": { + "denque": "^2.0.1", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^4.0.0", + "lru-cache": "^6.0.0", + "named-placeholders": "^1.1.2", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -7221,6 +7282,30 @@ "thenify-all": "^1.0.0" } }, + "named-placeholders": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", + "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", + "requires": { + "lru-cache": "^4.1.3" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -7938,6 +8023,11 @@ "genfun": "^5.0.0" } }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -8478,8 +8568,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "scriptjs": { "version": "2.5.9", @@ -8493,6 +8582,11 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -8886,6 +8980,11 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sqlstring": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", + "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==" + }, "ssf": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", diff --git a/package.json b/package.json index 2ff9abee12..1343d9448f 100644 --- a/package.json +++ b/package.json @@ -23,5 +23,8 @@ "doc": "lerna run doc", "install:local:dep": "cd packages/nc-lib-gui;npm uninstall -S xc-lib;rm package-lock.json; npm i ../../../xc-lib-private; cd ../xc-instant;npm uninstall -S xc-lib xc-lib-gui;npm i ../../../xc-lib-private;npm i ../xc-lib-gui", "install:npm:dep": "cd packages/nc-lib-gui;npm uninstall -S xc-lib; npm i -S xc-lib@latest; cd ../xc-instant;npm uninstall -S xc-lib xc-lib-gui;npm i -S xc-lib@latest xc-lib-gui@latest;npm i ../xc-lib-gui" + }, + "dependencies": { + "mysql2": "^2.3.3" } } diff --git a/scripts/cypress/cypress.json b/scripts/cypress/cypress.json index 6a9446d944..80957bd1cb 100644 --- a/scripts/cypress/cypress.json +++ b/scripts/cypress/cypress.json @@ -19,7 +19,12 @@ "screenshotOnRunFailure": false, "numTestsKeptInMemory": 0, "env": { - "testMode": "extREST.extGQL" + "testMode": "extREST.extGQL", + "db": { + "host": "127.0.0.1", + "user": "root", + "password": "password" + } }, "supportedOptionsForTestModes": [ "extGQL", diff --git a/scripts/cypress/integration/common/1e_meta_sync.js b/scripts/cypress/integration/common/1e_meta_sync.js new file mode 100644 index 0000000000..4c25206927 --- /dev/null +++ b/scripts/cypress/integration/common/1e_meta_sync.js @@ -0,0 +1,134 @@ +import { mainPage } from "../../support/page_objects/mainPage"; +import { loginPage } from "../../support/page_objects/navigation"; +import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; + +export const genTest = (type, xcdb) => { + if (!isTestSuiteActive(type, xcdb)) return; + + describe(`${type.toUpperCase()} api - Meta Sync`, () => { + // Run once before test- create project (rest/graphql) + // + before(() => { + // loginPage.loginAndOpenProject(type); + }); + + function openMetaTab(msg) { + // open Project metadata tab + // + mainPage.navigationDraw(mainPage.PROJ_METADATA).click(); + cy.get(".nc-meta-mgmt-metadata-tab") + .should('exist') + .click({ force: true }); + // kludge, at times test failed to open tab on click + cy.get(".nc-meta-mgmt-metadata-tab") + .should('exist') + .click({ force: true }); + + // validate alert message + cy.get(".v-alert") + .contains(msg) + .should("exist"); + } + + function closeMetaTab() { + // user href link to find meta mgmt tab + cy.get('[href="#disableOrEnableModel||||Meta Management"]') + .find("button.mdi-close") + .click({ force: true }); + // refresh + cy.refreshTableTab(); + } + + function metaSyncValidate(scenario, context) { + if (scenario === 'out of sync') { + openMetaTab(`Tables metadata is out of sync`); + cy.get('.nc-btn-sync-meta-data').should('exist').click(); + cy.toastWait(`Table metadata ${context} successfully`); + + } else { + openMetaTab(`Tables metadata is in sync`); + } + closeMetaTab(); + } + + beforeEach(() => { + // ensure tables are in sync before each operation + openMetaTab(`Tables metadata is in sync`); + closeMetaTab(); + }) + + it(`Create table`, () => { + // Create Table + cy.task("queryDb", `CREATE TABLE sakila.table1 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`); + cy.task("queryDb", `CREATE TABLE sakila.table2 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`); + metaSyncValidate('out of sync', 'added'); + }) + + it(`Add relation`, () => { + // Add relation (FK) + cy.task("queryDb", `ALTER TABLE sakila.table1 ADD INDEX fk1_idx (col1 ASC) VISIBLE`) + cy.task("queryDb", `ALTER TABLE sakila.table1 ADD CONSTRAINT fk1 FOREIGN KEY (col1) REFERENCES sakila.table2 (id) ON DELETE NO ACTION ON UPDATE NO ACTION`); + // fix me + metaSyncValidate('in sync'); + }) + + it(`Remove relation`, () => { + // Remove relation (FK) + cy.task("queryDb", `ALTER TABLE sakila.table1 DROP FOREIGN KEY fk1`); + cy.task("queryDb", `ALTER TABLE sakila.table1 DROP INDEX fk1_idx`); + // fix me + metaSyncValidate('in sync'); + }) + + it(`Add column`, () => { + // Add Column + cy.task("queryDb", `ALTER TABLE sakila.table1 ADD COLUMN newCol VARCHAR(45) NULL AFTER id`); + // fix me + metaSyncValidate('in sync'); + }) + + it(`Rename column`, () => { + // Rename Column + cy.task("queryDb", `ALTER TABLE sakila.table1 CHANGE COLUMN newCol newColName VARCHAR(45) NULL DEFAULT NULL`); + // fix me + metaSyncValidate('in sync'); + }) + + it(`Delete column`, () => { + // Remove Column + cy.task("queryDb", `ALTER TABLE sakila.table1 DROP COLUMN newColName`); + // fix me + metaSyncValidate('in sync'); + }) + + it(`Delete table`, () => { + // DROP TABLE + cy.task("queryDb", `DROP TABLE sakila.table1`); + cy.task("queryDb", `DROP TABLE sakila.table2`); + metaSyncValidate('out of sync', 'deleted'); + }) + }); +}; + +/** + * @copyright Copyright (c) 2021, Xgene Cloud Ltd + * + * @author Pranav C Balan + * @author Raju Udava + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ diff --git a/scripts/cypress/integration/test/gqlTableOps.js b/scripts/cypress/integration/test/gqlTableOps.js index 8b7bd7c20f..f1c56651fc 100644 --- a/scripts/cypress/integration/test/gqlTableOps.js +++ b/scripts/cypress/integration/test/gqlTableOps.js @@ -4,6 +4,7 @@ let t1a = require("../common/1a_table_operations"); let t1c = require("../common/1c_sql_view"); let t1d = require("../common/1d_table_view_drag_drop_reorder"); let t1b = require("../common/1b_table_column_operations"); +let t1e = require("../common/1e_meta_sync"); let t2a = require("../common/2a_table_with_belongs_to_colulmn"); let t2b = require("../common/2b_table_with_m2m_column"); let t3a = require("../common/3a_filter_sort_fields_operations"); @@ -26,6 +27,7 @@ const nocoTestSuite = (type, xcdb) => { t1b.genTest(type, xcdb); t1c.genTest(type, xcdb); t1d.genTest(type, xcdb); + t1e.genTest(type, xcdb); t2a.genTest(type, xcdb); t2b.genTest(type, xcdb); t3a.genTest(type, xcdb); diff --git a/scripts/cypress/integration/test/restTableOps.js b/scripts/cypress/integration/test/restTableOps.js index 4eee66fade..ab52710573 100644 --- a/scripts/cypress/integration/test/restTableOps.js +++ b/scripts/cypress/integration/test/restTableOps.js @@ -4,6 +4,7 @@ let t1a = require("../common/1a_table_operations"); let t1b = require("../common/1b_table_column_operations"); let t1c = require("../common/1c_sql_view"); let t1d = require("../common/1d_table_view_drag_drop_reorder"); +let t1e = require("../common/1e_meta_sync") let t2a = require("../common/2a_table_with_belongs_to_colulmn"); let t2b = require("../common/2b_table_with_m2m_column"); let t3a = require("../common/3a_filter_sort_fields_operations"); @@ -26,6 +27,7 @@ const nocoTestSuite = (type, xcdb) => { t1b.genTest(type, xcdb); t1c.genTest(type, xcdb); t1d.genTest(type, xcdb); + t1e.genTest(type, xcdb); t2a.genTest(type, xcdb); t2b.genTest(type, xcdb); t3a.genTest(type, xcdb); diff --git a/scripts/cypress/plugins/index.js b/scripts/cypress/plugins/index.js index 33d1b93d79..9732941194 100644 --- a/scripts/cypress/plugins/index.js +++ b/scripts/cypress/plugins/index.js @@ -47,5 +47,30 @@ module.exports = (on, config) => { console.log(`##Cypress>> ${message}`); return null; }, + queryDb: (query) => { + return queryTestDb(query, config); + }, }); }; + +// mysql connection +// https://gist.github.com/fityanos/0a345e9e9de498b6c629f78e6b2835f5 + +const mysql = require("mysql2"); +function queryTestDb(query, config) { + // creates a new mysql connection using credentials from cypress.json env's + const connection = mysql.createConnection(config.env.db); + // start connection to db + connection.connect(); + // exec query + disconnect to db as a Promise + return new Promise((resolve, reject) => { + connection.query(query, (error, results) => { + if (error) reject(error); + else { + connection.end(); + // console.log(results) + return resolve(results); + } + }); + }); +} diff --git a/scripts/cypress/support/commands.js b/scripts/cypress/support/commands.js index 09934487d8..f0b2152d63 100644 --- a/scripts/cypress/support/commands.js +++ b/scripts/cypress/support/commands.js @@ -107,6 +107,20 @@ Cypress.Commands.add("openOrCreateRestProject", (_args) => { cy.url({ timeout: 20000 }).should("contain", "#/nc/"); }); +Cypress.Commands.add("refreshTableTab", () => { + cy.task("log", `[refreshTableTab]`); + + cy.get(".nc-project-tree") + .find(".v-list-item__title:contains(Tables)", { timeout: 10000 }) + .should("exist") + .first() + .rightclick({ force: true }); + + cy.getActiveMenu().find('[role="menuitem"]').contains('Tables Refresh').click() + + cy.toastWait('Tables refreshed'); +}) + // tn: table name // rc: row count. validate row count if rc!=0 Cypress.Commands.add("openTableTab", (tn, rc) => {