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

wip: feat: add types and start setting up SSE response handler in server #462

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion harness/helpers/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import {
callVariableValue,
sendCommand,
} from './commands'
import { config_sse } from '../mockData'
import { config_sse, SSEMessage } from '../mockData'
import { ProxyClientOptions } from './proxyClientOptions'
import SseStream from 'ssestream'
import { sseStreams } from '../mockServer'

const oldFetch = fetch

Expand Down Expand Up @@ -439,6 +441,17 @@ export class LocalTestClient extends BaseTestClient {
getValidConfig() {
return config_sse(getMockServerUrl(), `/client/${this.clientId}/sse`)
}

getSSEStream(): SseStream {
return sseStreams[this.clientId]
}
sendSSEMessage(message: SSEMessage) {
const sseStream = this.getSSEStream()
if (!sseStream) {
throw new Error('SSE Stream not initialized')
}
sseStream.write(JSON.stringify(message))
}
}

export class CloudTestClient extends BaseTestClient {
Expand Down
3 changes: 1 addition & 2 deletions harness/helpers/proxyClientOptions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { getMockServerUrl } from './helpers'

export type ProxyClientOptions = {
eventsAPIURI?: string
configCDNURI?: string
Expand All @@ -11,4 +9,5 @@ export type ProxyClientOptions = {
enableRealtimeUpdates?: boolean
logLevel?: string
enableClientBootstrapping?: boolean
enableSSE?: boolean
}
1 change: 1 addition & 0 deletions harness/mockData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './config'
export * from './features'
export * from './variables'
export * from './users'
export * from './sse'
14 changes: 14 additions & 0 deletions harness/mockData/sse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

export const SSEMessageExample = "{\"id\":\"yATzPE/mOzgY:0\",\"timestamp\":1712853334259,\"channel\":\"dvc_server_4fedfbd7a1aef0848768c8fad8f4536ca57e0ba0_v1\",\"data\":\"{\\\"etag\\\":\\\"\\\\\\\"714bc6a9acb038971923289ee6ce665b\\\\\\\"\\\",\\\"lastModified\\\":1712853333000}\",\"name\":\"change\"}"

export class SSEMessageData {
etag: string
lastModified: number
}
export class SSEMessage {
id: string
timestamp: number
channel: string
data: string
name: string
}
24 changes: 20 additions & 4 deletions harness/mockServer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import Router from '@koa/router'
import axios from 'axios'
import bodyParser from 'koa-bodyparser'
import SseStream from 'ssestream'

// NOTE: This file is excecuted by the jest environment, which does not share a memory space / module cache with the
// jest test files. This means that any things you want to be able to access from test context
// (like the unmatchedRequests) will need to be bound to the global scope inside the jest-environment and accessed
// through that

let unmatchedRequests = []

export const sseStreams: Map<string, SseStream> = new Map()
export const assertNoUnmatchedRequests = async (
currentClientId,
testNameMap,
Expand All @@ -22,18 +23,18 @@

if (url.includes(currentClientId)) {
console.error('Unmatched requests: ' + currentUnmatchedRequests)
throw new Error(

Check failure on line 26 in harness/mockServer/index.ts

View workflow job for this annotation

GitHub Actions / Test Report

harness/features/initialize.local.test.ts ► Initialize Tests - Local ► defaults variable when config fails to be retrieved, and then recovers

Failed test found in: jest-junit.xml Error: Error: Unexpected requests received: Error: Nock: No match for request {
Raw output
Error: Unexpected requests received: Error: Nock: No match for request {
  "method": "GET",
  "url": "https://myfakenockurl/client/cdd5ab73-6623-4371-82b5-ee565df4cb18/config/v2/server/dvc_server_cdd5ab73-6623-4371-82b5-ee565df4cb18.json",
  "headers": {
    "accept": "application/json, text/plain, */*",
    "content-type": "application/json",
    "host": "172.17.0.1:33225",
    "connection": "Keep-Alive",
    "accept-encoding": "gzip",
    "user-agent": "okhttp/4.10.0"
  }
}
    at assertNoUnmatchedRequests (/home/runner/work/test-harness/test-harness/harness/mockServer/index.ts:26:19)
    at cleanupCurrentClient (/home/runner/work/test-harness/test-harness/harness/helpers/helpers.ts:94:22)
    at processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async Object.<anonymous> (/home/runner/work/test-harness/test-harness/harness/helpers/helpers.ts:74:9)
'Unexpected requests received: ' + currentUnmatchedRequests,
)
} else {
const testName = testNameMap[clientId]
console.error(
`Unmatched requests from test case ${testName} ` +
currentUnmatchedRequests,
currentUnmatchedRequests,
)
throw new Error(
`Unexpected requests received from test case ${testName} ` +
currentUnmatchedRequests,
currentUnmatchedRequests,
)
}
}
Expand All @@ -43,6 +44,21 @@
const app = new Koa()
const router = new Router()

router.param('clientId', (clientId, ctx, next) => {
ctx.clientId = clientId
return next()
}).all('/client/:clientId/sse', async (ctx) => {
console.log(ctx.body)
let sseStream = sseStreams[ctx.clientId]
if (!sseStream) {
sseStream = new SseStream(ctx.req)
sseStreams[ctx.clientId] = sseStream
}
sseStream.pipe(ctx.res)
ctx.res.on('close', () => {
sseStream.unpipe(ctx.res)
})
})
router.all('/(.*)', async (ctx) => {
const { headers, request } = ctx

Expand All @@ -66,7 +82,7 @@
} else {
response = await axios[request.method.toLowerCase()](
`https://myfakenockurl${ctx.request.url}`,
request.body,
ctx.request.body,
{
headers,
},
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
"devDependencies": {
"@devcycle/types": "^1.14.0",
"@eresearchqut/jest-testcontainers": "^3.2.0",
"@koa/router": "^12.0.0",
"@koa/router": "^12.0.1",
"@types/jest": "^29.2.3",
"@types/koa-bodyparser": "^4.3.12",
"@types/koa__router": "^12.0.4",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"@typescript-eslint/parser": "^5.44.0",
"axios": "^1.1.3",
Expand All @@ -50,6 +52,7 @@
"dependencies": {
"dotenv": "^16.0.3",
"object-path-immutable": "^4.1.2",
"ssestream": "^1.1.0",
"uuid": "^9.0.0"
},
"lint-staged": {
Expand Down
Loading
Loading