@@ -21,7 +21,7 @@ import neo4j from '../../src/v1';
2121import { READ , WRITE } from '../../src/v1/driver' ;
2222import boltStub from '../internal/bolt-stub' ;
2323import RoutingTable from '../../src/v1/internal/routing-table' ;
24- import { SESSION_EXPIRED } from '../../src/v1/error' ;
24+ import { SERVICE_UNAVAILABLE , SESSION_EXPIRED } from '../../src/v1/error' ;
2525import lolex from 'lolex' ;
2626
2727describe ( 'routing driver with stub server' , ( ) => {
@@ -1915,6 +1915,89 @@ describe('routing driver with stub server', () => {
19151915 testAddressPurgeOnDatabaseError ( `RETURN 1` , READ , done ) ;
19161916 } ) ;
19171917
1918+ it ( 'should use resolver function that returns array during first discovery' , done => {
1919+ testResolverFunctionDuringFirstDiscovery ( [ '127.0.0.1:9010' ] , done ) ;
1920+ } ) ;
1921+
1922+ it ( 'should use resolver function that returns promise during first discovery' , done => {
1923+ testResolverFunctionDuringFirstDiscovery ( Promise . resolve ( [ '127.0.0.1:9010' ] ) , done ) ;
1924+ } ) ;
1925+
1926+ it ( 'should fail first discovery when configured resolver function throws' , done => {
1927+ const failureFunction = ( ) => {
1928+ throw new Error ( 'Broken resolver' ) ;
1929+ } ;
1930+ testResolverFunctionFailureDuringFirstDiscovery ( failureFunction , null , 'Broken resolver' , done ) ;
1931+ } ) ;
1932+
1933+ it ( 'should fail first discovery when configured resolver function returns no addresses' , done => {
1934+ const failureFunction = ( ) => {
1935+ return [ ] ;
1936+ } ;
1937+ testResolverFunctionFailureDuringFirstDiscovery ( failureFunction , SERVICE_UNAVAILABLE , 'No routing servers available' , done ) ;
1938+ } ) ;
1939+
1940+ it ( 'should fail first discovery when configured resolver function returns a string instead of array of addresses' , done => {
1941+ const failureFunction = ( ) => {
1942+ return 'Hello' ;
1943+ } ;
1944+ testResolverFunctionFailureDuringFirstDiscovery ( failureFunction , null , 'Configured resolver function should either return an array of addresses' , done ) ;
1945+ } ) ;
1946+
1947+ it ( 'should use resolver function during rediscovery when existing routers fail' , done => {
1948+ if ( ! boltStub . supported ) {
1949+ done ( ) ;
1950+ return ;
1951+ }
1952+
1953+ const router1 = boltStub . start ( './test/resources/boltstub/get_routing_table.script' , 9001 ) ;
1954+ const router2 = boltStub . start ( './test/resources/boltstub/acquire_endpoints.script' , 9042 ) ;
1955+ const reader = boltStub . start ( './test/resources/boltstub/read_server.script' , 9005 ) ;
1956+
1957+ boltStub . run ( ( ) => {
1958+ const resolverFunction = address => {
1959+ if ( address === '127.0.0.1:9001' ) {
1960+ return [ '127.0.0.1:9010' , '127.0.0.1:9011' , '127.0.0.1:9042' ] ;
1961+ }
1962+ throw new Error ( `Unexpected address ${ address } ` ) ;
1963+ } ;
1964+
1965+ const driver = boltStub . newDriver ( 'bolt+routing://127.0.0.1:9001' , { resolver : resolverFunction } ) ;
1966+
1967+ const session = driver . session ( READ ) ;
1968+ // run a query that should trigger discovery against 9001 and then read from it
1969+ session . run ( 'MATCH (n) RETURN n.name AS name' )
1970+ . then ( result => {
1971+ expect ( result . records . map ( record => record . get ( 0 ) ) ) . toEqual ( [ 'Alice' , 'Bob' , 'Eve' ] ) ;
1972+
1973+ // 9001 should now exit and read transaction should fail to read from all existing readers
1974+ // it should then rediscover using addresses from resolver, only 9042 of them works and can respond with table containing reader 9005
1975+ session . readTransaction ( tx => tx . run ( 'MATCH (n) RETURN n.name' ) )
1976+ . then ( result => {
1977+ expect ( result . records . map ( record => record . get ( 0 ) ) ) . toEqual ( [ 'Bob' , 'Alice' , 'Tina' ] ) ;
1978+
1979+ assertHasRouters ( driver , [ '127.0.0.1:9001' , '127.0.0.1:9002' , '127.0.0.1:9003' ] ) ;
1980+ assertHasReaders ( driver , [ '127.0.0.1:9005' , '127.0.0.1:9006' ] ) ;
1981+ assertHasWriters ( driver , [ '127.0.0.1:9007' , '127.0.0.1:9008' ] ) ;
1982+
1983+ session . close ( ( ) => {
1984+ driver . close ( ) ;
1985+ router1 . exit ( code1 => {
1986+ router2 . exit ( code2 => {
1987+ reader . exit ( code3 => {
1988+ expect ( code1 ) . toEqual ( 0 ) ;
1989+ expect ( code2 ) . toEqual ( 0 ) ;
1990+ expect ( code3 ) . toEqual ( 0 ) ;
1991+ done ( ) ;
1992+ } ) ;
1993+ } ) ;
1994+ } ) ;
1995+ } ) ;
1996+ } ) . catch ( done . fail ) ;
1997+ } ) . catch ( done . fail ) ;
1998+ } ) ;
1999+ } ) ;
2000+
19182001 function testAddressPurgeOnDatabaseError ( query , accessMode , done ) {
19192002 if ( ! boltStub . supported ) {
19202003 done ( ) ;
@@ -2146,6 +2229,74 @@ describe('routing driver with stub server', () => {
21462229 return Object . keys ( driver . _openConnections ) . length ;
21472230 }
21482231
2232+ function testResolverFunctionDuringFirstDiscovery ( resolutionResult , done ) {
2233+ if ( ! boltStub . supported ) {
2234+ done ( ) ;
2235+ return ;
2236+ }
2237+
2238+ const router = boltStub . start ( './test/resources/boltstub/acquire_endpoints.script' , 9010 ) ;
2239+ const reader = boltStub . start ( './test/resources/boltstub/read_server.script' , 9005 ) ;
2240+
2241+ boltStub . run ( ( ) => {
2242+ const resolverFunction = address => {
2243+ if ( address === 'neo4j.com:7687' ) {
2244+ return resolutionResult ;
2245+ }
2246+ throw new Error ( `Unexpected address ${ address } ` ) ;
2247+ } ;
2248+
2249+ const driver = boltStub . newDriver ( 'bolt+routing://neo4j.com' , { resolver : resolverFunction } ) ;
2250+
2251+ const session = driver . session ( READ ) ;
2252+ session . run ( 'MATCH (n) RETURN n.name' )
2253+ . then ( result => {
2254+ expect ( result . records . map ( record => record . get ( 0 ) ) ) . toEqual ( [ 'Bob' , 'Alice' , 'Tina' ] ) ;
2255+ session . close ( ( ) => {
2256+ driver . close ( ) ;
2257+
2258+ router . exit ( code1 => {
2259+ reader . exit ( code2 => {
2260+ expect ( code1 ) . toEqual ( 0 ) ;
2261+ expect ( code2 ) . toEqual ( 0 ) ;
2262+ done ( ) ;
2263+ } ) ;
2264+ } ) ;
2265+ } ) ;
2266+ } )
2267+ . catch ( done . fail ) ;
2268+ } ) ;
2269+ }
2270+
2271+ function testResolverFunctionFailureDuringFirstDiscovery ( failureFunction , expectedCode , expectedMessage , done ) {
2272+ if ( ! boltStub . supported ) {
2273+ done ( ) ;
2274+ return ;
2275+ }
2276+
2277+ const resolverFunction = address => {
2278+ if ( address === 'neo4j.com:8989' ) {
2279+ return failureFunction ( ) ;
2280+ }
2281+ throw new Error ( 'Unexpected address' ) ;
2282+ } ;
2283+
2284+ const driver = boltStub . newDriver ( 'bolt+routing://neo4j.com:8989' , { resolver : resolverFunction } ) ;
2285+ const session = driver . session ( ) ;
2286+
2287+ session . run ( 'RETURN 1' )
2288+ . then ( result => done . fail ( result ) )
2289+ . catch ( error => {
2290+ if ( expectedCode ) {
2291+ expect ( error . code ) . toEqual ( expectedCode ) ;
2292+ }
2293+ if ( expectedMessage ) {
2294+ expect ( error . message . indexOf ( expectedMessage ) ) . toBeGreaterThan ( - 1 ) ;
2295+ }
2296+ done ( ) ;
2297+ } ) ;
2298+ }
2299+
21492300 class MemorizingRoutingTable extends RoutingTable {
21502301
21512302 constructor ( initialTable ) {
0 commit comments