Skip to content

Commit 579b614

Browse files
committed
Add multi-db routing stub tests
1 parent af970ef commit 579b614

File tree

60 files changed

+373
-46
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+373
-46
lines changed

src/internal/connection-provider-routing.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ export default class RoutingConnectionProvider extends ConnectionProvider {
295295
const connectionProvider = new SingleConnectionProvider(connection)
296296

297297
if (connection.version().compareTo(VERSION_4_0_0) < 0) {
298-
return new Session({ mode: READ, connectionProvider })
298+
return new Session({ mode: WRITE, connectionProvider })
299299
}
300300

301301
return new Session({
@@ -306,11 +306,7 @@ export default class RoutingConnectionProvider extends ConnectionProvider {
306306
})
307307
.catch(error => {
308308
// unable to acquire connection towards the given router
309-
if (
310-
error &&
311-
(error.code === UNAUTHORIZED_ERROR_CODE ||
312-
error.code === DATABASE_NOT_FOUND_ERROR_CODE)
313-
) {
309+
if (error && error.code === UNAUTHORIZED_ERROR_CODE) {
314310
// auth error and not finding system database is a sign of a configuration issue
315311
// discovery should not proceed
316312
throw error

src/internal/routing-util.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@
1919

2020
import { newError, PROTOCOL_ERROR, SERVICE_UNAVAILABLE } from '../error'
2121
import Integer, { int } from '../integer'
22-
import { ServerVersion, VERSION_3_2_0, VERSION_4_0_0 } from './server-version'
22+
import { VERSION_4_0_0 } from './server-version'
2323
import Bookmark from './bookmark'
2424
import TxConfig from './tx-config'
25-
import { ACCESS_MODE_WRITE } from './constants'
25+
import { ACCESS_MODE_READ, ACCESS_MODE_WRITE } from './constants'
2626
import ServerAddress from './server-address'
2727

2828
const CONTEXT = 'context'
29-
const CALL_GET_SERVERS = 'CALL dbms.cluster.routing.getServers'
3029
const CALL_GET_ROUTING_TABLE = `CALL dbms.cluster.routing.getRoutingTable($${CONTEXT})`
3130
const DATABASE = 'database'
3231
const CALL_GET_ROUTING_TABLE_MULTI_DB = `CALL dbms.routing.getRoutingTable($${CONTEXT}, $${DATABASE})`
3332
const PROCEDURE_NOT_FOUND_CODE = 'Neo.ClientError.Procedure.ProcedureNotFound'
33+
const DATABASE_NOT_FOUND_CODE = 'Neo.ClientError.Database.DatabaseNotFound'
3434

3535
export default class RoutingUtil {
3636
constructor (routingContext) {
@@ -51,7 +51,9 @@ export default class RoutingUtil {
5151
return result.records
5252
})
5353
.catch(error => {
54-
if (error.code === PROCEDURE_NOT_FOUND_CODE) {
54+
if (error.code === DATABASE_NOT_FOUND_CODE) {
55+
throw error
56+
} else if (error.code === PROCEDURE_NOT_FOUND_CODE) {
5557
// throw when getServers procedure not found because this is clearly a configuration issue
5658
throw newError(
5759
`Server at ${routerAddress.asHostPort()} can't perform routing. Make sure you are connecting to a causal cluster`,
@@ -139,22 +141,20 @@ export default class RoutingUtil {
139141

140142
if (serverVersion.compareTo(VERSION_4_0_0) >= 0) {
141143
query = CALL_GET_ROUTING_TABLE_MULTI_DB
142-
params = {}
143-
params[CONTEXT] = this._routingContext
144-
params[DATABASE] = database
145-
} else if (serverVersion.compareTo(VERSION_3_2_0) >= 0) {
146-
query = CALL_GET_ROUTING_TABLE
147-
params = {}
148-
params[CONTEXT] = this._routingContext
144+
params = {
145+
context: this._routingContext,
146+
database: database || null
147+
}
149148
} else {
150-
query = CALL_GET_SERVERS
151-
params = {}
149+
query = CALL_GET_ROUTING_TABLE
150+
params = { context: this._routingContext }
152151
}
153152

154153
connection.protocol().run(query, params, streamObserver, {
155154
bookmark: Bookmark.empty(),
156155
txConfig: TxConfig.empty(),
157-
mode: ACCESS_MODE_WRITE
156+
mode: session._mode,
157+
database: session._database
158158
})
159159
})
160160
}

test/internal/node/routing.driver.boltkit.test.js

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,6 +2665,233 @@ describe('routing driver with stub server', () => {
26652665
})
26662666
})
26672667

2668+
describe('Multi-Database', () => {
2669+
function verifyDiscoverAndRead (script, database, done) {
2670+
if (!boltStub.supported) {
2671+
done()
2672+
return
2673+
}
2674+
2675+
// Given
2676+
const server = boltStub.start(
2677+
`./test/resources/boltstub/v4/acquire_endpoints_${database ||
2678+
'default_database'}.script`,
2679+
9001
2680+
)
2681+
const readServer = boltStub.start(
2682+
`./test/resources/boltstub/v4/${script}.script`,
2683+
9005
2684+
)
2685+
2686+
boltStub.run(() => {
2687+
const driver = boltStub.newDriver('neo4j://127.0.0.1:9001')
2688+
// When
2689+
const session = driver.session({
2690+
database: database,
2691+
defaultAccessMode: READ
2692+
})
2693+
session.run('MATCH (n) RETURN n.name').then(() => {
2694+
session.close()
2695+
// Then
2696+
expect(
2697+
hasAddressInConnectionPool(driver, '127.0.0.1:9001')
2698+
).toBeTruthy()
2699+
expect(
2700+
hasAddressInConnectionPool(driver, '127.0.0.1:9005')
2701+
).toBeTruthy()
2702+
assertHasRouters(
2703+
driver,
2704+
['127.0.0.1:9001', '127.0.0.1:9002', '127.0.0.1:9003'],
2705+
database
2706+
)
2707+
assertHasReaders(
2708+
driver,
2709+
['127.0.0.1:9005', '127.0.0.1:9006'],
2710+
database
2711+
)
2712+
assertHasWriters(
2713+
driver,
2714+
['127.0.0.1:9007', '127.0.0.1:9008'],
2715+
database
2716+
)
2717+
2718+
driver.close()
2719+
server.exit(code => {
2720+
readServer.exit(readCode => {
2721+
expect(code).toEqual(0)
2722+
expect(readCode).toEqual(0)
2723+
done()
2724+
})
2725+
})
2726+
})
2727+
})
2728+
}
2729+
2730+
function verifyDiscoverAndWrite (script, database, done) {
2731+
if (!boltStub.supported) {
2732+
done()
2733+
return
2734+
}
2735+
2736+
// Given
2737+
const server = boltStub.start(
2738+
`./test/resources/boltstub/v4/acquire_endpoints_${database ||
2739+
'default_database'}.script`,
2740+
9001
2741+
)
2742+
const writeServer = boltStub.start(
2743+
`./test/resources/boltstub/v4/${script}.script`,
2744+
9007
2745+
)
2746+
2747+
boltStub.run(() => {
2748+
const driver = boltStub.newDriver('neo4j://127.0.0.1:9001')
2749+
// When
2750+
const session = driver.session({ database: database })
2751+
session.run("CREATE (n {name:'Bob'})").then(() => {
2752+
session.close()
2753+
// Then
2754+
expect(
2755+
hasAddressInConnectionPool(driver, '127.0.0.1:9001')
2756+
).toBeTruthy()
2757+
expect(
2758+
hasAddressInConnectionPool(driver, '127.0.0.1:9007')
2759+
).toBeTruthy()
2760+
assertHasRouters(
2761+
driver,
2762+
['127.0.0.1:9001', '127.0.0.1:9002', '127.0.0.1:9003'],
2763+
database
2764+
)
2765+
assertHasReaders(
2766+
driver,
2767+
['127.0.0.1:9005', '127.0.0.1:9006'],
2768+
database
2769+
)
2770+
assertHasWriters(
2771+
driver,
2772+
['127.0.0.1:9007', '127.0.0.1:9008'],
2773+
database
2774+
)
2775+
2776+
driver.close()
2777+
server.exit(code => {
2778+
writeServer.exit(writeCode => {
2779+
expect(code).toEqual(0)
2780+
expect(writeCode).toEqual(0)
2781+
done()
2782+
})
2783+
})
2784+
})
2785+
})
2786+
}
2787+
2788+
it('should discover servers for default database and read', done => {
2789+
verifyDiscoverAndRead('read', '', done)
2790+
})
2791+
2792+
it('should discover servers for aDatabase and read', done => {
2793+
verifyDiscoverAndRead('read_from_aDatabase', 'aDatabase', done)
2794+
})
2795+
2796+
it('should discover servers for default database and write', done => {
2797+
verifyDiscoverAndWrite('write', '', done)
2798+
})
2799+
2800+
it('should discover servers for aDatabase and write', done => {
2801+
verifyDiscoverAndWrite('write_to_aDatabase', 'aDatabase', done)
2802+
})
2803+
2804+
it('should fail discovery if database not found', done => {
2805+
if (!boltStub.supported) {
2806+
done()
2807+
return
2808+
}
2809+
2810+
// Given
2811+
const server = boltStub.start(
2812+
`./test/resources/boltstub/v4/acquire_endpoints_db_not_found.script`,
2813+
9001
2814+
)
2815+
2816+
boltStub.run(() => {
2817+
const driver = boltStub.newDriver('neo4j://127.0.0.1:9001')
2818+
// When
2819+
const session = driver.session({ database: 'aDatabase' })
2820+
2821+
session.run('CREATE ()').catch(error => {
2822+
// Then
2823+
expect(error.code).toEqual(
2824+
'Neo.ClientError.Database.DatabaseNotFound'
2825+
)
2826+
expect(error.message).toEqual('database not found')
2827+
2828+
session.close()
2829+
driver.close()
2830+
server.exit(code => {
2831+
expect(code).toEqual(0)
2832+
done()
2833+
})
2834+
})
2835+
})
2836+
})
2837+
2838+
it('should try next server for empty routing table response', done => {
2839+
if (!boltStub.supported) {
2840+
done()
2841+
return
2842+
}
2843+
2844+
// Given
2845+
const router1 = boltStub.start(
2846+
`./test/resources/boltstub/v4/acquire_endpoints_aDatabase_no_servers.script`,
2847+
9001
2848+
)
2849+
const router2 = boltStub.start(
2850+
`./test/resources/boltstub/v4/acquire_endpoints_aDatabase.script`,
2851+
9002
2852+
)
2853+
const reader1 = boltStub.start(
2854+
`./test/resources/boltstub/v4/read_from_aDatabase.script`,
2855+
9005
2856+
)
2857+
2858+
boltStub.run(() => {
2859+
const driver = boltStub.newDriver('neo4j://127.0.0.1:9000', {
2860+
resolver: address => [
2861+
'neo4j://127.0.0.1:9001',
2862+
'neo4j://127.0.0.1:9002'
2863+
]
2864+
})
2865+
2866+
// When
2867+
const session = driver.session({
2868+
database: 'aDatabase',
2869+
defaultAccessMode: READ
2870+
})
2871+
session.run('MATCH (n) RETURN n.name').then(result => {
2872+
expect(result.records.map(record => record.get(0))).toEqual([
2873+
'Bob',
2874+
'Alice',
2875+
'Tina'
2876+
])
2877+
2878+
session.close()
2879+
driver.close()
2880+
router1.exit(code1 => {
2881+
router2.exit(code2 => {
2882+
reader1.exit(code3 => {
2883+
expect(code1).toEqual(0)
2884+
expect(code2).toEqual(0)
2885+
expect(code3).toEqual(0)
2886+
done()
2887+
})
2888+
})
2889+
})
2890+
})
2891+
})
2892+
})
2893+
})
2894+
26682895
function testAddressPurgeOnDatabaseError (script, query, accessMode, done) {
26692896
if (!boltStub.supported) {
26702897
done()

test/internal/routing-util.test.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,6 @@ describe('RoutingUtil', () => {
100100
})
101101
})
102102

103-
it('should use getServers procedure when server version is older than 3.2.0', done => {
104-
const connection = new FakeConnection().withServerVersion('Neo4j/3.1.9')
105-
const session = FakeSession.withFakeConnection(connection)
106-
107-
callRoutingProcedure(session, '', {}).then(() => {
108-
expect(connection.seenStatements).toEqual([
109-
'CALL dbms.cluster.routing.getServers'
110-
])
111-
expect(connection.seenParameters).toEqual([{}])
112-
done()
113-
})
114-
})
115-
116103
it('should use getRoutingTable procedure with empty routing context when server version is 3.2.0', done => {
117104
const connection = new FakeConnection().withServerVersion('Neo4j/3.2.0')
118105
const session = FakeSession.withFakeConnection(connection)
@@ -329,7 +316,9 @@ describe('RoutingUtil', () => {
329316
expect(connection.seenStatements).toEqual([
330317
'CALL dbms.routing.getRoutingTable($context, $database)'
331318
])
332-
expect(connection.seenParameters).toEqual([{ context, database }])
319+
expect(connection.seenParameters).toEqual([
320+
{ context, database: database || null }
321+
])
333322
done()
334323
})
335324
}

test/resources/boltstub/v3/acquire_endpoints.script

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
!: BOLT 3
22
!: AUTO HELLO
33
!: AUTO RESET
4+
!: AUTO GOODBYE
45

56
C: RUN "CALL dbms.cluster.routing.getRoutingTable($context)" {"context": {}} {}
67
PULL_ALL
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
!: BOLT 2
2-
!: AUTO INIT
1+
!: BOLT 3
2+
!: AUTO HELLO
33
!: AUTO RESET
44

5-
C: RUN "CALL dbms.cluster.routing.getRoutingTable($context)" {"context": {}}
5+
C: RUN "CALL dbms.cluster.routing.getRoutingTable($context)" {"context": {}} {}
66
PULL_ALL
77
S: <EXIT>

test/resources/boltstub/v3/acquire_endpoints_multiple_records.script

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
!: BOLT 3
22
!: AUTO HELLO
33
!: AUTO RESET
4+
!: AUTO GOODBYE
45

56
C: RUN "CALL dbms.cluster.routing.getRoutingTable($context)" {"context": {}} {}
67
PULL_ALL

test/resources/boltstub/v3/acquire_endpoints_no_readers.script

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
!: BOLT 3
22
!: AUTO HELLO
33
!: AUTO RESET
4+
!: AUTO GOODBYE
45

56
C: RUN "CALL dbms.cluster.routing.getRoutingTable($context)" {"context": {}} {}
67
PULL_ALL

test/resources/boltstub/v3/acquire_endpoints_no_records.script

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
!: BOLT 3
22
!: AUTO HELLO
33
!: AUTO RESET
4+
!: AUTO GOODBYE
45

56
C: RUN "CALL dbms.cluster.routing.getRoutingTable($context)" {"context": {}} {}
67
PULL_ALL

0 commit comments

Comments
 (0)