Skip to content

Commit fde79d3

Browse files
committed
Add Testkit support to DenoJS
Enabling the support for the acceptance tests to the generated DenoJS driver is a step towards to release it as library.
1 parent 4080b19 commit fde79d3

File tree

12 files changed

+191
-33
lines changed

12 files changed

+191
-33
lines changed

packages/bolt-connection/src/channel/browser/browser-channel.js

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,26 @@ export default class WebSocketChannel {
138138
if (this._pending !== null) {
139139
this._pending.push(buffer)
140140
} else if (buffer instanceof ChannelBuffer) {
141-
try {
142-
this._ws.send(buffer._buffer)
143-
} catch (error) {
144-
if (this._ws.readyState !== WS_OPEN) {
145-
// Websocket has been closed
146-
this._handleConnectionError()
147-
} else {
148-
// Some other error occured
149-
throw error
141+
// We should wait for the connection state change before sending
142+
setTimeout(() => {
143+
try {
144+
if (this._ws.readyState !== WS_OPEN){
145+
console.log('WebSocket not open')
146+
return;
147+
}
148+
this._ws.send(buffer._buffer)
149+
} catch (error) {
150+
if (this._ws.readyState !== WS_OPEN) {
151+
// Websocket has been closed
152+
this._handleConnectionError()
153+
} else {
154+
console.log('errror', error)
155+
// Some other error occured
156+
throw error
157+
}
150158
}
151-
}
159+
}, 500)
160+
console.log('after timeout')
152161
} else {
153162
throw newError("Don't know how to send buffer: " + buffer)
154163
}
@@ -160,14 +169,17 @@ export default class WebSocketChannel {
160169
*/
161170
close () {
162171
return new Promise((resolve, reject) => {
163-
if (this._ws && this._ws.readyState !== WS_CLOSED) {
164-
this._open = false
165-
this._clearConnectionTimeout()
166-
this._ws.onclose = () => resolve()
167-
this._ws.close()
168-
} else {
169-
resolve()
170-
}
172+
setTimeout(() => {
173+
if (this._ws && this._ws.readyState !== WS_CLOSED && this._ws.readyState !== WS_CLOSING) {
174+
this._open = false
175+
this._clearConnectionTimeout()
176+
this._ws.onclose = () => resolve()
177+
this._ws.close()
178+
} else {
179+
resolve()
180+
}
181+
}, 500)
182+
171183
})
172184
}
173185

packages/testkit-backend/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
},
1111
"type": "module",
1212
"scripts": {
13-
"build": "rollup src/index.js --config rollup.config.js",
14-
"start": "node --version | grep -q v10. && node -r esm src/index.js || node --experimental-specifier-resolution=node src/index.js",
13+
"build": "echo 'Error: no build script specified'",
14+
"build::": "rollup src/index.js --config rollup.config.js",
15+
"start::": "node --version | grep -q v10. && node -r esm src/index.js || node --experimental-specifier-resolution=node src/index.js",
16+
"start": "deno run --allow-read --allow-write --allow-net --allow-env --allow-run src/index.deno.ts",
1517
"clean": "rm -fr node_modules public/index.js",
1618
"prepare": "npm run build",
1719
"node": "node"

packages/testkit-backend/src/cypher-native-binders.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import neo4j from './neo4j'
1+
import neo4j from './neo4j.deno.js'
22

33
export function valueResponse (name, value) {
44
return { name: name, data: { value: value } }

packages/testkit-backend/src/feature/common.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import tls from 'tls'
1+
22

33
const SUPPORTED_TLS = (() => {
4+
const tls = {
5+
DEFAULT_MAX_VERSION: false
6+
}
47
if (tls.DEFAULT_MAX_VERSION) {
58
const min = Number(tls.DEFAULT_MIN_VERSION.split('TLSv')[1])
69
const max = Number(tls.DEFAULT_MAX_VERSION.split('TLSv')[1])

packages/testkit-backend/src/feature/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import commonFeatures from './common'
2-
import rxFeatures from './rx'
3-
import asyncFeatures from './async'
1+
import commonFeatures from './common.js'
2+
import rxFeatures from './rx.js'
3+
import asyncFeatures from './async.js'
44

55
const featuresByContext = new Map([
66
['async', asyncFeatures],
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import Context from './context.js';
2+
import { getShouldRunTest } from './skipped-tests/index.js';
3+
import neo4j from "../../neo4j-driver-deno/lib/mod.ts";
4+
import { createGetFeatures } from './feature/index.js';
5+
import * as handlers from './request-handlers.js';
6+
7+
const listener = Deno.listen({ port: 9876 });
8+
let index = 0;
9+
const contexts = new Map<number, Context>();
10+
11+
interface RequestHandler {
12+
(c: Context, data: any, wire: any): void
13+
}
14+
15+
interface RequestHandlerMap {
16+
[key: string]: RequestHandler
17+
}
18+
19+
addEventListener('uncaughtException', (event) => {
20+
console.log('unhandled rejection', event);
21+
})
22+
23+
// @ts-ignore
24+
const requestHandlers: RequestHandlerMap = handlers as RequestHandlerMap
25+
26+
addEventListener('events.errorMonitor', (event) => {
27+
console.log('something here ========================')
28+
})
29+
30+
interface Backend {
31+
openContext(contextId: number): void
32+
closeContext(contextId: number): void
33+
handle(contextId: number, conn: Deno.Conn, request: { name: string, data: object }): void
34+
}
35+
36+
function write(conn: Deno.Conn, response: object) {
37+
const responseStr = JSON.stringify(response, (_, value) =>
38+
typeof value === 'bigint' ? `${value}n` : value
39+
)
40+
const responseArr = ['#response begin', responseStr, '#response end'].join('\n') + '\n'
41+
console.log('response', responseArr);
42+
conn.write(new TextEncoder().encode(responseArr))
43+
.catch(e => {
44+
console.log('error writing to connection', e);
45+
});
46+
}
47+
48+
const descriptor = [] as string[]
49+
const shouldRunTest = getShouldRunTest(descriptor);
50+
const getFeatures = createGetFeatures(descriptor);
51+
52+
const backend: Backend = {
53+
openContext: (contextId) => {
54+
console.log("Open context:", contextId);
55+
contexts.set(contextId, new Context(shouldRunTest, getFeatures));
56+
},
57+
closeContext: (contextId) => {
58+
console.log('Close context', contextId);
59+
contexts.delete(contextId);
60+
},
61+
handle: (contextId, conn, req) => {
62+
const { data, name } = req;
63+
if (!contexts.has(contextId)) {
64+
throw new Error(`Context ${contextId} does not exist`)
65+
} else if (!(name in requestHandlers)) {
66+
console.log('Unknown request: ' + name)
67+
throw new Error(`Unknown request: ${name}`)
68+
}
69+
70+
console.log('Handle', req.name, req.data);
71+
72+
const handler: (c: Context, data: any, wire: any) => void = requestHandlers[name as string];
73+
74+
handler(contexts.get(contextId)!!, data, {
75+
writeResponse: (response: object) => write(conn, response),
76+
writeError: (e: Error) => {
77+
console.log('writeError', e);
78+
if (e.name && e instanceof neo4j.Neo4jError) {
79+
if (contexts.has(contextId)) {
80+
const id = contexts.get(contextId)!!.addError(e)
81+
write(conn, { name: 'DriverError', data: { id, msg: e.message + ' (' + e.code + ')', code: e.code } })
82+
return
83+
} else {
84+
console.log('Context does not exist', contextId, e)
85+
}
86+
return
87+
}
88+
write(conn, { name: 'BackendError', data: { msg: e.message } })
89+
90+
},
91+
writeBackendError: (msg: string) => write(conn, { name: 'BackendError', data: { msg } })
92+
});
93+
}
94+
}
95+
96+
for await (const conn of listener) {
97+
const contextId = index++;
98+
handleConnection(conn, contextId)
99+
}
100+
101+
async function handleConnection( conn: Deno.Conn, contextId: number): Promise<void> {
102+
backend.openContext(contextId);
103+
let inRequest = false
104+
let requestString = ''
105+
for await (const message of Deno.iter(conn)) {
106+
const rawTxtMessage = new TextDecoder().decode(message);
107+
const lines = rawTxtMessage.split('\n');
108+
for (const line of lines) {
109+
switch (line) {
110+
case '#request begin':
111+
if(inRequest) {
112+
throw new Error('Already in request');
113+
}
114+
inRequest = true;
115+
break;
116+
case '#request end':
117+
if(!inRequest) {
118+
throw new Error('Not in request');
119+
}
120+
const request = JSON.parse(requestString);
121+
backend.handle(contextId, conn, request);
122+
inRequest = false;
123+
requestString = '';
124+
break
125+
case '':
126+
// ignore empty lines
127+
break;
128+
default:
129+
if(!inRequest) {
130+
throw new Error('Not in request');
131+
}
132+
requestString += line;
133+
break
134+
}
135+
}
136+
}
137+
backend.closeContext(contextId);
138+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import neo4j from '../../neo4j-driver-deno/lib/mod.ts'
2+
3+
export default neo4j

packages/testkit-backend/src/request-handlers.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import neo4j from './neo4j'
1+
import neo4j from './neo4j.deno.js'
22
import { cypherToNative } from './cypher-native-binders.js'
33
import * as responses from './responses.js'
44

@@ -51,7 +51,7 @@ export function NewDriver (context, data, wire) {
5151
userAgent,
5252
resolver,
5353
useBigInt: true,
54-
logging: neo4j.logging.console(process.env.LOG_LEVEL)
54+
logging: neo4j.logging.console('debug')
5555
}
5656
if ('encrypted' in data) {
5757
config.encrypted = data.encrypted ? 'ENCRYPTION_ON' : 'ENCRYPTION_OFF'

packages/testkit-backend/src/skipped-tests/browser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import skip, { ifEndsWith, ifEquals, ifStartsWith } from './skip'
1+
import skip, { ifEndsWith, ifEquals, ifStartsWith } from './skip.js'
22
const skippedTests = [
33
skip(
44
"Browser doesn't support socket timeouts",

packages/testkit-backend/src/skipped-tests/common.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import skip, { ifEquals, ifEndsWith, ifStartsWith } from './skip'
1+
import skip, { ifEquals, ifEndsWith, ifStartsWith } from './skip.js'
22

33
const skippedTests = [
44
skip(

packages/testkit-backend/src/skipped-tests/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import commonSkippedTests from './common'
2-
import browserSkippedTests from './browser'
3-
import rxSessionSkippedTests from './rx'
1+
import commonSkippedTests from './common.js'
2+
import browserSkippedTests from './browser.js'
3+
import rxSessionSkippedTests from './rx.js'
44

55
const skippedTestsByContext = new Map([
66
['browser', browserSkippedTests],

packages/testkit-backend/src/skipped-tests/rx.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { skip, ifEquals } from './skip'
1+
import { skip, ifEquals } from './skip.js'
22

33
const skippedTests = [
44
skip(

0 commit comments

Comments
 (0)