UNPKG

9.92 kBJavaScriptView Raw
1var assert = require('assert');
2var http = require('http');
3var WebSocket = require('ws');
4var zetta = require('../');
5var zettacluster = require('zetta-cluster');
6var Scout = require('./fixture/example_scout');
7var VirtualDevice = require('../lib/virtual_device');
8var LedJSON = require('./fixture/virtual_device.json');
9
10var mockSocket = {
11 on: function(){},
12 subscribe: function(topic, cb){
13 if(cb) {
14 cb();
15 }
16 },
17 unsubscribe: function(){}
18};
19
20describe('Virtual Device', function() {
21 var base = null;
22 var cluster = null;
23 var device = null;
24 var socket = null;
25 var deviceJson = null;
26 var vdevice = null;
27
28 var startPort = 2600;
29
30 beforeEach(function(done) {
31 cluster = zettacluster({ zetta: zetta })
32 .server('cloud')
33 .server('detroit1', [Scout], ['cloud'])
34 .on('ready', function() {
35 socket = cluster.servers['cloud'].httpServer.peers['detroit1'];
36 if (!socket) {
37 done(new Error('socket not found'));
38 }
39
40 var did = Object.keys(cluster.servers['detroit1'].runtime._jsDevices)[0];
41 device = cluster.servers['detroit1'].runtime._jsDevices[did];
42 var id = cluster.servers['detroit1'].id;
43 base = 'localhost:' + cluster.servers['cloud']._testPort + '/servers/' + cluster.servers['cloud'].locatePeer(id) + '/devices/' + did;
44
45 http.get('http://' + base, function(res) {
46 var buffer = [];
47 var len = 0;
48 res.on('readable', function() {
49 var data;
50 while (data = res.read()) {
51 buffer.push(data);
52 len += data.length;
53 }
54 });
55 res.on('end', function() {
56 var buf = Buffer.concat(buffer, len);
57 deviceJson = JSON.parse(buf.toString());
58 vdevice = new VirtualDevice(deviceJson, socket);
59 vdevice.on('ready', function() {
60 setTimeout(done, 100);
61 });
62 });
63 res.on('error', function(err) {
64 done(err);
65 });
66 })
67 })
68 .run(function(err){
69 if (err) {
70 return done(err);
71 }
72 });
73 });
74
75 afterEach(function(done) {
76 cluster.stop();
77 setTimeout(done, 10); // fix issues with server not being closed before a new one starts
78 });
79
80 describe('.call method', function() {
81
82 it('call should work without arguments', function(done) {
83 vdevice.call('change', function(err) {
84 assert.equal(err, null);
85 });
86 var timer = setTimeout(function() {
87 done(new Error('Faied to recv transition call on detroit device'));
88 }, 100);
89
90 device.on('change', function() {
91 clearTimeout(timer);
92 done();
93 });
94 });
95
96 it('call should work with arguments', function(done) {
97 vdevice.call('test', 'hello', function(err) {
98 assert.equal(err, null);
99 });
100 var timer = setTimeout(function() {
101 done(new Error('Faied to recv transition call on detroit device'));
102 }, 100);
103
104 device.on('test', function() {
105 clearTimeout(timer);
106 assert.equal(device.value, 'hello');
107 done();
108 });
109 });
110
111 it('call should work with arguments, after peer reconnects', function(done) {
112
113 var timer = setTimeout(function() {
114 done(new Error('Faied to recv transition call on detroit device'));
115 }, 1500);
116
117 vdevice.call('test', 'hello', function(err) {
118 assert.equal(err, null);
119
120 clearTimeout(timer);
121 assert.equal(device.value, 'hello');
122
123 var socket = cluster.servers['cloud'].httpServer.peers['detroit1'];
124 socket.close();
125
126 setTimeout(function() {
127 vdevice.call('test', 'hello1', function(err) {
128 assert.equal(err, null);
129 });
130 var timer = setTimeout(function() {
131 done(new Error('Faied to recv transition call on detroit device'));
132 }, 1500);
133
134 device.on('test', function() {
135 clearTimeout(timer);
136 assert.equal(device.value, 'hello1');
137 done();
138 });
139 }, 1500);
140 });
141
142 });
143 });
144
145 describe('Device log monitor stream', function() {
146
147 it('should update virtual devices state when detroit device updates', function(done) {
148 assert.equal(vdevice.state, 'ready');
149 device.call('change', function() {
150 assert.equal(device.state, 'changed');
151 setTimeout(function() {
152 assert.equal(vdevice.state, 'changed');
153 done();
154 }, 100);
155 });
156 });
157
158 it('should update virtual devices state when virtual device calls transition', function(done) {
159 assert.equal(vdevice.state, 'ready');
160 vdevice.call('change', function() {
161 assert.equal(device.state, 'changed');
162 setTimeout(function() {
163 assert.equal(vdevice.state, 'changed');
164 done();
165 }, 100);
166 });
167 });
168
169 });
170
171
172
173 describe('Device monitor streams on properties', function() {
174
175 it('should update virtual device when value increments locally', function(done) {
176 assert.equal(vdevice.bar, 0);
177 assert.equal(device.bar, 0);
178 device.incrementStreamValue();
179 assert.equal(device.bar, 1);
180 setTimeout(function() {
181 assert.equal(vdevice.bar, 1);
182 done();
183 }, 100);
184 });
185
186 it('should implement .createReadStream() for object stream', function(done) {
187 vdevice.createReadStream('bar').on('data', function(msg) {
188 assert.equal(msg.data, 1);
189 done();
190 });
191
192 setTimeout(function(){
193 device.incrementStreamValue();
194 }, 10);
195 })
196
197 it('should implement .createReadStream() for binary stream', function(done) {
198 vdevice.createReadStream('foobar').on('data', function(buf) {
199 assert.deepEqual(buf, new Buffer([1]));
200 done();
201 });
202 setTimeout(function(){
203 device.incrementFooBar();
204 }, 10);
205 })
206
207 it('should recv data event after a client ws disconnected on the same topic', function(done) {
208
209 var url = 'ws://localhost:' + cluster.servers['cloud']._testPort + '/servers/detroit1/events?topic=testdriver%2F' + device.id + '%2Fbar';
210
211 var recv = 0;
212 var wsRecv = 0;
213 vdevice.streams.bar.on('data', function(data) {
214 recv++;
215 });
216
217 device.incrementStreamValue();
218
219 setTimeout(function() {
220 assert.equal(recv, 1);
221 var socket = new WebSocket(url);
222 socket.on('message', function() {
223 wsRecv++;
224 });
225 socket.on('open', function() {
226 device.incrementStreamValue();
227 setTimeout(function() {
228 assert.equal(recv, 2);
229 assert.equal(wsRecv, 1);
230
231 socket.close();
232 device.incrementStreamValue();
233 setTimeout(function() {
234 assert.equal(recv, 3);
235 assert.equal(wsRecv, 1);
236 done();
237 }, 300);
238 },300);
239 });
240 socket.on('error', done);
241
242 }, 300);
243 });
244
245 });
246
247 describe('Device binary streams', function() {
248
249 it('should only subscribe to a binary stream if used', function(done) {
250 var topic = device.type + '/' + device.id + '/foobar';
251 assert.equal(cluster.servers['detroit1'].pubsub._listeners[topic], undefined);
252 vdevice.streams.foobar.on('data', function() {});
253 setTimeout(function() {
254 assert.notEqual(cluster.servers['detroit1'].pubsub._listeners[topic], undefined);
255 done();
256 }, 100);
257 });
258
259 it('should pass binary data from local device to virtual', function(done) {
260 var recv = 0;
261 vdevice.streams.foobar.on('data', function(data) {
262 recv++;
263 assert.deepEqual(data, new Buffer([recv]));
264 });
265
266 setTimeout(function() {
267 device.incrementFooBar();
268 device.incrementFooBar();
269 device.incrementFooBar();
270
271 setTimeout(function() {
272 assert.equal(recv, 3);
273 done();
274 }, 100);
275 }, 100);
276 });
277
278 });
279
280
281
282 describe('basic unit tests', function() {
283
284 var device = null;
285 beforeEach(function() {
286 device = new VirtualDevice(LedJSON , mockSocket);
287 });
288
289 it('wires up logs, properties, and actions', function() {
290 assert.equal(device.state, 'off');
291 assert.equal(Object.keys(device.streams).length, 2);
292 });
293
294 it('will change properties with update.', function() {
295 device._update({ properties: {state: 'on'}});
296 assert.equal(device.state, 'on');
297 });
298
299 it('will return the proper action given a name', function() {
300 var action = device._getAction('turn-on');
301 assert.ok(action);
302 assert.equal(action.name, 'turn-on');
303 assert.equal(action.fields.length, 1);
304 });
305
306 it('will return link given a title', function() {
307 var link = device._getLinkWithTitle('state');
308 assert.ok(link);
309 assert.equal(link.title, 'state');
310 assert.equal(link.rel[0], 'monitor');
311 assert.equal(link.rel[1], 'http://rels.zettajs.io/object-stream');
312 });
313
314 it('will return an array of links if searched for by rel', function() {
315 var links = device._getLinksWithRel('http://rels.zettajs.io/object-stream');
316 assert.ok(links);
317 assert.equal(links.length, 2);
318 assert.ok(Array.isArray(links));
319 });
320
321 it('will parse out a topic for a particular link', function() {
322 var link = device._getLinkWithTitle('state');
323 var topic = device._getTopic(link);
324 assert.equal(topic, 'led/0eaf8607-5b8c-45ee-afae-9a5f9e1f34e2/state');
325 });
326
327 it('will encode transition arguments into an object', function() {
328 var action = device._getAction('turn-on');
329 var data = device._encodeData(action, {});
330 assert.ok(data);
331 assert.equal(Object.keys(data)[0], 'action');
332 assert.equal(data.action, 'turn-on');
333 });
334 });
335
336});
337