feat(cluster): create way to test single/gossip/cluster
* docker-compose files to easily setup cluster or single node eventstore * programmatic tests for single/gossip/cluster
This commit is contained in:
parent
e9834daa31
commit
da6d059547
38
README.md
38
README.md
|
@ -112,12 +112,27 @@ To generate a test event, open a separate console and run:
|
|||
|
||||
## Running the tests
|
||||
|
||||
### Local testing
|
||||
|
||||
To run the tests it is recommended that you use an in-memory instance of the eventstore so you don't pollute your dev instance.
|
||||
|
||||
EventStore.ClusterNode.exe --run-projections=all --memdb –certificate-file=yourcert.pfx
|
||||
or
|
||||
./run-node.sh --run-projections=all --memdb –certificate-file=yourcert.p12
|
||||
|
||||
You can also use docker-compose :
|
||||
|
||||
```bash
|
||||
# start the single node cluster
|
||||
npm run compose:single:start
|
||||
# if you want to wait for the cluster to be available
|
||||
npm run compose:wait
|
||||
# run the tests
|
||||
npm run test
|
||||
# to cleanup (stop containres, delete volumes)
|
||||
npm run compose:single:stop
|
||||
```
|
||||
|
||||
For SSL setup see:
|
||||
|
||||
https://eventstore.org/docs/server/setting_up_ssl/
|
||||
|
@ -128,6 +143,29 @@ To execute the tests suites simply run
|
|||
|
||||
npm test
|
||||
|
||||
### Isolated environment
|
||||
|
||||
To be able to run the tests for different connection types (tcp, gossip, cluster) docker-compose files are available to setup the environment and run the tests.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
* docker
|
||||
* docker-compose
|
||||
|
||||
#### Run
|
||||
|
||||
To execute the tests suites for single node cluster (tcp connection) simply run
|
||||
|
||||
npm run test:single
|
||||
|
||||
To execute the tests suites for multiple nodes cluster (gossip connection) simply run
|
||||
|
||||
npm run test:gossip
|
||||
|
||||
To execute the tests suites for multiple nodes cluster (dns discovery connection) simply run
|
||||
|
||||
npm run test:cluster
|
||||
|
||||
## Porting .Net Task to Node.js
|
||||
|
||||
Any async commands returns a [Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) object in replacement of .Net Task.
|
||||
|
|
147
docker-compose-cluster.yaml
Normal file
147
docker-compose-cluster.yaml
Normal file
|
@ -0,0 +1,147 @@
|
|||
version: '3.4'
|
||||
|
||||
services:
|
||||
eventstore.db:
|
||||
image: eventstore/eventstore:release-5.0.8
|
||||
environment:
|
||||
- EVENTSTORE_WORKER_THREADS=5
|
||||
- EVENTSTORE_CLUSTER_SIZE=3
|
||||
- EVENTSTORE_RUN_PROJECTIONS=All
|
||||
- EVENTSTORE_DB=/var/lib/eventstore-data
|
||||
- EVENTSTORE_INDEX=/var/lib/eventstore-index
|
||||
- EVENTSTORE_LOG=/var/log/eventstore
|
||||
- EVENTSTORE_CLUSTER_GOSSIP_PORT=2112
|
||||
- EVENTSTORE_INT_TCP_PORT=1112
|
||||
- EVENTSTORE_EXT_TCP_PORT=1113
|
||||
- EVENTSTORE_INT_HTTP_PORT=2112
|
||||
- EVENTSTORE_EXT_HTTP_PORT=2113
|
||||
- EVENTSTORE_DISCOVER_VIA_DNS=true
|
||||
- EVENTSTORE_CLUSTER_DNS=eventstore.local
|
||||
- EVENTSTORE_INT_IP=192.168.33.10
|
||||
- EVENTSTORE_EXT_IP=192.168.33.10
|
||||
ports:
|
||||
- "1112:1112"
|
||||
- "1113:1113"
|
||||
- "2112:2112"
|
||||
- "2113:2113"
|
||||
networks:
|
||||
app_net:
|
||||
aliases:
|
||||
- eventstore.local
|
||||
ipv4_address: 192.168.33.10
|
||||
volumes:
|
||||
- type: volume
|
||||
source: eventstore-volume-data
|
||||
target: /var/lib/eventstore-data
|
||||
- type: volume
|
||||
source: eventstore-volume-index
|
||||
target: /var/lib/eventstore-index
|
||||
- type: volume
|
||||
source: eventstore-volume-logs
|
||||
target: /var/log/eventstore
|
||||
|
||||
eventstore.db2:
|
||||
image: eventstore/eventstore:release-5.0.8
|
||||
environment:
|
||||
- EVENTSTORE_WORKER_THREADS=5
|
||||
- EVENTSTORE_CLUSTER_SIZE=3
|
||||
- EVENTSTORE_RUN_PROJECTIONS=All
|
||||
- EVENTSTORE_DB=/var/lib/eventstore-data
|
||||
- EVENTSTORE_INDEX=/var/lib/eventstore-index
|
||||
- EVENTSTORE_LOG=/var/log/eventstore
|
||||
- EVENTSTORE_CLUSTER_GOSSIP_PORT=2112
|
||||
- EVENTSTORE_INT_TCP_PORT=1112
|
||||
- EVENTSTORE_EXT_TCP_PORT=1113
|
||||
- EVENTSTORE_INT_HTTP_PORT=2112
|
||||
- EVENTSTORE_EXT_HTTP_PORT=2113
|
||||
- EVENTSTORE_DISCOVER_VIA_DNS=true
|
||||
- EVENTSTORE_CLUSTER_DNS=eventstore.local
|
||||
- EVENTSTORE_INT_IP=192.168.33.11
|
||||
- EVENTSTORE_EXT_IP=192.168.33.11
|
||||
expose:
|
||||
- "1113"
|
||||
- "1112"
|
||||
- "2112"
|
||||
- "2113"
|
||||
networks:
|
||||
app_net:
|
||||
aliases:
|
||||
- eventstore.local
|
||||
ipv4_address: 192.168.33.11
|
||||
volumes:
|
||||
- type: volume
|
||||
source: eventstore-volume-data2
|
||||
target: /var/lib/eventstore-data
|
||||
- type: volume
|
||||
source: eventstore-volume-index2
|
||||
target: /var/lib/eventstore-index
|
||||
- type: volume
|
||||
source: eventstore-volume-logs2
|
||||
target: /var/log/eventstore
|
||||
|
||||
eventstore.db3:
|
||||
image: eventstore/eventstore:release-5.0.8
|
||||
environment:
|
||||
- EVENTSTORE_WORKER_THREADS=5
|
||||
- EVENTSTORE_CLUSTER_SIZE=3
|
||||
- EVENTSTORE_RUN_PROJECTIONS=All
|
||||
- EVENTSTORE_DB=/var/lib/eventstore-data
|
||||
- EVENTSTORE_INDEX=/var/lib/eventstore-index
|
||||
- EVENTSTORE_LOG=/var/log/eventstore
|
||||
- EVENTSTORE_CLUSTER_GOSSIP_PORT=2112
|
||||
- EVENTSTORE_INT_TCP_PORT=1112
|
||||
- EVENTSTORE_EXT_TCP_PORT=1113
|
||||
- EVENTSTORE_INT_HTTP_PORT=2112
|
||||
- EVENTSTORE_EXT_HTTP_PORT=2113
|
||||
- EVENTSTORE_DISCOVER_VIA_DNS=true
|
||||
- EVENTSTORE_CLUSTER_DNS=eventstore.local
|
||||
- EVENTSTORE_INT_IP=192.168.33.12
|
||||
- EVENTSTORE_EXT_IP=192.168.33.12
|
||||
expose:
|
||||
- "1113"
|
||||
- "1112"
|
||||
- "2112"
|
||||
- "2113"
|
||||
networks:
|
||||
app_net:
|
||||
aliases:
|
||||
- eventstore.local
|
||||
ipv4_address: 192.168.33.12
|
||||
volumes:
|
||||
- type: volume
|
||||
source: eventstore-volume-data3
|
||||
target: /var/lib/eventstore-data
|
||||
- type: volume
|
||||
source: eventstore-volume-index3
|
||||
target: /var/lib/eventstore-index
|
||||
- type: volume
|
||||
source: eventstore-volume-logs3
|
||||
target: /var/log/eventstore
|
||||
|
||||
nodejs:
|
||||
image: node:14
|
||||
working_dir: /var/code
|
||||
volumes:
|
||||
- .:/var/code
|
||||
- /var/code/node_modules
|
||||
command: bash -c "tail -f /dev/null"
|
||||
networks:
|
||||
- app_net
|
||||
|
||||
volumes:
|
||||
eventstore-volume-data:
|
||||
eventstore-volume-index:
|
||||
eventstore-volume-logs:
|
||||
eventstore-volume-data2:
|
||||
eventstore-volume-index2:
|
||||
eventstore-volume-logs2:
|
||||
eventstore-volume-data3:
|
||||
eventstore-volume-index3:
|
||||
eventstore-volume-logs3:
|
||||
|
||||
networks:
|
||||
app_net:
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: "192.168.33.0/24"
|
54
docker-compose-single.yaml
Normal file
54
docker-compose-single.yaml
Normal file
|
@ -0,0 +1,54 @@
|
|||
version: '3.4'
|
||||
|
||||
services:
|
||||
eventstore.db:
|
||||
image: eventstore/eventstore:release-5.0.8
|
||||
environment:
|
||||
- EVENTSTORE_CLUSTER_SIZE=1
|
||||
- EVENTSTORE_RUN_PROJECTIONS=All
|
||||
- EVENTSTORE_START_STANDARD_PROJECTIONS=True
|
||||
- EVENTSTORE_DB=/var/lib/eventstore-data
|
||||
- EVENTSTORE_INDEX=/var/lib/eventstore-index
|
||||
- EVENTSTORE_LOG=/var/log/eventstore
|
||||
- EVENTSTORE_EXT_TCP_PORT=1113
|
||||
- EVENTSTORE_EXT_HTTP_PORT=2113
|
||||
- EVENTSTORE_INT_IP=192.168.33.10
|
||||
- EVENTSTORE_EXT_IP=192.168.33.10
|
||||
ports:
|
||||
- "1113:1113"
|
||||
- "2113:2113"
|
||||
volumes:
|
||||
- type: volume
|
||||
source: eventstore-volume-data
|
||||
target: /var/lib/eventstore-data
|
||||
- type: volume
|
||||
source: eventstore-volume-index
|
||||
target: /var/lib/eventstore-index
|
||||
- type: volume
|
||||
source: eventstore-volume-logs
|
||||
target: /var/log/eventstore
|
||||
networks:
|
||||
app_net:
|
||||
ipv4_address: 192.168.33.10
|
||||
|
||||
nodejs:
|
||||
image: node:14
|
||||
working_dir: /var/code
|
||||
volumes:
|
||||
- .:/var/code
|
||||
- /var/code/node_modules
|
||||
command: bash -c "tail -f /dev/null"
|
||||
networks:
|
||||
- app_net
|
||||
|
||||
volumes:
|
||||
eventstore-volume-data:
|
||||
eventstore-volume-index:
|
||||
eventstore-volume-logs:
|
||||
|
||||
networks:
|
||||
app_net:
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: "192.168.33.0/24"
|
4743
package-lock.json
generated
4743
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
|
@ -16,6 +16,17 @@
|
|||
"test": "nodeunit",
|
||||
"test-debug": "TESTS_VERBOSE_LOGGING=1 nodeunit",
|
||||
"test:jest:watch": "jest --watch --coverage",
|
||||
"test:single": "npm run compose:single:start && npm run compose:wait && npm run compose:single:test ; npm run compose:single:stop",
|
||||
"test:gossip": "npm run compose:cluster:start && npm run compose:wait && npm run compose:gossip:test ; npm run compose:cluster:stop",
|
||||
"test:cluster": "npm run compose:cluster:start && npm run compose:wait && npm run compose:cluster:test ; npm run compose:cluster:stop",
|
||||
"compose:single:start": "docker-compose -f docker-compose-single.yaml up --build -d",
|
||||
"compose:cluster:start": "docker-compose -f docker-compose-cluster.yaml up --build -d",
|
||||
"compose:single:stop": "docker-compose -f docker-compose-single.yaml down -v --remove-orphans",
|
||||
"compose:cluster:stop": "docker-compose -f docker-compose-cluster.yaml down -v --remove-orphans",
|
||||
"compose:wait": "while [[ \"$(curl -s -o /dev/null -w ''%{http_code}'' localhost:2113/ping)\" != \"200\" ]]; do sleep 5; done",
|
||||
"compose:single:test": "docker-compose -f docker-compose-single.yaml exec nodejs bash -c \"npm i && npm run build && EVENTSTORE_CONNECTION_TYPE=tcp EVENTSTORE_HOST=192.168.33.10 npm run test-debug\"",
|
||||
"compose:cluster:test": "docker-compose -f docker-compose-cluster.yaml exec nodejs bash -c \"npm i && npm run build && EVENTSTORE_CONNECTION_TYPE=gossip EVENTSTORE_HOST=192.168.33.10 EVENTSTORE_HOST_1=192.168.33.10 EVENTSTORE_HOST_2=192.168.33.11 EVENTSTORE_HOST_3=192.168.33.12 npm run test-debug\"",
|
||||
"compose:gossip:test": "docker-compose -f docker-compose-cluster.yaml exec nodejs bash -c \"npm i && npm run build && EVENTSTORE_CONNECTION_TYPE=dns EVENTSTORE_HOST=192.168.33.10 npm run test-debug\"",
|
||||
"prepublishOnly": "npm run build && npm run gendocs",
|
||||
"gendocs": "rm -rf docs && jsdoc src -r -d docs"
|
||||
},
|
||||
|
|
|
@ -11,38 +11,102 @@ protobufJS.util.Long = undefined;
|
|||
protobufJS.configure();
|
||||
|
||||
var settings = {
|
||||
log: new NoopLogger()
|
||||
log: new NoopLogger(),
|
||||
};
|
||||
if (process.env.TESTS_VERBOSE_LOGGING === '1') {
|
||||
settings.verboseLogging = true;
|
||||
settings.log = new FileLogger('test-verbose.log');
|
||||
}
|
||||
|
||||
var tcpEndPoint = {host: 'localhost', port: 1113};
|
||||
|
||||
function setUp(cb) {
|
||||
function setUpWithGossipSeeds(cb) {
|
||||
var gossipSeeds = [
|
||||
new client.GossipSeed({ host: process.env.EVENTSTORE_HOST_1 || '192.168.33.10', port: 2113 }),
|
||||
new client.GossipSeed({ host: process.env.EVENTSTORE_HOST_2 || '192.168.33.11', port: 2113 }),
|
||||
new client.GossipSeed({ host: process.env.EVENTSTORE_HOST_3 || '192.168.33.12', port: 2113 }),
|
||||
];
|
||||
this.log = settings.log;
|
||||
this.testStreamName = 'test-' + uuid.v4();
|
||||
var connected = false;
|
||||
this.conn = client.EventStoreConnection.create(settings, tcpEndPoint);
|
||||
this.conn.connect()
|
||||
this.conn = client.createConnection(settings, gossipSeeds);
|
||||
this.conn
|
||||
.connect()
|
||||
.then(function () {
|
||||
//Doesn't mean anything, connection is just initiated
|
||||
settings.log.debug("Connection to %j initialized.", tcpEndPoint);
|
||||
settings.log.debug('Connection to %j initialized.', gossipSeeds);
|
||||
})
|
||||
.catch(function (err) {
|
||||
settings.log.error(err, "Initializing connection to %j failed.", tcpEndPoint);
|
||||
settings.log.error(err, 'Initializing connection to %j failed.', gossipSeeds);
|
||||
cb(err);
|
||||
});
|
||||
this.conn.on('closed', function (reason) {
|
||||
if (connected) return;
|
||||
var error = new Error("Connection failed: " + reason);
|
||||
settings.log.error(error, "Connection to %j failed.", tcpEndPoint);
|
||||
var error = new Error('Connection failed: ' + reason);
|
||||
settings.log.error(error, 'Connection to %j failed.', gossipSeeds);
|
||||
cb(error);
|
||||
});
|
||||
this.conn.on('connected', function (tcpEndPoint) {
|
||||
if (connected) return;
|
||||
settings.log.debug("Connected to %j.", tcpEndPoint);
|
||||
settings.log.debug('Connected to %j.', tcpEndPoint);
|
||||
connected = true;
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
function setUpWithDns(cb) {
|
||||
var clusterDns = 'discover://eventstore.local:2113';
|
||||
this.log = settings.log;
|
||||
this.testStreamName = 'test-' + uuid.v4();
|
||||
var connected = false;
|
||||
this.conn = client.createConnection(settings, clusterDns);
|
||||
this.conn
|
||||
.connect()
|
||||
.then(function () {
|
||||
//Doesn't mean anything, connection is just initiated
|
||||
settings.log.debug('Connection to %j initialized.', clusterDns);
|
||||
})
|
||||
.catch(function (err) {
|
||||
settings.log.error(err, 'Initializing connection to %j failed.', clusterDns);
|
||||
cb(err);
|
||||
});
|
||||
this.conn.on('closed', function (reason) {
|
||||
if (connected) return;
|
||||
var error = new Error('Connection failed: ' + reason);
|
||||
settings.log.error(error, 'Connection to %j failed.', clusterDns);
|
||||
cb(error);
|
||||
});
|
||||
this.conn.on('connected', function (tcpEndPoint) {
|
||||
if (connected) return;
|
||||
settings.log.debug('Connected to %j.', tcpEndPoint);
|
||||
connected = true;
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
function setUpWithTcpEndpoint(cb) {
|
||||
var tcpEndPoint = { host: process.env.EVENTSTORE_HOST || 'localhost', port: 1113 };
|
||||
this.log = settings.log;
|
||||
this.testStreamName = 'test-' + uuid.v4();
|
||||
var connected = false;
|
||||
this.conn = client.EventStoreConnection.create(settings, tcpEndPoint);
|
||||
this.conn
|
||||
.connect()
|
||||
.then(function () {
|
||||
//Doesn't mean anything, connection is just initiated
|
||||
settings.log.debug('Connection to %j initialized.', tcpEndPoint);
|
||||
})
|
||||
.catch(function (err) {
|
||||
settings.log.error(err, 'Initializing connection to %j failed.', tcpEndPoint);
|
||||
cb(err);
|
||||
});
|
||||
this.conn.on('closed', function (reason) {
|
||||
if (connected) return;
|
||||
var error = new Error('Connection failed: ' + reason);
|
||||
settings.log.error(error, 'Connection to %j failed.', tcpEndPoint);
|
||||
cb(error);
|
||||
});
|
||||
this.conn.on('connected', function (tcpEndPoint) {
|
||||
if (connected) return;
|
||||
settings.log.debug('Connected to %j.', tcpEndPoint);
|
||||
connected = true;
|
||||
cb();
|
||||
});
|
||||
|
@ -50,7 +114,7 @@ function setUp(cb) {
|
|||
|
||||
function tearDown(cb) {
|
||||
this.conn.close();
|
||||
this.conn.on('closed', function() {
|
||||
this.conn.on('closed', function () {
|
||||
cb();
|
||||
});
|
||||
this.conn = null;
|
||||
|
@ -58,9 +122,8 @@ function tearDown(cb) {
|
|||
|
||||
function areEqual(name, actual, expected) {
|
||||
if (typeof expected !== 'object' || expected === null)
|
||||
this.strictEqual(actual, expected, util.format("Failed %s === %s, got %s.", name, expected, actual));
|
||||
else
|
||||
this.deepEqual(actual, expected, util.format("Failed %s deepEqual %j, got %j.", name, expected, actual));
|
||||
this.strictEqual(actual, expected, util.format('Failed %s === %s, got %s.', name, expected, actual));
|
||||
else this.deepEqual(actual, expected, util.format('Failed %s deepEqual %j, got %j.', name, expected, actual));
|
||||
}
|
||||
|
||||
function fail(reason) {
|
||||
|
@ -69,55 +132,75 @@ function fail(reason) {
|
|||
|
||||
function eventEqualEventData(name, resolvedEvent, eventData) {
|
||||
var ev = resolvedEvent.originalEvent;
|
||||
this.ok(ev !== null, util.format("Failed %s !== null.", name + ".originalEvent"));
|
||||
this.ok(ev !== null, util.format('Failed %s !== null.', name + '.originalEvent'));
|
||||
if (ev === null) return;
|
||||
this.areEqual(name + ".originalEvent.eventId", ev.eventId, eventData.eventId);
|
||||
this.areEqual(name + ".originalEvent.eventType", ev.eventType, eventData.type);
|
||||
this.ok(Buffer.compare(ev.data, eventData.data) === 0, name + ".originalEvent.data is not equal to original data.");
|
||||
this.ok(Buffer.compare(ev.metadata, eventData.metadata) === 0, name + ".originalEvent.metadata is not equal to original metadata.");
|
||||
this.areEqual(name + '.originalEvent.eventId', ev.eventId, eventData.eventId);
|
||||
this.areEqual(name + '.originalEvent.eventType', ev.eventType, eventData.type);
|
||||
this.ok(Buffer.compare(ev.data, eventData.data) === 0, name + '.originalEvent.data is not equal to original data.');
|
||||
this.ok(
|
||||
Buffer.compare(ev.metadata, eventData.metadata) === 0,
|
||||
name + '.originalEvent.metadata is not equal to original metadata.'
|
||||
);
|
||||
}
|
||||
|
||||
function testRecordedEvent(name, event) {
|
||||
this.ok(Long.isLong(event.eventNumber), name + ".eventNumber is not a Long");
|
||||
this.ok(event.created instanceof Date, name + ".created is not a Date");
|
||||
this.ok(typeof event.createdEpoch === 'number', name + ".createdEpoch is not a number");
|
||||
this.ok(Long.isLong(event.eventNumber), name + '.eventNumber is not a Long');
|
||||
this.ok(event.created instanceof Date, name + '.created is not a Date');
|
||||
this.ok(typeof event.createdEpoch === 'number', name + '.createdEpoch is not a number');
|
||||
}
|
||||
|
||||
function testLiveEvent(name, event, evNumber) {
|
||||
this.ok(event.event, name + ".event not defined (or null)");
|
||||
this.ok(event.originalEvent, name + ".originalEvent not defined (or null)");
|
||||
this.ok(event.isResolved === false, name + ".isResolved should be true");
|
||||
this.ok(event.originalPosition instanceof client.Position, name + ".originalPosition is not an instance of Position");
|
||||
this.ok(event.originalStreamId, name + ".originalStreamId not defined (or null)");
|
||||
this.ok(Long.isLong(event.originalEventNumber), name + ".originalEventNumber is not a Long");
|
||||
this.ok(event.event, name + '.event not defined (or null)');
|
||||
this.ok(event.originalEvent, name + '.originalEvent not defined (or null)');
|
||||
this.ok(event.isResolved === false, name + '.isResolved should be true');
|
||||
this.ok(event.originalPosition instanceof client.Position, name + '.originalPosition is not an instance of Position');
|
||||
this.ok(event.originalStreamId, name + '.originalStreamId not defined (or null)');
|
||||
this.ok(Long.isLong(event.originalEventNumber), name + '.originalEventNumber is not a Long');
|
||||
if (typeof evNumber === 'number') {
|
||||
this.ok(event.originalEventNumber.toNumber() === evNumber, name + '.originalEventNumber expected ' + evNumber + ' got ' + event.originalEventNumber);
|
||||
this.ok(
|
||||
event.originalEventNumber.toNumber() === evNumber,
|
||||
name + '.originalEventNumber expected ' + evNumber + ' got ' + event.originalEventNumber
|
||||
);
|
||||
}
|
||||
testRecordedEvent.call(this, name + '.event', event.event);
|
||||
}
|
||||
|
||||
function testReadEvent(name, event, evNumber) {
|
||||
this.ok(event.event, name + ".event not defined (or null)");
|
||||
this.ok(event.originalEvent, name + ".originalEvent not defined (or null)");
|
||||
this.ok(event.isResolved === false, name + ".isResolved should be true");
|
||||
this.ok(event.originalPosition === null, name + ".originalPosition is not null");
|
||||
this.ok(event.originalStreamId, name + ".originalStreamId not defined (or null)");
|
||||
this.ok(Long.isLong(event.originalEventNumber), name + ".originalEventNumber is not a Long");
|
||||
this.ok(event.event, name + '.event not defined (or null)');
|
||||
this.ok(event.originalEvent, name + '.originalEvent not defined (or null)');
|
||||
this.ok(event.isResolved === false, name + '.isResolved should be true');
|
||||
this.ok(event.originalPosition === null, name + '.originalPosition is not null');
|
||||
this.ok(event.originalStreamId, name + '.originalStreamId not defined (or null)');
|
||||
this.ok(Long.isLong(event.originalEventNumber), name + '.originalEventNumber is not a Long');
|
||||
if (typeof evNumber === 'number') {
|
||||
this.ok(event.originalEventNumber.toNumber() === evNumber, name + '.originalEventNumber expected ' + evNumber + ' got ' + event.originalEventNumber);
|
||||
this.ok(
|
||||
event.originalEventNumber.toNumber() === evNumber,
|
||||
name + '.originalEventNumber expected ' + evNumber + ' got ' + event.originalEventNumber
|
||||
);
|
||||
}
|
||||
testRecordedEvent.call(this, name + '.event', event.event);
|
||||
}
|
||||
|
||||
var _ = {
|
||||
'setUp': setUp,
|
||||
'tearDown': tearDown
|
||||
tearDown: tearDown,
|
||||
};
|
||||
|
||||
switch (process.env.EVENTSTORE_CONNECTION_TYPE) {
|
||||
case 'gossip':
|
||||
_.setUp = setUpWithGossipSeeds;
|
||||
break;
|
||||
case 'dns':
|
||||
_.setUp = setUpWithDns;
|
||||
break;
|
||||
case 'tcp':
|
||||
default:
|
||||
_.setUp = setUpWithTcpEndpoint;
|
||||
}
|
||||
|
||||
function wrap(name, testFunc) {
|
||||
var base = _[name];
|
||||
if (base === undefined) {
|
||||
return function(test) {
|
||||
return function (test) {
|
||||
settings.log.debug('--- %s ---', name);
|
||||
test.areEqual = areEqual.bind(test);
|
||||
test.fail = fail.bind(test);
|
||||
|
@ -125,36 +208,48 @@ function wrap(name, testFunc) {
|
|||
test.testLiveEvent = testLiveEvent.bind(test);
|
||||
test.testReadEvent = testReadEvent.bind(test);
|
||||
return testFunc.call(this, test);
|
||||
};
|
||||
}
|
||||
}
|
||||
return function(cb) {
|
||||
return function (cb) {
|
||||
var self = this;
|
||||
base.call(this, function(err) {
|
||||
base.call(this, function (err) {
|
||||
if (err) return cb(err);
|
||||
return testFunc.call(self, cb);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.init = function(testSuite, addSetUpTearDownIfNotPresent) {
|
||||
module.exports.init = function (testSuite, addSetUpTearDownIfNotPresent) {
|
||||
var thisObj = {};
|
||||
if (addSetUpTearDownIfNotPresent === undefined) addSetUpTearDownIfNotPresent = true;
|
||||
for(var k in testSuite) {
|
||||
for (var k in testSuite) {
|
||||
if (testSuite.hasOwnProperty(k)) {
|
||||
testSuite[k] = wrap(k, testSuite[k]).bind(thisObj);
|
||||
}
|
||||
}
|
||||
if (!addSetUpTearDownIfNotPresent) return;
|
||||
if (!testSuite.hasOwnProperty('setUp')) testSuite['setUp'] = setUp.bind(thisObj);
|
||||
if (!testSuite.hasOwnProperty('setUp')) {
|
||||
switch (process.env.EVENTSTORE_CONNECTION_TYPE) {
|
||||
case 'gossip':
|
||||
testSuite['setUp'] = setUpWithGossipSeeds.bind(thisObj);
|
||||
break;
|
||||
case 'dns':
|
||||
testSuite['setUp'] = setUpWithDns.bind(thisObj);
|
||||
break;
|
||||
case 'tcp':
|
||||
default:
|
||||
testSuite['setUp'] = setUpWithTcpEndpoint.bind(thisObj);
|
||||
}
|
||||
}
|
||||
if (!testSuite.hasOwnProperty('tearDown')) testSuite['tearDown'] = tearDown.bind(thisObj);
|
||||
};
|
||||
module.exports.settings = function(settingsOverride) {
|
||||
module.exports.settings = function (settingsOverride) {
|
||||
var obj = {};
|
||||
for(var prop in settings) {
|
||||
for (var prop in settings) {
|
||||
obj[prop] = settings[prop];
|
||||
}
|
||||
if (!settingsOverride) return obj;
|
||||
for(var prop in settingsOverride) {
|
||||
for (var prop in settingsOverride) {
|
||||
obj[prop] = settingsOverride[prop];
|
||||
}
|
||||
return obj;
|
||||
|
|
|
@ -4,59 +4,18 @@ var GossipSeed = require('../src/gossipSeed');
|
|||
var testBase = require('./common/base_test');
|
||||
|
||||
var withSsl = !!process.env.NODE_ESC_WITH_SSL;
|
||||
const evenstStoreType = process.env.EVENTSTORE_CONNECTION_TYPE;
|
||||
|
||||
module.exports = {
|
||||
'Connect To Endpoint Happy Path': function (test) {
|
||||
test.expect(1);
|
||||
var tcpEndpoint = {host: 'localhost', port: 1113};
|
||||
var conn = client.EventStoreConnection.create(testBase.settings(), tcpEndpoint);
|
||||
conn.connect()
|
||||
.catch(function (err) {
|
||||
test.done(err);
|
||||
});
|
||||
conn.on('connected', function (endPoint) {
|
||||
test.areEqual("connected endPoint", endPoint, tcpEndpoint);
|
||||
done();
|
||||
});
|
||||
conn.on('error', done);
|
||||
module.exports = {}
|
||||
|
||||
function done(err) {
|
||||
conn.close();
|
||||
if (err) return test.done(err);
|
||||
test.done();
|
||||
}
|
||||
},
|
||||
'Connect To Endpoint That Doesn\'t Exist': function (test) {
|
||||
test.expect(1);
|
||||
var tcpEndpoint = {host: 'localhost', port: 11112};
|
||||
var conn = client.EventStoreConnection.create(testBase.settings({maxReconnections: 1}), tcpEndpoint);
|
||||
conn.connect()
|
||||
.catch(function (err) {
|
||||
test.done(err);
|
||||
});
|
||||
conn.on('connected', function () {
|
||||
test.ok(false, "Should not be able to connect.");
|
||||
test.done();
|
||||
});
|
||||
conn.on('error', function (err) {
|
||||
test.done(err);
|
||||
});
|
||||
conn.on('closed', function (reason) {
|
||||
test.ok(reason.indexOf("Reconnection limit reached") === 0, "Wrong expected reason.");
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
'Create a connection with tcp://host:port string': function (test) {
|
||||
var conn = client.createConnection({}, 'tcp://localhost:1113');
|
||||
conn.close();
|
||||
test.done();
|
||||
}/*,
|
||||
'Connect to Cluster using gossip seeds': function (test) {
|
||||
switch(evenstStoreType){
|
||||
case 'gossip':
|
||||
module.exports['Connect to Cluster using gossip seeds'] = function (test) {
|
||||
test.expect(1);
|
||||
var gossipSeeds = [
|
||||
new GossipSeed({host: 'localhost', port: 1113}),
|
||||
new GossipSeed({host: 'localhost', port: 2113}),
|
||||
new GossipSeed({host: 'localhost', port: 3113})
|
||||
new GossipSeed({host: process.env.EVENTSTORE_HOST_1 || '192.168.33.10', port: 2113}),
|
||||
new GossipSeed({host: process.env.EVENTSTORE_HOST_2 || '192.168.33.11', port: 2113}),
|
||||
new GossipSeed({host: process.env.EVENTSTORE_HOST_3 || '192.168.33.12', port: 2113})
|
||||
];
|
||||
var conn = client.EventStoreConnection.create(testBase.settings(), gossipSeeds);
|
||||
conn.connect()
|
||||
|
@ -64,7 +23,7 @@ module.exports = {
|
|||
test.done(err);
|
||||
});
|
||||
conn.on('connected', function(endPoint){
|
||||
test.ok(endPoint, "no endpoint");
|
||||
test.ok(endPoint, 'no endpoint');
|
||||
done();
|
||||
});
|
||||
conn.on('error', done);
|
||||
|
@ -74,16 +33,132 @@ module.exports = {
|
|||
if (err) return test.done(err);
|
||||
test.done();
|
||||
}
|
||||
}*/
|
||||
};
|
||||
};
|
||||
|
||||
module.exports['Connect To Cluster with bad gossip seeds'] = function (test) {
|
||||
test.expect(3);
|
||||
var gossipSeeds = [
|
||||
new GossipSeed({host: '1.2.3.4', port: 1113}),
|
||||
new GossipSeed({host: '2.3.4.5', port: 2113}),
|
||||
new GossipSeed({host: '3.4.5.6', port: 3113})
|
||||
];
|
||||
var conn = client.EventStoreConnection.create(testBase.settings({maxDiscoverAttempts: 1}), gossipSeeds);
|
||||
conn.connect()
|
||||
.catch(function (err) {
|
||||
test.ok(err.message.indexOf('Couldn\'t resolve target end point') === 0, 'Wrong expected reason.');
|
||||
});
|
||||
conn.on('connected', function () {
|
||||
test.ok(false, 'Should not be able to connect.');
|
||||
});
|
||||
conn.on('error', function (err) {
|
||||
test.ok(err.message.indexOf('Failed to discover candidate in 1 attempts') === 0, 'Wrong expected reason.');
|
||||
});
|
||||
conn.on('closed', function (reason) {
|
||||
test.ok(reason.indexOf('Failed to resolve TCP end point to which to connect') === 0, 'Wrong expected reason.');
|
||||
test.done();
|
||||
});
|
||||
};
|
||||
break;
|
||||
case 'dns':
|
||||
module.exports['Connect to Cluster using dns discover'] = function (test) {
|
||||
test.expect(1);
|
||||
var clusterDns = 'discover://eventstore.local:2113';
|
||||
var conn = client.EventStoreConnection.create(testBase.settings(), clusterDns);
|
||||
conn.connect()
|
||||
.catch(function(err) {
|
||||
test.done(err);
|
||||
});
|
||||
conn.on('connected', function(endPoint){
|
||||
test.ok(endPoint, 'no endpoint');
|
||||
done();
|
||||
});
|
||||
conn.on('error', done);
|
||||
|
||||
function done(err) {
|
||||
conn.close();
|
||||
if (err) return test.done(err);
|
||||
test.done();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports['Connect To Cluster with bad dns discover'] = function (test) {
|
||||
test.expect(3);
|
||||
var clusterDns = 'discover://eventstore-bad.local:2113';
|
||||
var conn = client.EventStoreConnection.create(testBase.settings({maxDiscoverAttempts: 1}), clusterDns);
|
||||
conn.connect()
|
||||
.catch(function (err) {
|
||||
test.ok(err.message.indexOf('Couldn\'t resolve target end point') === 0, 'Wrong expected reason.');
|
||||
});
|
||||
conn.on('connected', function () {
|
||||
test.ok(false, 'Should not be able to connect.');
|
||||
});
|
||||
conn.on('error', function (err) {
|
||||
test.ok(err.message.indexOf('Failed to discover candidate in 1 attempts') === 0, 'Wrong expected reason.');
|
||||
});
|
||||
conn.on('closed', function (reason) {
|
||||
test.ok(reason.indexOf('Failed to resolve TCP end point to which to connect') === 0, 'Wrong expected reason.');
|
||||
test.done();
|
||||
});
|
||||
};
|
||||
break;
|
||||
case 'tcp':
|
||||
default:
|
||||
module.exports['Connect To Endpoint Happy Path'] = function (test) {
|
||||
test.expect(1);
|
||||
var tcpEndpoint = {host: process.env.EVENTSTORE_HOST || 'localhost', port: 1113};
|
||||
var conn = client.EventStoreConnection.create(testBase.settings(), tcpEndpoint);
|
||||
conn.connect()
|
||||
.catch(function (err) {
|
||||
test.done(err);
|
||||
});
|
||||
conn.on('connected', function (endPoint) {
|
||||
test.areEqual('connected endPoint', endPoint, tcpEndpoint);
|
||||
done();
|
||||
});
|
||||
conn.on('error', done);
|
||||
|
||||
function done(err) {
|
||||
conn.close();
|
||||
if (err) return test.done(err);
|
||||
test.done();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports['Connect To Endpoint That Doesn\'t Exist'] = function (test) {
|
||||
test.expect(1);
|
||||
var tcpEndpoint = {host: process.env.EVENTSTORE_HOST || 'localhost', port: 11112};
|
||||
var conn = client.EventStoreConnection.create(testBase.settings({maxReconnections: 1}), tcpEndpoint);
|
||||
conn.connect()
|
||||
.catch(function (err) {
|
||||
test.done(err);
|
||||
});
|
||||
conn.on('connected', function () {
|
||||
test.ok(false, 'Should not be able to connect.');
|
||||
test.done();
|
||||
});
|
||||
conn.on('error', function (err) {
|
||||
test.done(err);
|
||||
});
|
||||
conn.on('closed', function (reason) {
|
||||
test.ok(reason.indexOf('Reconnection limit reached') === 0, 'Wrong expected reason.');
|
||||
test.done();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports['Create a connection with tcp://host:port string'] = function (test) {
|
||||
var conn = client.createConnection({}, `tcp://${process.env.EVENTSTORE_HOST || 'localhost'}:1113`);
|
||||
conn.close();
|
||||
test.done();
|
||||
};
|
||||
}
|
||||
|
||||
if (withSsl) {
|
||||
module.exports['Connect to secure tcp endpoint'] = function(test) {
|
||||
var conn = client.createConnection({
|
||||
useSslConnection: true,
|
||||
targetHost: 'localhost',
|
||||
targetHost: process.env.EVENTSTORE_HOST || 'localhost',
|
||||
validateServer: false
|
||||
}, 'tcp://localhost:1115');
|
||||
}, `tcp://${process.env.EVENTSTORE_HOST || 'localhost'}:1115`);
|
||||
conn.on('error', function (err) {
|
||||
test.done(err);
|
||||
});
|
||||
|
|
|
@ -9,20 +9,6 @@ function createRandomEvent() {
|
|||
|
||||
var testStreamName = 'test-' + uuid.v4();
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(resolve, ms);
|
||||
})
|
||||
}
|
||||
|
||||
function delayOnlyFirst(count, action) {
|
||||
if (count === 0) return action();
|
||||
return delay(200)
|
||||
.then(function () {
|
||||
action();
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'Test Create Persistent Subscription': function(test) {
|
||||
var settings = client.PersistentSubscriptionSettings.create();
|
||||
|
@ -46,10 +32,8 @@ module.exports = {
|
|||
test.done();
|
||||
}
|
||||
function eventAppeared(s, e) {
|
||||
return delayOnlyFirst(receivedEvents.length, function () {
|
||||
receivedEvents.push(e);
|
||||
if (receivedEvents.length === 2) s.stop();
|
||||
});
|
||||
}
|
||||
function subscriptionDropped(connection, reason, error) {
|
||||
if (error) return done(error);
|
||||
|
|
|
@ -2,7 +2,7 @@ const client = require('../lib/dist');
|
|||
const userCredentials = new client.UserCredentials('admin', 'changeit');
|
||||
|
||||
const log = new client.NoopLogger();
|
||||
const httpEndpoint = 'http://127.0.0.1:2113';
|
||||
const httpEndpoint = `http://${process.env.EVENTSTORE_HOST || "localhost"}:2113`;
|
||||
const operationTimeout = 5000;
|
||||
|
||||
const simpleProjection = "\
|
||||
|
|
|
@ -7,20 +7,6 @@ function createRandomEvent() {
|
|||
return client.createJsonEventData(uuid.v4(), {a: uuid.v4(), b: Math.random()}, {createdAt: Date.now()}, 'testEvent');
|
||||
}
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(resolve, ms);
|
||||
})
|
||||
}
|
||||
|
||||
function delayOnlyFirst(count, action) {
|
||||
if (count === 0) return action();
|
||||
return delay(200)
|
||||
.then(function () {
|
||||
action();
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'Test Subscribe to All From (Start)': function(test) {
|
||||
test.expect(6);
|
||||
|
@ -48,14 +34,12 @@ module.exports = {
|
|||
}
|
||||
function eventAppeared(s, e) {
|
||||
var isLive = liveProcessing;
|
||||
delayOnlyFirst(isLive ? liveEvents.length : catchUpEvents.length, function() {
|
||||
if (isLive) {
|
||||
liveEvents.push(e);
|
||||
} else {
|
||||
catchUpEvents.push(e);
|
||||
}
|
||||
if (isLive && liveEvents.length === 2) s.stop();
|
||||
});
|
||||
}
|
||||
function liveProcessingStarted() {
|
||||
liveProcessing = true;
|
||||
|
@ -99,14 +83,12 @@ module.exports = {
|
|||
}
|
||||
function eventAppeared(s, e) {
|
||||
var isLive = liveProcessing;
|
||||
delayOnlyFirst(isLive ? liveEvents.length : catchUpEvents.length, function() {
|
||||
if (isLive) {
|
||||
liveEvents.push(e);
|
||||
} else {
|
||||
catchUpEvents.push(e);
|
||||
}
|
||||
if (isLive && liveEvents.length === 2) s.stop();
|
||||
});
|
||||
}
|
||||
function liveProcessingStarted() {
|
||||
liveProcessing = true;
|
||||
|
@ -149,14 +131,12 @@ module.exports = {
|
|||
}
|
||||
function eventAppeared(s, e) {
|
||||
var isLive = liveProcessing;
|
||||
delayOnlyFirst(isLive ? liveEvents.length : catchUpEvents.length, function() {
|
||||
if (isLive) {
|
||||
liveEvents.push(e);
|
||||
} else {
|
||||
catchUpEvents.push(e);
|
||||
}
|
||||
if (isLive && liveEvents.length === 2) s.stop();
|
||||
});
|
||||
}
|
||||
function liveProcessingStarted() {
|
||||
liveProcessing = true;
|
||||
|
|
|
@ -2,20 +2,6 @@ const uuid = require('uuid');
|
|||
const client = require('../lib/dist');
|
||||
const allCredentials = new client.UserCredentials("admin", "changeit");
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(resolve, ms);
|
||||
})
|
||||
}
|
||||
|
||||
function delayOnlyFirst(count, action) {
|
||||
if (count === 0) return action();
|
||||
return delay(200)
|
||||
.then(function () {
|
||||
action();
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'Test Subscribe To All Happy Path': function(test) {
|
||||
const resolveLinkTos = false;
|
||||
|
@ -44,10 +30,15 @@ module.exports = {
|
|||
|
||||
var receivedEvents = [];
|
||||
function eventAppeared(subscription, event) {
|
||||
delayOnlyFirst(receivedEvents.length, function() {
|
||||
// Filter non-compliant events (only the one we've published)
|
||||
let eventData;
|
||||
try {
|
||||
eventData = JSON.parse(event.event.data.toString());
|
||||
} catch(e){}
|
||||
if (eventData && eventData.a && eventData.b){
|
||||
receivedEvents.push(event);
|
||||
}
|
||||
if (receivedEvents.length === numberOfPublishedEvents) subscription.close();
|
||||
});
|
||||
}
|
||||
function subscriptionDropped(subscription, reason, error) {
|
||||
if (error) return done(error);
|
||||
|
|
|
@ -6,20 +6,6 @@ function createRandomEvent() {
|
|||
return client.createJsonEventData(uuid.v4(), {a: uuid.v4(), b: Math.random()}, {createdAt: Date.now()}, 'testEvent');
|
||||
}
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(resolve, ms);
|
||||
})
|
||||
}
|
||||
|
||||
function delayOnlyFirst(count, action) {
|
||||
if (count === 0) return action();
|
||||
return delay(200)
|
||||
.then(function () {
|
||||
action();
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'Test Subscribe to Stream From Beginning (null)': function(test) {
|
||||
test.expect(48);
|
||||
|
@ -37,14 +23,12 @@ module.exports = {
|
|||
|
||||
function eventAppeared(s, e) {
|
||||
var isLive = liveProcessing;
|
||||
delayOnlyFirst(isLive ? liveEvents.length : catchUpEvents.length, function() {
|
||||
if (isLive) {
|
||||
liveEvents.push(e);
|
||||
} else {
|
||||
catchUpEvents.push(e);
|
||||
}
|
||||
if (isLive && liveEvents.length === 2) s.stop();
|
||||
});
|
||||
}
|
||||
function liveProcessingStarted() {
|
||||
liveProcessing = true;
|
||||
|
@ -93,14 +77,12 @@ module.exports = {
|
|||
|
||||
function eventAppeared(s, e) {
|
||||
var isLive = liveProcessing;
|
||||
delayOnlyFirst(isLive ? liveEvents.length : catchUpEvents.length, function() {
|
||||
if (isLive) {
|
||||
liveEvents.push(e);
|
||||
} else {
|
||||
catchUpEvents.push(e);
|
||||
}
|
||||
if (isLive && liveEvents.length === 2) s.stop();
|
||||
});
|
||||
}
|
||||
function liveProcessingStarted() {
|
||||
liveProcessing = true;
|
||||
|
|
|
@ -2,20 +2,6 @@ const uuid = require('uuid');
|
|||
const client = require('../lib/dist');
|
||||
const Long = require('long');
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(resolve, ms);
|
||||
})
|
||||
}
|
||||
|
||||
function delayOnlyFirst(count, action) {
|
||||
if (count === 0) return action();
|
||||
return delay(200)
|
||||
.then(function () {
|
||||
action();
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'Test Subscribe To Stream Happy Path': function(test) {
|
||||
const resolveLinkTos = false;
|
||||
|
@ -43,10 +29,15 @@ module.exports = {
|
|||
|
||||
var receivedEvents = [];
|
||||
function eventAppeared(subscription, event) {
|
||||
delayOnlyFirst(receivedEvents.length, function () {
|
||||
// Filter non-compliant events (only the one we've published)
|
||||
let eventData;
|
||||
try {
|
||||
eventData = JSON.parse(event.event.data.toString());
|
||||
} catch(e){}
|
||||
if (eventData && eventData.a && eventData.b){
|
||||
receivedEvents.push(event);
|
||||
}
|
||||
if (receivedEvents.length === numberOfPublishedEvents) subscription.close();
|
||||
});
|
||||
}
|
||||
function subscriptionDropped(subscription, reason, error) {
|
||||
if (error) return done(error);
|
||||
|
|
Loading…
Reference in New Issue
Block a user