Timoney, Daniel (dt5972) | 324ee36 | 2017-02-15 10:37:53 -0500 | [diff] [blame] | 1 | /** |
| 2 | * Copyright 2014 IBM Corp. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | **/ |
| 16 | |
| 17 | var should = require("should"); |
| 18 | var sinon = require('sinon'); |
| 19 | var RedNode = require("../../../red/nodes/Node"); |
| 20 | var comms = require('../../../red/comms'); |
| 21 | |
| 22 | describe('Node', function() { |
| 23 | describe('#constructor',function() { |
| 24 | it('is called with an id and a type',function() { |
| 25 | var n = new RedNode({id:'123',type:'abc'}); |
| 26 | n.should.have.property('id','123'); |
| 27 | n.should.have.property('type','abc'); |
| 28 | n.should.not.have.property('name'); |
| 29 | n.wires.should.be.empty; |
| 30 | }); |
| 31 | |
| 32 | it('is called with an id, a type and a name',function() { |
| 33 | var n = new RedNode({id:'123',type:'abc',name:'barney'}); |
| 34 | n.should.have.property('id','123'); |
| 35 | n.should.have.property('type','abc'); |
| 36 | n.should.have.property('name','barney'); |
| 37 | n.wires.should.be.empty; |
| 38 | }); |
| 39 | |
| 40 | it('is called with an id, a type and some wires',function() { |
| 41 | var n = new RedNode({id:'123',type:'abc',wires:['123','456']}); |
| 42 | n.should.have.property('id','123'); |
| 43 | n.should.have.property('type','abc'); |
| 44 | n.should.not.have.property('name'); |
| 45 | n.wires.should.have.length(2); |
| 46 | }); |
| 47 | |
| 48 | }); |
| 49 | |
| 50 | describe('#close', function() { |
| 51 | it('emits close event when closed',function(done) { |
| 52 | var n = new RedNode({id:'123',type:'abc'}); |
| 53 | n.on('close',function() { |
| 54 | done(); |
| 55 | }); |
| 56 | var p = n.close(); |
| 57 | should.not.exist(p); |
| 58 | }); |
| 59 | |
| 60 | it('returns a promise when provided a callback with a done parameter',function(testdone) { |
| 61 | var n = new RedNode({id:'123',type:'abc'}); |
| 62 | n.on('close',function(done) { |
| 63 | setTimeout(function() { |
| 64 | done(); |
| 65 | },200); |
| 66 | }); |
| 67 | var p = n.close(); |
| 68 | should.exist(p); |
| 69 | p.then(function() { |
| 70 | testdone(); |
| 71 | }); |
| 72 | }); |
| 73 | }); |
| 74 | |
| 75 | |
| 76 | describe('#receive', function() { |
| 77 | it('emits input event when called', function(done) { |
| 78 | var n = new RedNode({id:'123',type:'abc'}); |
| 79 | var message = {payload:"hello world"}; |
| 80 | n.on('input',function(msg) { |
| 81 | should.deepEqual(msg,message); |
| 82 | done(); |
| 83 | }); |
| 84 | n.receive(message); |
| 85 | }); |
| 86 | }); |
| 87 | |
| 88 | describe('#send', function() { |
| 89 | |
| 90 | it('emits a single message', function(done) { |
| 91 | var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]}); |
| 92 | var n2 = new RedNode({id:'n2',type:'abc'}); |
| 93 | var message = {payload:"hello world"}; |
| 94 | |
| 95 | n2.on('input',function(msg) { |
| 96 | // msg equals message, but is a new copy |
| 97 | should.deepEqual(msg,message); |
| 98 | should.notStrictEqual(msg,message); |
| 99 | done(); |
| 100 | }); |
| 101 | |
| 102 | n1.send(message); |
| 103 | }); |
| 104 | |
| 105 | it('emits multiple messages on a single output', function(done) { |
| 106 | var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]}); |
| 107 | var n2 = new RedNode({id:'n2',type:'abc'}); |
| 108 | |
| 109 | var messages = [ |
| 110 | {payload:"hello world"}, |
| 111 | {payload:"hello world again"} |
| 112 | ]; |
| 113 | |
| 114 | var rcvdCount = 0; |
| 115 | |
| 116 | n2.on('input',function(msg) { |
| 117 | should.deepEqual(msg,messages[rcvdCount]); |
| 118 | should.notStrictEqual(msg,messages[rcvdCount]); |
| 119 | rcvdCount += 1; |
| 120 | if (rcvdCount == 2) { |
| 121 | done(); |
| 122 | } |
| 123 | }); |
| 124 | n1.send([messages]); |
| 125 | }); |
| 126 | |
| 127 | it('emits messages to multiple outputs', function(done) { |
| 128 | var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2'],['n3'],['n4','n5']]}); |
| 129 | var n2 = new RedNode({id:'n2',type:'abc'}); |
| 130 | var n3 = new RedNode({id:'n3',type:'abc'}); |
| 131 | var n4 = new RedNode({id:'n4',type:'abc'}); |
| 132 | var n5 = new RedNode({id:'n5',type:'abc'}); |
| 133 | |
| 134 | var messages = [ |
| 135 | {payload:"hello world"}, |
| 136 | null, |
| 137 | {payload:"hello world again"} |
| 138 | ]; |
| 139 | |
| 140 | var rcvdCount = 0; |
| 141 | |
| 142 | n2.on('input',function(msg) { |
| 143 | should.deepEqual(msg,messages[0]); |
| 144 | should.notStrictEqual(msg,messages[0]); |
| 145 | rcvdCount += 1; |
| 146 | if (rcvdCount == 3) { |
| 147 | done(); |
| 148 | } |
| 149 | }); |
| 150 | |
| 151 | n3.on('input',function(msg) { |
| 152 | should.fail(null,null,"unexpected message"); |
| 153 | }); |
| 154 | |
| 155 | n4.on('input',function(msg) { |
| 156 | should.deepEqual(msg,messages[2]); |
| 157 | should.notStrictEqual(msg,messages[2]); |
| 158 | rcvdCount += 1; |
| 159 | if (rcvdCount == 3) { |
| 160 | done(); |
| 161 | } |
| 162 | }); |
| 163 | |
| 164 | n5.on('input',function(msg) { |
| 165 | should.deepEqual(msg,messages[2]); |
| 166 | should.notStrictEqual(msg,messages[2]); |
| 167 | rcvdCount += 1; |
| 168 | if (rcvdCount == 3) { |
| 169 | done(); |
| 170 | } |
| 171 | }); |
| 172 | |
| 173 | n1.send(messages); |
| 174 | }); |
| 175 | |
| 176 | it('emits no messages', function(done) { |
| 177 | var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]}); |
| 178 | var n2 = new RedNode({id:'n2',type:'abc'}); |
| 179 | |
| 180 | n2.on('input',function(msg) { |
| 181 | should.fail(null,null,"unexpected message"); |
| 182 | }); |
| 183 | |
| 184 | setTimeout(function() { |
| 185 | done(); |
| 186 | }, 200); |
| 187 | |
| 188 | n1.send(); |
| 189 | }); |
| 190 | |
| 191 | it('emits messages ignoring non-existent nodes', function(done) { |
| 192 | var n1 = new RedNode({id:'n1',type:'abc',wires:[['n9'],['n2']]}); |
| 193 | var n2 = new RedNode({id:'n2',type:'abc'}); |
| 194 | |
| 195 | var messages = [ |
| 196 | {payload:"hello world"}, |
| 197 | {payload:"hello world again"} |
| 198 | ]; |
| 199 | |
| 200 | n2.on('input',function(msg) { |
| 201 | should.deepEqual(msg,messages[1]); |
| 202 | should.notStrictEqual(msg,messages[1]); |
| 203 | done(); |
| 204 | }); |
| 205 | |
| 206 | n1.send(messages); |
| 207 | }); |
| 208 | |
| 209 | it('emits messages without cloning req or res', function(done) { |
| 210 | var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]}); |
| 211 | var n2 = new RedNode({id:'n2',type:'abc'}); |
| 212 | |
| 213 | var req = {}; |
| 214 | var res = {}; |
| 215 | var cloned = {}; |
| 216 | var message = {payload: "foo", cloned: cloned, req: req, res: res}; |
| 217 | |
| 218 | n2.on('input',function(msg) { |
| 219 | should.deepEqual(msg, message); |
| 220 | msg.cloned.should.not.be.exactly(message.cloned); |
| 221 | msg.req.should.be.exactly(message.req); |
| 222 | msg.res.should.be.exactly(message.res); |
| 223 | done(); |
| 224 | }); |
| 225 | |
| 226 | n1.send(message); |
| 227 | }); |
| 228 | |
| 229 | }); |
| 230 | |
| 231 | describe('#log', function() { |
| 232 | it('emits a log message', function(done) { |
| 233 | var n = new RedNode({id:'123',type:'abc'}); |
| 234 | n.on('log',function(obj) { |
| 235 | should.deepEqual({level:"log", id:n.id, |
| 236 | type:n.type, msg:"a log message"}, obj); |
| 237 | done(); |
| 238 | }); |
| 239 | n.log("a log message"); |
| 240 | }); |
| 241 | }); |
| 242 | |
| 243 | describe('#log', function() { |
| 244 | it('emits a log message with a name', function(done) { |
| 245 | var n = new RedNode({id:'123', type:'abc', name:"barney"}); |
| 246 | n.on('log',function(obj) { |
| 247 | should.deepEqual({level:"log", id:n.id, name: "barney", |
| 248 | type:n.type, msg:"a log message"}, obj); |
| 249 | done(); |
| 250 | }); |
| 251 | n.log("a log message"); |
| 252 | }); |
| 253 | }); |
| 254 | |
| 255 | describe('#warn', function() { |
| 256 | it('emits a warning', function(done) { |
| 257 | var n = new RedNode({id:'123',type:'abc'}); |
| 258 | n.on('log',function(obj) { |
| 259 | should.deepEqual({level:"warn", id:n.id, |
| 260 | type:n.type, msg:"a warning"}, obj); |
| 261 | done(); |
| 262 | }); |
| 263 | n.warn("a warning"); |
| 264 | }); |
| 265 | }); |
| 266 | |
| 267 | describe('#error', function() { |
| 268 | it('emits an error message', function(done) { |
| 269 | var n = new RedNode({id:'123',type:'abc'}); |
| 270 | n.on('log',function(obj) { |
| 271 | should.deepEqual({level:"error", id:n.id, |
| 272 | type:n.type, msg:"an error message"}, obj); |
| 273 | done(); |
| 274 | }); |
| 275 | n.error("an error message"); |
| 276 | }); |
| 277 | }); |
| 278 | |
| 279 | describe('#status', function() { |
| 280 | after(function() { |
| 281 | comms.publish.restore(); |
| 282 | }); |
| 283 | it('publishes status', function(done) { |
| 284 | var n = new RedNode({id:'123',type:'abc'}); |
| 285 | var status = {fill:"green",shape:"dot",text:"connected"}; |
| 286 | sinon.stub(comms, 'publish', function(topic, message, retain) { |
| 287 | topic.should.equal('status/123'); |
| 288 | message.should.equal(status); |
| 289 | retain.should.be.true; |
| 290 | done(); |
| 291 | }); |
| 292 | |
| 293 | n.status(status); |
| 294 | }); |
| 295 | }); |
| 296 | |
| 297 | }); |