3 var Dns = require('dns');
4 var Dgram = require('dgram');
5 var Lab = require('lab');
6 var Sntp = require('../lib');
16 var lab = exports.lab = Lab.script();
17 var before = lab.before;
18 var after = lab.after;
19 var describe = lab.experiment;
21 var expect = Lab.expect;
24 describe('SNTP', function () {
26 describe('#time', function () {
28 it('returns consistent result over multiple tries', function (done) {
30 Sntp.time(function (err, time) {
32 expect(err).to.not.exist;
33 expect(time).to.exist;
36 Sntp.time(function (err, time) {
38 expect(err).to.not.exist;
39 expect(time).to.exist;
41 expect(Math.abs(t1 - t2)).is.below(200);
47 it('resolves reference IP', function (done) {
49 Sntp.time({ host: 'ntp.exnet.com', resolveReference: true }, function (err, time) {
51 expect(err).to.not.exist;
52 expect(time).to.exist;
53 expect(time.referenceHost).to.exist;
58 it('times out on no response', function (done) {
60 Sntp.time({ port: 124, timeout: 100 }, function (err, time) {
63 expect(time).to.not.exist;
64 expect(err.message).to.equal('Timeout');
69 it('errors on error event', { parallel: false }, function (done) {
71 var orig = Dgram.createSocket;
72 Dgram.createSocket = function (type) {
74 Dgram.createSocket = orig;
75 var socket = Dgram.createSocket(type);
76 setImmediate(function () { socket.emit('error', new Error('Fake')) });
80 Sntp.time(function (err, time) {
83 expect(time).to.not.exist;
84 expect(err.message).to.equal('Fake');
89 it('errors on incorrect sent size', { parallel: false }, function (done) {
91 var orig = Dgram.Socket.prototype.send;
92 Dgram.Socket.prototype.send = function (buf, offset, length, port, address, callback) {
94 Dgram.Socket.prototype.send = orig;
95 return callback(null, 40);
98 Sntp.time(function (err, time) {
100 expect(err).to.exist;
101 expect(time).to.not.exist;
102 expect(err.message).to.equal('Could not send entire message');
107 it('times out on invalid host', function (done) {
109 Sntp.time({ host: 'error', timeout: 10000 }, function (err, time) {
111 expect(err).to.exist;
112 expect(time).to.not.exist;
113 expect(err.message).to.contain('getaddrinfo');
118 it('fails on bad response buffer size', function (done) {
120 var server = Dgram.createSocket('udp4');
121 server.on('message', function (message, remote) {
122 var message = new Buffer(10);
123 server.send(message, 0, message.length, remote.port, remote.address, function (err, bytes) {
131 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
133 expect(err).to.exist;
134 expect(err.message).to.equal('Invalid server response');
139 var messup = function (bytes) {
141 var server = Dgram.createSocket('udp4');
142 server.on('message', function (message, remote) {
144 var message = new Buffer([
145 0x24, 0x01, 0x00, 0xe3,
146 0x00, 0x00, 0x00, 0x00,
147 0x00, 0x00, 0x00, 0x00,
148 0x41, 0x43, 0x54, 0x53,
149 0xd4, 0xa8, 0x2d, 0xc7,
150 0x1c, 0x5d, 0x49, 0x1b,
151 0xd4, 0xa8, 0x2d, 0xe6,
152 0x67, 0xef, 0x9d, 0xb2,
153 0xd4, 0xa8, 0x2d, 0xe6,
154 0x71, 0xed, 0xb5, 0xfb,
155 0xd4, 0xa8, 0x2d, 0xe6,
156 0x71, 0xee, 0x6c, 0xc5
159 for (var i = 0, il = bytes.length; i < il; ++i) {
160 message[bytes[i][0]] = bytes[i][1];
163 server.send(message, 0, message.length, remote.port, remote.address, function (err, bytes) {
172 it('fails on bad version', function (done) {
174 messup([[0, (0 << 6) + (3 << 3) + (4 << 0)]]);
176 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
178 expect(err).to.exist;
179 expect(time.version).to.equal(3);
180 expect(err.message).to.equal('Invalid server response');
185 it('fails on bad originateTimestamp', function (done) {
187 messup([[24, 0x83], [25, 0xaa], [26, 0x7e], [27, 0x80], [28, 0], [29, 0], [30, 0], [31, 0]]);
189 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
191 expect(err).to.exist;
192 expect(err.message).to.equal('Invalid server response');
197 it('fails on bad receiveTimestamp', function (done) {
199 messup([[32, 0x83], [33, 0xaa], [34, 0x7e], [35, 0x80], [36, 0], [37, 0], [38, 0], [39, 0]]);
201 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
203 expect(err).to.exist;
204 expect(err.message).to.equal('Invalid server response');
209 it('fails on bad originate timestamp and alarm li', function (done) {
211 messup([[0, (3 << 6) + (4 << 3) + (4 << 0)]]);
213 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
215 expect(err).to.exist;
216 expect(err.message).to.equal('Wrong originate timestamp');
217 expect(time.leapIndicator).to.equal('alarm');
222 it('returns time with death stratum and last61 li', function (done) {
224 messup([[0, (1 << 6) + (4 << 3) + (4 << 0)], [1, 0]]);
226 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
228 expect(time.stratum).to.equal('death');
229 expect(time.leapIndicator).to.equal('last-minute-61');
234 it('returns time with reserved stratum and last59 li', function (done) {
236 messup([[0, (2 << 6) + (4 << 3) + (4 << 0)], [1, 0x1f]]);
238 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
240 expect(time.stratum).to.equal('reserved');
241 expect(time.leapIndicator).to.equal('last-minute-59');
246 it('fails on bad mode (symmetric-active)', function (done) {
248 messup([[0, (0 << 6) + (4 << 3) + (1 << 0)]]);
250 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
252 expect(err).to.exist;
253 expect(time.mode).to.equal('symmetric-active');
258 it('fails on bad mode (symmetric-passive)', function (done) {
260 messup([[0, (0 << 6) + (4 << 3) + (2 << 0)]]);
262 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
264 expect(err).to.exist;
265 expect(time.mode).to.equal('symmetric-passive');
270 it('fails on bad mode (client)', function (done) {
272 messup([[0, (0 << 6) + (4 << 3) + (3 << 0)]]);
274 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
276 expect(err).to.exist;
277 expect(time.mode).to.equal('client');
282 it('fails on bad mode (broadcast)', function (done) {
284 messup([[0, (0 << 6) + (4 << 3) + (5 << 0)]]);
286 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
288 expect(err).to.exist;
289 expect(time.mode).to.equal('broadcast');
294 it('fails on bad mode (reserved)', function (done) {
296 messup([[0, (0 << 6) + (4 << 3) + (6 << 0)]]);
298 Sntp.time({ host: 'localhost', port: 49123 }, function (err, time) {
300 expect(err).to.exist;
301 expect(time.mode).to.equal('reserved');
307 describe('#offset', function () {
309 it('gets the current offset', function (done) {
311 Sntp.offset(function (err, offset) {
313 expect(err).to.not.exist;
314 expect(offset).to.not.equal(0);
319 it('gets the current offset from cache', function (done) {
321 Sntp.offset(function (err, offset) {
323 expect(err).to.not.exist;
324 expect(offset).to.not.equal(0);
325 var offset1 = offset;
326 Sntp.offset({}, function (err, offset) {
328 expect(err).to.not.exist;
329 expect(offset).to.equal(offset1);
335 it('gets the new offset on different server', function (done) {
337 Sntp.offset(function (err, offset) {
339 expect(err).to.not.exist;
340 expect(offset).to.not.equal(0);
341 var offset1 = offset;
342 Sntp.offset({ host: 'nist1-sj.ustiming.org' }, function (err, offset) {
344 expect(err).to.not.exist;
345 expect(offset).to.not.equal(offset1);
351 it('gets the new offset on different server', function (done) {
353 Sntp.offset(function (err, offset) {
355 expect(err).to.not.exist;
356 expect(offset).to.not.equal(0);
357 var offset1 = offset;
358 Sntp.offset({ port: 123 }, function (err, offset) {
360 expect(err).to.not.exist;
361 expect(offset).to.not.equal(offset1);
367 it('fails getting the current offset on invalid server', function (done) {
369 Sntp.offset({ host: 'error' }, function (err, offset) {
371 expect(err).to.exist;
372 expect(offset).to.equal(0);
378 describe('#now', function () {
380 it('starts auto-sync, gets now, then stops', function (done) {
384 var before = Sntp.now();
385 expect(before).to.equal(Date.now());
387 Sntp.start(function () {
389 var now = Sntp.now();
390 expect(now).to.not.equal(Date.now());
397 it('starts twice', function (done) {
399 Sntp.start(function () {
401 Sntp.start(function () {
403 var now = Sntp.now();
404 expect(now).to.not.equal(Date.now());
412 it('starts auto-sync, gets now, waits, gets again after timeout', function (done) {
416 var before = Sntp.now();
417 expect(before).to.equal(Date.now());
419 Sntp.start({ clockSyncRefresh: 100 }, function () {
421 var now = Sntp.now();
422 expect(now).to.not.equal(Date.now());
423 expect(now).to.equal(Sntp.now());
425 setTimeout(function () {
427 expect(Sntp.now()).to.not.equal(now);