aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/node/test
diff options
context:
space:
mode:
authorGravatar murgatroid99 <michael.lumish@gmail.com>2015-01-12 18:14:35 -0800
committerGravatar murgatroid99 <michael.lumish@gmail.com>2015-01-12 18:14:35 -0800
commite5061519185627e58495bede780f757339ba07c5 (patch)
tree7bf63f4bcc35d2141351d8cf29fac7a6eb5dfe63 /src/node/test
parent470a3ea1a192e53a61012c30a6a9a5efcc712948 (diff)
Clean commit of Node.js library source
Diffstat (limited to 'src/node/test')
-rw-r--r--src/node/test/byte_buffer_test.js~35
-rw-r--r--src/node/test/call_test.js169
-rw-r--r--src/node/test/call_test.js~6
-rw-r--r--src/node/test/channel_test.js55
-rw-r--r--src/node/test/client_server_test.js150
-rw-r--r--src/node/test/client_server_test.js~59
-rw-r--r--src/node/test/completion_queue_test.js~30
-rw-r--r--src/node/test/constant_test.js97
-rw-r--r--src/node/test/constant_test.js~25
-rw-r--r--src/node/test/data/README1
-rw-r--r--src/node/test/data/ca.pem15
-rw-r--r--src/node/test/data/server1.key16
-rw-r--r--src/node/test/data/server1.pem16
-rw-r--r--src/node/test/end_to_end_test.js168
-rw-r--r--src/node/test/end_to_end_test.js~72
-rw-r--r--src/node/test/math_client_test.js176
-rw-r--r--src/node/test/math_client_test.js~87
-rw-r--r--src/node/test/server_test.js88
-rw-r--r--src/node/test/server_test.js~22
19 files changed, 1287 insertions, 0 deletions
diff --git a/src/node/test/byte_buffer_test.js~ b/src/node/test/byte_buffer_test.js~
new file mode 100644
index 0000000000..8f272e5bd6
--- /dev/null
+++ b/src/node/test/byte_buffer_test.js~
@@ -0,0 +1,35 @@
+var assert = require('assert');
+var grpc = require('..build/Release/grpc');
+
+describe('byte buffer', function() {
+ describe('constructor', function() {
+ it('should reject bad constructor calls', function() {
+ it('should require at least one argument', function() {
+ assert.throws(new grpc.ByteBuffer(), TypeError);
+ });
+ it('should reject non-string arguments', function() {
+ assert.throws(new grpc.ByteBuffer(0), TypeError);
+ assert.throws(new grpc.ByteBuffer(1.5), TypeError);
+ assert.throws(new grpc.ByteBuffer(null), TypeError);
+ assert.throws(new grpc.ByteBuffer(Date.now()), TypeError);
+ });
+ it('should accept string arguments', function() {
+ assert.doesNotThrow(new grpc.ByteBuffer(''));
+ assert.doesNotThrow(new grpc.ByteBuffer('test'));
+ assert.doesNotThrow(new grpc.ByteBuffer('\0'));
+ });
+ });
+ });
+ describe('bytes', function() {
+ it('should return the passed string', function() {
+ it('should preserve simple strings', function() {
+ var buffer = new grpc.ByteBuffer('test');
+ assert.strictEqual(buffer.bytes(), 'test');
+ });
+ it('should preserve null characters', function() {
+ var buffer = new grpc.ByteBuffer('test\0test');
+ assert.strictEqual(buffer.bytes(), 'test\0test');
+ });
+ });
+ });
+});
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
new file mode 100644
index 0000000000..25860d040d
--- /dev/null
+++ b/src/node/test/call_test.js
@@ -0,0 +1,169 @@
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+
+var channel = new grpc.Channel('localhost:7070');
+
+/**
+ * Helper function to return an absolute deadline given a relative timeout in
+ * seconds.
+ * @param {number} timeout_secs The number of seconds to wait before timing out
+ * @return {Date} A date timeout_secs in the future
+ */
+function getDeadline(timeout_secs) {
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + timeout_secs);
+ return deadline;
+}
+
+describe('call', function() {
+ describe('constructor', function() {
+ it('should reject anything less than 3 arguments', function() {
+ assert.throws(function() {
+ new grpc.Call();
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Call(channel);
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Call(channel, 'method');
+ }, TypeError);
+ });
+ it('should succeed with a Channel, a string, and a date or number',
+ function() {
+ assert.doesNotThrow(function() {
+ new grpc.Call(channel, 'method', new Date());
+ });
+ assert.doesNotThrow(function() {
+ new grpc.Call(channel, 'method', 0);
+ });
+ });
+ it('should fail with a closed channel', function() {
+ var local_channel = new grpc.Channel('hostname');
+ local_channel.close();
+ assert.throws(function() {
+ new grpc.Call(channel, 'method');
+ });
+ });
+ it('should fail with other types', function() {
+ assert.throws(function() {
+ new grpc.Call({}, 'method', 0);
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Call(channel, null, 0);
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Call(channel, 'method', 'now');
+ }, TypeError);
+ });
+ });
+ describe('addMetadata', function() {
+ it('should succeed with objects containing keys and values', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.doesNotThrow(function() {
+ call.addMetadata();
+ });
+ assert.doesNotThrow(function() {
+ call.addMetadata({'key' : 'key',
+ 'value' : new Buffer('value')});
+ });
+ assert.doesNotThrow(function() {
+ call.addMetadata({'key' : 'key1',
+ 'value' : new Buffer('value1')},
+ {'key' : 'key2',
+ 'value' : new Buffer('value2')});
+ });
+ });
+ it('should fail with other parameter types', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.addMetadata(null);
+ }, TypeError);
+ assert.throws(function() {
+ call.addMetadata('value');
+ }, TypeError);
+ assert.throws(function() {
+ call.addMetadata(5);
+ }, TypeError);
+ });
+ it('should fail if startInvoke was already called', function(done) {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ call.startInvoke(function() {},
+ function() {},
+ function() {done();},
+ 0);
+ assert.throws(function() {
+ call.addMetadata({'key' : 'key', 'value' : new Buffer('value') });
+ }, function(err) {
+ return err.code === grpc.callError.ALREADY_INVOKED;
+ });
+ // Cancel to speed up the test
+ call.cancel();
+ });
+ });
+ describe('startInvoke', function() {
+ it('should fail with fewer than 4 arguments', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.startInvoke();
+ }, TypeError);
+ assert.throws(function() {
+ call.startInvoke(function() {});
+ }, TypeError);
+ assert.throws(function() {
+ call.startInvoke(function() {},
+ function() {});
+ }, TypeError);
+ assert.throws(function() {
+ call.startInvoke(function() {},
+ function() {},
+ function() {});
+ }, TypeError);
+ });
+ it('should work with 3 args and an int', function(done) {
+ assert.doesNotThrow(function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ call.startInvoke(function() {},
+ function() {},
+ function() {done();},
+ 0);
+ // Cancel to speed up the test
+ call.cancel();
+ });
+ });
+ it('should reject incorrectly typed arguments', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.startInvoke(0, 0, 0, 0);
+ }, TypeError);
+ assert.throws(function() {
+ call.startInvoke(function() {},
+ function() {},
+ function() {}, 'test');
+ });
+ });
+ });
+ describe('serverAccept', function() {
+ it('should fail with fewer than 1 argument1', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.serverAccept();
+ }, TypeError);
+ });
+ it('should return an error when called on a client Call', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.serverAccept(function() {});
+ }, function(err) {
+ return err.code === grpc.callError.NOT_ON_CLIENT;
+ });
+ });
+ });
+ describe('cancel', function() {
+ it('should succeed', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.doesNotThrow(function() {
+ call.cancel();
+ });
+ });
+ });
+});
diff --git a/src/node/test/call_test.js~ b/src/node/test/call_test.js~
new file mode 100644
index 0000000000..9506f209bd
--- /dev/null
+++ b/src/node/test/call_test.js~
@@ -0,0 +1,6 @@
+var assert = require('assert');
+var grpc = require('../build/Release/grpc');
+
+describe('call', function() {
+ describe('constructor', function() {
+ it('should reject anything less than 4 arguments', function() { \ No newline at end of file
diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js
new file mode 100644
index 0000000000..61833875b6
--- /dev/null
+++ b/src/node/test/channel_test.js
@@ -0,0 +1,55 @@
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+
+describe('channel', function() {
+ describe('constructor', function() {
+ it('should require a string for the first argument', function() {
+ assert.doesNotThrow(function() {
+ new grpc.Channel('hostname');
+ });
+ assert.throws(function() {
+ new grpc.Channel();
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Channel(5);
+ });
+ });
+ it('should accept an object for the second parameter', function() {
+ assert.doesNotThrow(function() {
+ new grpc.Channel('hostname', {});
+ });
+ assert.throws(function() {
+ new grpc.Channel('hostname', 5);
+ });
+ });
+ it('should only accept objects with string or int values', function() {
+ assert.doesNotThrow(function() {
+ new grpc.Channel('hostname', {'key' : 'value'});
+ });
+ assert.doesNotThrow(function() {
+ new grpc.Channel('hostname', {'key' : 5});
+ });
+ assert.throws(function() {
+ new grpc.Channel('hostname', {'key' : null});
+ });
+ assert.throws(function() {
+ new grpc.Channel('hostname', {'key' : new Date()});
+ });
+ });
+ });
+ describe('close', function() {
+ it('should succeed silently', function() {
+ var channel = new grpc.Channel('hostname', {});
+ assert.doesNotThrow(function() {
+ channel.close();
+ });
+ });
+ it('should be idempotent', function() {
+ var channel = new grpc.Channel('hostname', {});
+ assert.doesNotThrow(function() {
+ channel.close();
+ channel.close();
+ });
+ });
+ });
+});
diff --git a/src/node/test/client_server_test.js b/src/node/test/client_server_test.js
new file mode 100644
index 0000000000..9f15a76520
--- /dev/null
+++ b/src/node/test/client_server_test.js
@@ -0,0 +1,150 @@
+var assert = require('assert');
+var fs = require('fs');
+var path = require('path');
+var grpc = require('bindings')('grpc.node');
+var Server = require('../server');
+var client = require('../client');
+var port_picker = require('../port_picker');
+var common = require('../common');
+var _ = require('highland');
+
+var ca_path = path.join(__dirname, 'data/ca.pem');
+
+var key_path = path.join(__dirname, 'data/server1.key');
+
+var pem_path = path.join(__dirname, 'data/server1.pem');
+
+/**
+ * Helper function to return an absolute deadline given a relative timeout in
+ * seconds.
+ * @param {number} timeout_secs The number of seconds to wait before timing out
+ * @return {Date} A date timeout_secs in the future
+ */
+function getDeadline(timeout_secs) {
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + timeout_secs);
+ return deadline;
+}
+
+/**
+ * Responds to every request with the same data as a response
+ * @param {Stream} stream
+ */
+function echoHandler(stream) {
+ stream.pipe(stream);
+}
+
+/**
+ * Responds to every request with an error status
+ * @param {Stream} stream
+ */
+function errorHandler(stream) {
+ throw {
+ 'code' : grpc.status.UNIMPLEMENTED,
+ 'details' : 'error details'
+ };
+}
+
+describe('echo client', function() {
+ it('should receive echo responses', function(done) {
+ port_picker.nextAvailablePort(function(port) {
+ var server = new Server();
+ server.bind(port);
+ server.register('echo', echoHandler);
+ server.start();
+
+ var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
+ var channel = new grpc.Channel(port);
+ var stream = client.makeRequest(
+ channel,
+ 'echo');
+ _(messages).map(function(val) {
+ return new Buffer(val);
+ }).pipe(stream);
+ var index = 0;
+ stream.on('data', function(chunk) {
+ assert.equal(messages[index], chunk.toString());
+ index += 1;
+ });
+ stream.on('end', function() {
+ server.shutdown();
+ done();
+ });
+ });
+ });
+ it('should get an error status that the server throws', function(done) {
+ port_picker.nextAvailablePort(function(port) {
+ var server = new Server();
+ server.bind(port);
+ server.register('error', errorHandler);
+ server.start();
+
+ var channel = new grpc.Channel(port);
+ var stream = client.makeRequest(
+ channel,
+ 'error',
+ null,
+ getDeadline(1));
+
+ stream.on('data', function() {});
+ stream.write(new Buffer('test'));
+ stream.end();
+ stream.on('status', function(status) {
+ assert.equal(status.code, grpc.status.UNIMPLEMENTED);
+ assert.equal(status.details, 'error details');
+ server.shutdown();
+ done();
+ });
+
+ });
+ });
+});
+/* TODO(mlumish): explore options for reducing duplication between this test
+ * and the insecure echo client test */
+describe('secure echo client', function() {
+ it('should recieve echo responses', function(done) {
+ port_picker.nextAvailablePort(function(port) {
+ fs.readFile(ca_path, function(err, ca_data) {
+ assert.ifError(err);
+ fs.readFile(key_path, function(err, key_data) {
+ assert.ifError(err);
+ fs.readFile(pem_path, function(err, pem_data) {
+ assert.ifError(err);
+ var creds = grpc.Credentials.createSsl(ca_data);
+ var server_creds = grpc.ServerCredentials.createSsl(null,
+ key_data,
+ pem_data);
+
+ var server = new Server({'credentials' : server_creds});
+ server.bind(port, true);
+ server.register('echo', echoHandler);
+ server.start();
+
+ var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
+ var channel = new grpc.Channel(port, {
+ 'grpc.ssl_target_name_override' : 'foo.test.google.com',
+ 'credentials' : creds
+ });
+ var stream = client.makeRequest(
+ channel,
+ 'echo');
+
+ _(messages).map(function(val) {
+ return new Buffer(val);
+ }).pipe(stream);
+ var index = 0;
+ stream.on('data', function(chunk) {
+ assert.equal(messages[index], chunk.toString());
+ index += 1;
+ });
+ stream.on('end', function() {
+ server.shutdown();
+ done();
+ });
+ });
+
+ });
+ });
+ });
+ });
+});
diff --git a/src/node/test/client_server_test.js~ b/src/node/test/client_server_test.js~
new file mode 100644
index 0000000000..22a0523939
--- /dev/null
+++ b/src/node/test/client_server_test.js~
@@ -0,0 +1,59 @@
+var assert = require('assert');
+var grpc = require('../build/Debug/grpc');
+var Server = require('../server');
+var client = require('../client');
+var port_picker = require('../port_picker');
+var iterators = require('async-iterators');
+
+/**
+ * General function to process an event by checking that there was no error and
+ * calling the callback passed as a tag.
+ * @param {*} err Truthy values indicate an error (in this case, that there was
+ * no event available).
+ * @param {grpc.Event} event The event to process.
+ */
+function processEvent(err, event) {
+ assert.ifError(err);
+ assert.notEqual(event, null);
+ event.getTag()(event);
+}
+
+/**
+ * Responds to every request with the same data as a response
+ * @param {{next:function(function(*, Buffer))}} arg_iter The async iterator of
+ * arguments.
+ * @return {{next:function(function(*, Buffer))}} The async iterator of results
+ */
+function echoHandler(arg_iter) {
+ return {
+ 'next' : function(write) {
+ arg_iter.next(function(err, value) {
+ if (value == undefined) {
+ write({
+ 'code' : grpc.status.OK,
+ 'details' : 'OK'
+ });
+ } else {
+ write(err, value);
+ }
+ });
+ }
+ };
+}
+
+describe('echo client server', function() {
+ it('should recieve echo responses', function(done) {
+ port_picker.nextAvailablePort(function(port) {
+ var server = new Server(port);
+ server.register('echo', echoHandler);
+ server.start();
+
+ var messages = ['echo1', 'echo2', 'echo3'];
+ var channel = new grpc.Channel(port);
+ var responses = client.makeRequest(channel,
+ 'echo',
+ iterators.fromArray(messages));
+ assert.equal(messages, iterators.toArray(responses));
+ });
+ });
+});
diff --git a/src/node/test/completion_queue_test.js~ b/src/node/test/completion_queue_test.js~
new file mode 100644
index 0000000000..5d2d509be6
--- /dev/null
+++ b/src/node/test/completion_queue_test.js~
@@ -0,0 +1,30 @@
+var assert = require('assert');
+var grpc = require('../build/Release/grpc');
+
+describe('completion queue', function() {
+ describe('constructor', function() {
+ it('should succeed with now arguments', function() {
+ assert.doesNotThrow(function() {
+ new grpc.CompletionQueue();
+ });
+ });
+ });
+ describe('next', function() {
+ it('should require a date parameter', function() {
+ var queue = new grpc.CompletionQueue();
+ assert.throws(function() {
+ queue->next();
+ }, TypeError);
+ assert.throws(function() {
+ queue->next('test');
+ }, TypeError);
+ assert.doesNotThrow(function() {
+ queue->next(Date.now());
+ });
+ });
+ it('should return null from a new queue', function() {
+ var queue = new grpc.CompletionQueue();
+ assert.strictEqual(queue->next(Date.now()), null);
+ });
+ });
+}); \ No newline at end of file
diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js
new file mode 100644
index 0000000000..b9f8958da9
--- /dev/null
+++ b/src/node/test/constant_test.js
@@ -0,0 +1,97 @@
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+
+/**
+ * List of all status names
+ * @const
+ * @type {Array.<string>}
+ */
+var statusNames = [
+ 'OK',
+ 'CANCELLED',
+ 'UNKNOWN',
+ 'INVALID_ARGUMENT',
+ 'DEADLINE_EXCEEDED',
+ 'NOT_FOUND',
+ 'ALREADY_EXISTS',
+ 'PERMISSION_DENIED',
+ 'UNAUTHENTICATED',
+ 'RESOURCE_EXHAUSTED',
+ 'FAILED_PRECONDITION',
+ 'ABORTED',
+ 'OUT_OF_RANGE',
+ 'UNIMPLEMENTED',
+ 'INTERNAL',
+ 'UNAVAILABLE',
+ 'DATA_LOSS'
+];
+
+/**
+ * List of all call error names
+ * @const
+ * @type {Array.<string>}
+ */
+var callErrorNames = [
+ 'OK',
+ 'ERROR',
+ 'NOT_ON_SERVER',
+ 'NOT_ON_CLIENT',
+ 'ALREADY_INVOKED',
+ 'NOT_INVOKED',
+ 'ALREADY_FINISHED',
+ 'TOO_MANY_OPERATIONS',
+ 'INVALID_FLAGS'
+];
+
+/**
+ * List of all op error names
+ * @const
+ * @type {Array.<string>}
+ */
+var opErrorNames = [
+ 'OK',
+ 'ERROR'
+];
+
+/**
+ * List of all completion type names
+ * @const
+ * @type {Array.<string>}
+ */
+var completionTypeNames = [
+ 'QUEUE_SHUTDOWN',
+ 'READ',
+ 'INVOKE_ACCEPTED',
+ 'WRITE_ACCEPTED',
+ 'FINISH_ACCEPTED',
+ 'CLIENT_METADATA_READ',
+ 'FINISHED',
+ 'SERVER_RPC_NEW'
+];
+
+describe('constants', function() {
+ it('should have all of the status constants', function() {
+ for (var i = 0; i < statusNames.length; i++) {
+ assert(grpc.status.hasOwnProperty(statusNames[i]),
+ 'status missing: ' + statusNames[i]);
+ }
+ });
+ it('should have all of the call errors', function() {
+ for (var i = 0; i < callErrorNames.length; i++) {
+ assert(grpc.callError.hasOwnProperty(callErrorNames[i]),
+ 'call error missing: ' + callErrorNames[i]);
+ }
+ });
+ it('should have all of the op errors', function() {
+ for (var i = 0; i < opErrorNames.length; i++) {
+ assert(grpc.opError.hasOwnProperty(opErrorNames[i]),
+ 'op error missing: ' + opErrorNames[i]);
+ }
+ });
+ it('should have all of the completion types', function() {
+ for (var i = 0; i < completionTypeNames.length; i++) {
+ assert(grpc.completionType.hasOwnProperty(completionTypeNames[i]),
+ 'completion type missing: ' + completionTypeNames[i]);
+ }
+ });
+});
diff --git a/src/node/test/constant_test.js~ b/src/node/test/constant_test.js~
new file mode 100644
index 0000000000..8ad9f81bbe
--- /dev/null
+++ b/src/node/test/constant_test.js~
@@ -0,0 +1,25 @@
+var assert = require("assert");
+var grpc = require("../build/Release");
+
+var status_names = [
+ "OK",
+ "CANCELLED",
+ "UNKNOWN",
+ "INVALID_ARGUMENT",
+ "DEADLINE_EXCEEDED",
+ "NOT_FOUND",
+ "ALREADY_EXISTS",
+ "PERMISSION_DENIED",
+ "UNAUTHENTICATED",
+ "RESOURCE_EXHAUSTED",
+ "FAILED_PRECONDITION",
+ "ABORTED",
+ "OUT_OF_RANGE",
+ "UNIMPLEMENTED",
+ "INTERNAL",
+ "UNAVAILABLE",
+ "DATA_LOSS"
+];
+
+describe("constants", function() {
+ it("should have all of the status constants", function() {
diff --git a/src/node/test/data/README b/src/node/test/data/README
new file mode 100644
index 0000000000..888d95b900
--- /dev/null
+++ b/src/node/test/data/README
@@ -0,0 +1 @@
+CONFIRMEDTESTKEY
diff --git a/src/node/test/data/ca.pem b/src/node/test/data/ca.pem
new file mode 100644
index 0000000000..6c8511a73c
--- /dev/null
+++ b/src/node/test/data/ca.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
+Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
+YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
+BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
++L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
+g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
+Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
+sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
+oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
+Dfcog5wrJytaQ6UA0wE=
+-----END CERTIFICATE-----
diff --git a/src/node/test/data/server1.key b/src/node/test/data/server1.key
new file mode 100644
index 0000000000..143a5b8765
--- /dev/null
+++ b/src/node/test/data/server1.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
+M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
+3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
+AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
+V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
+tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
+dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
+K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
+81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
+DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
+aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
+ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
+XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
+F98XJ7tIFfJq
+-----END PRIVATE KEY-----
diff --git a/src/node/test/data/server1.pem b/src/node/test/data/server1.pem
new file mode 100644
index 0000000000..8e582e571f
--- /dev/null
+++ b/src/node/test/data/server1.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
+MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
+c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
+JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
+RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
+3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
+BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
+b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
+KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
+wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
+aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+-----END CERTIFICATE-----
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
new file mode 100644
index 0000000000..64b207cb5c
--- /dev/null
+++ b/src/node/test/end_to_end_test.js
@@ -0,0 +1,168 @@
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+var port_picker = require('../port_picker');
+
+/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ * complete.
+ * @param {number} count The number of calls to the resulting function if the
+ * test passes.
+ * @return {function()} The function that should be called at the end of each
+ * sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+ return function() {
+ count -= 1;
+ if (count <= 0) {
+ done();
+ }
+ };
+}
+
+describe('end-to-end', function() {
+ it('should start and end a request without error', function(complete) {
+ port_picker.nextAvailablePort(function(port) {
+ var server = new grpc.Server();
+ var done = multiDone(function() {
+ complete();
+ server.shutdown();
+ }, 2);
+ server.addHttp2Port(port);
+ var channel = new grpc.Channel(port);
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 3);
+ var status_text = 'xyz';
+ var call = new grpc.Call(channel,
+ 'dummy_method',
+ deadline);
+ call.startInvoke(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.INVOKE_ACCEPTED);
+
+ call.writesDone(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ });
+ },function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.CLIENT_METADATA_READ);
+ },function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ var status = event.data;
+ assert.strictEqual(status.code, grpc.status.OK);
+ assert.strictEqual(status.details, status_text);
+ done();
+ }, 0);
+
+ server.start();
+ server.requestCall(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
+ var server_call = event.call;
+ assert.notEqual(server_call, null);
+ server_call.serverAccept(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ }, 0);
+ server_call.serverEndInitialMetadata(0);
+ server_call.startWriteStatus(
+ grpc.status.OK,
+ status_text,
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ done();
+ });
+ });
+ });
+ });
+
+ it('should send and receive data without error', function(complete) {
+ port_picker.nextAvailablePort(function(port) {
+ var req_text = 'client_request';
+ var reply_text = 'server_response';
+ var server = new grpc.Server();
+ var done = multiDone(function() {
+ complete();
+ server.shutdown();
+ }, 6);
+ server.addHttp2Port(port);
+ var channel = new grpc.Channel(port);
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 3);
+ var status_text = 'success';
+ var call = new grpc.Call(channel,
+ 'dummy_method',
+ deadline);
+ call.startInvoke(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.INVOKE_ACCEPTED);
+ call.startWrite(
+ new Buffer(req_text),
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.WRITE_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ call.writesDone(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ done();
+ });
+ }, 0);
+ call.startRead(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.READ);
+ assert.strictEqual(event.data.toString(), reply_text);
+ done();
+ });
+ },function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.CLIENT_METADATA_READ);
+ done();
+ },function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ var status = event.data;
+ assert.strictEqual(status.code, grpc.status.OK);
+ assert.strictEqual(status.details, status_text);
+ done();
+ }, 0);
+
+ server.start();
+ server.requestCall(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
+ var server_call = event.call;
+ assert.notEqual(server_call, null);
+ server_call.serverAccept(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ done();
+ });
+ server_call.serverEndInitialMetadata(0);
+ server_call.startRead(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.READ);
+ assert.strictEqual(event.data.toString(), req_text);
+ server_call.startWrite(
+ new Buffer(reply_text),
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.WRITE_ACCEPTED);
+ assert.strictEqual(event.data,
+ grpc.opError.OK);
+ server_call.startWriteStatus(
+ grpc.status.OK,
+ status_text,
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ done();
+ });
+ }, 0);
+ });
+ });
+ });
+ });
+});
diff --git a/src/node/test/end_to_end_test.js~ b/src/node/test/end_to_end_test.js~
new file mode 100644
index 0000000000..74184a287f
--- /dev/null
+++ b/src/node/test/end_to_end_test.js~
@@ -0,0 +1,72 @@
+var assert = require('assert');
+var grpc = require('../build/Release/grpc');
+
+describe('end-to-end', function() {
+ it('should start and end a request without error', function() {
+ var event;
+ var client_queue = new grpc.CompletionQueue();
+ var server_queue = new grpc.CompletionQueue();
+ var server = new grpc.Server(server_queue);
+ server.addHttp2Port('localhost:9000');
+ var channel = new grpc.Channel('localhost:9000');
+ var deadline = Infinity;
+ var status_text = 'xyz';
+ var call = new grpc.Call(channel, 'dummy_method', deadline);
+ var tag = 1;
+ assert.strictEqual(call.startInvoke(client_queue, tag, tag, tag),
+ grpc.callError.OK);
+ var server_tag = 2;
+
+ // the client invocation was accepted
+ event = client_queue.next(deadline);
+ assert.notEqual(event, null);
+ assert.strictEqual(event->getType(), grpc.completionType.INVOKE_ACCEPTED);
+
+ assert.strictEqual(call.writesDone(tag), grpc.callError.CALL_OK);
+ event = client_queue.next(deadline);
+ assert.notEqual(event, null);
+ assert.strictEqual(event.getType(), grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.getData(), grpc.opError.OK);
+
+ // check that a server rpc new was recieved
+ assert(server.start());
+ assert.strictEqual(server.requestCall(server_tag, server_tag),
+ grpc.callError.OK);
+ event = server_queue.next(deadline);
+ assert.notEqual(event, null);
+ assert.strictEqual(event.getType(), grpc.completionType.SERVER_RPC_NEW);
+ var server_call = event.getCall();
+ assert.notEqual(server_call, null);
+ assert.strictEqual(server_call.accept(server_queue, server_tag),
+ grpc.callError.OK);
+
+ // the server sends the status
+ assert.strictEqual(server_call.start_write_status(grpc.status.OK,
+ status_text,
+ server_tag),
+ grpc.callError.OK);
+ event = server_queue.next(deadline);
+ assert.notEqual(event, null);
+ assert.strictEqual(event.getType(), grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.getData(), grpc.opError.OK);
+
+ // the client gets CLIENT_METADATA_READ
+ event = client_queue.next(deadline);
+ assert.notEqual(event, null);
+ assert.strictEqual(event.getType(),
+ grpc.completionType.CLIENT_METADATA_READ);
+
+ // the client gets FINISHED
+ event = client_queue.next(deadline);
+ assert.notEqual(event, null);
+ assert.strictEqual(event.getType(), grpc.completionType.FINISHED);
+ var status = event.getData();
+ assert.strictEqual(status.code, grpc.status.OK);
+ assert.strictEqual(status.details, status_text);
+
+ // the server gets FINISHED
+ event = client_queue.next(deadline);
+ assert.notEqual(event, null);
+ assert.strictEqual(event.getType(), grpc.completionType.FINISHED);
+ });
+});
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
new file mode 100644
index 0000000000..dd2e183831
--- /dev/null
+++ b/src/node/test/math_client_test.js
@@ -0,0 +1,176 @@
+var assert = require('assert');
+var client = require('../surface_client.js');
+var ProtoBuf = require('protobufjs');
+var port_picker = require('../port_picker');
+
+var builder = ProtoBuf.loadProtoFile(__dirname + '/../examples/math.proto');
+var math = builder.build('math');
+
+/**
+ * Get a function that deserializes a specific type of protobuf.
+ * @param {function()} cls The constructor of the message type to deserialize
+ * @return {function(Buffer):cls} The deserialization function
+ */
+function deserializeCls(cls) {
+ /**
+ * Deserialize a buffer to a message object
+ * @param {Buffer} arg_buf The buffer to deserialize
+ * @return {cls} The resulting object
+ */
+ return function deserialize(arg_buf) {
+ return cls.decode(arg_buf);
+ };
+}
+
+/**
+ * Serialize an object to a buffer
+ * @param {*} arg The object to serialize
+ * @return {Buffer} The serialized object
+ */
+function serialize(arg) {
+ return new Buffer(arg.encode().toBuffer());
+}
+
+/**
+ * Sends a Div request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {DivArg} argument The argument to the call. Should be serializable
+ * with serialize
+ * @param {function(?Error, value=)} The callback to for when the response is
+ * received
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var div = client.makeUnaryRequestFunction(
+ '/Math/Div',
+ serialize,
+ deserializeCls(math.DivReply));
+
+/**
+ * Sends a Fib request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var fib = client.makeServerStreamRequestFunction(
+ '/Math/Fib',
+ serialize,
+ deserializeCls(math.Num));
+
+/**
+ * Sends a Sum request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {function(?Error, value=)} The callback to for when the response is
+ * received
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var sum = client.makeClientStreamRequestFunction(
+ '/Math/Sum',
+ serialize,
+ deserializeCls(math.Num));
+
+/**
+ * Sends a DivMany request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var divMany = client.makeBidiStreamRequestFunction(
+ '/Math/DivMany',
+ serialize,
+ deserializeCls(math.DivReply));
+
+/**
+ * Channel to use to make requests to a running server.
+ */
+var channel;
+
+/**
+ * Server to test against
+ */
+var server = require('../examples/math_server.js');
+
+
+describe('Math client', function() {
+ before(function(done) {
+ port_picker.nextAvailablePort(function(port) {
+ server.bind(port).listen();
+ channel = new client.Channel(port);
+ done();
+ });
+ });
+ after(function() {
+ server.shutdown();
+ });
+ it('should handle a single request', function(done) {
+ var arg = new math.DivArgs({dividend: 7, divisor: 4});
+ var call = div(channel, arg, function handleDivResult(err, value) {
+ assert.ifError(err);
+ assert.equal(value.get('quotient'), 1);
+ assert.equal(value.get('remainder'), 3);
+ });
+ call.on('status', function checkStatus(status) {
+ assert.strictEqual(status.code, client.status.OK);
+ done();
+ });
+ });
+ it('should handle a server streaming request', function(done) {
+ var arg = new math.FibArgs({limit: 7});
+ var call = fib(channel, arg);
+ var expected_results = [1, 1, 2, 3, 5, 8, 13];
+ var next_expected = 0;
+ call.on('data', function checkResponse(value) {
+ assert.equal(value.get('num'), expected_results[next_expected]);
+ next_expected += 1;
+ });
+ call.on('status', function checkStatus(status) {
+ assert.strictEqual(status.code, client.status.OK);
+ done();
+ });
+ });
+ it('should handle a client streaming request', function(done) {
+ var call = sum(channel, function handleSumResult(err, value) {
+ assert.ifError(err);
+ assert.equal(value.get('num'), 21);
+ });
+ for (var i = 0; i < 7; i++) {
+ call.write(new math.Num({'num': i}));
+ }
+ call.end();
+ call.on('status', function checkStatus(status) {
+ assert.strictEqual(status.code, client.status.OK);
+ done();
+ });
+ });
+ it('should handle a bidirectional streaming request', function(done) {
+ function checkResponse(index, value) {
+ assert.equal(value.get('quotient'), index);
+ assert.equal(value.get('remainder'), 1);
+ }
+ var call = divMany(channel);
+ var response_index = 0;
+ call.on('data', function(value) {
+ checkResponse(response_index, value);
+ response_index += 1;
+ });
+ for (var i = 0; i < 7; i++) {
+ call.write(new math.DivArgs({dividend: 2 * i + 1, divisor: 2}));
+ }
+ call.end();
+ call.on('status', function checkStatus(status) {
+ assert.strictEqual(status.code, client.status.OK);
+ done();
+ });
+ });
+});
diff --git a/src/node/test/math_client_test.js~ b/src/node/test/math_client_test.js~
new file mode 100644
index 0000000000..eaa424ad7f
--- /dev/null
+++ b/src/node/test/math_client_test.js~
@@ -0,0 +1,87 @@
+var client = require('../surface_client.js');
+
+var builder = ProtoBuf.loadProtoFile(__dirname + '/../examples/math.proto');
+var math = builder.build('math');
+
+/**
+ * Get a function that deserializes a specific type of protobuf.
+ * @param {function()} cls The constructor of the message type to deserialize
+ * @return {function(Buffer):cls} The deserialization function
+ */
+function deserializeCls(cls) {
+ /**
+ * Deserialize a buffer to a message object
+ * @param {Buffer} arg_buf The buffer to deserialize
+ * @return {cls} The resulting object
+ */
+ return function deserialize(arg_buf) {
+ return cls.decode(arg_buf);
+ };
+}
+
+/**
+ * Serialize an object to a buffer
+ * @param {*} arg The object to serialize
+ * @return {Buffer} The serialized object
+ */
+function serialize(arg) {
+ return new Buffer(arg.encode.toBuffer());
+}
+
+/**
+ * Sends a Div request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {function(?Error, value=)} The callback to for when the response is
+ * received
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var div = client.makeUnaryRequestFunction('/Math/Div',
+ serialize,
+ deserialize(math.DivReply));
+
+/**
+ * Sends a Fib request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var fib = client.makeServerStreamRequestFunction('/Math/Fib',
+ serialize,
+ deserialize(math.Num));
+
+/**
+ * Sends a Sum request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {function(?Error, value=)} The callback to for when the response is
+ * received
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var sum = client.makeClientStreamRequestFunction('/Math/Sum',
+ serialize,
+ deserialize(math.Num));
+
+/**
+ * Sends a DivMany request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var divMany = client.makeBidiStreamRequestFunction('/Math/DivMany',
+ serialize,
+ deserialize(math.DivReply));
+
+var channel = new client.Channel('localhost:7070');
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
new file mode 100644
index 0000000000..4dd972c3ff
--- /dev/null
+++ b/src/node/test/server_test.js
@@ -0,0 +1,88 @@
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+var Server = require('../server');
+var port_picker = require('../port_picker');
+
+/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ * complete.
+ * @param {number} count The number of calls to the resulting function if the
+ * test passes.
+ * @return {function()} The function that should be called at the end of each
+ * sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+ return function() {
+ count -= 1;
+ if (count <= 0) {
+ done();
+ }
+ };
+}
+
+/**
+ * Responds to every request with the same data as a response
+ * @param {Stream} stream
+ */
+function echoHandler(stream) {
+ stream.pipe(stream);
+}
+
+describe('echo server', function() {
+ it('should echo inputs as responses', function(done) {
+ done = multiDone(done, 4);
+ port_picker.nextAvailablePort(function(port) {
+ var server = new Server();
+ server.bind(port);
+ server.register('echo', echoHandler);
+ server.start();
+
+ var req_text = 'echo test string';
+ var status_text = 'OK';
+
+ var channel = new grpc.Channel(port);
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 3);
+ var call = new grpc.Call(channel,
+ 'echo',
+ deadline);
+ call.startInvoke(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.INVOKE_ACCEPTED);
+ call.startWrite(
+ new Buffer(req_text),
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.WRITE_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ call.writesDone(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ done();
+ });
+ }, 0);
+ call.startRead(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.READ);
+ assert.strictEqual(event.data.toString(), req_text);
+ done();
+ });
+ },function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.CLIENT_METADATA_READ);
+ done();
+ },function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ var status = event.data;
+ assert.strictEqual(status.code, grpc.status.OK);
+ assert.strictEqual(status.details, status_text);
+ server.shutdown();
+ done();
+ }, 0);
+ });
+ });
+});
diff --git a/src/node/test/server_test.js~ b/src/node/test/server_test.js~
new file mode 100644
index 0000000000..3613e08232
--- /dev/null
+++ b/src/node/test/server_test.js~
@@ -0,0 +1,22 @@
+var assert = require('assert');
+var grpc = require('./build/Debug/grpc');
+var Server = require('server');
+
+function echoHandler(arg_iter) {
+ return {
+ 'next' : function(write) {
+ arg_iter.next(function(err, value) {
+ write(err, value);
+ });
+ }
+ }
+}
+
+describe('echo server', function() {
+ it('should echo inputs as responses', function(done) {
+ var server = new Server('localhost:5000');
+ server.register('echo', echoHandler);
+ server.start();
+
+ });
+}); \ No newline at end of file