fix odl patches
[ccsdk/distribution.git] / dgbuilder / test / red / nodes / credentials_spec.js
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 when = require("when");
20 var util = require("util");
21
22 var index = require("../../../red/nodes/index");
23 var credentials = require("../../../red/nodes/credentials");
24
25 describe('Credentials', function() {
26     
27     afterEach(function() {
28         index.clearRegistry();
29     });
30     
31     it('loads from storage',function(done) {
32         
33         var storage = {
34             getCredentials: function() {
35                 return when.promise(function(resolve,reject) {
36                     resolve({"a":{"b":1,"c":2}});
37                 });
38             }
39         };
40         
41         credentials.init(storage);
42         
43         credentials.load().then(function() {
44                 
45             credentials.get("a").should.have.property('b',1);
46             credentials.get("a").should.have.property('c',2);
47             
48             done();
49         });
50     });
51     
52     
53     it('saves to storage', function(done) {
54         var storage = {
55             getCredentials: function() {
56                 return when.promise(function(resolve,reject) {
57                     resolve({"a":{"b":1,"c":2}});
58                 });
59             },
60             saveCredentials: function(creds) {
61                 return when(true);
62             }
63         };
64         sinon.spy(storage,"saveCredentials");
65         credentials.init(storage);
66         credentials.load().then(function() {
67             should.not.exist(credentials.get("b"))
68             credentials.add('b',{"d":3});
69             storage.saveCredentials.callCount.should.be.exactly(1);
70             credentials.get("b").should.have.property('d',3);
71             storage.saveCredentials.restore();
72             done();
73         });
74     });
75     
76     it('deletes from storage', function(done) {
77         var storage = {
78             getCredentials: function() {
79                 return when.promise(function(resolve,reject) {
80                     resolve({"a":{"b":1,"c":2}});
81                 });
82             },
83             saveCredentials: function(creds) {
84                 return when(true);
85             }
86         };
87         sinon.spy(storage,"saveCredentials");
88         credentials.init(storage);
89         credentials.load().then(function() {
90             should.exist(credentials.get("a"))
91             credentials.delete('a');
92             storage.saveCredentials.callCount.should.be.exactly(1);
93             should.not.exist(credentials.get("a"));
94             storage.saveCredentials.restore();
95             done();
96         });
97             
98     });
99             
100     it('clean up from storage', function(done) {
101         var storage = {
102             getCredentials: function() {
103                 return when.promise(function(resolve,reject) {
104                     resolve({"a":{"b":1,"c":2}});
105                 });
106             },
107             saveCredentials: function(creds) {
108                 return when(true);
109             }
110         };
111         sinon.spy(storage,"saveCredentials");
112         credentials.init(storage);
113         credentials.load().then(function() {
114             should.exist(credentials.get("a"));
115             credentials.clean(function() {
116                 return false;
117             });
118             storage.saveCredentials.callCount.should.be.exactly(1);
119             should.not.exist(credentials.get("a"));
120             storage.saveCredentials.restore();
121             done();
122         });
123     });
124     
125     it('handle error loading from storage', function(done) {
126         var storage = {
127             getCredentials: function() {
128                 return when.promise(function(resolve,reject) {
129                     reject("test forcing failure");
130                 });
131             },
132             saveCredentials: function(creds) {
133                 return when(true);
134             }
135         };
136         var logmsg = 'no errors yet';
137         sinon.stub(util, 'log', function(msg) {
138             logmsg = msg;
139         });
140         
141         credentials.init(storage);
142         credentials.load().then(function() {
143             should.equal('[red] Error loading credentials : test forcing failure', logmsg);
144             util.log.restore();
145             done();
146         }).otherwise(function(err){
147             util.log.restore();
148             done(err);
149         });
150     });
151     
152     it('credential type is not registered when extract', function(done) {
153         var testFlows = [{"type":"test","id":"tab1","label":"Sheet 1"}];
154         var storage = {
155                 getFlows: function() {
156                     var defer = when.defer();
157                     defer.resolve(testFlows);
158                     return defer.promise;
159                 },
160                 getCredentials: function() {
161                     return when.promise(function(resolve,reject) {
162                         resolve({"tab1":{"b":1,"c":2}});
163                     });
164                 },
165                 saveFlows: function(conf) {
166                     var defer = when.defer();
167                     defer.resolve();
168                     should.deepEqual(testFlows, conf);
169                     return defer.promise;
170                 },
171                 saveCredentials: function(creds) {
172                     return when(true);
173                 },
174                 getSettings: function() {
175                     return when({});
176                 },
177                 saveSettings: function(s) {
178                     return when();
179                 }
180         };
181         function TestNode(n) {
182             index.createNode(this, n);
183             
184             this.id = 'tab1';
185             this.type = 'test';
186             this.name = 'barney';
187             var node = this;
188
189             this.on("log", function() {
190                 // do nothing
191             });
192         }
193         var logmsg = 'nothing logged yet';
194         sinon.stub(util, 'log', function(msg) {
195             logmsg = msg;
196         });
197         var settings = {
198             available: function() { return false;}
199         }
200         index.init(settings, storage);
201         index.registerType('test', TestNode);   
202         index.loadFlows().then(function() {
203             var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});   
204             credentials.extract(testnode);
205             should.equal(logmsg, 'Credential Type test is not registered.');
206             util.log.restore();
207             done();
208         }).otherwise(function(err){
209             util.log.restore();
210             done(err);
211         });
212     });
213     
214     describe('extract and store credential updates in the provided node', function() {
215         var path = require('path');
216         var fs = require('fs-extra');
217         var http = require('http');
218         var express = require('express');
219         var server = require("../../../red/server");
220         var localfilesystem = require("../../../red/storage/localfilesystem");
221         var app = express();
222         var RED = require("../../../red/red.js");
223         
224         var userDir = path.join(__dirname,".testUserHome");
225         before(function(done) {
226             fs.remove(userDir,function(err) {
227                 fs.mkdir(userDir,function() {
228                     sinon.stub(index, 'load', function() {
229                         return when.promise(function(resolve,reject){
230                             resolve([]);
231                         });
232                     });
233                     sinon.stub(localfilesystem, 'getCredentials', function() {
234                          return when.promise(function(resolve,reject) {
235                                 resolve({"tab1":{"foo": 2, "pswd":'sticks'}});
236                          });
237                     }) ;
238                     RED.init(http.createServer(function(req,res){app(req,res)}),
239                              {userDir: userDir});
240                     server.start().then(function () {
241                         done(); 
242                      });
243                 });
244             });
245         });
246     
247         after(function(done) {
248             fs.remove(userDir,done);
249             server.stop();
250             index.load.restore();
251             localfilesystem.getCredentials.restore();
252         });
253     
254         function TestNode(n) {
255             index.createNode(this, n);
256             var node = this;
257             this.on("log", function() {
258                 // do nothing
259             });
260         }
261         
262         it(': credential updated with good value', function(done) {
263             index.registerType('test', TestNode, {
264                 credentials: {
265                     foo: {type:"test"}
266                 }
267             });   
268             index.loadFlows().then(function() {
269                 var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});   
270                 credentials.extract(testnode);
271                 should.exist(credentials.get('tab1'));
272                 credentials.get('tab1').should.have.property('foo',2);
273                 
274                 // set credentials to be an updated value and checking this is extracted properly
275                 testnode.credentials = {"foo": 3};
276                 credentials.extract(testnode);
277                 should.exist(credentials.get('tab1'));
278                 credentials.get('tab1').should.not.have.property('foo',2);
279                 credentials.get('tab1').should.have.property('foo',3);
280                 done();                    
281             }).otherwise(function(err){
282                 done(err);
283             });
284         });
285
286         it(': credential updated with empty value', function(done) {
287             index.registerType('test', TestNode, {
288                 credentials: {
289                     foo: {type:"test"}
290                 }
291             });   
292             index.loadFlows().then(function() {
293                 var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});   
294                 // setting value of "foo" credential to be empty removes foo as a property
295                 testnode.credentials = {"foo": ''};
296                 credentials.extract(testnode);
297                 should.exist(credentials.get('tab1'));
298                 credentials.get('tab1').should.not.have.property('foo',2);
299                 credentials.get('tab1').should.not.have.property('foo');
300                 done();                    
301             }).otherwise(function(err){
302                 done(err);
303             });
304         });
305  
306         it(': undefined credential updated', function(done) {
307             index.registerType('test', TestNode, {
308                 credentials: {
309                     foo: {type:"test"}
310                 }
311             });   
312             index.loadFlows().then(function() {
313                 var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});   
314                 // setting value of an undefined credential should not change anything
315                 testnode.credentials = {"bar": 4};
316                 credentials.extract(testnode);
317                 should.exist(credentials.get('tab1'));
318                 credentials.get('tab1').should.have.property('foo',2);
319                 credentials.get('tab1').should.not.have.property('bar');
320                 done();                    
321             }).otherwise(function(err){
322                 done(err);
323             });
324         });
325         
326         it(': password credential updated', function(done) {
327             index.registerType('password', TestNode, {
328                 credentials: {
329                     pswd: {type:"password"}
330                 }
331             });   
332             index.loadFlows().then(function() {
333                 var testnode = new TestNode({id:'tab1',type:'password',name:'barney'});   
334                 // setting value of password credential should update password 
335                 testnode.credentials = {"pswd": 'fiddle'};
336                 credentials.extract(testnode);
337                 should.exist(credentials.get('tab1'));
338                 credentials.get('tab1').should.have.property('pswd','fiddle');
339                 credentials.get('tab1').should.not.have.property('pswd','sticks');
340                 done();                    
341             }).otherwise(function(err){
342                 done(err);
343             });
344         });    
345
346         it(': password credential not updated', function(done) {
347             index.registerType('password', TestNode, {
348                 credentials: {
349                     pswd: {type:"password"}
350                 }
351             });   
352             index.loadFlows().then(function() {
353                 var testnode = new TestNode({id:'tab1',type:'password',name:'barney'});   
354                 // setting value of password credential should update password 
355                 testnode.credentials = {"pswd": '__PWRD__'};
356                 credentials.extract(testnode);
357                 should.exist(credentials.get('tab1'));
358                 credentials.get('tab1').should.have.property('pswd','sticks');
359                 credentials.get('tab1').should.not.have.property('pswd','__PWRD__');
360                 done();                    
361             }).otherwise(function(err){
362                 done(err);
363             });
364         });    
365     
366     })
367
368     describe('registerEndpoint', function() {
369         var path = require('path');
370         var fs = require('fs-extra');
371         var http = require('http');
372         var express = require('express');
373         var request = require('supertest');
374         
375         var server = require("../../../red/server");
376         var localfilesystem = require("../../../red/storage/localfilesystem");
377         var app = express();
378         var RED = require("../../../red/red.js");
379         
380         var userDir = path.join(__dirname,".testUserHome");
381         before(function(done) {
382             fs.remove(userDir,function(err) {
383                 fs.mkdir(userDir,function() {
384                     sinon.stub(index, 'load', function() {
385                         return when.promise(function(resolve,reject){
386                             resolve([]);
387                         });
388                     });
389                     sinon.stub(localfilesystem, 'getCredentials', function() {
390                          return when.promise(function(resolve,reject) {
391                                 resolve({"tab1":{"foo": 2, "pswd":'sticks'}});
392                          });
393                     }) ;
394                     RED.init(http.createServer(function(req,res){app(req,res)}),
395                              {userDir: userDir});
396                     server.start().then(function () {
397                         done(); 
398                      });
399                 });
400             });
401         });
402     
403         after(function(done) {
404             fs.remove(userDir,done);
405             server.stop();
406             index.load.restore();
407             localfilesystem.getCredentials.restore();
408         });
409     
410         function TestNode(n) {
411             index.createNode(this, n);
412             var node = this;
413             this.on("log", function() {
414                 // do nothing
415             });
416         }
417         
418         it(': valid credential type', function(done) {
419             index.registerType('test', TestNode, {
420                 credentials: {
421                     foo: {type:"test"}
422                 }
423             });   
424             index.loadFlows().then(function() {
425                 var testnode = new TestNode({id:'tab1',type:'foo',name:'barney'});   
426                 request(RED.httpAdmin).get('/credentials/test/tab1').expect(200).end(function(err,res) {
427                     if (err) {
428                         done(err);
429                     }
430                     res.body.should.have.property('foo', 2);
431                     done();
432                 });              
433             }).otherwise(function(err){
434                 done(err);
435             });
436         });
437         
438         it(': password credential type', function(done) {
439             index.registerType('password', TestNode, {
440                 credentials: {
441                     pswd: {type:"password"}
442                 }
443             });   
444             index.loadFlows().then(function() {
445                 var testnode = new TestNode({id:'tab1',type:'pswd',name:'barney'});   
446                 request(RED.httpAdmin).get('/credentials/password/tab1').expect(200).end(function(err,res) {
447                     if (err) {
448                         done(err);
449                     }
450                     res.body.should.have.property('has_pswd', true);
451                     res.body.should.not.have.property('pswd');
452                     done();
453                 });              
454             }).otherwise(function(err){
455                 done(err);
456             });
457         });    
458         
459         it(': returns 404 for undefined credential type', function(done) {
460             index.registerType('test', TestNode, {
461                 credentials: {
462                     foo: {type:"test"}
463                 }
464             });   
465             index.loadFlows().then(function() {
466                 var testnode = new TestNode({id:'tab1',type:'foo',name:'barney'});   
467                 request(RED.httpAdmin).get('/credentials/unknownType/tab1').expect(404).end(done);              
468             }).otherwise(function(err){
469                 done(err);
470             });
471         });
472         
473         it(': undefined nodeID', function(done) {
474             index.registerType('test', TestNode, {
475                 credentials: {
476                     foo: {type:"test"}
477                 }
478             });   
479             index.loadFlows().then(function() {
480                 var testnode = new TestNode({id:'tab1',type:'foo',name:'barney'});   
481                 request(RED.httpAdmin).get('/credentials/test/unknownNode').expect(200).end(function(err,res) {
482                     if (err) {
483                         done(err);
484                     }
485                     var b = res.body;
486                     res.body.should.not.have.property('foo');
487                     done();
488                 });              
489             }).otherwise(function(err){
490                 done(err);
491             });
492         });
493         
494     })        
495     
496 })     
497