mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-21 03:36:01 +00:00
feat: basic cassandra tests setup
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
const stableStringify = require('json-stable-stringify');
|
const stableStringify = require('json-stable-stringify');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const fp = require('lodash/fp');
|
const fp = require('lodash/fp');
|
||||||
const { testWrapper } = require('../tools');
|
const { testWrapper, removeNotNull, transformSqlForEngine } = require('../tools');
|
||||||
const engines = require('../engines');
|
const engines = require('../engines');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const {
|
const {
|
||||||
@@ -33,36 +33,36 @@ function checkTableStructure(engine, t1, t2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function testTableDiff(engine, conn, driver, mangle) {
|
async function testTableDiff(engine, conn, driver, mangle) {
|
||||||
await driver.query(conn, formatQueryWithoutParams(driver, `create table ~t0 (~id int not null primary key)`));
|
const initQuery = formatQueryWithoutParams(driver, `create table ~t0 (~id int not null primary key)`);
|
||||||
|
await driver.query(conn, transformSqlForEngine(engine, initQuery));
|
||||||
|
|
||||||
await driver.query(
|
const query = formatQueryWithoutParams(
|
||||||
conn,
|
driver,
|
||||||
formatQueryWithoutParams(
|
`create table ~t1 (
|
||||||
driver,
|
|
||||||
`create table ~t1 (
|
|
||||||
~col_pk int not null primary key,
|
~col_pk int not null primary key,
|
||||||
~col_std int,
|
~col_std int,
|
||||||
~col_def int default 12,
|
~col_def int ${engine.skipDefaultValue ? '' : 'default 12'},
|
||||||
${engine.skipReferences ? '' : '~col_fk int references ~t0(~id),'}
|
${engine.skipReferences ? '' : '~col_fk int references ~t0(~id),'}
|
||||||
~col_idx int,
|
~col_idx int,
|
||||||
~col_uq int ${engine.skipUnique ? '' : 'unique'} ,
|
~col_uq int ${engine.skipUnique ? '' : 'unique'} ,
|
||||||
~col_ref int ${engine.skipUnique ? '' : 'unique'}
|
~col_ref int ${engine.skipUnique ? '' : 'unique'}
|
||||||
)`
|
)`
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await driver.query(conn, transformSqlForEngine(engine, query));
|
||||||
|
|
||||||
if (!engine.skipIndexes) {
|
if (!engine.skipIndexes) {
|
||||||
await driver.query(conn, formatQueryWithoutParams(driver, `create index ~idx1 on ~t1(~col_idx)`));
|
const query = formatQueryWithoutParams(driver, `create index ~idx1 on ~t1(~col_idx)`);
|
||||||
|
await driver.query(conn, transformSqlForEngine(engine, query));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!engine.skipReferences) {
|
if (!engine.skipReferences) {
|
||||||
await driver.query(
|
const query = formatQueryWithoutParams(
|
||||||
conn,
|
driver,
|
||||||
formatQueryWithoutParams(
|
`create table ~t2 (~id int not null primary key, ~fkval int null references ~t1(~col_ref))`
|
||||||
driver,
|
|
||||||
`create table ~t2 (~id int not null primary key, ~fkval int null references ~t1(~col_ref))`
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await driver.query(conn, transformSqlForEngine(engine, query));
|
||||||
}
|
}
|
||||||
|
|
||||||
const tget = x => x.tables.find(y => y.pureName == 't1');
|
const tget = x => x.tables.find(y => y.pureName == 't1');
|
||||||
@@ -89,14 +89,12 @@ const TESTED_COLUMNS = ['col_pk', 'col_std', 'col_def', 'col_fk', 'col_ref', 'co
|
|||||||
// const TESTED_COLUMNS = ['col_std'];
|
// const TESTED_COLUMNS = ['col_std'];
|
||||||
// const TESTED_COLUMNS = ['col_ref'];
|
// const TESTED_COLUMNS = ['col_ref'];
|
||||||
|
|
||||||
function engines_columns_source() {
|
function create_engines_columns_source(engines) {
|
||||||
return _.flatten(
|
return _.flatten(
|
||||||
engines.map(engine =>
|
engines.map(engine =>
|
||||||
TESTED_COLUMNS.filter(col => !col.endsWith('_pk') || !engine.skipPkColumnTesting).map(column => [
|
TESTED_COLUMNS.filter(col => col.endsWith('_pk') || !engine.skipNonPkRename)
|
||||||
engine.label,
|
.filter(col => !col.endsWith('_pk') || !engine.skipPkColumnTesting)
|
||||||
column,
|
.map(column => [engine.label, column, engine])
|
||||||
engine,
|
|
||||||
])
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -117,26 +115,45 @@ describe('Alter table', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
test.each(engines_columns_source())(
|
const columnsSource = create_engines_columns_source(engines);
|
||||||
'Drop column - %s - %s',
|
const dropableColumnsSrouce = columnsSource.filter(
|
||||||
testWrapper(async (conn, driver, column, engine) => {
|
([_label, col, engine]) => !engine.skipPkDrop || !col.endsWith('_pk')
|
||||||
await testTableDiff(engine, conn, driver, tbl => (tbl.columns = tbl.columns.filter(x => x.columnName != column)));
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
|
const hasDropableColumns = dropableColumnsSrouce.length > 0;
|
||||||
|
|
||||||
test.each(engines_columns_source())(
|
if (hasDropableColumns) {
|
||||||
'Change nullability - %s - %s',
|
test.each(dropableColumnsSrouce)(
|
||||||
testWrapper(async (conn, driver, column, engine) => {
|
'Drop column - %s - %s',
|
||||||
await testTableDiff(
|
testWrapper(async (conn, driver, column, engine) => {
|
||||||
engine,
|
await testTableDiff(
|
||||||
conn,
|
engine,
|
||||||
driver,
|
conn,
|
||||||
tbl => (tbl.columns = tbl.columns.map(x => (x.columnName == column ? { ...x, notNull: true } : x)))
|
driver,
|
||||||
);
|
tbl => (tbl.columns = tbl.columns.filter(x => x.columnName != column))
|
||||||
})
|
);
|
||||||
);
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test.each(engines_columns_source())(
|
const hasEnginesWithNullable = engines.filter(x => !x.skipNullable).length > 0;
|
||||||
|
|
||||||
|
if (hasEnginesWithNullable) {
|
||||||
|
const source = create_engines_columns_source(engines.filter(x => !x.skipNullable));
|
||||||
|
|
||||||
|
test.each(source)(
|
||||||
|
'Change nullability - %s - %s',
|
||||||
|
testWrapper(async (conn, driver, column, engine) => {
|
||||||
|
await testTableDiff(
|
||||||
|
engine,
|
||||||
|
conn,
|
||||||
|
driver,
|
||||||
|
tbl => (tbl.columns = tbl.columns.map(x => (x.columnName == column ? { ...x, notNull: true } : x)))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test.each(columnsSource)(
|
||||||
'Rename column - %s - %s',
|
'Rename column - %s - %s',
|
||||||
testWrapper(async (conn, driver, column, engine) => {
|
testWrapper(async (conn, driver, column, engine) => {
|
||||||
await testTableDiff(
|
await testTableDiff(
|
||||||
@@ -157,32 +174,37 @@ describe('Alter table', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
test.each(engines.map(engine => [engine.label, engine]))(
|
const enginesWithDefault = engines.filter(x => !x.skipDefaultValue);
|
||||||
'Add default value - %s',
|
const hasEnginesWithDefault = enginesWithDefault.length > 0;
|
||||||
testWrapper(async (conn, driver, engine) => {
|
|
||||||
await testTableDiff(engine, conn, driver, tbl => {
|
|
||||||
tbl.columns.find(x => x.columnName == 'col_std').defaultValue = '123';
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
test.each(engines.map(engine => [engine.label, engine]))(
|
if (hasEnginesWithDefault) {
|
||||||
'Unset default value - %s',
|
test.each(enginesWithDefault.map(engine => [engine.label, engine]))(
|
||||||
testWrapper(async (conn, driver, engine) => {
|
'Add default value - %s',
|
||||||
await testTableDiff(engine, conn, driver, tbl => {
|
testWrapper(async (conn, driver, engine) => {
|
||||||
tbl.columns.find(x => x.columnName == 'col_def').defaultValue = undefined;
|
await testTableDiff(engine, conn, driver, tbl => {
|
||||||
});
|
tbl.columns.find(x => x.columnName == 'col_std').defaultValue = '123';
|
||||||
})
|
});
|
||||||
);
|
})
|
||||||
|
);
|
||||||
|
|
||||||
test.each(engines.map(engine => [engine.label, engine]))(
|
test.each(enginesWithDefault.map(engine => [engine.label, engine]))(
|
||||||
'Change default value - %s',
|
'Unset default value - %s',
|
||||||
testWrapper(async (conn, driver, engine) => {
|
testWrapper(async (conn, driver, engine) => {
|
||||||
await testTableDiff(engine, conn, driver, tbl => {
|
await testTableDiff(engine, conn, driver, tbl => {
|
||||||
tbl.columns.find(x => x.columnName == 'col_def').defaultValue = '567';
|
tbl.columns.find(x => x.columnName == 'col_def').defaultValue = undefined;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test.each(enginesWithDefault.map(engine => [engine.label, engine]))(
|
||||||
|
'Change default value - %s',
|
||||||
|
testWrapper(async (conn, driver, engine) => {
|
||||||
|
await testTableDiff(engine, conn, driver, tbl => {
|
||||||
|
tbl.columns.find(x => x.columnName == 'col_def').defaultValue = '567';
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// test.each(engines.map(engine => [engine.label, engine]))(
|
// test.each(engines.map(engine => [engine.label, engine]))(
|
||||||
// 'Change autoincrement - %s',
|
// 'Change autoincrement - %s',
|
||||||
|
|||||||
@@ -85,31 +85,36 @@ describe('DB Import/export', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
test.each(engines.filter(x => x.dumpFile).map(engine => [engine.label, engine]))(
|
const enginesWithDumpFile = engines.filter(x => x.dumpFile);
|
||||||
'Import SQL dump - %s',
|
const hasEnginesWithDumpFile = enginesWithDumpFile.length > 0;
|
||||||
testWrapper(async (conn, driver, engine) => {
|
|
||||||
// const reader = await fakeObjectReader({ delay: 10 });
|
|
||||||
// const reader = await fakeObjectReader();
|
|
||||||
await importDatabase({
|
|
||||||
systemConnection: conn,
|
|
||||||
driver,
|
|
||||||
inputFile: engine.dumpFile,
|
|
||||||
});
|
|
||||||
|
|
||||||
const structure = await driver.analyseFull(conn);
|
if (hasEnginesWithDumpFile) {
|
||||||
|
test.each(enginesWithDumpFile.filter(x => x.dumpFile).map(engine => [engine.label, engine]))(
|
||||||
|
'Import SQL dump - %s',
|
||||||
|
testWrapper(async (conn, driver, engine) => {
|
||||||
|
// const reader = await fakeObjectReader({ delay: 10 });
|
||||||
|
// const reader = await fakeObjectReader();
|
||||||
|
await importDatabase({
|
||||||
|
systemConnection: conn,
|
||||||
|
driver,
|
||||||
|
inputFile: engine.dumpFile,
|
||||||
|
});
|
||||||
|
|
||||||
for (const check of engine.dumpChecks || []) {
|
const structure = await driver.analyseFull(conn);
|
||||||
const res = await driver.query(conn, check.sql);
|
|
||||||
expect(res.rows[0].res.toString()).toEqual(check.res);
|
|
||||||
}
|
|
||||||
|
|
||||||
// const res1 = await driver.query(conn, `select count(*) as cnt from t1`);
|
for (const check of engine.dumpChecks || []) {
|
||||||
// expect(res1.rows[0].cnt.toString()).toEqual('6');
|
const res = await driver.query(conn, check.sql);
|
||||||
|
expect(res.rows[0].res.toString()).toEqual(check.res);
|
||||||
|
}
|
||||||
|
|
||||||
// const res2 = await driver.query(conn, `select count(*) as cnt from t2`);
|
// const res1 = await driver.query(conn, `select count(*) as cnt from t1`);
|
||||||
// expect(res2.rows[0].cnt.toString()).toEqual('6');
|
// expect(res1.rows[0].cnt.toString()).toEqual('6');
|
||||||
})
|
|
||||||
);
|
// const res2 = await driver.query(conn, `select count(*) as cnt from t2`);
|
||||||
|
// expect(res2.rows[0].cnt.toString()).toEqual('6');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
test.each(engines.map(engine => [engine.label, engine]))(
|
test.each(engines.map(engine => [engine.label, engine]))(
|
||||||
'Export one table - %s',
|
'Export one table - %s',
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ describe('Deploy database', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
test.each(engines.filter(x => !x.skipChangeColumn).map(engine => [engine.label, engine]))(
|
test.each(engines.filter(x => !x.skipChangeColumn || x.skipNullability).map(engine => [engine.label, engine]))(
|
||||||
'Change column to NOT NULL column with default - %s',
|
'Change column to NOT NULL column with default - %s',
|
||||||
testWrapper(async (conn, driver, engine) => {
|
testWrapper(async (conn, driver, engine) => {
|
||||||
await testDatabaseDeploy(engine, conn, driver, [
|
await testDatabaseDeploy(engine, conn, driver, [
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// @ts-check
|
||||||
const views = {
|
const views = {
|
||||||
type: 'views',
|
type: 'views',
|
||||||
create1: 'CREATE VIEW ~obj1 AS SELECT ~id FROM ~t1',
|
create1: 'CREATE VIEW ~obj1 AS SELECT ~id FROM ~t1',
|
||||||
@@ -13,6 +14,7 @@ const matviews = {
|
|||||||
drop2: 'DROP MATERIALIZED VIEW obj2',
|
drop2: 'DROP MATERIALIZED VIEW obj2',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').TestEngineInfo} */
|
||||||
const mysqlEngine = {
|
const mysqlEngine = {
|
||||||
label: 'MySQL',
|
label: 'MySQL',
|
||||||
connection: {
|
connection: {
|
||||||
@@ -160,6 +162,7 @@ const mysqlEngine = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').TestEngineInfo} */
|
||||||
const mariaDbEngine = {
|
const mariaDbEngine = {
|
||||||
label: 'MariaDB',
|
label: 'MariaDB',
|
||||||
connection: {
|
connection: {
|
||||||
@@ -180,6 +183,7 @@ const mariaDbEngine = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').TestEngineInfo} */
|
||||||
const postgreSqlEngine = {
|
const postgreSqlEngine = {
|
||||||
label: 'PostgreSQL',
|
label: 'PostgreSQL',
|
||||||
connection: {
|
connection: {
|
||||||
@@ -352,6 +356,7 @@ $$ LANGUAGE plpgsql;`,
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').TestEngineInfo} */
|
||||||
const sqlServerEngine = {
|
const sqlServerEngine = {
|
||||||
label: 'SQL Server',
|
label: 'SQL Server',
|
||||||
connection: {
|
connection: {
|
||||||
@@ -465,6 +470,7 @@ const sqlServerEngine = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').TestEngineInfo} */
|
||||||
const sqliteEngine = {
|
const sqliteEngine = {
|
||||||
label: 'SQLite',
|
label: 'SQLite',
|
||||||
generateDbFile: true,
|
generateDbFile: true,
|
||||||
@@ -500,6 +506,7 @@ const sqliteEngine = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').TestEngineInfo} */
|
||||||
const cockroachDbEngine = {
|
const cockroachDbEngine = {
|
||||||
label: 'CockroachDB',
|
label: 'CockroachDB',
|
||||||
connection: {
|
connection: {
|
||||||
@@ -511,6 +518,7 @@ const cockroachDbEngine = {
|
|||||||
objects: [views, matviews],
|
objects: [views, matviews],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').TestEngineInfo} */
|
||||||
const clickhouseEngine = {
|
const clickhouseEngine = {
|
||||||
label: 'ClickHouse',
|
label: 'ClickHouse',
|
||||||
connection: {
|
connection: {
|
||||||
@@ -533,6 +541,7 @@ const clickhouseEngine = {
|
|||||||
skipChangeColumn: true,
|
skipChangeColumn: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').TestEngineInfo} */
|
||||||
const oracleEngine = {
|
const oracleEngine = {
|
||||||
label: 'Oracle',
|
label: 'Oracle',
|
||||||
connection: {
|
connection: {
|
||||||
@@ -592,6 +601,30 @@ const oracleEngine = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').TestEngineInfo} */
|
||||||
|
const cassandraEngine = {
|
||||||
|
label: 'Cassandra',
|
||||||
|
connection: {
|
||||||
|
server: 'localhost:15942',
|
||||||
|
engine: 'cassandra@dbgate-plugin-cassandra',
|
||||||
|
},
|
||||||
|
removeNotNull: true,
|
||||||
|
|
||||||
|
alterTableAddColumnSyntax: false,
|
||||||
|
skipOnCI: false,
|
||||||
|
skipReferences: true,
|
||||||
|
// dbSnapshotBySeconds: true,
|
||||||
|
// setNullDefaultInsteadOfDrop: true,
|
||||||
|
skipIncrementalAnalysis: true,
|
||||||
|
skipNonPkRename: true,
|
||||||
|
skipPkDrop: true,
|
||||||
|
skipDefaultValue: true,
|
||||||
|
skipNullability: true,
|
||||||
|
skipUnique: true,
|
||||||
|
skipIndexes: true,
|
||||||
|
// objects: [],
|
||||||
|
};
|
||||||
|
|
||||||
const enginesOnCi = [
|
const enginesOnCi = [
|
||||||
// all engines, which would be run on GitHub actions
|
// all engines, which would be run on GitHub actions
|
||||||
mysqlEngine,
|
mysqlEngine,
|
||||||
@@ -606,16 +639,18 @@ const enginesOnCi = [
|
|||||||
|
|
||||||
const enginesOnLocal = [
|
const enginesOnLocal = [
|
||||||
// all engines, which would be run on local test
|
// all engines, which would be run on local test
|
||||||
mysqlEngine,
|
cassandraEngine,
|
||||||
|
// mysqlEngine,
|
||||||
// mariaDbEngine,
|
// mariaDbEngine,
|
||||||
// postgreSqlEngine,
|
// postgreSqlEngine,
|
||||||
// sqlServerEngine,
|
// sqlServerEngine,
|
||||||
sqliteEngine,
|
// sqliteEngine,
|
||||||
// cockroachDbEngine,
|
// cockroachDbEngine,
|
||||||
// clickhouseEngine,
|
// clickhouseEngine,
|
||||||
// oracleEngine,
|
// oracleEngine,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** @type {any} */
|
||||||
module.exports = process.env.CITEST ? enginesOnCi : enginesOnLocal;
|
module.exports = process.env.CITEST ? enginesOnCi : enginesOnLocal;
|
||||||
|
|
||||||
module.exports.mysqlEngine = mysqlEngine;
|
module.exports.mysqlEngine = mysqlEngine;
|
||||||
@@ -626,3 +661,4 @@ module.exports.sqliteEngine = sqliteEngine;
|
|||||||
module.exports.cockroachDbEngine = cockroachDbEngine;
|
module.exports.cockroachDbEngine = cockroachDbEngine;
|
||||||
module.exports.clickhouseEngine = clickhouseEngine;
|
module.exports.clickhouseEngine = clickhouseEngine;
|
||||||
module.exports.oracleEngine = oracleEngine;
|
module.exports.oracleEngine = oracleEngine;
|
||||||
|
module.exports.cassandraEngine = cassandraEngine;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// @ts-check
|
||||||
const requireEngineDriver = require('dbgate-api/src/utility/requireEngineDriver');
|
const requireEngineDriver = require('dbgate-api/src/utility/requireEngineDriver');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
@@ -81,9 +82,27 @@ const testWrapperPrepareOnly =
|
|||||||
await body(conn, driver, ...other);
|
await body(conn, driver, ...other);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @param {string} sql
|
||||||
|
* @returns {string} */
|
||||||
|
const removeNotNull = sql => sql.replace(/not null/gi, '');
|
||||||
|
|
||||||
|
/** @param {import('dbgate-types').TestEngineInfo} engine
|
||||||
|
* @param {string} sql
|
||||||
|
* @returns {string} */
|
||||||
|
const transformSqlForEngine = (engine, sql) => {
|
||||||
|
let result = sql;
|
||||||
|
|
||||||
|
if (engine.removeNotNull) {
|
||||||
|
result = removeNotNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
randomDbName,
|
randomDbName,
|
||||||
connect,
|
connect,
|
||||||
testWrapper,
|
testWrapper,
|
||||||
testWrapperPrepareOnly,
|
testWrapperPrepareOnly,
|
||||||
|
transformSqlForEngine,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user