Skip to content

Commit

Permalink
e2e test, install peer deps, vitest projects use devdeps
Browse files Browse the repository at this point in the history
  • Loading branch information
enisdenjo committed Oct 17, 2024
1 parent 27b55aa commit 00e3106
Show file tree
Hide file tree
Showing 15 changed files with 733 additions and 41 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,27 @@ jobs:
run: yarn install
- name: Test
run: yarn test

# TODO: various gateway runners
e2e:
needs: [unit]
strategy:
fail-fast: false
matrix:
node-version:
- 18
- 20
- 22
name: E2E / Node v${{matrix.node-version}}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up env
uses: the-guild-org/shared-config/setup@v1
with:
node-version: ${{matrix.node-version}}
- name: Install
run: yarn install
- name: Test
run: yarn test:e2e
14 changes: 14 additions & 0 deletions e2e/auto-type-merging/__snapshots__/auto-type-merging.e2e.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`should execute 'GetPet' 1`] = `
{
"data": {
"getPetById": {
"__typename": "Pet",
"id": 1,
"name": "Cat 1",
"vaccinated": false,
},
},
}
`;
37 changes: 37 additions & 0 deletions e2e/auto-type-merging/auto-type-merging.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { createTenv, type Container } from '@internal/e2e';
import { beforeAll, expect, it } from 'vitest';

const { compose, service, serve, container } = createTenv(__dirname);

let petstore!: Container;
beforeAll(async () => {
petstore = await container({
name: 'petstore',
image: 'swaggerapi/petstore3:1.0.7',
containerPort: 8080,
healthcheck: ['CMD-SHELL', 'wget --spider http://localhost:8080'],
});
});

it.concurrent.each([
{
name: 'GetPet',
query: /* GraphQL */ `
query GetPet {
getPetById(petId: 1) {
__typename
id
name
vaccinated
}
}
`,
},
])('should execute $name', async ({ query }) => {
const { output } = await compose({
output: 'graphql',
services: [petstore, await service('vaccination')],
});
const { execute } = await serve({ supergraph: output });
await expect(execute({ query })).resolves.toMatchSnapshot();
});
61 changes: 61 additions & 0 deletions e2e/auto-type-merging/auto-type-merging.loadtest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os from 'os';
import {
createTbench,
createTenv,
type Container,
type Tbench,
type TbenchResult,
} from '@internal/e2e';
import { beforeAll, expect, it } from 'vitest';

const { serve, compose, service, container } = createTenv(__dirname);

let tbench: Tbench;
let petstore!: Container;
beforeAll(async () => {
tbench = await createTbench(
// to give space for jest and the serve process.
os.availableParallelism() - 2,
);
petstore = await container({
name: 'petstore',
image: 'swaggerapi/petstore3:1.0.7',
containerPort: 8080,
healthcheck: ['CMD-SHELL', 'wget --spider http://0.0.0.0:8080'],
});
});

const threshold: TbenchResult = {
maxCpu: Infinity, // we dont care
maxMem: 500, // MB
slowestRequest: 1, // second
};

it(`should perform within threshold ${JSON.stringify(threshold)}`, async () => {
const { output } = await compose({
services: [petstore, await service('vaccination')],
output: 'graphql',
});
const server = await serve({ supergraph: output });
const result = await tbench.sustain({
server,
params: {
query: /* GraphQL */ `
query GetPet {
getPetById(petId: 1) {
__typename
id
name
vaccinated
}
}
`,
},
});

console.debug(result);

expect(result.maxCpu).toBeLessThan(threshold.maxCpu);
expect(result.maxMem).toBeLessThan(threshold.maxMem);
expect(result.slowestRequest).toBeLessThan(threshold.slowestRequest);
});
39 changes: 39 additions & 0 deletions e2e/auto-type-merging/mesh.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
camelCase,
createFilterTransform,
createNamingConventionTransform,
defineConfig,
loadGraphQLHTTPSubgraph,
} from '@graphql-mesh/compose-cli';
import { Opts } from '@internal/testing';
import { loadOpenAPISubgraph } from '@omnigraph/openapi';

const opts = Opts(process.argv);

export const composeConfig = defineConfig({
subgraphs: [
{
sourceHandler: loadOpenAPISubgraph('petstore', {
source: `http://localhost:${opts.getServicePort('petstore')}/api/v3/openapi.json`,
// endpoint must be manually specified because the openapi.json spec doesn't contain one
endpoint: `http://localhost:${opts.getServicePort('petstore')}/api/v3`,
}),
transforms: [
createFilterTransform({
rootFieldFilter: (typeName, fieldName) =>
typeName === 'Query' && fieldName === 'getPetById',
}),
],
},
{
sourceHandler: loadGraphQLHTTPSubgraph('vaccination', {
endpoint: `http://localhost:${opts.getServicePort('vaccination')}/graphql`,
}),
transforms: [
createNamingConventionTransform({
fieldNames: camelCase,
}),
],
},
],
});
16 changes: 16 additions & 0 deletions e2e/auto-type-merging/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "@e2e/auto-type-merging",
"private": true,
"devDependencies": {
"@graphql-mesh/compose-cli": "^1.1.1",
"@graphql-mesh/cross-helpers": "^0.4.7",
"@graphql-mesh/store": "^0.102.7",
"@graphql-mesh/types": "^0.102.7",
"@graphql-mesh/utils": "^0.102.7",
"@graphql-tools/utils": "^10.5.5",
"@omnigraph/openapi": "^0.107.1",
"graphql": "^16.9.0",
"graphql-yoga": "^5.7.0",
"tslib": "^2.8.0"
}
}
36 changes: 36 additions & 0 deletions e2e/auto-type-merging/services/vaccination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createServer } from 'http';
import { Opts } from '@internal/testing';
import { createSchema, createYoga } from 'graphql-yoga';

export const yoga = createYoga({
schema: createSchema({
typeDefs: /* GraphQL */ `
scalar BigInt
type Query {
pet_by_id(id: BigInt!): Pet
}
type Pet {
id: BigInt!
vaccinated: Boolean!
}
`,
resolvers: {
Query: {
pet_by_id: async (_root, args, _context, _info) => {
return {
id: args.id,
vaccinated: false,
};
},
},
},
}),
});

const port = Opts(process.argv).getServicePort('vaccination', true);

createServer(yoga).listen(port, () => {
console.log(`Vaccination service listening on http://localhost:${port}`);
});
7 changes: 4 additions & 3 deletions internal/e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
"name": "@internal/e2e",
"type": "module",
"private": true,
"dependencies": {
"devDependencies": {
"@apollo/gateway": "^2.8.3",
"@types/dockerode": "^3.3.28",
"@types/node": "^22.7.6",
"@whatwg-node/disposablestack": "^0.0.5",
"@whatwg-node/fetch": "^0.9.21",
"dockerode": "^4.0.2",
"glob": "^11.0.0",
"threads": "^1.7.0",
"tsx": "^4.16.5"
"graphql": "^16.9.0",
"threads": "^1.7.0"
}
}
10 changes: 4 additions & 6 deletions internal/e2e/src/tenv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const retries = 120,
interval = 500,
timeout = retries * interval; // 1min

const __project = path.resolve(__dirname, '..', '..') + path.sep;
const __project = path.resolve(__dirname, '..', '..', '..') + path.sep;

const docker = new Dockerode();

Expand Down Expand Up @@ -412,7 +412,7 @@ export function createTenv(cwd: string): Tenv {
'node',
'--import',
'tsx',
path.resolve(__project, 'packages', 'serve-cli', 'src', 'bin.ts'),
path.resolve(__project, 'packages', 'gateway', 'src', 'bin.ts'),
...(supergraph ? ['supergraph', supergraph] : []),
...args,
createPortOpt(port),
Expand Down Expand Up @@ -488,10 +488,8 @@ export function createTenv(cwd: string): Tenv {
}
const [proc, waitForExit] = await spawn(
{ cwd, pipeLogs, env },
'node',
'--import',
'tsx',
path.resolve(__project, 'packages', 'compose-cli', 'src', 'bin.ts'),
'yarn',
'mesh-compose',
output && createOpt('output', output),
...services.map(({ name, port }) => createServicePortOpt(name, port)),
...args,
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"private": true,
"workspaces": [
"packages/*",
"internal/*"
"internal/*",
"e2e/*"
],
"packageManager": "[email protected]",
"scripts": {
Expand All @@ -13,7 +14,8 @@
"check:lint": "eslint 'packages/**/src/**/*.ts'",
"check:types": "yarn tsc",
"format": "yarn check:format --write",
"test": "vitest"
"test": "vitest --project unit",
"test:e2e": "vitest --project e2e"
},
"devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
Expand All @@ -25,6 +27,7 @@
"prettier": "^3.3.3",
"prettier-plugin-pkg": "^0.18.1",
"prettier-plugin-sh": "^0.14.0",
"tsx": "^4.16.5",
"typescript": "^5.6.3",
"typescript-eslint": "^8.9.0",
"vite": "^5.4.9",
Expand Down
9 changes: 6 additions & 3 deletions packages/gateway/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,17 @@
"@graphql-mesh/plugin-prometheus": "^1.1.0",
"@graphql-mesh/plugin-rate-limit": "^0.102.6",
"@graphql-mesh/plugin-snapshot": "^0.102.6",
"@graphql-mesh/store": "^0.102.7",
"@graphql-mesh/transport-http-callback": "^0.4.1",
"@graphql-mesh/transport-ws": "^0.3.7",
"@graphql-mesh/types": "^0.102.6",
"@graphql-mesh/utils": "^0.102.6",
"@graphql-tools/utils": "^10.5.3",
"commander": "^12.0.0",
"dotenv": "^16.3.1",
"parse-duration": "^1.1.0"
"graphql-yoga": "^5.7.0",
"parse-duration": "^1.1.0",
"tslib": "^2.8.0"
},
"devDependencies": {
"@parcel/watcher": "^2.3.0",
Expand All @@ -79,11 +82,11 @@
"@tsconfig/node18": "^18.2.4",
"@types/adm-zip": "^0.5.5",
"adm-zip": "^0.5.15",
"graphql": "^16.9.0",
"pkgroll": "^2.5.0",
"postject": "^1.0.0-alpha.6",
"rollup": "^4.18.1",
"rollup-plugin-tsconfig-paths": "^1.5.2",
"tsx": "^4.16.5"
"rollup-plugin-tsconfig-paths": "^1.5.2"
},
"sideEffects": false
}
9 changes: 7 additions & 2 deletions packages/runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@
"@graphql-mesh/hmac-upstream-signature": "^1.1.0",
"@graphql-mesh/plugin-hive": "^0.102.8",
"@graphql-mesh/plugin-response-cache": "^0.102.6",
"@graphql-mesh/store": "^0.102.7",
"@graphql-mesh/transport-common": "^0.7.7",
"@graphql-mesh/transport-http": "^0.6.7",
"@graphql-mesh/types": "^0.102.7",
"@graphql-mesh/utils": "^0.102.6",
"@graphql-tools/batch-delegate": "^9.0.3",
"@graphql-tools/delegate": "^10.0.21",
Expand All @@ -69,12 +71,15 @@
"@types/node": "^22.7.5",
"@whatwg-node/disposablestack": "^0.0.5",
"@whatwg-node/server": "^0.9.46",
"graphql-yoga": "^5.7.0"
"graphql-yoga": "^5.7.0",
"tslib": "^2.8.0"
},
"devDependencies": {
"@envelop/disable-introspection": "6.0.0",
"@envelop/disable-introspection": "^6.0.0",
"@graphql-mesh/fusion-composition": "^0.6.1",
"@graphql-mesh/transport-rest": "^0.7.8",
"@whatwg-node/fetch": "^0.9.21",
"graphql": "^16.9.0",
"graphql-sse": "^2.5.3",
"html-minifier-terser": "7.2.0",
"pkgroll": "^2.5.0"
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"./internal/**/src",
"./packages/**/src",
"./packages/**/tests",
"./packages/**/scripts"
"./packages/**/scripts",
"./e2e"
]
}
Loading

0 comments on commit 00e3106

Please sign in to comment.