-
Notifications
You must be signed in to change notification settings - Fork 39
chore(node-client-sdk): Add contract tests and hello example #1749
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
Open
joker23
wants to merge
5
commits into
main
Choose a base branch
from
skz/sdk-2195/node-client-sdk-next-contract-tests-and-hello-example
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
b896f04
chore(node-client-sdk): Add contract tests and hello example
joker23 06b95fe
fix: Use build:client for contract test utils in node-client CI
joker23 53dfe09
fix: Update CI matrix to Node 20 and 22, drop EOL Node 18
joker23 e5d88be
fix: Address BugBot findings -- flag listener arg, release-please con…
joker23 fa32e43
fix: Build js-contract-test-utils before contract-test service locally
joker23 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # Node Client SDK Contract Tests | ||
|
|
||
| This directory contains the contract test implementation for the LaunchDarkly Client-Side SDK for Node.js using the [SDK Test Harness](https://github.com/launchdarkly/sdk-test-harness). | ||
|
|
||
| The contract test service is an Express server that exposes a REST API on port 8000. The test harness sends commands to this service, which creates and manages SDK client instances and executes flag evaluations, events, and other operations. | ||
|
|
||
| ## Running locally | ||
|
|
||
| From the SDK package directory (`packages/sdk/node-client`): | ||
|
|
||
| ```bash | ||
| yarn contract-tests | ||
| ``` | ||
|
|
||
| This builds the SDK and the contract-test service, starts the service in the background on port 8000, downloads the matching `sdk-test-harness` binary, and runs the harness against the service. The harness shuts the service down when it finishes via `-stop-service-at-end`. | ||
|
|
||
| To run the service on its own (e.g. when iterating against a local checkout of `sdk-test-harness`): | ||
|
|
||
| ```bash | ||
| yarn contract-test-service | ||
| ``` | ||
|
|
||
| Then run the harness from your local clone in another terminal. | ||
|
|
||
| ## Suppressions | ||
|
|
||
| Two suppression files cover tests that are not yet supported or are known to differ: | ||
|
|
||
| - `testharness-suppressions.txt` -- default | ||
| - `testharness-suppressions-fdv2.txt` -- when running the harness from the `feat/fdv2` branch | ||
|
|
||
| Override the suppressions file by setting the `SUPPRESSIONS` environment variable: | ||
|
|
||
| ```bash | ||
| SUPPRESSIONS=./contract-tests/testharness-suppressions-fdv2.txt yarn contract-tests | ||
| ``` | ||
|
|
||
| ## Other environment variables | ||
|
|
||
| - `TEST_HARNESS_PARAMS` -- extra params appended to the harness command line (e.g. `-run TestName`). | ||
| - `VERSION` -- the major version of `sdk-test-harness` to download. Defaults to `v2`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "name": "@launchdarkly/node-client-sdk-contract-tests", | ||
| "version": "0.0.0", | ||
| "main": "dist/src/index.js", | ||
| "scripts": { | ||
| "start": "node --inspect dist/src/index.js", | ||
| "build": "tsc", | ||
| "dev": "tsc --watch" | ||
| }, | ||
| "type": "module", | ||
| "author": "", | ||
| "license": "Apache-2.0", | ||
| "private": true, | ||
| "dependencies": { | ||
| "@launchdarkly/js-contract-test-utils": "workspace:^", | ||
| "@launchdarkly/node-client-sdk": "workspace:^", | ||
| "body-parser": "^1.19.0", | ||
| "express": "^4.17.1" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/body-parser": "^1.19.2", | ||
| "@types/express": "^4.17.13", | ||
| "@types/node": "^18.11.9", | ||
| "typescript": "^5.5.3" | ||
| } | ||
| } |
33 changes: 33 additions & 0 deletions
33
packages/sdk/node-client/contract-tests/run-contract-tests.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #!/bin/sh | ||
| # Runs the SDK contract tests locally against a fresh build of @launchdarkly/node-client-sdk. | ||
| # | ||
| # Mirrors the GitHub Actions workflow at .github/workflows/node-client.yml: builds the SDK | ||
| # and its contract-test service, starts the service in the background, downloads the matching | ||
| # sdk-test-harness binary, and runs the harness against the service. | ||
| # | ||
| # Environment variables: | ||
| # SUPPRESSIONS Path to the suppressions file to pass via --skip-from. Defaults to | ||
| # ./testharness-suppressions.txt (next to this script). Use | ||
| # ./testharness-suppressions-fdv2.txt when running the harness from the | ||
| # feat/fdv2 branch. | ||
| # TEST_HARNESS_PARAMS Extra params appended to the harness command line. | ||
| # VERSION sdk-test-harness major version to download. Defaults to v2. | ||
|
|
||
| set -e | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| SUPPRESSIONS="${SUPPRESSIONS:-$SCRIPT_DIR/testharness-suppressions.txt}" | ||
| VERSION="${VERSION:-v2}" | ||
|
|
||
| yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/node-client-sdk' run build | ||
| yarn workspace @launchdarkly/js-contract-test-utils build:client | ||
| yarn workspace @launchdarkly/node-client-sdk-contract-tests build | ||
|
|
||
| yarn workspace @launchdarkly/node-client-sdk-contract-tests start & | ||
| SERVICE_PID=$! | ||
| trap 'kill $SERVICE_PID 2>/dev/null || true' EXIT | ||
|
|
||
| curl -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/main/downloader/run.sh \ | ||
| | VERSION="$VERSION" \ | ||
| PARAMS="-url http://localhost:8000 -debug -stop-service-at-end --skip-from=$SUPPRESSIONS $TEST_HARNESS_PARAMS" \ | ||
| sh | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| import bodyParser from 'body-parser'; | ||
| import express, { Request, Response } from 'express'; | ||
| import { Server } from 'http'; | ||
|
|
||
| import { ClientPool } from '@launchdarkly/js-contract-test-utils'; | ||
|
|
||
| import { Log } from './log.js'; | ||
| import { badCommandError, newSdkClientEntity, SdkClientEntity } from './sdkClientEntity.js'; | ||
|
|
||
| const app = express(); | ||
| let server: Server | null = null; | ||
|
|
||
| const port = 8000; | ||
|
|
||
| const clients = new ClientPool<SdkClientEntity>(); | ||
|
|
||
| const mainLog = Log('service'); | ||
|
|
||
| app.use(bodyParser.json()); | ||
|
|
||
| app.get('/', (req: Request, res: Response) => { | ||
| res.header('Content-Type', 'application/json'); | ||
| res.json({ | ||
| capabilities: [ | ||
| 'client-side', | ||
| 'service-endpoints', | ||
| 'tags', | ||
| 'user-type', | ||
| 'inline-context', | ||
| 'inline-context-all', | ||
| 'client-prereq-events', | ||
| 'client-per-context-summaries', | ||
| 'evaluation-hooks', | ||
| 'track-hooks', | ||
| 'anonymous-redaction', | ||
| 'strongly-typed', | ||
| 'event-gzip', | ||
| 'flag-change-listeners', | ||
| 'tls:skip-verify-peer', | ||
| 'tls:custom-ca', | ||
| 'wrapper', | ||
| ], | ||
| }); | ||
| }); | ||
|
|
||
| app.delete('/', (req: Request, res: Response) => { | ||
| mainLog.info('Test service has told us to exit'); | ||
| res.status(204); | ||
| res.send(); | ||
|
|
||
| // Defer the following actions till after the response has been sent | ||
| setTimeout(() => { | ||
| if (server) { | ||
| server.close(() => process.exit()); | ||
| } | ||
| // We force-quit with process.exit because, even after closing the server, there could be some | ||
| // scheduled tasks lingering if an SDK instance didn't get cleaned up properly. | ||
| }, 1); | ||
| }); | ||
|
|
||
| app.post('/', async (req: Request, res: Response) => { | ||
| const options = req.body; | ||
|
|
||
| try { | ||
| const client = await newSdkClientEntity(options); | ||
| const clientId = clients.add(client); | ||
|
|
||
| res.status(201); | ||
| res.set('Location', `/clients/${clientId}`); | ||
| } catch (e) { | ||
| res.status(500); | ||
| const message = e instanceof Error ? e.message : JSON.stringify(e); | ||
| mainLog.error(`Error creating client: ${message}`); | ||
| res.write(message); | ||
| } | ||
| res.send(); | ||
| }); | ||
|
|
||
| app.post('/clients/:id', async (req: Request, res: Response) => { | ||
| const client = clients.get(req.params.id); | ||
| if (!client) { | ||
| res.status(404); | ||
| } else { | ||
| try { | ||
| const respValue = await client.doCommand(req.body); | ||
| if (respValue) { | ||
| res.status(200); | ||
| res.write(JSON.stringify(respValue)); | ||
| } else { | ||
| res.status(204); | ||
| } | ||
| } catch (e) { | ||
| const isBadRequest = e === badCommandError; | ||
| res.status(isBadRequest ? 400 : 500); | ||
| const message = e instanceof Error ? e.message : JSON.stringify(e); | ||
| res.write(message); | ||
| if (!isBadRequest && e instanceof Error && e.stack) { | ||
| // eslint-disable-next-line no-console | ||
| console.log(e.stack); | ||
| } | ||
| } | ||
| } | ||
| res.send(); | ||
| }); | ||
|
|
||
| app.delete('/clients/:id', async (req: Request, res: Response) => { | ||
| const client = clients.get(req.params.id); | ||
| if (!client) { | ||
| res.status(404); | ||
| res.send(); | ||
| } else { | ||
| await client.close(); | ||
| clients.remove(req.params.id); | ||
| res.status(204); | ||
| res.send(); | ||
| } | ||
| }); | ||
|
|
||
| server = app.listen(port, () => { | ||
| // eslint-disable-next-line no-console | ||
| console.log('Listening on port %d', port); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import { basicLogger, LDLogger } from '@launchdarkly/node-client-sdk'; | ||
|
|
||
| export interface Logger { | ||
| info: (message: string) => void; | ||
| error: (message: string) => void; | ||
| } | ||
|
|
||
| export function Log(tag: string): Logger { | ||
| function doLog(level: string, message: string): void { | ||
| // eslint-disable-next-line no-console | ||
| console.log(`${new Date().toISOString()} [${tag}] ${level}: ${message}`); | ||
| } | ||
| return { | ||
| info: (message: string) => doLog('info', message), | ||
| error: (message: string) => doLog('error', message), | ||
| }; | ||
| } | ||
|
|
||
| export function sdkLogger(tag: string): LDLogger { | ||
| return basicLogger({ | ||
| level: 'debug', | ||
| destination: (line: string) => { | ||
| // eslint-disable-next-line no-console | ||
| console.log(`${new Date().toISOString()} [${tag}.sdk] ${line}`); | ||
| }, | ||
| }); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.