util.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. 'use strict';
  2. var crypto = require('crypto');
  3. var Connection = require('../lib/connection').Connection;
  4. var PassThrough = require('stream').PassThrough;
  5. var defs = require('../lib/defs');
  6. var assert = require('assert');
  7. var schedule = (typeof setImmediate === 'function') ?
  8. setImmediate : process.nextTick;
  9. function randomString() {
  10. var hash = crypto.createHash('sha1');
  11. hash.update(crypto.randomBytes(64));
  12. return hash.digest('base64');
  13. }
  14. // Set up a socket pair {client, server}, such that writes to the
  15. // client are readable from the server, and writes to the server are
  16. // readable at the client.
  17. //
  18. // +---+ +---+
  19. // | C | | S |
  20. // --write->| l |----->| e |--read-->
  21. // | i | | r |
  22. // <--read--| e |<-----| v |<-write--
  23. // | n | | e |
  24. // | t | | r |
  25. // +---+ +---+
  26. //
  27. // I also need to make sure that end called on either socket affects
  28. // the other.
  29. function socketPair() {
  30. var server = new PassThrough();
  31. var client = new PassThrough();
  32. server.write = client.push.bind(client);
  33. client.write = server.push.bind(server);
  34. function end(chunk, encoding) {
  35. if (chunk) this.push(chunk, encoding);
  36. this.push(null);
  37. }
  38. server.end = end.bind(client);
  39. client.end = end.bind(server);
  40. return {client: client, server: server};
  41. }
  42. function runServer(socket, run) {
  43. var frames = new Connection(socket);
  44. // We will be closing the socket without doing a closing handshake,
  45. // so cheat
  46. frames.expectSocketClose = true;
  47. // We also need to create some channel buffers, again a cheat
  48. frames.freshChannel(null);
  49. frames.freshChannel(null);
  50. frames.freshChannel(null);
  51. function send(id, fields, channel, content) {
  52. channel = channel || 0;
  53. if (content) {
  54. schedule(function() {
  55. frames.sendMessage(channel, id, fields,
  56. defs.BasicProperties, fields,
  57. content);
  58. });
  59. }
  60. else {
  61. schedule(function() {
  62. frames.sendMethod(channel, id, fields);
  63. });
  64. }
  65. }
  66. function wait(method) {
  67. return function() {
  68. return new Promise(function(resolve, reject) {
  69. if (method) {
  70. frames.step(function(e, f) {
  71. if (e !== null) return reject(e);
  72. if (f.id === method)
  73. resolve(f);
  74. else
  75. reject(new Error("Expected method: " + method +
  76. ", got " + f.id));
  77. });
  78. }
  79. else {
  80. frames.step(function(e, f) {
  81. if (e !== null) return reject(e);
  82. else resolve(f);
  83. });
  84. }
  85. });
  86. };
  87. }
  88. run(send, wait);
  89. return frames;
  90. }
  91. // Produce a callback that will complete the test successfully
  92. function succeed(done) {
  93. return function() { done(); }
  94. }
  95. // Produce a callback that will complete the test successfully
  96. // only if the value is an object, it has the specified
  97. // attribute, and its value is equals to the expected value
  98. function succeedIfAttributeEquals(attribute, value, done) {
  99. return function(object) {
  100. if (object && !(object instanceof Error) && value === object[attribute]) {
  101. return done();
  102. }
  103. done(new Error(attribute + " is not equal to " + value));
  104. };
  105. }
  106. // Produce a callback that will fail the test, given either an error
  107. // (to be used as a failure continuation) or any other value (to be
  108. // used as a success continuation when failure is expected)
  109. function fail(done) {
  110. return function(err) {
  111. if (err instanceof Error) done(err);
  112. else done(new Error("Expected to fail, instead got " + err.toString()));
  113. }
  114. }
  115. // Create a function that will call done once it's been called itself
  116. // `count` times. If it's called with an error value, it will
  117. // immediately call done with that error value.
  118. function latch(count, done) {
  119. var awaiting = count;
  120. var alive = true;
  121. return function(err) {
  122. if (err instanceof Error && alive) {
  123. alive = false;
  124. done(err);
  125. }
  126. else {
  127. awaiting--;
  128. if (awaiting === 0 && alive) {
  129. alive = false;
  130. done();
  131. }
  132. }
  133. };
  134. }
  135. // Call a thunk with a continuation that will be called with an error
  136. // if the thunk throws one, or nothing if it runs to completion.
  137. function completes(thunk, done) {
  138. try {
  139. thunk();
  140. done();
  141. }
  142. catch (e) { done(e); }
  143. }
  144. // Construct a Node.JS-style callback from a success continuation and
  145. // an error continuation
  146. function kCallback(k, ek) {
  147. return function(err, val) {
  148. if (err === null) k && k(val);
  149. else ek && ek(err);
  150. };
  151. }
  152. // A noddy way to make tests depend on the node version.
  153. function versionGreaterThan(actual, spec) {
  154. function int(e) { return parseInt(e); }
  155. var version = actual.split('.').map(int);
  156. var desired = spec.split('.').map(int);
  157. for (var i=0; i < desired.length; i++) {
  158. var a = version[i], b = desired[i];
  159. if (a != b) return a > b;
  160. }
  161. return false;
  162. }
  163. suite('versionGreaterThan', function() {
  164. test('full spec', function() {
  165. assert(versionGreaterThan('0.8.26', '0.6.12'));
  166. assert(versionGreaterThan('0.8.26', '0.8.21'));
  167. });
  168. test('partial spec', function() {
  169. assert(versionGreaterThan('0.9.12', '0.8'));
  170. });
  171. test('not greater', function() {
  172. assert(!versionGreaterThan('0.8.12', '0.8.26'));
  173. assert(!versionGreaterThan('0.6.2', '0.6.12'));
  174. assert(!versionGreaterThan('0.8.29', '0.8'));
  175. });
  176. test
  177. });
  178. module.exports = {
  179. socketPair: socketPair,
  180. runServer: runServer,
  181. succeed: succeed,
  182. succeedIfAttributeEquals: succeedIfAttributeEquals,
  183. fail: fail,
  184. latch: latch,
  185. completes: completes,
  186. kCallback: kCallback,
  187. schedule: schedule,
  188. randomString: randomString,
  189. versionGreaterThan: versionGreaterThan
  190. };