Files
directus/tests-blackbox/setup/setup.ts
ian f1a8e0446f Fix duplicated results and functions in nested filters (#14798)
* Speed query up by reusing existing aliases which reduces table joins

* Use subquery in top level m2o to remove duplicates

* Fix linting

* Apply distinct on primary key field in subqueries

* Use distinct instead as there are only primary keys

* Apply subquery on top level

* Try remove sub sub query

* Test if working for all vendors

* Add support for _none and _some

* Use subquery only when field depth > 1

* Add tests

* Use original table names for columns with functions (#14690)

* Use original table names for columns with functions

* Extract filter function path parsing as shared util

* Fix filter function path when adding node

* Pass the originalCollectionName into filter functions

* Update unit test

* Replace functions within deep GraphQL

* Fix invalid operator error for _none and _some

* Add filter function tests

* Revert triggering for all vendors

* Simplify aliasMap

* Replace functions in filter within GraphQL aggregate query

* Add API support for filtering of alias field

* Mark schema as optional

* Shift logical operators upwards

* Separate recursive parseFilter

* Rework shifting of logical operators

* Error on invalid usage of _none and _some

* Use inner join to preserve sort order

* Run tests for all vendors

* Reuse aliasMap for sort and filter

* Sort on top level query

* Remove unnecessary limit on wrapper query

* Refactor applyQuery options

* Remove duplicates from nested multi relational sort

* Fix offset in MSSQL requiring OrderBy

* Disable schema cache

* Use inner query only for nested sort or multi relational filter

* Fix MSSQL duplicate order column

* Use inner query only for multi relational

* Additional integration tests

* Order within partition for multi relational sorts

* Rename to directus_row_number

* Fix unit test

* Add base sort and filter tests

* Fix Oracle uppercased rowNumber column

* Fix unit test

* Fix top level query sort with function

* Parse functions in inner query

* Increase clarity with knex.ref()

* Remove sort filter for top level primary key

* Fix unit test

* Bypass queries with groupBy

* Add collection to aliasMap to fix functions in nested sort

* Fix multi relational sort with functions

* Add tests for filter and sort with functions

* Fix accidental deletion of brackets

* Fix top level alias filter node interface

* Update M2M sort tests

* Add M2A tests

* Cast m2a primary key as varchar2 for oracle

* Enable filtering tests for M2A

* Fix prototype polluting assignment in aliasMap

* Remove unnecessary currentKey

* Simplify code to increase readability

Co-authored-by: Brainslug <br41nslug@users.noreply.github.com>

* Fix linting and missing 'this' error

* Revert optional chaining

* Add mysql5 to tests

* Fix mysql5 missing rowNumber()

* Overcome indexing delays in MySQL5

* Verify MySQL5 sorting is in order as the result count varies between runs

* Skip joining when sorting field already exists

* Simplify variable assignment

Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com>

* Fix linting

* Reduce duplicate logic with vars

* Transform _func fields in GraphQL only for valid functions

* Fix unit test

* Fix unsupported date_part() in CrDB

Co-authored-by: Brainslug <br41nslug@users.noreply.github.com>
Co-authored-by: Roger Stringer <roger@directus.io>
Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com>
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
2022-12-21 11:56:18 -05:00

158 lines
5.0 KiB
TypeScript

/* eslint-disable no-console */
import knex from 'knex';
import { Listr } from 'listr2';
import vendors from '../common/get-dbs-to-test';
import config, { getUrl } from '../common/config';
import global from './global';
import { spawn, spawnSync } from 'child_process';
import axios from 'axios';
import { writeFileSync } from 'fs';
import { awaitDatabaseConnection, awaitDirectusConnection } from '../utils/await-connection';
import * as common from '../common';
import { clone } from 'lodash';
let started = false;
export default async (): Promise<void> => {
if (started) return;
started = true;
console.log('\n\n');
console.log(`👮‍♀️ Starting tests!\n`);
await new Listr([
{
title: 'Bootstrap databases and start servers',
task: async () => {
return new Listr(
vendors.map((vendor) => {
return {
title: config.names[vendor]!,
task: async () => {
const database = knex(config.knexConfig[vendor]!);
await awaitDatabaseConnection(database, config.knexConfig[vendor]!.waitTestSQL);
if (vendor === 'sqlite3') {
writeFileSync('test.db', '');
}
const bootstrap = spawnSync('node', ['api/cli', 'bootstrap'], { env: config.envs[vendor] });
if (bootstrap.stderr.length > 0) {
throw new Error(`Directus-${vendor} bootstrap failed: \n ${bootstrap.stderr.toString()}`);
}
await database.migrate.latest();
await database.seed.run();
await database.destroy();
if (!process.env.TEST_LOCAL) {
const server = spawn('node', ['api/cli', 'start'], { env: config.envs[vendor] });
global.directus[vendor] = server;
let serverOutput = '';
server.stdout.setEncoding('utf8');
server.stdout.on('data', (data) => {
serverOutput += data.toString();
});
server.on('exit', (code) => {
if (process.env.TEST_SAVE_LOGS) {
writeFileSync(__dirname + `/../server-log-${vendor}.txt`, serverOutput);
}
if (code !== null) throw new Error(`Directus-${vendor} server failed: \n ${serverOutput}`);
});
// Give the server some time to start
await awaitDirectusConnection(Number(config.envs[vendor]!.PORT!));
server.on('exit', () => undefined);
// Set up separate directus instance without system cache
const noCacheEnv = clone(config.envs[vendor]!);
noCacheEnv.CACHE_SCHEMA = 'false';
noCacheEnv.PORT = String(parseInt(noCacheEnv.PORT!) + 50);
const serverNoCache = spawn('node', ['api/cli', 'start'], { env: noCacheEnv });
global.directusNoCache[vendor] = serverNoCache;
let serverNoCacheOutput = '';
serverNoCache.stdout.setEncoding('utf8');
serverNoCache.stdout.on('data', (data) => {
serverNoCacheOutput += data.toString();
});
serverNoCache.on('exit', (code) => {
if (process.env.TEST_SAVE_LOGS) {
writeFileSync(__dirname + `/../server-log-${vendor}-no-cache.txt`, serverNoCacheOutput);
}
if (code !== null)
throw new Error(`Directus-${vendor}-no-cache server failed: \n ${serverNoCacheOutput}`);
});
// Give the server some time to start
await awaitDirectusConnection(Number(noCacheEnv.PORT!));
serverNoCache.on('exit', () => undefined);
}
},
};
}),
{ concurrent: true }
);
},
},
{
title: 'Setup test data flow',
task: async () => {
return new Listr([
{
title: 'Testing server connectivity and bootstrap tests flow',
task: async () => {
const totalTestsCount = Number(process.env.totalTestsCount);
if (isNaN(totalTestsCount)) {
throw new Error('Unable to read totalTestsCount');
}
for (const vendor of vendors) {
try {
const serverUrl = getUrl(vendor);
let response = await axios.get(
`${serverUrl}/items/tests_flow_data?access_token=${common.USER.TESTS_FLOW.TOKEN}`
);
if (response.status !== 200) {
continue;
}
const body = {
total_tests_count: totalTestsCount,
};
response = await axios.post(`${serverUrl}/items/tests_flow_data`, body, {
headers: {
Authorization: 'Bearer ' + common.USER.TESTS_FLOW.TOKEN,
'Content-Type': 'application/json',
},
});
if (response.status === 200) {
process.env.serverUrl = serverUrl;
break;
}
} catch (err) {
continue;
}
}
if (!process.env.serverUrl) {
throw new Error('Unable to connect to any directus server');
}
},
},
]);
},
},
])
.run()
.catch((reason) => {
for (const server of Object.values(global.directus)) {
server?.kill();
}
for (const serverNoCache of Object.values(global.directusNoCache)) {
serverNoCache?.kill();
}
throw new Error(reason);
});
console.log('\n');
};