Skip to content

Commit b857656

Browse files
committed
Couple integration tests for IPv6 support
Added tests to verify that driver can connect to real single-instance database using localhost IPv6 address. Added test to check that driver can receive IPv6 addresses in routing procedure response (using stub server). Introduced convenience method to read server version using given driver instance.
1 parent 54622da commit b857656

File tree

7 files changed

+149
-16
lines changed

7 files changed

+149
-16
lines changed

src/v1/internal/server-version.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,22 @@ class ServerVersion {
3636
this.patch = patch;
3737
}
3838

39+
/**
40+
* Fetch server version using the given driver.
41+
* @param {Driver} driver the driver to use.
42+
* @return {Promise<ServerVersion>} promise resolved with a {@link ServerVersion} object or rejected with error.
43+
*/
44+
static fromDriver(driver) {
45+
const session = driver.session();
46+
return session.run('RETURN 1').then(result => {
47+
session.close();
48+
return ServerVersion.fromString(result.summary.server.version);
49+
});
50+
}
51+
3952
/**
4053
* Parse given string to a {@link ServerVersion} object.
41-
* @param versionStr the string to parse.
54+
* @param {string} versionStr the string to parse.
4255
* @return {ServerVersion} version for the given string.
4356
* @throws Error if given string can't be parsed.
4457
*/

test/internal/server-version.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
* limitations under the License.
1818
*/
1919

20+
import neo4j from '../../src/v1';
21+
import sharedNeo4j from '../internal/shared-neo4j';
2022
import {ServerVersion, VERSION_3_2_0, VERSION_IN_DEV} from '../../src/v1/internal/server-version';
2123

2224
describe('ServerVersion', () => {
@@ -80,6 +82,33 @@ describe('ServerVersion', () => {
8082
verifyVersion(parse('Neo4j/Dev'), 0, 0, 0);
8183
});
8284

85+
it('should fetch version using driver', done => {
86+
const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken);
87+
ServerVersion.fromDriver(driver).then(version => {
88+
driver.close();
89+
expect(version).not.toBeNull();
90+
expect(version).toBeDefined();
91+
expect(version instanceof ServerVersion).toBeTruthy();
92+
done();
93+
}).catch(error => {
94+
driver.close();
95+
done.fail(error);
96+
});
97+
});
98+
99+
it('should fail to fetch version using incorrect driver', done => {
100+
const driver = neo4j.driver('bolt://localhost:4242', sharedNeo4j.authToken); // use wrong port
101+
ServerVersion.fromDriver(driver).then(version => {
102+
driver.close();
103+
done.fail('Should not be able to fetch version: ' + JSON.stringify(version));
104+
}).catch(error => {
105+
expect(error).not.toBeNull();
106+
expect(error).toBeDefined();
107+
driver.close();
108+
done();
109+
});
110+
});
111+
83112
it('should compare equal versions', () => {
84113
expect(new ServerVersion(3, 1, 0).compareTo(new ServerVersion(3, 1, 0))).toEqual(0);
85114
expect(new ServerVersion(1, 9, 12).compareTo(new ServerVersion(1, 9, 12))).toEqual(0);

test/internal/shared-neo4j.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,13 @@ class SupportedPlatform extends UnsupportedPlatform {
6464
}
6565

6666
spawn(command, args) {
67-
return this._childProcess.spawnSync(command, args);
67+
const options = {
68+
// ignore stdin, use default values for stdout and stderr
69+
// otherwise spawned java process does not see IPv6 address of the local interface and Neo4j fails to start
70+
// https://github.com/nodejs/node-v0.x-archive/issues/7406
71+
stdio: ['ignore', null, null]
72+
};
73+
return this._childProcess.spawnSync(command, args, options);
6874
}
6975

7076
listDir(path) {
@@ -94,6 +100,11 @@ const username = 'neo4j';
94100
const password = 'password';
95101
const authToken = neo4j.auth.basic(username, password);
96102

103+
const additionalConfig = {
104+
// tell neo4j to listen for IPv6 connections, only supported by 3.1+
105+
'dbms.connectors.default_listen_address': '::'
106+
};
107+
97108
const neoCtrlVersionParam = '-e';
98109
const defaultNeo4jVersion = '3.2.5';
99110
const defaultNeoCtrlArgs = `${neoCtrlVersionParam} ${defaultNeo4jVersion}`;
@@ -113,6 +124,7 @@ function start(dir, givenNeoCtrlArgs) {
113124

114125
if (boltKitCheckResult.successful) {
115126
const neo4jDir = installNeo4j(dir, givenNeoCtrlArgs);
127+
configureNeo4j(neo4jDir);
116128
createDefaultUser(neo4jDir);
117129
startNeo4j(neo4jDir);
118130
} else {
@@ -158,6 +170,18 @@ function installNeo4j(dir, givenNeoCtrlArgs) {
158170
}
159171
}
160172

173+
function configureNeo4j(neo4jDir) {
174+
console.log('Configuring Neo4j at: \'' + neo4jDir + '\' with ' + JSON.stringify(additionalConfig));
175+
176+
const configEntries = Object.keys(additionalConfig).map(key => `${key}=${additionalConfig[key]}`);
177+
const configureResult = runCommand('neoctrl-configure', [neo4jDir, ...configEntries]);
178+
if (!configureResult.successful) {
179+
throw new Error('Unable to configure Neo4j.\n' + configureResult.fullOutput);
180+
}
181+
182+
console.log('Configured Neo4j at: \'' + neo4jDir + '\'');
183+
}
184+
161185
function createDefaultUser(neo4jDir) {
162186
console.log('Creating user \'' + username + '\' for Neo4j at: \'' + neo4jDir + '\'');
163187
const result = runCommand('neoctrl-create-user', [neo4jDir, username, password]);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
!: AUTO INIT
2+
!: AUTO RESET
3+
!: AUTO PULL_ALL
4+
5+
C: RUN "CALL dbms.cluster.routing.getServers" {}
6+
PULL_ALL
7+
S: SUCCESS {"fields": ["ttl", "servers"]}
8+
RECORD [9223372036854775807, [{"addresses": ["127.0.0.1:9001", "[::1]:9001"],"role": "READ"}, {"addresses": ["[2001:db8:a0b:12f0::1]:9002","[3731:54:65fe:2::a7]:9003"], "role": "WRITE"},{"addresses": ["[ff02::1]:9001","[684D:1111:222:3333:4444:5555:6:77]:9002","[::1]:9003"], "role": "ROUTE"}]]
9+
SUCCESS {}
10+
C: RUN "MATCH (n) RETURN n.name" {}
11+
PULL_ALL
12+
S: SUCCESS {"fields": ["n.name"]}
13+
SUCCESS {}
14+

test/v1/driver.test.js

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,22 @@ import sharedNeo4j from '../internal/shared-neo4j';
2222
import FakeConnection from '../internal/fake-connection';
2323
import lolex from 'lolex';
2424
import {DEFAULT_ACQUISITION_TIMEOUT, DEFAULT_MAX_SIZE} from '../../src/v1/internal/pool-config';
25+
import {ServerVersion, VERSION_3_1_0} from '../../src/v1/internal/server-version';
2526

2627
describe('driver', () => {
2728

2829
let clock;
2930
let driver;
31+
let serverVersion;
32+
33+
beforeAll(done => {
34+
const tmpDriver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken);
35+
ServerVersion.fromDriver(tmpDriver).then(version => {
36+
tmpDriver.close();
37+
serverVersion = version;
38+
done();
39+
});
40+
});
3041

3142
afterEach(() => {
3243
if (clock) {
@@ -39,13 +50,6 @@ describe('driver', () => {
3950
}
4051
});
4152

42-
fit('apa', done => {
43-
driver = neo4j.driver('bolt://[::1]', sharedNeo4j.authToken);
44-
driver.session().run('return 1').then(result => console.log(result.records))
45-
.catch(error => console.log(error))
46-
.then(() => done());
47-
});
48-
4953
it('should expose sessions', () => {
5054
// Given
5155
driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken);
@@ -313,6 +317,30 @@ describe('driver', () => {
313317
});
314318
});
315319

320+
it('should connect to IPv6 address without port', done => {
321+
testIPv6Connection('bolt://[::1]', done);
322+
});
323+
324+
it('should connect to IPv6 address wit port', done => {
325+
testIPv6Connection('bolt://[::1]:7687', done);
326+
});
327+
328+
function testIPv6Connection(url, done) {
329+
if (serverVersion.compareTo(VERSION_3_1_0) < 0) {
330+
// IPv6 listen address only supported starting from neo4j 3.1, so let's ignore the rest
331+
done();
332+
}
333+
334+
driver = neo4j.driver('bolt://[::1]', sharedNeo4j.authToken);
335+
336+
const session = driver.session();
337+
session.run('RETURN 42').then(result => {
338+
expect(result.records[0].get(0).toNumber()).toEqual(42);
339+
session.close();
340+
done();
341+
});
342+
}
343+
316344
/**
317345
* Starts new transaction to force new network connection.
318346
* @param {Driver} driver - the driver to use.

test/v1/routing.driver.boltkit.test.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ describe('routing driver with stub server', () => {
3838
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
3939
});
4040

41-
it('should discover server', done => {
41+
it('should discover servers', done => {
4242
if (!boltStub.supported) {
4343
done();
4444
return;
@@ -68,6 +68,33 @@ describe('routing driver with stub server', () => {
6868
});
6969
});
7070

71+
it('should discover IPv6 servers', done => {
72+
if (!boltStub.supported) {
73+
done();
74+
return;
75+
}
76+
77+
const server = boltStub.start('./test/resources/boltstub/discover_ipv6_servers_and_read.script', 9001);
78+
79+
boltStub.run(() => {
80+
const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001');
81+
const session = driver.session(READ);
82+
session.run('MATCH (n) RETURN n.name').then(() => {
83+
84+
expect(hasAddressInConnectionPool(driver, '127.0.0.1:9001')).toBeTruthy();
85+
assertHasReaders(driver, ['127.0.0.1:9001', '[::1]:9001']);
86+
assertHasWriters(driver, ['[2001:db8:a0b:12f0::1]:9002', '[3731:54:65fe:2::a7]:9003']);
87+
assertHasRouters(driver, ['[ff02::1]:9001', '[684D:1111:222:3333:4444:5555:6:77]:9002', '[::1]:9003']);
88+
89+
driver.close();
90+
server.exit(code => {
91+
expect(code).toEqual(0);
92+
done();
93+
});
94+
});
95+
});
96+
});
97+
7198
it('should purge connections to stale servers after routing table refresh', done => {
7299
if (!boltStub.supported) {
73100
done();

test/v1/types.test.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,10 @@ describe('byte arrays', () => {
146146
beforeAll(done => {
147147
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
148148

149-
const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken);
150-
const session = driver.session();
151-
session.run('RETURN 1').then(result => {
152-
driver.close();
153-
const serverVersion = ServerVersion.fromString(result.summary.server.version);
154-
serverSupportsByteArrays = serverVersion.compareTo(VERSION_3_2_0) >= 0;
149+
const tmpDriver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken);
150+
ServerVersion.fromDriver(tmpDriver).then(version => {
151+
tmpDriver.close();
152+
serverSupportsByteArrays = version.compareTo(VERSION_3_2_0) >= 0;
155153
done();
156154
});
157155
});

0 commit comments

Comments
 (0)