Move tests to match source hierarchy.

This commit is contained in:
Mark Hindess
2014-07-17 08:06:30 +01:00
parent 2b423fe9be
commit 67bd4f373f
6 changed files with 9 additions and 9 deletions

239
test/red/nodes/Node_spec.js Normal file
View File

@@ -0,0 +1,239 @@
/**
* Copyright 2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var RedNode = require("../../../red/nodes/Node");
describe('Node', function() {
describe('#constructor',function() {
it('is called with an id and a type',function() {
var n = new RedNode({id:'123',type:'abc'});
n.should.have.property('id','123');
n.should.have.property('type','abc');
n.should.not.have.property('name');
n.wires.should.be.empty;
});
it('is called with an id, a type and a name',function() {
var n = new RedNode({id:'123',type:'abc',name:'barney'});
n.should.have.property('id','123');
n.should.have.property('type','abc');
n.should.have.property('name','barney');
n.wires.should.be.empty;
});
it('is called with an id, a type and some wires',function() {
var n = new RedNode({id:'123',type:'abc',wires:['123','456']});
n.should.have.property('id','123');
n.should.have.property('type','abc');
n.should.not.have.property('name');
n.wires.should.have.length(2);
});
});
describe('#close', function() {
it('emits close event when closed',function(done) {
var n = new RedNode({id:'123',type:'abc'});
n.on('close',function() {
done();
});
var p = n.close();
should.not.exist(p);
});
it('returns a promise when provided a callback with a done parameter',function(testdone) {
var n = new RedNode({id:'123',type:'abc'});
n.on('close',function(done) {
setTimeout(function() {
done();
},200);
});
var p = n.close();
should.exist(p);
p.then(function() {
testdone();
});
});
});
describe('#receive', function() {
it('emits input event when called', function(done) {
var n = new RedNode({id:'123',type:'abc'});
var message = {payload:"hello world"};
n.on('input',function(msg) {
should.deepEqual(msg,message);
done();
});
n.receive(message);
});
});
describe('#send', function() {
it('emits a single message', function(done) {
var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
var n2 = new RedNode({id:'n2',type:'abc'});
var message = {payload:"hello world"};
n2.on('input',function(msg) {
// msg equals message, but is a new copy
should.deepEqual(msg,message);
should.notStrictEqual(msg,message);
done();
});
n1.send(message);
});
it('emits multiple messages on a single output', function(done) {
var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
var n2 = new RedNode({id:'n2',type:'abc'});
var messages = [
{payload:"hello world"},
{payload:"hello world again"}
];
var rcvdCount = 0;
n2.on('input',function(msg) {
should.deepEqual(msg,messages[rcvdCount]);
should.notStrictEqual(msg,messages[rcvdCount]);
rcvdCount += 1;
if (rcvdCount == 2) {
done();
}
});
n1.send([messages]);
});
it('emits messages to multiple outputs', function(done) {
var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2'],['n3'],['n4','n5']]});
var n2 = new RedNode({id:'n2',type:'abc'});
var n3 = new RedNode({id:'n3',type:'abc'});
var n4 = new RedNode({id:'n4',type:'abc'});
var n5 = new RedNode({id:'n5',type:'abc'});
var messages = [
{payload:"hello world"},
null,
{payload:"hello world again"}
];
var rcvdCount = 0;
n2.on('input',function(msg) {
should.deepEqual(msg,messages[0]);
should.notStrictEqual(msg,messages[0]);
rcvdCount += 1;
if (rcvdCount == 3) {
done();
}
});
n3.on('input',function(msg) {
should.fail(null,null,"unexpected message");
});
n4.on('input',function(msg) {
should.deepEqual(msg,messages[2]);
should.notStrictEqual(msg,messages[2]);
rcvdCount += 1;
if (rcvdCount == 3) {
done();
}
});
n5.on('input',function(msg) {
should.deepEqual(msg,messages[2]);
should.notStrictEqual(msg,messages[2]);
rcvdCount += 1;
if (rcvdCount == 3) {
done();
}
});
n1.send(messages);
});
it('emits no messages', function(done) {
var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
var n2 = new RedNode({id:'n2',type:'abc'});
n2.on('input',function(msg) {
should.fail(null,null,"unexpected message");
});
setTimeout(function() {
done();
}, 200);
n1.send();
});
});
describe('#log', function() {
it('emits a log message', function(done) {
var n = new RedNode({id:'123',type:'abc'});
n.on('log',function(obj) {
should.deepEqual({level:"log", id:n.id,
type:n.type, msg:"a log message"}, obj);
done();
});
n.log("a log message");
});
});
describe('#log', function() {
it('emits a log message with a name', function(done) {
var n = new RedNode({id:'123', type:'abc', name:"barney"});
n.on('log',function(obj) {
should.deepEqual({level:"log", id:n.id, name: "barney",
type:n.type, msg:"a log message"}, obj);
done();
});
n.log("a log message");
});
});
describe('#warn', function() {
it('emits a warning', function(done) {
var n = new RedNode({id:'123',type:'abc'});
n.on('log',function(obj) {
should.deepEqual({level:"warn", id:n.id,
type:n.type, msg:"a warning"}, obj);
done();
});
n.warn("a warning");
});
});
describe('#error', function() {
it('emits an error message', function(done) {
var n = new RedNode({id:'123',type:'abc'});
n.on('log',function(obj) {
should.deepEqual({level:"error", id:n.id,
type:n.type, msg:"an error message"}, obj);
done();
});
n.error("an error message");
});
});
});

View File

@@ -0,0 +1,119 @@
/**
* Copyright 2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var sinon = require("sinon");
var when = require("when");
var credentials = require("../red/nodes/credentials");
describe('Credentials', function() {
it('loads from storage',function(done) {
var storage = {
getCredentials: function() {
console.log("ONE");
return when.promise(function(resolve,reject) {
resolve({"a":{"b":1,"c":2}});
});
}
};
credentials.init(storage);
credentials.load().then(function() {
credentials.get("a").should.have.property('b',1);
credentials.get("a").should.have.property('c',2);
done();
});
});
it('saves to storage', function(done) {
var storage = {
getCredentials: function() {
return when.promise(function(resolve,reject) {
resolve({"a":{"b":1,"c":2}});
});
},
saveCredentials: function(creds) {
return when(true);
}
};
sinon.spy(storage,"saveCredentials");
credentials.init(storage);
credentials.load().then(function() {
should.not.exist(credentials.get("b"))
credentials.add('b',{"d":3});
storage.saveCredentials.callCount.should.be.exactly(1);
credentials.get("b").should.have.property('d',3);
done();
});
});
it('deletes from storage', function(done) {
var storage = {
getCredentials: function() {
return when.promise(function(resolve,reject) {
resolve({"a":{"b":1,"c":2}});
});
},
saveCredentials: function(creds) {
return when(true);
}
};
sinon.spy(storage,"saveCredentials");
credentials.init(storage);
credentials.load().then(function() {
should.exist(credentials.get("a"))
credentials.delete('a');
storage.saveCredentials.callCount.should.be.exactly(1);
should.not.exist(credentials.get("a"));
done();
});
});
it('clean up from storage', function(done) {
var storage = {
getCredentials: function() {
return when.promise(function(resolve,reject) {
resolve({"a":{"b":1,"c":2}});
});
},
saveCredentials: function(creds) {
return when(true);
}
};
sinon.spy(storage,"saveCredentials");
credentials.init(storage);
credentials.load().then(function() {
should.exist(credentials.get("a"));
credentials.clean(function() {
return false;
});
storage.saveCredentials.callCount.should.be.exactly(1);
should.not.exist(credentials.get("a"));
done();
});
});
})

View File

@@ -0,0 +1,121 @@
/**
* Copyright 2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var when = require("when");
var flows = require("../../../red/nodes/flows");
var RedNode = require("../../../red/nodes/Node");
var RED = require("../../../red/nodes");
var events = require("../../../red/events");
function loadFlows(testFlows, cb) {
var storage = {
getFlows: function() {
var defer = when.defer();
defer.resolve(testFlows);
return defer.promise;
},
getCredentials: function() {
var defer = when.defer();
defer.resolve({});
return defer.promise;
},
};
RED.init({}, storage);
flows.load().then(function() {
should.deepEqual(testFlows, flows.getFlows());
cb();
});
}
describe('flows', function() {
describe('#add',function() {
it('should be called by node constructor',function(done) {
var n = new RedNode({id:'123',type:'abc'});
should.deepEqual(n, flows.get("123"));
flows.clear().then(function() {
done();
});
});
});
describe('#each',function() {
it('should "visit" all nodes',function(done) {
var nodes = [
new RedNode({id:'n0'}),
new RedNode({id:'n1'})
];
var count = 0;
flows.each(function(node) {
should.deepEqual(nodes[count], node);
count += 1;
if (count == 2) {
done();
}
});
});
});
describe('#load',function() {
it('should load nothing when storage is empty',function(done) {
loadFlows([], done);
});
it('should load and start an empty tab flow',function(done) {
loadFlows([{"type":"tab","id":"tab1","label":"Sheet 1"}],
function() {});
events.once('nodes-started', function() { done(); });
});
it('should load and start a registered node type', function(done) {
RED.registerType('debug', function() {});
loadFlows([{"id":"n1","type":"debug"}], function() { });
events.once('nodes-started', function() { done(); });
});
it('should load and start when node type is registered',
function(done) {
loadFlows([{"id":"n2","type":"inject"}],
function() {
RED.registerType('inject', function() { });
});
events.once('nodes-started', function() { done(); });
});
});
describe('#setFlows',function() {
it('should save and start an empty tab flow',function(done) {
var saved = 0;
var testFlows = [{"type":"tab","id":"tab1","label":"Sheet 1"}];
var storage = {
saveFlows: function(conf) {
var defer = when.defer();
defer.resolve();
should.deepEqual(testFlows, conf);
return defer.promise;
},
saveCredentials: function (creds) {
return when(true);
}
};
RED.init({}, storage);
flows.setFlows(testFlows);
events.once('nodes-started', function() { done(); });
});
});
});

View File

@@ -0,0 +1,34 @@
/**
* Copyright 2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var RedNodes = require("../../../red/nodes");
var RedNode = require("../../../red/nodes/Node");
describe('NodeRegistry', function() {
it('automatically registers new nodes',function() {
var testNode = RedNodes.getNode('123');
should.not.exist(n);
var n = new RedNode({id:'123',type:'abc'});
var newNode = RedNodes.getNode('123');
should.strictEqual(n,newNode);
});
})

View File

@@ -0,0 +1,367 @@
/**
* Copyright 2013, 2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var fs = require('fs-extra');
var path = require('path');
var localfilesystem = require("../../../red/storage/localfilesystem");
describe('LocalFileSystem', function() {
var userDir = path.join(__dirname,".testUserHome");
var testFlow = [{"type":"tab","id":"d8be2a6d.2741d8","label":"Sheet 1"}];
beforeEach(function(done) {
fs.remove(userDir,function(err) {
fs.mkdir(userDir,done);
});
});
afterEach(function(done) {
fs.remove(userDir,done);
});
it('should initialise the user directory',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
fs.existsSync(path.join(userDir,"lib")).should.be.true;
fs.existsSync(path.join(userDir,"lib",'flows')).should.be.true;
done();
}).otherwise(function(err) {
done(err);
});
});
it('should handle missing flow file',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
var flowFile = 'flows_'+require('os').hostname()+'.json';
var flowFilePath = path.join(userDir,flowFile);
fs.existsSync(flowFilePath).should.be.false;
localfilesystem.getFlows().then(function(flows) {
flows.should.eql([]);
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should save flows to the default file',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
var flowFile = 'flows_'+require('os').hostname()+'.json';
var flowFilePath = path.join(userDir,flowFile);
var flowFileBackupPath = path.join(userDir,"flows.backup");
fs.existsSync(flowFilePath).should.be.false;
fs.existsSync(flowFileBackupPath).should.be.false;
localfilesystem.saveFlows(testFlow).then(function() {
fs.existsSync(flowFilePath).should.be.true;
fs.existsSync(flowFileBackupPath).should.be.false;
localfilesystem.getFlows().then(function(flows) {
flows.should.eql(testFlow);
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should save flows to the specified file',function(done) {
var defaultFlowFile = 'flows_'+require('os').hostname()+'.json';
var defaultFlowFilePath = path.join(userDir,defaultFlowFile);
var flowFile = 'test.json';
var flowFilePath = path.join(userDir,flowFile);
localfilesystem.init({userDir:userDir, flowFile:flowFilePath}).then(function() {
fs.existsSync(defaultFlowFilePath).should.be.false;
fs.existsSync(flowFilePath).should.be.false;
localfilesystem.saveFlows(testFlow).then(function() {
fs.existsSync(defaultFlowFilePath).should.be.false;
fs.existsSync(flowFilePath).should.be.true;
localfilesystem.getFlows().then(function(flows) {
flows.should.eql(testFlow);
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should backup the flows file', function(done) {
var defaultFlowFile = 'flows_'+require('os').hostname()+'.json';
var defaultFlowFilePath = path.join(userDir,defaultFlowFile);
var flowFile = 'test.json';
var flowFilePath = path.join(userDir,flowFile);
var flowFileBackupPath = path.join(userDir,"flows.backup");
localfilesystem.init({userDir:userDir, flowFile:flowFilePath}).then(function() {
fs.existsSync(defaultFlowFilePath).should.be.false;
fs.existsSync(flowFilePath).should.be.false;
fs.existsSync(flowFileBackupPath).should.be.false;
localfilesystem.saveFlows(testFlow).then(function() {
fs.existsSync(flowFileBackupPath).should.be.false;
fs.existsSync(defaultFlowFilePath).should.be.false;
fs.existsSync(flowFilePath).should.be.true;
var content = fs.readFileSync(flowFilePath,'utf8');
var testFlow2 = [{"type":"tab","id":"bc5672ad.2741d8","label":"Sheet 2"}];
localfilesystem.saveFlows(testFlow2).then(function() {
fs.existsSync(flowFileBackupPath).should.be.true;
fs.existsSync(defaultFlowFilePath).should.be.false;
fs.existsSync(flowFilePath).should.be.true;
var backupContent = fs.readFileSync(flowFileBackupPath,'utf8');
content.should.equal(backupContent);
var content2 = fs.readFileSync(flowFilePath,'utf8');
content2.should.not.equal(backupContent);
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should handle missing credentials', function(done) {
var flowFile = 'test.json';
var flowFilePath = path.join(userDir,flowFile);
var credFile = path.join(userDir,"test_cred.json");
localfilesystem.init({userDir:userDir, flowFile:flowFilePath}).then(function() {
fs.existsSync(credFile).should.be.false;
localfilesystem.getCredentials().then(function(creds) {
creds.should.eql({});
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should handle credentials', function(done) {
var flowFile = 'test.json';
var flowFilePath = path.join(userDir,flowFile);
var credFile = path.join(userDir,"test_cred.json");
localfilesystem.init({userDir:userDir, flowFile:flowFilePath}).then(function() {
fs.existsSync(credFile).should.be.false;
var credentials = {"abc":{"type":"creds"}};
localfilesystem.saveCredentials(credentials).then(function() {
fs.existsSync(credFile).should.be.true;
localfilesystem.getCredentials().then(function(creds) {
creds.should.eql(credentials);
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should return an empty list of library flows',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
localfilesystem.getAllFlows().then(function(flows) {
flows.should.eql({});
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should return a valid list of library flows',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
var flowLib = path.join(userDir,"lib","flows");
fs.closeSync(fs.openSync(path.join(flowLib,"A.json"),"w"));
fs.closeSync(fs.openSync(path.join(flowLib,"B.json"),"w"));
fs.mkdirSync(path.join(flowLib,"C"));
fs.closeSync(fs.openSync(path.join(flowLib,"C","D.json"),"w"));
var testFlowsList = {"d":{"C":{"f":["D"]}},"f":["A","B"]};
localfilesystem.getAllFlows().then(function(flows) {
flows.should.eql(testFlowsList);
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should fail a non-existent flow', function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
localfilesystem.getFlow("a/b/c.json").then(function(flow) {
should.fail(flow,"No flow","Flow found");
}).otherwise(function(err) {
// err should be null, so this will pass
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should return a flow',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
var testflowString = JSON.stringify(testFlow);
localfilesystem.saveFlow("a/b/c/d.json",testflowString).then(function() {
localfilesystem.getFlow("a/b/c/d.json").then(function(flow) {
flow.should.eql(testflowString);
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should return an empty list of library objects',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
localfilesystem.getLibraryEntry('object','').then(function(flows) {
flows.should.eql({});
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should return an error for a non-existent library object',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
localfilesystem.getLibraryEntry('object','A/B').then(function(flows) {
should.fail(null,null,"non-existent flow");
}).otherwise(function(err) {
should.exist(err);
done();
});
}).otherwise(function(err) {
done(err);
});
});
function createObjectLibrary() {
var objLib = path.join(userDir,"lib","object");
fs.mkdirSync(objLib);
fs.mkdirSync(path.join(objLib,"A"));
fs.mkdirSync(path.join(objLib,"B"));
fs.mkdirSync(path.join(objLib,"B","C"));
fs.writeFileSync(path.join(objLib,"file1.js"),"// abc: def\n// not a metaline \n\n Hi",'utf8');
fs.writeFileSync(path.join(objLib,"B","file2.js"),"// ghi: jkl\n// not a metaline \n\n Hi",'utf8');
}
it('should return a directory listing of library objects',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
createObjectLibrary();
localfilesystem.getLibraryEntry('object','').then(function(flows) {
flows.should.eql([ 'A', 'B', { abc: 'def', fn: 'file1.js' } ]);
localfilesystem.getLibraryEntry('object','B').then(function(flows) {
flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]);
localfilesystem.getLibraryEntry('object','B/C').then(function(flows) {
flows.should.eql([]);
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should return a library object',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
createObjectLibrary();
localfilesystem.getLibraryEntry('object','B/file2.js').then(function(body) {
body.should.eql("// not a metaline \n\n Hi");
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
it('should return a newly saved library object',function(done) {
localfilesystem.init({userDir:userDir}).then(function() {
createObjectLibrary();
localfilesystem.getLibraryEntry('object','B').then(function(flows) {
flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]);
localfilesystem.saveLibraryEntry('object','B/D/file3.js',{mno:'pqr'},"// another non meta line\n\n Hi There").then(function() {
localfilesystem.getLibraryEntry('object','B/D').then(function(flows) {
flows.should.eql([ { mno: 'pqr', fn: 'file3.js' } ]);
localfilesystem.getLibraryEntry('object','B/D/file3.js').then(function(body) {
body.should.eql("// another non meta line\n\n Hi There");
done();
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
}).otherwise(function(err) {
done(err);
});
});
});