surface_test.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. /*
  2. *
  3. * Copyright 2015, Google Inc.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are
  8. * met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above
  13. * copyright notice, this list of conditions and the following disclaimer
  14. * in the documentation and/or other materials provided with the
  15. * distribution.
  16. * * Neither the name of Google Inc. nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. */
  33. 'use strict';
  34. var assert = require('assert');
  35. var surface_client = require('../src/client.js');
  36. var ProtoBuf = require('protobufjs');
  37. var grpc = require('..');
  38. var math_proto = ProtoBuf.loadProtoFile(__dirname + '/math/math.proto');
  39. var mathService = math_proto.lookup('math.Math');
  40. var _ = require('lodash');
  41. /**
  42. * This is used for testing functions with multiple asynchronous calls that
  43. * can happen in different orders. This should be passed the number of async
  44. * function invocations that can occur last, and each of those should call this
  45. * function's return value
  46. * @param {function()} done The function that should be called when a test is
  47. * complete.
  48. * @param {number} count The number of calls to the resulting function if the
  49. * test passes.
  50. * @return {function()} The function that should be called at the end of each
  51. * sequence of asynchronous functions.
  52. */
  53. function multiDone(done, count) {
  54. return function() {
  55. count -= 1;
  56. if (count <= 0) {
  57. done();
  58. }
  59. };
  60. }
  61. var server_insecure_creds = grpc.ServerCredentials.createInsecure();
  62. describe('File loader', function() {
  63. it('Should load a proto file by default', function() {
  64. assert.doesNotThrow(function() {
  65. grpc.load(__dirname + '/test_service.proto');
  66. });
  67. });
  68. it('Should load a proto file with the proto format', function() {
  69. assert.doesNotThrow(function() {
  70. grpc.load(__dirname + '/test_service.proto', 'proto');
  71. });
  72. });
  73. it('Should load a json file with the json format', function() {
  74. assert.doesNotThrow(function() {
  75. grpc.load(__dirname + '/test_service.json', 'json');
  76. });
  77. });
  78. it('Should fail to load a file with an unknown format', function() {
  79. assert.throws(function() {
  80. grpc.load(__dirname + '/test_service.proto', 'fake_format');
  81. });
  82. });
  83. });
  84. describe('Server.prototype.addProtoService', function() {
  85. var server;
  86. var dummyImpls = {
  87. 'div': function() {},
  88. 'divMany': function() {},
  89. 'fib': function() {},
  90. 'sum': function() {}
  91. };
  92. beforeEach(function() {
  93. server = new grpc.Server();
  94. });
  95. afterEach(function() {
  96. server.forceShutdown();
  97. });
  98. it('Should succeed with a single service', function() {
  99. assert.doesNotThrow(function() {
  100. server.addProtoService(mathService, dummyImpls);
  101. });
  102. });
  103. it('Should fail with conflicting method names', function() {
  104. server.addProtoService(mathService, dummyImpls);
  105. assert.throws(function() {
  106. server.addProtoService(mathService, dummyImpls);
  107. });
  108. });
  109. it('Should fail with missing handlers', function() {
  110. assert.throws(function() {
  111. server.addProtoService(mathService, {
  112. 'div': function() {},
  113. 'divMany': function() {},
  114. 'fib': function() {}
  115. });
  116. }, /math.Math.Sum/);
  117. });
  118. it('Should fail if the server has been started', function() {
  119. server.start();
  120. assert.throws(function() {
  121. server.addProtoService(mathService, dummyImpls);
  122. });
  123. });
  124. });
  125. describe('Client constructor building', function() {
  126. var illegal_service_attrs = {
  127. $method : {
  128. path: '/illegal/$method',
  129. requestStream: false,
  130. responseStream: false,
  131. requestSerialize: _.identity,
  132. requestDeserialize: _.identity,
  133. responseSerialize: _.identity,
  134. responseDeserialize: _.identity
  135. }
  136. };
  137. it('Should reject method names starting with $', function() {
  138. assert.throws(function() {
  139. grpc.makeGenericClientConstructor(illegal_service_attrs);
  140. }, /\$/);
  141. });
  142. });
  143. describe('waitForClientReady', function() {
  144. var server;
  145. var port;
  146. var Client;
  147. var client;
  148. before(function() {
  149. server = new grpc.Server();
  150. port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure());
  151. server.start();
  152. Client = surface_client.makeProtobufClientConstructor(mathService);
  153. });
  154. beforeEach(function() {
  155. client = new Client('localhost:' + port, grpc.credentials.createInsecure());
  156. });
  157. after(function() {
  158. server.forceShutdown();
  159. });
  160. it('should complete when called alone', function(done) {
  161. grpc.waitForClientReady(client, Infinity, function(error) {
  162. assert.ifError(error);
  163. done();
  164. });
  165. });
  166. it('should complete when a call is initiated', function(done) {
  167. grpc.waitForClientReady(client, Infinity, function(error) {
  168. assert.ifError(error);
  169. done();
  170. });
  171. var call = client.div({}, function(err, response) {});
  172. call.cancel();
  173. });
  174. it('should complete if called more than once', function(done) {
  175. done = multiDone(done, 2);
  176. grpc.waitForClientReady(client, Infinity, function(error) {
  177. assert.ifError(error);
  178. done();
  179. });
  180. grpc.waitForClientReady(client, Infinity, function(error) {
  181. assert.ifError(error);
  182. done();
  183. });
  184. });
  185. it('should complete if called when already ready', function(done) {
  186. grpc.waitForClientReady(client, Infinity, function(error) {
  187. assert.ifError(error);
  188. grpc.waitForClientReady(client, Infinity, function(error) {
  189. assert.ifError(error);
  190. done();
  191. });
  192. });
  193. });
  194. });
  195. describe('Echo service', function() {
  196. var server;
  197. var client;
  198. before(function() {
  199. var test_proto = ProtoBuf.loadProtoFile(__dirname + '/echo_service.proto');
  200. var echo_service = test_proto.lookup('EchoService');
  201. server = new grpc.Server();
  202. server.addProtoService(echo_service, {
  203. echo: function(call, callback) {
  204. callback(null, call.request);
  205. }
  206. });
  207. var port = server.bind('localhost:0', server_insecure_creds);
  208. var Client = surface_client.makeProtobufClientConstructor(echo_service);
  209. client = new Client('localhost:' + port, grpc.credentials.createInsecure());
  210. server.start();
  211. });
  212. after(function() {
  213. server.forceShutdown();
  214. });
  215. it('should echo the recieved message directly', function(done) {
  216. client.echo({value: 'test value', value2: 3}, function(error, response) {
  217. assert.ifError(error);
  218. assert.deepEqual(response, {value: 'test value', value2: 3});
  219. done();
  220. });
  221. });
  222. });
  223. describe('Generic client and server', function() {
  224. function toString(val) {
  225. return val.toString();
  226. }
  227. function toBuffer(str) {
  228. return new Buffer(str);
  229. }
  230. var string_service_attrs = {
  231. 'capitalize' : {
  232. path: '/string/capitalize',
  233. requestStream: false,
  234. responseStream: false,
  235. requestSerialize: toBuffer,
  236. requestDeserialize: toString,
  237. responseSerialize: toBuffer,
  238. responseDeserialize: toString
  239. }
  240. };
  241. describe('String client and server', function() {
  242. var client;
  243. var server;
  244. before(function() {
  245. server = new grpc.Server();
  246. server.addService(string_service_attrs, {
  247. capitalize: function(call, callback) {
  248. callback(null, _.capitalize(call.request));
  249. }
  250. });
  251. var port = server.bind('localhost:0', server_insecure_creds);
  252. server.start();
  253. var Client = grpc.makeGenericClientConstructor(string_service_attrs);
  254. client = new Client('localhost:' + port,
  255. grpc.credentials.createInsecure());
  256. });
  257. after(function() {
  258. server.forceShutdown();
  259. });
  260. it('Should respond with a capitalized string', function(done) {
  261. client.capitalize('abc', function(err, response) {
  262. assert.ifError(err);
  263. assert.strictEqual(response, 'Abc');
  264. done();
  265. });
  266. });
  267. });
  268. });
  269. describe('Echo metadata', function() {
  270. var client;
  271. var server;
  272. var metadata;
  273. before(function() {
  274. var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
  275. var test_service = test_proto.lookup('TestService');
  276. server = new grpc.Server();
  277. server.addProtoService(test_service, {
  278. unary: function(call, cb) {
  279. call.sendMetadata(call.metadata);
  280. cb(null, {});
  281. },
  282. clientStream: function(stream, cb){
  283. stream.on('data', function(data) {});
  284. stream.on('end', function() {
  285. stream.sendMetadata(stream.metadata);
  286. cb(null, {});
  287. });
  288. },
  289. serverStream: function(stream) {
  290. stream.sendMetadata(stream.metadata);
  291. stream.end();
  292. },
  293. bidiStream: function(stream) {
  294. stream.on('data', function(data) {});
  295. stream.on('end', function() {
  296. stream.sendMetadata(stream.metadata);
  297. stream.end();
  298. });
  299. }
  300. });
  301. var port = server.bind('localhost:0', server_insecure_creds);
  302. var Client = surface_client.makeProtobufClientConstructor(test_service);
  303. client = new Client('localhost:' + port, grpc.credentials.createInsecure());
  304. server.start();
  305. metadata = new grpc.Metadata();
  306. metadata.set('key', 'value');
  307. });
  308. after(function() {
  309. server.forceShutdown();
  310. });
  311. it('with unary call', function(done) {
  312. var call = client.unary({}, function(err, data) {
  313. assert.ifError(err);
  314. }, metadata);
  315. call.on('metadata', function(metadata) {
  316. assert.deepEqual(metadata.get('key'), ['value']);
  317. done();
  318. });
  319. });
  320. it('with client stream call', function(done) {
  321. var call = client.clientStream(function(err, data) {
  322. assert.ifError(err);
  323. }, metadata);
  324. call.on('metadata', function(metadata) {
  325. assert.deepEqual(metadata.get('key'), ['value']);
  326. done();
  327. });
  328. call.end();
  329. });
  330. it('with server stream call', function(done) {
  331. var call = client.serverStream({}, metadata);
  332. call.on('data', function() {});
  333. call.on('metadata', function(metadata) {
  334. assert.deepEqual(metadata.get('key'), ['value']);
  335. done();
  336. });
  337. });
  338. it('with bidi stream call', function(done) {
  339. var call = client.bidiStream(metadata);
  340. call.on('data', function() {});
  341. call.on('metadata', function(metadata) {
  342. assert.deepEqual(metadata.get('key'), ['value']);
  343. done();
  344. });
  345. call.end();
  346. });
  347. it('shows the correct user-agent string', function(done) {
  348. var version = require('../../../package.json').version;
  349. var call = client.unary({}, function(err, data) { assert.ifError(err); },
  350. metadata);
  351. call.on('metadata', function(metadata) {
  352. assert(_.startsWith(metadata.get('user-agent')[0],
  353. 'grpc-node/' + version));
  354. done();
  355. });
  356. });
  357. });
  358. describe('Other conditions', function() {
  359. var test_service;
  360. var Client;
  361. var client;
  362. var server;
  363. var port;
  364. before(function() {
  365. var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
  366. test_service = test_proto.lookup('TestService');
  367. server = new grpc.Server();
  368. var trailer_metadata = new grpc.Metadata();
  369. trailer_metadata.add('trailer-present', 'yes');
  370. server.addProtoService(test_service, {
  371. unary: function(call, cb) {
  372. var req = call.request;
  373. if (req.error) {
  374. cb(new Error('Requested error'), null, trailer_metadata);
  375. } else {
  376. cb(null, {count: 1}, trailer_metadata);
  377. }
  378. },
  379. clientStream: function(stream, cb){
  380. var count = 0;
  381. var errored;
  382. stream.on('data', function(data) {
  383. if (data.error) {
  384. errored = true;
  385. cb(new Error('Requested error'), null, trailer_metadata);
  386. } else {
  387. count += 1;
  388. }
  389. });
  390. stream.on('end', function() {
  391. if (!errored) {
  392. cb(null, {count: count}, trailer_metadata);
  393. }
  394. });
  395. },
  396. serverStream: function(stream) {
  397. var req = stream.request;
  398. if (req.error) {
  399. var err = new Error('Requested error');
  400. err.metadata = trailer_metadata;
  401. stream.emit('error', err);
  402. } else {
  403. for (var i = 0; i < 5; i++) {
  404. stream.write({count: i});
  405. }
  406. stream.end(trailer_metadata);
  407. }
  408. },
  409. bidiStream: function(stream) {
  410. var count = 0;
  411. stream.on('data', function(data) {
  412. if (data.error) {
  413. var err = new Error('Requested error');
  414. err.metadata = trailer_metadata.clone();
  415. err.metadata.add('count', '' + count);
  416. stream.emit('error', err);
  417. } else {
  418. stream.write({count: count});
  419. count += 1;
  420. }
  421. });
  422. stream.on('end', function() {
  423. stream.end(trailer_metadata);
  424. });
  425. }
  426. });
  427. port = server.bind('localhost:0', server_insecure_creds);
  428. Client = surface_client.makeProtobufClientConstructor(test_service);
  429. client = new Client('localhost:' + port, grpc.credentials.createInsecure());
  430. server.start();
  431. });
  432. after(function() {
  433. server.forceShutdown();
  434. });
  435. it('channel.getTarget should be available', function() {
  436. assert.strictEqual(typeof grpc.getClientChannel(client).getTarget(),
  437. 'string');
  438. });
  439. describe('Server recieving bad input', function() {
  440. var misbehavingClient;
  441. var badArg = new Buffer([0xFF]);
  442. before(function() {
  443. var test_service_attrs = {
  444. unary: {
  445. path: '/TestService/Unary',
  446. requestStream: false,
  447. responseStream: false,
  448. requestSerialize: _.identity,
  449. responseDeserialize: _.identity
  450. },
  451. clientStream: {
  452. path: '/TestService/ClientStream',
  453. requestStream: true,
  454. responseStream: false,
  455. requestSerialize: _.identity,
  456. responseDeserialize: _.identity
  457. },
  458. serverStream: {
  459. path: '/TestService/ServerStream',
  460. requestStream: false,
  461. responseStream: true,
  462. requestSerialize: _.identity,
  463. responseDeserialize: _.identity
  464. },
  465. bidiStream: {
  466. path: '/TestService/BidiStream',
  467. requestStream: true,
  468. responseStream: true,
  469. requestSerialize: _.identity,
  470. responseDeserialize: _.identity
  471. }
  472. };
  473. var Client = surface_client.makeClientConstructor(test_service_attrs,
  474. 'TestService');
  475. misbehavingClient = new Client('localhost:' + port,
  476. grpc.credentials.createInsecure());
  477. });
  478. it('should respond correctly to a unary call', function(done) {
  479. misbehavingClient.unary(badArg, function(err, data) {
  480. assert(err);
  481. assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT);
  482. done();
  483. });
  484. });
  485. it('should respond correctly to a client stream', function(done) {
  486. var call = misbehavingClient.clientStream(function(err, data) {
  487. assert(err);
  488. assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT);
  489. done();
  490. });
  491. call.write(badArg);
  492. // TODO(mlumish): Remove call.end()
  493. call.end();
  494. });
  495. it('should respond correctly to a server stream', function(done) {
  496. var call = misbehavingClient.serverStream(badArg);
  497. call.on('data', function(data) {
  498. assert.fail(data, null, 'Unexpected data', '===');
  499. });
  500. call.on('error', function(err) {
  501. assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT);
  502. done();
  503. });
  504. });
  505. it('should respond correctly to a bidi stream', function(done) {
  506. var call = misbehavingClient.bidiStream();
  507. call.on('data', function(data) {
  508. assert.fail(data, null, 'Unexpected data', '===');
  509. });
  510. call.on('error', function(err) {
  511. assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT);
  512. done();
  513. });
  514. call.write(badArg);
  515. // TODO(mlumish): Remove call.end()
  516. call.end();
  517. });
  518. });
  519. describe('Trailing metadata', function() {
  520. it('should be present when a unary call succeeds', function(done) {
  521. var call = client.unary({error: false}, function(err, data) {
  522. assert.ifError(err);
  523. });
  524. call.on('status', function(status) {
  525. assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
  526. done();
  527. });
  528. });
  529. it('should be present when a unary call fails', function(done) {
  530. var call = client.unary({error: true}, function(err, data) {
  531. assert(err);
  532. });
  533. call.on('status', function(status) {
  534. assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
  535. done();
  536. });
  537. });
  538. it('should be present when a client stream call succeeds', function(done) {
  539. var call = client.clientStream(function(err, data) {
  540. assert.ifError(err);
  541. });
  542. call.write({error: false});
  543. call.write({error: false});
  544. call.end();
  545. call.on('status', function(status) {
  546. assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
  547. done();
  548. });
  549. });
  550. it('should be present when a client stream call fails', function(done) {
  551. var call = client.clientStream(function(err, data) {
  552. assert(err);
  553. });
  554. call.write({error: false});
  555. call.write({error: true});
  556. call.end();
  557. call.on('status', function(status) {
  558. assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
  559. done();
  560. });
  561. });
  562. it('should be present when a server stream call succeeds', function(done) {
  563. var call = client.serverStream({error: false});
  564. call.on('data', function(){});
  565. call.on('status', function(status) {
  566. assert.strictEqual(status.code, grpc.status.OK);
  567. assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
  568. done();
  569. });
  570. });
  571. it('should be present when a server stream call fails', function(done) {
  572. var call = client.serverStream({error: true});
  573. call.on('data', function(){});
  574. call.on('error', function(error) {
  575. assert.deepEqual(error.metadata.get('trailer-present'), ['yes']);
  576. done();
  577. });
  578. });
  579. it('should be present when a bidi stream succeeds', function(done) {
  580. var call = client.bidiStream();
  581. call.write({error: false});
  582. call.write({error: false});
  583. call.end();
  584. call.on('data', function(){});
  585. call.on('status', function(status) {
  586. assert.strictEqual(status.code, grpc.status.OK);
  587. assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
  588. done();
  589. });
  590. });
  591. it('should be present when a bidi stream fails', function(done) {
  592. var call = client.bidiStream();
  593. call.write({error: false});
  594. call.write({error: true});
  595. call.end();
  596. call.on('data', function(){});
  597. call.on('error', function(error) {
  598. assert.deepEqual(error.metadata.get('trailer-present'), ['yes']);
  599. done();
  600. });
  601. });
  602. });
  603. describe('Error object should contain the status', function() {
  604. it('for a unary call', function(done) {
  605. client.unary({error: true}, function(err, data) {
  606. assert(err);
  607. assert.strictEqual(err.code, grpc.status.UNKNOWN);
  608. assert.strictEqual(err.message, 'Requested error');
  609. done();
  610. });
  611. });
  612. it('for a client stream call', function(done) {
  613. var call = client.clientStream(function(err, data) {
  614. assert(err);
  615. assert.strictEqual(err.code, grpc.status.UNKNOWN);
  616. assert.strictEqual(err.message, 'Requested error');
  617. done();
  618. });
  619. call.write({error: false});
  620. call.write({error: true});
  621. call.end();
  622. });
  623. it('for a server stream call', function(done) {
  624. var call = client.serverStream({error: true});
  625. call.on('data', function(){});
  626. call.on('error', function(error) {
  627. assert.strictEqual(error.code, grpc.status.UNKNOWN);
  628. assert.strictEqual(error.message, 'Requested error');
  629. done();
  630. });
  631. });
  632. it('for a bidi stream call', function(done) {
  633. var call = client.bidiStream();
  634. call.write({error: false});
  635. call.write({error: true});
  636. call.end();
  637. call.on('data', function(){});
  638. call.on('error', function(error) {
  639. assert.strictEqual(error.code, grpc.status.UNKNOWN);
  640. assert.strictEqual(error.message, 'Requested error');
  641. done();
  642. });
  643. });
  644. });
  645. describe('call.getPeer should return the peer', function() {
  646. it('for a unary call', function(done) {
  647. var call = client.unary({error: false}, function(err, data) {
  648. assert.ifError(err);
  649. done();
  650. });
  651. assert.strictEqual(typeof call.getPeer(), 'string');
  652. });
  653. it('for a client stream call', function(done) {
  654. var call = client.clientStream(function(err, data) {
  655. assert.ifError(err);
  656. done();
  657. });
  658. assert.strictEqual(typeof call.getPeer(), 'string');
  659. call.write({error: false});
  660. call.end();
  661. });
  662. it('for a server stream call', function(done) {
  663. var call = client.serverStream({error: false});
  664. assert.strictEqual(typeof call.getPeer(), 'string');
  665. call.on('data', function(){});
  666. call.on('status', function(status) {
  667. assert.strictEqual(status.code, grpc.status.OK);
  668. done();
  669. });
  670. });
  671. it('for a bidi stream call', function(done) {
  672. var call = client.bidiStream();
  673. assert.strictEqual(typeof call.getPeer(), 'string');
  674. call.write({error: false});
  675. call.end();
  676. call.on('data', function(){});
  677. call.on('status', function(status) {
  678. done();
  679. });
  680. });
  681. });
  682. });
  683. describe('Call propagation', function() {
  684. var proxy;
  685. var proxy_impl;
  686. var test_service;
  687. var Client;
  688. var client;
  689. var server;
  690. before(function() {
  691. var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
  692. test_service = test_proto.lookup('TestService');
  693. server = new grpc.Server();
  694. server.addProtoService(test_service, {
  695. unary: function(call) {},
  696. clientStream: function(stream) {},
  697. serverStream: function(stream) {},
  698. bidiStream: function(stream) {}
  699. });
  700. var port = server.bind('localhost:0', server_insecure_creds);
  701. Client = surface_client.makeProtobufClientConstructor(test_service);
  702. client = new Client('localhost:' + port, grpc.credentials.createInsecure());
  703. server.start();
  704. });
  705. after(function() {
  706. server.forceShutdown();
  707. });
  708. beforeEach(function() {
  709. proxy = new grpc.Server();
  710. proxy_impl = {
  711. unary: function(call) {},
  712. clientStream: function(stream) {},
  713. serverStream: function(stream) {},
  714. bidiStream: function(stream) {}
  715. };
  716. });
  717. afterEach(function() {
  718. proxy.forceShutdown();
  719. });
  720. describe('Cancellation', function() {
  721. it('With a unary call', function(done) {
  722. done = multiDone(done, 2);
  723. proxy_impl.unary = function(parent, callback) {
  724. client.unary(parent.request, function(err, value) {
  725. try {
  726. assert(err);
  727. assert.strictEqual(err.code, grpc.status.CANCELLED);
  728. } finally {
  729. callback(err, value);
  730. done();
  731. }
  732. }, null, {parent: parent});
  733. call.cancel();
  734. };
  735. proxy.addProtoService(test_service, proxy_impl);
  736. var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
  737. proxy.start();
  738. var proxy_client = new Client('localhost:' + proxy_port,
  739. grpc.credentials.createInsecure());
  740. var call = proxy_client.unary({}, function(err, value) {
  741. done();
  742. });
  743. });
  744. it('With a client stream call', function(done) {
  745. done = multiDone(done, 2);
  746. proxy_impl.clientStream = function(parent, callback) {
  747. client.clientStream(function(err, value) {
  748. try {
  749. assert(err);
  750. assert.strictEqual(err.code, grpc.status.CANCELLED);
  751. } finally {
  752. callback(err, value);
  753. done();
  754. }
  755. }, null, {parent: parent});
  756. call.cancel();
  757. };
  758. proxy.addProtoService(test_service, proxy_impl);
  759. var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
  760. proxy.start();
  761. var proxy_client = new Client('localhost:' + proxy_port,
  762. grpc.credentials.createInsecure());
  763. var call = proxy_client.clientStream(function(err, value) {
  764. done();
  765. });
  766. });
  767. it('With a server stream call', function(done) {
  768. done = multiDone(done, 2);
  769. proxy_impl.serverStream = function(parent) {
  770. var child = client.serverStream(parent.request, null,
  771. {parent: parent});
  772. child.on('error', function(err) {
  773. assert(err);
  774. assert.strictEqual(err.code, grpc.status.CANCELLED);
  775. done();
  776. });
  777. call.cancel();
  778. };
  779. proxy.addProtoService(test_service, proxy_impl);
  780. var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
  781. proxy.start();
  782. var proxy_client = new Client('localhost:' + proxy_port,
  783. grpc.credentials.createInsecure());
  784. var call = proxy_client.serverStream({});
  785. call.on('error', function(err) {
  786. done();
  787. });
  788. });
  789. it('With a bidi stream call', function(done) {
  790. done = multiDone(done, 2);
  791. proxy_impl.bidiStream = function(parent) {
  792. var child = client.bidiStream(null, {parent: parent});
  793. child.on('error', function(err) {
  794. assert(err);
  795. assert.strictEqual(err.code, grpc.status.CANCELLED);
  796. done();
  797. });
  798. call.cancel();
  799. };
  800. proxy.addProtoService(test_service, proxy_impl);
  801. var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
  802. proxy.start();
  803. var proxy_client = new Client('localhost:' + proxy_port,
  804. grpc.credentials.createInsecure());
  805. var call = proxy_client.bidiStream();
  806. call.on('error', function(err) {
  807. done();
  808. });
  809. });
  810. });
  811. describe('Deadline', function() {
  812. /* jshint bitwise:false */
  813. var deadline_flags = (grpc.propagate.DEFAULTS &
  814. ~grpc.propagate.CANCELLATION);
  815. it('With a client stream call', function(done) {
  816. done = multiDone(done, 2);
  817. proxy_impl.clientStream = function(parent, callback) {
  818. client.clientStream(function(err, value) {
  819. try {
  820. assert(err);
  821. assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
  822. err.code === grpc.status.INTERNAL);
  823. } finally {
  824. callback(err, value);
  825. done();
  826. }
  827. }, null, {parent: parent, propagate_flags: deadline_flags});
  828. };
  829. proxy.addProtoService(test_service, proxy_impl);
  830. var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
  831. proxy.start();
  832. var proxy_client = new Client('localhost:' + proxy_port,
  833. grpc.credentials.createInsecure());
  834. var deadline = new Date();
  835. deadline.setSeconds(deadline.getSeconds() + 1);
  836. proxy_client.clientStream(function(err, value) {
  837. done();
  838. }, null, {deadline: deadline});
  839. });
  840. it('With a bidi stream call', function(done) {
  841. done = multiDone(done, 2);
  842. proxy_impl.bidiStream = function(parent) {
  843. var child = client.bidiStream(
  844. null, {parent: parent, propagate_flags: deadline_flags});
  845. child.on('error', function(err) {
  846. assert(err);
  847. assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
  848. err.code === grpc.status.INTERNAL);
  849. done();
  850. });
  851. };
  852. proxy.addProtoService(test_service, proxy_impl);
  853. var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
  854. proxy.start();
  855. var proxy_client = new Client('localhost:' + proxy_port,
  856. grpc.credentials.createInsecure());
  857. var deadline = new Date();
  858. deadline.setSeconds(deadline.getSeconds() + 1);
  859. var call = proxy_client.bidiStream(null, {deadline: deadline});
  860. call.on('error', function(err) {
  861. done();
  862. });
  863. });
  864. });
  865. });
  866. describe('Cancelling surface client', function() {
  867. var client;
  868. var server;
  869. before(function() {
  870. server = new grpc.Server();
  871. server.addProtoService(mathService, {
  872. 'div': function(stream) {},
  873. 'divMany': function(stream) {},
  874. 'fib': function(stream) {},
  875. 'sum': function(stream) {}
  876. });
  877. var port = server.bind('localhost:0', server_insecure_creds);
  878. var Client = surface_client.makeProtobufClientConstructor(mathService);
  879. client = new Client('localhost:' + port, grpc.credentials.createInsecure());
  880. server.start();
  881. });
  882. after(function() {
  883. server.forceShutdown();
  884. });
  885. it('Should correctly cancel a unary call', function(done) {
  886. var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) {
  887. assert.strictEqual(err.code, surface_client.status.CANCELLED);
  888. done();
  889. });
  890. call.cancel();
  891. });
  892. it('Should correctly cancel a client stream call', function(done) {
  893. var call = client.sum(function(err, resp) {
  894. assert.strictEqual(err.code, surface_client.status.CANCELLED);
  895. done();
  896. });
  897. call.cancel();
  898. });
  899. it('Should correctly cancel a server stream call', function(done) {
  900. var call = client.fib({'limit': 5});
  901. call.on('error', function(error) {
  902. assert.strictEqual(error.code, surface_client.status.CANCELLED);
  903. done();
  904. });
  905. call.cancel();
  906. });
  907. it('Should correctly cancel a bidi stream call', function(done) {
  908. var call = client.divMany();
  909. call.on('error', function(error) {
  910. assert.strictEqual(error.code, surface_client.status.CANCELLED);
  911. done();
  912. });
  913. call.cancel();
  914. });
  915. });