Skip to content
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

test(client): run functional tests in Data Proxy simulator #15010

Merged
merged 52 commits into from
Sep 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
8f88601
feat: add DATA_PROXY env var support to getTestClient
aqrln Aug 17, 2022
e530066
test: optionally connect to mini-proxy in blog-env-postgresql
aqrln Aug 17, 2022
bf46746
chore: fix a typo
aqrln Aug 18, 2022
59efd3a
test(client): skip sqlite with data proxy
aqrln Aug 18, 2022
0dc4b5e
test(client): initial hacky support for data proxy
aqrln Aug 18, 2022
72cbefd
feat: skip data proxy testing for test suites
aqrln Aug 18, 2022
cf5cb14
test: disable tracing tests with data proxy
aqrln Aug 18, 2022
0dc87f3
test: disable interactive-transactions tests with data proxy
aqrln Aug 18, 2022
ffabc97
test: skip metrics tests with data proxy
aqrln Aug 18, 2022
845c561
fix: delete added global on cleanup
aqrln Aug 19, 2022
d291469
test: disable more iTX tests with data proxy
aqrln Aug 19, 2022
bd8aee8
style: remove unused parameter
aqrln Aug 22, 2022
c11c609
test(client): manage mini-proxy
aqrln Aug 24, 2022
7fe8292
fix: update snapshots
aqrln Aug 25, 2022
f735531
tests(client): manage mini-proxy automatically
aqrln Aug 25, 2022
540b4b7
fix: run mini-proxy as a separate process
aqrln Aug 25, 2022
63288ae
chore: add mini-proxy bundle
aqrln Aug 25, 2022
13ab8f0
refactor: rename function
aqrln Aug 25, 2022
d4eea60
fix: add uncommitted changes
aqrln Aug 25, 2022
73aa959
refactor: use mini-proxy library
aqrln Aug 25, 2022
88ce62e
ci: add test pipeline for data proxy
aqrln Aug 26, 2022
dd7515e
chore: use mini-proxy from npm
aqrln Aug 26, 2022
4af3410
test: remove hacky mini-proxy code from blog-env-postgresql
aqrln Aug 26, 2022
b02a251
style: apply suggestion from code review
aqrln Aug 26, 2022
344d7ce
style: apply suggestion from code review
aqrln Aug 26, 2022
e735287
docs: update the doc comment
aqrln Aug 26, 2022
df45c42
docs: add comments for cli options
aqrln Aug 26, 2022
29209c2
test(client): test the edge client
aqrln Aug 26, 2022
4894110
chore: run edge client tests on ci too
aqrln Aug 29, 2022
bfd9395
refactor: make datasourceInfo access safer
aqrln Aug 29, 2022
bbd99c0
feat: add guard
aqrln Aug 29, 2022
cbb89cc
refactor: introduce ClientMeta
aqrln Aug 29, 2022
8c7836e
refactor: rename env var
aqrln Aug 29, 2022
05ef46f
fix: get rid of a warning
aqrln Aug 29, 2022
f316e0c
feat: conditionally skip specific runtime and add reason
aqrln Aug 29, 2022
64d2bdd
docs: document data proxy testing
aqrln Aug 29, 2022
f150dd1
test(client): disable some incompatible tests
aqrln Aug 30, 2022
58f2523
test: disable query logs test
aqrln Aug 30, 2022
899c05a
test: disable highly flaky test
aqrln Aug 30, 2022
696ac62
test: clarify comment
aqrln Aug 30, 2022
d659673
chore: don't start unused services
aqrln Aug 30, 2022
0488dbf
test: add --no-mini-proxy-default-ca flag
aqrln Aug 30, 2022
04e1842
test: rewrite comment after checking
aqrln Aug 30, 2022
74def2f
test: only skip test on mongodb
aqrln Aug 30, 2022
c000357
test: don't inject clientMeta to magic comments
aqrln Aug 30, 2022
3745027
test: add runtime matrix parameter
aqrln Aug 30, 2022
276752c
test: fix two suites with edge
aqrln Aug 30, 2022
7d3f610
Revert "test: add runtime matrix parameter"
aqrln Sep 6, 2022
8eafc21
tests: skip tests due to snapshot differences on edge
aqrln Sep 6, 2022
3ffd5cc
refactor: move the option up
aqrln Sep 6, 2022
3f47512
test: update snapshots
aqrln Sep 6, 2022
504139e
Revert "refactor: make datasourceInfo access safer"
aqrln Sep 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ packages/client/src/__tests__/types/
packages/cli/prisma-client/
packages/cli/install/
packages/cli/preinstall/
packages/cli/**/tmp-*
packages/cli/**/tmp-*
77 changes: 77 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,83 @@ jobs:
files: ./packages/client/src/__tests__/coverage/clover.xml
flags: client,${{ matrix.os }},${{ matrix.queryEngine }}
name: client-${{ matrix.os }}-${{ matrix.queryEngine }}

#
# CLIENT (functional tests with mini-proxy)
#
client-dataproxy:
millsp marked this conversation as resolved.
Show resolved Hide resolved
timeout-minutes: 35
runs-on: ${{ matrix.os }}

needs: detect_jobs_to_run
if: ${{ contains(needs.detect_jobs_to_run.outputs.jobs, '-all-') || contains(needs.detect_jobs_to_run.outputs.jobs, '-client-') }}

strategy:
fail-fast: false
matrix:
os: [buildjet-4vcpu-ubuntu-2004]
node: [14, 16, 18]
aqrln marked this conversation as resolved.
Show resolved Hide resolved

steps:
- uses: actions/checkout@v3

- name: Login to Docker Hub
uses: docker/login-action@v2
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
if: "${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }}"
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- run: docker-compose -f docker/docker-compose.yml up --detach postgres mysql mssql mongo cockroachdb

- uses: pnpm/action-setup@v2.2.2
with:
version: 7

- uses: actions/setup-node@v3
with:
cache: 'pnpm'
node-version: ${{ matrix.node }}

- run: bash .github/workflows/scripts/setup.sh
env:
CI: true
SKIP_GIT: true
GITHUB_CONTEXT: ${{ toJson(github) }}

- run: pnpm run test:functional --data-proxy
aqrln marked this conversation as resolved.
Show resolved Hide resolved
working-directory: packages/client
env:
CI: true
SKIP_GIT: true
GITHUB_CONTEXT: ${{ toJson(github) }}
TEST_FUNCTIONAL_POSTGRES_URI: 'postgres://prisma:prisma@localhost:5432/PRISMA_DB_NAME'
TEST_FUNCTIONAL_MYSQL_URI: 'mysql://root:root@localhost:3306/PRISMA_DB_NAME'
TEST_FUNCTIONAL_MSSQL_URI: 'sqlserver://localhost:1433;database=PRISMA_DB_NAME;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;'
TEST_FUNCTIONAL_MONGO_URI: 'mongodb://root:prisma@localhost:27018/PRISMA_DB_NAME?authSource=admin'
TEST_FUNCTIONAL_COCKROACH_URI: 'postgresql://prisma@localhost:26257/PRISMA_DB_NAME'

- run: pnpm run test:functional --data-proxy --edge-client
working-directory: packages/client
env:
CI: true
SKIP_GIT: true
GITHUB_CONTEXT: ${{ toJson(github) }}
TEST_FUNCTIONAL_POSTGRES_URI: 'postgres://prisma:prisma@localhost:5432/PRISMA_DB_NAME'
TEST_FUNCTIONAL_MYSQL_URI: 'mysql://root:root@localhost:3306/PRISMA_DB_NAME'
TEST_FUNCTIONAL_MSSQL_URI: 'sqlserver://localhost:1433;database=PRISMA_DB_NAME;user=SA;password=Pr1sm4_Pr1sm4;trustServerCertificate=true;'
TEST_FUNCTIONAL_MONGO_URI: 'mongodb://root:prisma@localhost:27018/PRISMA_DB_NAME?authSource=admin'
TEST_FUNCTIONAL_COCKROACH_URI: 'postgresql://prisma@localhost:26257/PRISMA_DB_NAME'

- uses: codecov/codecov-action@v3
with:
files: ./packages/client/src/__tests__/coverage/clover.xml
flags: client,${{ matrix.os }},dataproxy
name: client-${{ matrix.os }}-dataproxy

aqrln marked this conversation as resolved.
Show resolved Hide resolved
#
# CLIENT (memory tests)
#
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ reproductions/*

dev.db
junit.xml
/output.txt
/output.txt
danstarns marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 12 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,13 @@ testMatrix.setupTestSuite(
from: ['mongodb'],
reason: 'The test is for SQL databases only',
},
skipDataProxy: {
// similarly, you can opt out of testing with the Data Proxy
// client (either completely or for certain runtimes) and
// specify the reason
runtimes: ['node', 'edge'],
reason: "This test doesn't work with Data Proxy",
},
},
)
```
Expand All @@ -339,6 +346,11 @@ This test will run for every permutation of the parameters from the matrix. Curr
- `pnpm test:functional:types` runs typechecking on all the suites, generated by `pnpm test:functional:code` command. If it reports any errors, you might want to examine generated test suite under `tests/functional/<your test name>/.generated` directory to get a better diagnostic.
- `pnpm test:functional` will run tests and perform type checks.

Add `--data-proxy` to any of these commands to generate the Data Proxy client
and run the tests under the local Data Proxy simulator called Mini-Proxy.
Furthermore, you can also add `--edge-client` in addition to `--data-proxy` to
test the edge client rather than the regular Node.js client.

### Conditionally skipping type tests

Sometimes different test matrix parameters will generate different TS types so, and as a result,
Expand Down
142 changes: 115 additions & 27 deletions packages/client/helpers/functional-test/run-tests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { arg } from '@prisma/internals'
import { arg, BinaryType, getPlatform } from '@prisma/internals'
import * as miniProxy from '@prisma/mini-proxy'
import execa, { ExecaChildProcess } from 'execa'
import fs from 'fs'

import { setupQueryEngine } from '../../tests/commonUtils/setupQueryEngine'
import { Providers } from '../../tests/functional/_utils/providers'
import { JestCli } from './JestCli'

Expand All @@ -8,49 +12,133 @@ const allProviders = new Set(Object.values(Providers))
const args = arg(
process.argv.slice(2),
{
// Update snapshots
'-u': Boolean,
// Only run the tests, don't typecheck
'--no-types': Boolean,
// Only typecheck, don't run the code tests
'--types-only': Boolean,
// Restrict the list of providers
'--provider': [String],
'-p': '--provider',
// Generate Data Proxy client and run tests using Mini-Proxy
'--data-proxy': Boolean,
// Use edge client (requires --data-proxy)
'--edge-client': Boolean,
// Don't start the Mini-Proxy server, expect it to be started externally
// and listening on the default port.
'--no-mini-proxy-server': Boolean,
// Don't override NODE_EXTRA_CA_CERTS. Useful if a custom mini-proxy
// server you start is not the one in node_modules. You then need to run
// `eval $(mini-proxy env)` in your shell before starting the tests.
'--no-mini-proxy-default-ca': Boolean,
// Enable debug logs in the bundled Mini-Proxy server
'--mini-proxy-debug': Boolean,
},
true,
true,
)

let jestCli = new JestCli(['--verbose', '--config', 'tests/functional/jest.config.js'])
async function main(): Promise<number | void> {
let jestCli = new JestCli(['--verbose', '--config', 'tests/functional/jest.config.js'])
let miniProxyProcess: ExecaChildProcess | undefined

if (args['--provider']) {
const providers = args['--provider'] as Providers[]
const unknownProviders = providers.filter((provider) => !allProviders.has(provider))
if (unknownProviders.length > 0) {
console.error(`Unknown providers: ${unknownProviders.join(', ')}`)
process.exit(1)
if (args['--provider']) {
const providers = args['--provider'] as Providers[]
const unknownProviders = providers.filter((provider) => !allProviders.has(provider))
if (unknownProviders.length > 0) {
console.error(`Unknown providers: ${unknownProviders.join(', ')}`)
process.exit(1)
}
jestCli = jestCli.withEnv({ ONLY_TEST_PROVIDERS: providers.join(',') })
}
jestCli = jestCli.withEnv({ ONLY_TEST_PROVIDERS: providers.join(',') })
}

const codeTestCli = jestCli.withArgs(['--testPathIgnorePatterns', 'typescript'])
if (args['--data-proxy']) {
if (!fs.existsSync(miniProxy.defaultServerConfig.cert)) {
await miniProxy.generateCertificates(miniProxy.defaultCertificatesConfig)
}

jestCli = jestCli.withEnv({
DATA_PROXY: 'true',
})

if (!args['--no-mini-proxy-default-ca']) {
jestCli = jestCli.withEnv({
NODE_EXTRA_CA_CERTS: miniProxy.defaultCertificatesConfig.caCert,
})
}

if (args['--edge-client']) {
jestCli = jestCli.withEnv({
TEST_DATA_PROXY_EDGE_CLIENT: 'true',
})
}

if (!args['--no-mini-proxy-server']) {
const qePath = await getBinaryForMiniProxy()

try {
if (args['-u']) {
const snapshotUpdate = codeTestCli.withArgs(['-u']).withArgs(args['_'])
snapshotUpdate.withEnv({ UPDATE_SNAPSHOTS: 'inline' }).run()
snapshotUpdate.withEnv({ UPDATE_SNAPSHOTS: 'external' }).run()
} else {
if (!args['--types-only']) {
codeTestCli.withArgs(['--']).withArgs(args['_']).run()
miniProxyProcess = execa('mini-proxy', ['server', '-q', qePath], {
preferLocal: true,
stdio: 'inherit',
env: {
DEBUG: args['--mini-proxy-debug'] ? 'mini-proxy:*' : process.env.DEBUG,
},
})
}
}

if (args['--edge-client'] && !args['--data-proxy']) {
throw new Error('--edge-client is only available when --data-proxy is used')
}

if (!args['--no-types']) {
jestCli.withArgs(['--', 'typescript']).run()
const codeTestCli = jestCli.withArgs(['--testPathIgnorePatterns', 'typescript'])

try {
if (args['-u']) {
const snapshotUpdate = codeTestCli.withArgs(['-u']).withArgs(args['_'])
snapshotUpdate.withEnv({ UPDATE_SNAPSHOTS: 'inline' }).run()
snapshotUpdate.withEnv({ UPDATE_SNAPSHOTS: 'external' }).run()
} else {
if (!args['--types-only']) {
codeTestCli.withArgs(['--']).withArgs(args['_']).run()
}

if (!args['--no-types']) {
jestCli.withArgs(['--', 'typescript']).run()
}
}
} catch (error) {
if (error.exitCode) {
// If it's execa error, exit without logging: we
aqrln marked this conversation as resolved.
Show resolved Hide resolved
// already have output from jest
return error.exitCode
}
throw error
} finally {
if (miniProxyProcess) {
miniProxyProcess.kill()
}
}
}

async function getBinaryForMiniProxy(): Promise<string> {
if (process.env.PRISMA_QUERY_ENGINE_BINARY) {
return process.env.PRISMA_QUERY_ENGINE_BINARY
}
} catch (error) {
if (error.exitCode) {
// If it's execa error, exit without logging: we
// already have output from jest
process.exit(error.exitCode)

const paths = await setupQueryEngine()
const platform = await getPlatform()
const qePath = paths[BinaryType.queryEngine]?.[platform]

if (!qePath) {
throw new Error('Query Engine binary missing')
}
throw error

return qePath
}

void main().then((code) => {
if (code) {
process.exit(code)
}
})
1 change: 1 addition & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"@prisma/instrumentation": "workspace:*",
"@prisma/internals": "workspace:*",
"@prisma/migrate": "workspace:*",
"@prisma/mini-proxy": "0.1.1",
"@swc-node/register": "1.5.1",
"@swc/core": "1.2.248",
"@swc/jest": "0.2.22",
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/utils/getTestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export async function getTestClient(schemaDir?: string, printWarnings?: boolean)
relativeEnvPaths,
datasourceNames: config.datasources.map((d) => d.name),
activeProvider,
dataProxy: false,
dataProxy: Boolean(process.env.DATA_PROXY),
}

return getPrismaClient(options)
Expand Down
6 changes: 3 additions & 3 deletions packages/client/tests/commonUtils/setupQueryEngine.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { enginesVersion } from '@prisma/engines'
import { download } from '@prisma/fetch-engine'
import { BinaryPaths, download } from '@prisma/fetch-engine'
import path from 'path'

/**
* Ensures the correct Query Engine (`node-api`/`binary`) is present. This is required as
* normally the downloading of the required engine is done in `getGenerators`. As the test
* clients bypass this we need to ensure the correct engine is present.
*/
export async function setupQueryEngine() {
export function setupQueryEngine(): Promise<BinaryPaths> {
const engineDownloadDir = path.resolve(__dirname, '..', '..')

await download({
return download({
binaries: {
'libquery-engine': engineDownloadDir,
'query-engine': engineDownloadDir,
Expand Down
6 changes: 3 additions & 3 deletions packages/client/tests/functional/_utils/defineMatrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { U } from 'ts-toolbelt'

import { TestSuiteMatrix } from './getTestSuiteInfo'
import { setupTestSuiteMatrix, TestSuiteMeta } from './setupTestSuiteMatrix'
import { MatrixOptions } from './types'
import { ClientMeta, MatrixOptions } from './types'

type MergedMatrixParams<MatrixT extends TestSuiteMatrix> = U.IntersectOf<MatrixT[number][number]>

Expand All @@ -17,15 +17,15 @@ export interface MatrixTestHelper<MatrixT extends TestSuiteMatrix> {
* and generic suite metadata as an arguments
*/
setupTestSuite(
tests: (suiteConfig: MergedMatrixParams<MatrixT>, suiteMeta: TestSuiteMeta) => void,
tests: (suiteConfig: MergedMatrixParams<MatrixT>, suiteMeta: TestSuiteMeta, clientMeta: ClientMeta) => void,
options?: MatrixOptions,
): void

/**
* Function for defining test schema. Must be used in your `prisma/_schema.ts`. Return value
* of this function should be used as a default export of that module.
*
* @param schemaCallback schema factory function. Receives all matrix paramters, used for the
* @param schemaCallback schema factory function. Receives all matrix parameters, used for the
* specific test suite at the moment.
*/
setupSchema(schemaCallback: SchemaCallback<MatrixT>): SchemaCallback<MatrixT>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export function getTestSuiteMeta() {
const testRoot = path.join(testsDir, testRootDirName)
const rootRelativeTestPath = path.relative(testRoot, testPath)
const rootRelativeTestDir = path.dirname(rootRelativeTestPath)
let testName
let testName: string
if (rootRelativeTestPath === 'tests.ts') {
testName = testRootDirName
} else {
Expand Down