Remove known unused files

This commit is contained in:
andrew.greene
2021-12-08 18:01:31 -07:00
parent 419a81034c
commit b1daa8932a
367 changed files with 1 additions and 75791 deletions

View File

@@ -1,30 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* 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 NR_TEST_UTILS = require("nr-test-utils");
var deprecated = NR_TEST_UTILS.require("@node-red/registry/lib/deprecated.js");
describe('deprecated', function() {
it('should return info on a node',function() {
deprecated.get("irc in").should.eql({module:"node-red-node-irc"});
});
it('should return null for non-deprecated node',function() {
should.not.exist(deprecated.get("foo"));
});
});

View File

@@ -1,371 +0,0 @@
// init: init,
// register: register,
// registerSubflow: registerSubflow,
// checkFlowDependencies: checkFlowDependencies,
// require: requireModule
//
const should = require("should");
const sinon = require("sinon");
const fs = require("fs-extra");
const path = require("path");
const os = require("os");
const NR_TEST_UTILS = require("nr-test-utils");
const externalModules = NR_TEST_UTILS.require("@node-red/registry/lib/externalModules");
const exec = NR_TEST_UTILS.require("@node-red/util/lib/exec");
const hooks = NR_TEST_UTILS.require("@node-red/util/lib/hooks");
let homeDir;
async function createUserDir() {
if (!homeDir) {
homeDir = path.join(os.tmpdir(),"nr-test-"+Math.floor(Math.random()*100000));
}
await fs.ensureDir(homeDir);
}
async function setupExternalModulesPackage(dependencies) {
await fs.writeFile(path.join(homeDir,"package.json"),`{
"name": "Node-RED-External-Modules",
"description": "These modules are automatically installed by Node-RED to use in Function nodes.",
"version": "1.0.0",
"private": true,
"dependencies": ${JSON.stringify(dependencies)}
}`)
}
describe("externalModules api", function() {
beforeEach(async function() {
await createUserDir()
})
afterEach(async function() {
hooks.clear();
await fs.remove(homeDir);
})
describe("checkFlowDependencies", function() {
beforeEach(function() {
sinon.stub(exec,"run").callsFake(async function(cmd, args, options) {
let error;
let moduleName = args[args.length-1];
if (moduleName === "moduleNotFound") {
error = new Error();
error.stderr = "E404";
} else if (moduleName === "moduleVersionNotFound") {
error = new Error();
error.stderr = "ETARGET";
} else if (moduleName === "moduleFail") {
error = new Error();
error.stderr = "Some unexpected install error";
}
if (error) {
throw error;
}
})
})
afterEach(function() {
exec.run.restore();
})
it("does nothing when no types are registered",async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "foo"}]}
])
exec.run.called.should.be.false();
});
it("skips install for modules already installed", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
await setupExternalModulesPackage({"foo": "1.2.3", "bar":"2.3.4"});
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "foo"}]}
])
exec.run.called.should.be.false();
})
it("skips install for built-in modules", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "fs"}]}
])
exec.run.called.should.be.false();
})
it("installs missing modules", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "foo"}]}
])
exec.run.called.should.be.true();
})
it("calls pre/postInstall hooks", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
let receivedPreEvent,receivedPostEvent;
hooks.add("preInstall", function(event) { event.args = ["a"]; receivedPreEvent = event; })
hooks.add("postInstall", function(event) { receivedPostEvent = event; })
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "foo"}]}
])
exec.run.called.should.be.true();
// exec.run.lastCall.args[1].should.eql([ 'install', 'a', 'foo' ]);
receivedPreEvent.should.have.property("module","foo")
receivedPreEvent.should.have.property("version")
receivedPreEvent.should.have.property("dir")
receivedPreEvent.should.eql(receivedPostEvent)
})
it("skips npm install if preInstall returns false", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
let receivedPreEvent,receivedPostEvent;
hooks.add("preInstall", function(event) { receivedPreEvent = event; return false })
hooks.add("postInstall", function(event) { receivedPostEvent = event; })
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "foo"}]}
])
exec.run.called.should.be.false();
receivedPreEvent.should.have.property("module","foo")
receivedPreEvent.should.have.property("version")
receivedPreEvent.should.have.property("dir")
receivedPreEvent.should.eql(receivedPostEvent)
})
it("installs missing modules from inside subflow module", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
externalModules.registerSubflow("sf", {"flow":[{type: "function", libs:[{module: "foo"}]}]});
await externalModules.checkFlowDependencies([
{type: "sf"}
])
exec.run.called.should.be.true();
})
it("reports install fail - 404", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
try {
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "moduleNotFound"}]}
])
throw new Error("checkFlowDependencies did not reject after install fail")
} catch(err) {
exec.run.called.should.be.true();
Array.isArray(err).should.be.true();
err.should.have.length(1);
err[0].should.have.property("module");
err[0].module.should.have.property("module","moduleNotFound");
err[0].should.have.property("error");
err[0].error.should.have.property("code",404);
}
})
it("reports install fail - target", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
try {
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "moduleVersionNotFound"}]}
])
throw new Error("checkFlowDependencies did not reject after install fail")
} catch(err) {
exec.run.called.should.be.true();
Array.isArray(err).should.be.true();
err.should.have.length(1);
err[0].should.have.property("module");
err[0].module.should.have.property("module","moduleVersionNotFound");
err[0].should.have.property("error");
err[0].error.should.have.property("code",404);
}
})
it("reports install fail - unexpected", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
try {
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "moduleFail"}]}
])
throw new Error("checkFlowDependencies did not reject after install fail")
} catch(err) {
exec.run.called.should.be.true();
Array.isArray(err).should.be.true();
err.should.have.length(1);
err[0].should.have.property("module");
err[0].module.should.have.property("module","moduleFail");
err[0].should.have.property("error");
err[0].error.should.have.property("code","unexpected_error");
}
})
it("reports install fail - multiple", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
externalModules.register("function", "libs");
try {
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "moduleNotFound"},{module: "moduleFail"}]}
])
throw new Error("checkFlowDependencies did not reject after install fail")
} catch(err) {
exec.run.called.should.be.true();
Array.isArray(err).should.be.true();
err.should.have.length(2);
// Sort the array so we know the order to test for
err.sort(function(A,B) {
return A.module.module.localeCompare(B.module.module);
})
err[1].should.have.property("module");
err[1].module.should.have.property("module","moduleNotFound");
err[1].should.have.property("error");
err[1].error.should.have.property("code",404);
err[0].should.have.property("module");
err[0].module.should.have.property("module","moduleFail");
err[0].should.have.property("error");
err[0].error.should.have.property("code","unexpected_error");
}
})
it("reports install fail - install disabled", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}, externalModules: {
modules: {
allowInstall: false
}
}});
externalModules.register("function", "libs");
try {
await externalModules.checkFlowDependencies([
{type: "function", libs:[{module: "foo"}]}
])
throw new Error("checkFlowDependencies did not reject after install fail")
} catch(err) {
// Should not try to install
exec.run.called.should.be.false();
Array.isArray(err).should.be.true();
err.should.have.length(1);
err[0].should.have.property("module");
err[0].module.should.have.property("module","foo");
err[0].should.have.property("error");
err[0].error.should.have.property("code","install_not_allowed");
}
})
it("reports install fail - module disallowed", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}, externalModules: {
modules: {
denyList: ['foo']
}
}});
externalModules.register("function", "libs");
try {
await externalModules.checkFlowDependencies([
// foo disallowed
// bar allowed
{type: "function", libs:[{module: "foo"},{module: "bar"}]}
])
throw new Error("checkFlowDependencies did not reject after install fail")
} catch(err) {
exec.run.calledOnce.should.be.true();
Array.isArray(err).should.be.true();
err.should.have.length(1);
err[0].should.have.property("module");
err[0].module.should.have.property("module","foo");
err[0].should.have.property("error");
err[0].error.should.have.property("code","install_not_allowed");
}
})
it("reports install fail - built-in module disallowed", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}, externalModules: {
modules: {
denyList: ['fs']
}
}});
externalModules.register("function", "libs");
try {
await externalModules.checkFlowDependencies([
// foo disallowed
// bar allowed
{type: "function", libs:[{module: "fs"},{module: "bar"}]}
])
throw new Error("checkFlowDependencies did not reject after install fail")
} catch(err) {
exec.run.calledOnce.should.be.true();
Array.isArray(err).should.be.true();
err.should.have.length(1);
err[0].should.have.property("module");
err[0].module.should.have.property("module","fs");
err[0].should.have.property("error");
err[0].error.should.have.property("code","module_not_allowed");
}
})
})
describe("require", async function() {
it("requires built-in modules", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
const result = externalModules.require("fs")
result.should.eql(require("fs"));
})
it("rejects unknown modules", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
try {
externalModules.require("foo")
throw new Error("require did not reject after fail")
} catch(err) {
err.should.have.property("code","module_not_allowed");
}
})
it("rejects disallowed modules", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}, externalModules: {
modules: {
denyList: ['fs']
}
}});
try {
externalModules.require("fs")
throw new Error("require did not reject after fail")
} catch(err) {
err.should.have.property("code","module_not_allowed");
}
})
})
describe("import", async function() {
it("import built-in modules", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
const result = await externalModules.import("fs")
// `result` won't have the `should` property
should.exist(result);
should.exist(result.existsSync);
})
it("rejects unknown modules", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}});
try {
await externalModules.import("foo")
throw new Error("import did not reject after fail")
} catch(err) {
err.should.have.property("code","module_not_allowed");
}
})
it("rejects disallowed modules", async function() {
externalModules.init({userDir: homeDir, get:()=>{}, set:()=>{}, externalModules: {
modules: {
denyList: ['fs']
}
}});
try {
await externalModules.import("fs")
throw new Error("import did not reject after fail")
} catch(err) {
err.should.have.property("code","module_not_allowed");
}
})
})
});

View File

@@ -1,127 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* 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 path = require("path");
var fs = require("fs");
var NR_TEST_UTILS = require("nr-test-utils");
var registry = NR_TEST_UTILS.require("@node-red/registry");
var installer = NR_TEST_UTILS.require("@node-red/registry/lib/installer");
var loader = NR_TEST_UTILS.require("@node-red/registry/lib/loader");
var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry");
describe('red/registry/index', function() {
var stubs = [];
afterEach(function() {
while(stubs.length) {
stubs.pop().restore();
}
})
describe('#init',function() {
it('intialises components', function() {
stubs.push(sinon.stub(installer,"init"));
stubs.push(sinon.stub(loader,"init"));
stubs.push(sinon.stub(typeRegistry,"init"));
registry.init({settings:{}});
installer.init.called.should.be.true();
loader.init.called.should.be.true();
typeRegistry.init.called.should.be.true();
})
});
describe('#addModule', function() {
it('loads the module and returns its info', function(done) {
stubs.push(sinon.stub(loader,"addModule").callsFake(function(module) {
return Promise.resolve();
}));
stubs.push(sinon.stub(typeRegistry,"getModuleInfo").callsFake(function(module) {
return "info";
}));
registry.addModule("foo").then(function(info) {
info.should.eql("info");
done();
}).catch(function(err) { done(err); });
});
it('rejects if loader rejects', function(done) {
stubs.push(sinon.stub(loader,"addModule").callsFake(function(module) {
return Promise.reject("error");
}));
stubs.push(sinon.stub(typeRegistry,"getModuleInfo").callsFake(function(module) {
return "info";
}));
registry.addModule("foo").then(function(info) {
done(new Error("unexpected resolve"));
}).catch(function(err) {
err.should.eql("error");
done();
})
});
});
describe('#enableNode',function() {
it('enables a node set',function(done) {
stubs.push(sinon.stub(typeRegistry,"enableNodeSet").callsFake(function() {
return Promise.resolve();
}));
stubs.push(sinon.stub(typeRegistry,"getNodeInfo").callsFake(function() {
return {id:"node-set",loaded:true};
}));
registry.enableNode("node-set").then(function(ns) {
typeRegistry.enableNodeSet.called.should.be.true();
ns.should.have.a.property('id','node-set');
done();
}).catch(function(err) { done(err); });
});
it('rejects if node unknown',function() {
stubs.push(sinon.stub(typeRegistry,"enableNodeSet").callsFake(function() {
throw new Error('failure');
}));
/*jshint immed: false */
(function(){
registry.enableNode("node-set")
}).should.throw();
});
it('triggers a node load',function(done) {
stubs.push(sinon.stub(typeRegistry,"enableNodeSet").callsFake(function() {
return Promise.resolve();
}));
var calls = 0;
stubs.push(sinon.stub(typeRegistry,"getNodeInfo").callsFake(function() {
// loaded=false on first call, true on subsequent
return {id:"node-set",loaded:(calls++>0)};
}));
stubs.push(sinon.stub(loader,"loadNodeSet").callsFake(function(){return Promise.resolve();}));
stubs.push(sinon.stub(typeRegistry,"getFullNodeInfo"));
registry.enableNode("node-set").then(function(ns) {
typeRegistry.enableNodeSet.called.should.be.true();
loader.loadNodeSet.called.should.be.true();
ns.should.have.a.property('id','node-set');
ns.should.have.a.property('loaded',true);
done();
}).catch(function(err) { done(err); });
});
});
});

View File

@@ -1,528 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* 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 path = require("path");
var fs = require('fs-extra');
var EventEmitter = require('events');
var NR_TEST_UTILS = require("nr-test-utils");
var installer = NR_TEST_UTILS.require("@node-red/registry/lib/installer");
var registry = NR_TEST_UTILS.require("@node-red/registry/lib/index");
var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry");
const { events, exec, log, hooks } = NR_TEST_UTILS.require("@node-red/util");
describe('nodes/registry/installer', function() {
var mockLog = {
log: sinon.stub(),
debug: sinon.stub(),
trace: sinon.stub(),
warn: sinon.stub(),
info: sinon.stub(),
metric: sinon.stub(),
_: function(msg) { return msg }
}
var execResponse;
beforeEach(function() {
sinon.stub(exec,"run").callsFake(() => execResponse || Promise.resolve(""))
installer.init({})
});
afterEach(function() {
execResponse = null;
if (registry.addModule.restore) {
registry.addModule.restore();
}
if (registry.removeModule.restore) {
registry.removeModule.restore();
}
if (typeRegistry.removeModule.restore) {
typeRegistry.removeModule.restore();
}
if (registry.getModuleInfo.restore) {
registry.getModuleInfo.restore();
}
if (typeRegistry.getModuleInfo.restore) {
typeRegistry.getModuleInfo.restore();
}
if (typeRegistry.setModulePendingUpdated.restore) {
typeRegistry.setModulePendingUpdated.restore();
}
if (fs.statSync.restore) {
fs.statSync.restore();
}
exec.run.restore();
hooks.clear();
});
describe("installs module", function() {
it("rejects module name that includes version", function(done) {
installer.installModule("module@version",null,null).catch(function(err) {
err.code.should.be.eql('invalid_module_name');
done();
}).catch(done);
});
it("rejects missing module name", function(done) {
installer.installModule("",null,null).catch(function(err) {
err.code.should.be.eql('invalid_module_name');
done();
}).catch(done);
});
it("rejects null module name", function(done) {
installer.installModule(null,null,null).catch(function(err) {
err.code.should.be.eql('invalid_module_name');
done();
}).catch(done);
});
it("rejects invalid url", function(done) {
installer.installModule("module",null,"abc").catch(function(err) {
err.code.should.be.eql('invalid_module_url');
done();
});
});
it("rejects when npm returns a 404", function(done) {
var res = {
code: 1,
stdout:"",
stderr:" 404 this_wont_exist"
}
var p = Promise.reject(res);
p.catch((err)=>{});
execResponse = p;
installer.installModule("this_wont_exist").catch(function(err) {
err.should.have.property("code",404);
done();
}).catch(done);
});
it("rejects when npm does not find specified version", function(done) {
var res = {
code: 1,
stdout:"",
stderr:" version not found: this_wont_exist@0.1.2"
}
var p = Promise.reject(res);
p.catch((err)=>{});
execResponse = p;
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
return {
version: "0.1.1"
}
});
installer.installModule("this_wont_exist","0.1.2").catch(function(err) {
err.code.should.be.eql(404);
done();
}).catch(done);
});
it("rejects when update requested to existing version", function(done) {
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
return {
user: true,
version: "0.1.1"
}
});
installer.installModule("this_wont_exist","0.1.1").catch(function(err) {
err.code.should.be.eql('module_already_loaded');
done();
}).catch(done);
});
it("rejects when update requested to existing version and url", function(done) {
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
return {
user: true,
version: "0.1.1"
}
});
installer.installModule("this_wont_exist","0.1.1","https://example/foo-0.1.1.tgz").catch(function(err) {
err.code.should.be.eql('module_already_loaded');
done();
}).catch(done);
});
it("rejects with generic error", function(done) {
var res = {
code: 1,
stdout:"",
stderr:" kaboom!"
}
var p = Promise.reject(res);
p.catch((err)=>{});
execResponse = p;
installer.installModule("this_wont_exist").then(function() {
done(new Error("Unexpected success"));
}).catch(err => {
// Expected result
done()
});
});
it("succeeds when module is found", function(done) {
var nodeInfo = {nodes:{module:"foo",types:["a"]}};
var res = {
code: 0,
stdout:"",
stderr:""
}
var p = Promise.resolve(res);
p.catch((err)=>{});
execResponse = p;
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
installer.installModule("this_wont_exist").then(function(info) {
info.should.eql(nodeInfo);
// commsMessages.should.have.length(1);
// commsMessages[0].topic.should.equal("node/added");
// commsMessages[0].msg.should.eql(nodeInfo.nodes);
done();
}).catch(done);
});
it("rejects when non-existant path is provided", function(done) {
this.timeout(20000);
var resourcesDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule","node_modules","NonExistant"));
installer.installModule(resourcesDir).then(function() {
done(new Error("Unexpected success"));
}).catch(function(err) {
if (err.hasOwnProperty("code")) {
err.code.should.eql(404);
done();
}
else {
console.log("ERRROR::"+err.toString()+"::");
err.toString().should.eql("Error: Install failed");
done();
}
});
});
it("succeeds when path is valid node-red module", function(done) {
var nodeInfo = {nodes:{module:"foo",types:["a"]}};
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
var resourcesDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule","node_modules","TestNodeModule"));
var res = {
code: 0,
stdout:"",
stderr:""
}
var p = Promise.resolve(res);
p.catch((err)=>{});
execResponse = p;
installer.installModule(resourcesDir).then(function(info) {
info.should.eql(nodeInfo);
done();
}).catch(done);
});
it("succeeds when url is valid node-red module", function(done) {
var nodeInfo = {nodes:{module:"foo",types:["a"]}};
var res = {
code: 0,
stdout:"",
stderr:""
}
var p = Promise.resolve(res);
p.catch((err)=>{});
execResponse = p;
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
installer.installModule("this_wont_exist",null,"https://example/foo-0.1.1.tgz").then(function(info) {
info.should.eql(nodeInfo);
done();
}).catch(done);
});
it("triggers preInstall and postInstall hooks", function(done) {
let receivedPreEvent,receivedPostEvent;
hooks.add("preInstall", function(event) { event.args = ["a"]; receivedPreEvent = event; })
hooks.add("postInstall", function(event) { receivedPostEvent = event; })
var nodeInfo = {nodes:{module:"foo",types:["a"]}};
var res = {code: 0,stdout:"",stderr:""}
var p = Promise.resolve(res);
p.catch((err)=>{});
execResponse = p;
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
installer.installModule("this_wont_exist","1.2.3").then(function(info) {
exec.run.called.should.be.true();
exec.run.lastCall.args[1].should.eql([ 'install', 'a', 'this_wont_exist@1.2.3' ]);
info.should.eql(nodeInfo);
should.exist(receivedPreEvent)
receivedPreEvent.should.have.property("module","this_wont_exist")
receivedPreEvent.should.have.property("version","1.2.3")
receivedPreEvent.should.have.property("dir")
receivedPreEvent.should.have.property("url")
receivedPreEvent.should.have.property("isExisting")
receivedPreEvent.should.have.property("isUpgrade")
receivedPreEvent.should.eql(receivedPostEvent)
done();
}).catch(done);
});
it("fails install if preInstall hook fails", function(done) {
let receivedEvent;
hooks.add("preInstall", function(event) { throw new Error("preInstall-error"); })
var nodeInfo = {nodes:{module:"foo",types:["a"]}};
installer.installModule("this_wont_exist","1.2.3").catch(function(err) {
exec.run.called.should.be.false();
done();
}).catch(done);
});
it("skips invoking npm if preInstall returns false", function(done) {
let receivedEvent;
hooks.add("preInstall", function(event) { return false })
hooks.add("postInstall", function(event) { receivedEvent = event; })
var nodeInfo = {nodes:{module:"foo",types:["a"]}};
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
installer.installModule("this_wont_exist","1.2.3").then(function() {
exec.run.called.should.be.false();
should.exist(receivedEvent);
done();
}).catch(done);
});
it("rollsback install if postInstall hook fails", function(done) {
hooks.add("postInstall", function(event) { throw new Error("fail"); })
installer.installModule("this_wont_exist","1.2.3").catch(function(err) {
exec.run.calledTwice.should.be.true();
exec.run.firstCall.args[1].includes("install").should.be.true();
exec.run.secondCall.args[1].includes("remove").should.be.true();
done();
}).catch(done);
});
describe("allowUpdate lists", function() {
it("rejects when update requested with allowUpdate set to false", function(done) {
installer.init({ externalModules: { palette: { allowUpdate: false } } })
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
return {
user: true,
version: "0.1.1"
}
});
installer.installModule("this_wont_exist","0.1.2").catch(function(err) {
err.code.should.be.eql('update_not_allowed');
done();
}).catch(done);
})
it("succeeds when update requested with module not on denyUpdateList", function(done) {
installer.init({ externalModules: { palette: { denyUpdateList: ['this_wont_exist'] } } })
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
return {
user: true,
version: "0.1.1"
}
});
var res = {
code: 0,
stdout:"",
stderr:""
}
var p = Promise.resolve(res);
p.catch((err)=>{});
execResponse = p;
var nodeInfo = {nodes:{module:"this_is_allowed",types:["a"]}};
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
sinon.stub(typeRegistry,"setModulePendingUpdated").callsFake(function() {
return Promise.resolve(nodeInfo);
});
installer.installModule("this_is_allowed","0.1.2").then(function() {
done();
}).catch(done);
})
it("rejects when update requested with module on denyUpdateList", function(done) {
installer.init({ externalModules: { palette: { denyUpdateList: ['this_wont_exist'] } } })
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
return {
user: true,
version: "0.1.1"
}
});
var res = {
code: 0,
stdout:"",
stderr:""
}
var p = Promise.resolve(res);
p.catch((err)=>{});
execResponse = p;
var nodeInfo = {nodes:{module:"this_is_allowed",types:["a"]}};
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
sinon.stub(typeRegistry,"setModulePendingUpdated").callsFake(function() {
return Promise.resolve(nodeInfo);
});
installer.installModule("this_wont_exist","0.1.2").catch(function(err) {
err.code.should.be.eql('update_not_allowed');
done();
}).catch(done);
})
it("succeeds when update requested with module on allowUpdateList", function(done) {
installer.init({ externalModules: { palette: { allowUpdateList: ['this_is_allowed'] } } })
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
return {
user: true,
version: "0.1.1"
}
});
var res = {
code: 0,
stdout:"",
stderr:""
}
var p = Promise.resolve(res);
p.catch((err)=>{});
execResponse = p;
var nodeInfo = {nodes:{module:"this_is_allowed",types:["a"]}};
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
sinon.stub(typeRegistry,"setModulePendingUpdated").callsFake(function() {
return Promise.resolve(nodeInfo);
});
installer.installModule("this_is_allowed","0.1.2").then(function() {
done();
}).catch(done);
})
it("rejects when update requested with module not on allowUpdateList", function(done) {
installer.init({ externalModules: { palette: { allowUpdateList: ['this_is_allowed'] } } })
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
return {
user: true,
version: "0.1.1"
}
});
var res = {
code: 0,
stdout:"",
stderr:""
}
var p = Promise.resolve(res);
p.catch((err)=>{});
execResponse = p;
var nodeInfo = {nodes:{module:"this_wont_exist",types:["a"]}};
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
sinon.stub(typeRegistry,"setModulePendingUpdated").callsFake(function() {
return Promise.resolve(nodeInfo);
});
installer.installModule("this_wont_exist","0.1.2").catch(function(err) {
err.code.should.be.eql('update_not_allowed');
done();
}).catch(done);
})
});
});
describe("uninstalls module", function() {
it("rejects invalid module names", function(done) {
var promises = [];
var rejectedCount = 0;
promises.push(installer.uninstallModule("this_wont_exist ").catch(() => {rejectedCount++}));
promises.push(installer.uninstallModule("this_wont_exist;no_it_really_wont").catch(() => {rejectedCount++}));
Promise.all(promises).then(function() {
rejectedCount.should.eql(2);
done();
}).catch(done);
});
it("rejects with generic error", function(done) {
var nodeInfo = [{module:"foo",types:["a"]}];
var removeModule = sinon.stub(registry,"removeModule").callsFake(function(md) {
return Promise.resolve(nodeInfo);
});
var res = {
code: 1,
stdout:"",
stderr:"error"
}
var p = Promise.reject(res);
p.catch((err)=>{});
execResponse = p;
installer.uninstallModule("this_wont_exist").then(function() {
done(new Error("Unexpected success"));
}).catch(err => {
// Expected result
done()
});
});
it("succeeds when module is found", function(done) {
var nodeInfo = [{module:"foo",types:["a"]}];
var removeModule = sinon.stub(typeRegistry,"removeModule").callsFake(function(md) {
return nodeInfo;
});
var getModuleInfo = sinon.stub(registry,"getModuleInfo").callsFake(function(md) {
return {nodes:[]};
});
var res = {
code: 0,
stdout:"",
stderr:""
}
var p = Promise.resolve(res);
p.catch((err)=>{});
execResponse = p;
sinon.stub(fs,"statSync").callsFake(function(fn) { return {}; });
installer.uninstallModule("this_wont_exist").then(function(info) {
info.should.eql(nodeInfo);
// commsMessages.should.have.length(1);
// commsMessages[0].topic.should.equal("node/removed");
// commsMessages[0].msg.should.eql(nodeInfo);
done();
}).catch(done);
});
});
});

View File

@@ -1,62 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* 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");
var path = require("path");
var NR_TEST_UTILS = require("nr-test-utils");
var library = NR_TEST_UTILS.require("@node-red/registry/lib/library");
describe("library api", function() {
it('returns null list when no modules have been registered', function() {
library.init();
should.not.exist(library.getExampleFlows());
});
it('returns null path when module is not known', function() {
library.init();
should.not.exist(library.getExampleFlowPath('foo','bar'));
});
it('returns a valid example path', function(done) {
library.init();
library.addExamplesDir("test-module",path.resolve(__dirname+'/resources/examples')).then(function() {
try {
var flows = library.getExampleFlows();
flows.should.deepEqual({"test-module":{"f":["one"]}});
var examplePath = library.getExampleFlowPath('test-module','one');
examplePath.should.eql(path.resolve(__dirname+'/resources/examples/one.json'))
library.removeExamplesDir('test-module');
try {
should.not.exist(library.getExampleFlows());
should.not.exist(library.getExampleFlowPath('test-module','one'));
done();
} catch(err) {
done(err);
}
}catch(err) {
done(err);
}
});
})
});

View File

@@ -1,720 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* 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 path = require("path");
var fs = require("fs-extra");
var NR_TEST_UTILS = require("nr-test-utils");
var loader = NR_TEST_UTILS.require("@node-red/registry/lib/loader");
var localfilesystem = NR_TEST_UTILS.require("@node-red/registry/lib/localfilesystem");
var registry = NR_TEST_UTILS.require("@node-red/registry/lib/registry");
var nodes = NR_TEST_UTILS.require("@node-red/registry");
var resourcesDir = path.resolve(path.join(__dirname,"resources","local"));
describe("red/nodes/registry/loader",function() {
var stubs = [];
before(function() {
sinon.stub(localfilesystem,"init");
});
after(function() {
localfilesystem.init.restore();
});
afterEach(function() {
while(stubs.length) {
stubs.pop().restore();
}
})
describe("#load",function() {
it("load empty set without settings available", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return {};}));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return false;}}});
loader.load(true).then(function() {
localfilesystem.getNodeFiles.called.should.be.true();
localfilesystem.getNodeFiles.lastCall.args[0].should.be.true();
registry.saveNodeList.called.should.be.false();
done();
})
});
it("load empty set with settings available triggers registery save", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return {};}));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load(true).then(function() {
registry.saveNodeList.called.should.be.true();
done();
}).catch(function(err) {
done(err);
})
});
it("load core node files scanned by lfs - single node single file", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
var result = {};
result["node-red"] = {
"name": "node-red",
"version": "1.2.3",
"nodes": {
"TestNode1": {
"file": path.join(resourcesDir,"TestNode1","TestNode1.js"),
"module": "node-red",
"name": "TestNode1"
}
}
};
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) {
registry.addModule.called.should.be.true();
var module = registry.addModule.lastCall.args[0];
module.should.have.property("name","node-red");
module.should.have.property("version","1.2.3");
module.should.have.property("nodes");
module.nodes.should.have.property("TestNode1");
module.nodes.TestNode1.should.have.property("id","node-red/TestNode1");
module.nodes.TestNode1.should.have.property("module","node-red");
module.nodes.TestNode1.should.have.property("name","TestNode1");
module.nodes.TestNode1.should.have.property("file");
module.nodes.TestNode1.should.have.property("template");
module.nodes.TestNode1.should.have.property("enabled",true);
module.nodes.TestNode1.should.have.property("loaded",true);
module.nodes.TestNode1.should.have.property("types");
module.nodes.TestNode1.types.should.have.a.length(1);
module.nodes.TestNode1.types[0].should.eql('test-node-1');
module.nodes.TestNode1.should.have.property("config");
module.nodes.TestNode1.config.should.not.eql("");
module.nodes.TestNode1.should.have.property("help");
module.nodes.TestNode1.help.should.have.property("en-US");
module.nodes.TestNode1.should.have.property("namespace","node-red");
nodes.registerType.calledOnce.should.be.true();
nodes.registerType.lastCall.args[0].should.eql('node-red/TestNode1');
nodes.registerType.lastCall.args[1].should.eql('test-node-1');
done();
}).catch(function(err) {
done(err);
});
});
it("load core node files scanned by lfs - ignore html if disableEditor true", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
var result = {};
result["node-red"] = {
"name": "node-red",
"version": "1.2.3",
"nodes": {
"TestNode1": {
"file": path.join(resourcesDir,"TestNode1","TestNode1.js"),
"module": "node-red",
"name": "TestNode1"
}
}
};
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{disableEditor: true, available:function(){return true;}}});
loader.load().then(function(result) {
registry.addModule.called.should.be.true();
var module = registry.addModule.lastCall.args[0];
module.should.have.property("name","node-red");
module.should.have.property("version","1.2.3");
module.should.have.property("nodes");
module.nodes.should.have.property("TestNode1");
module.nodes.TestNode1.should.have.property("id","node-red/TestNode1");
module.nodes.TestNode1.should.have.property("module","node-red");
module.nodes.TestNode1.should.have.property("name","TestNode1");
module.nodes.TestNode1.should.have.property("file");
module.nodes.TestNode1.should.have.property("template");
module.nodes.TestNode1.should.have.property("enabled",true);
module.nodes.TestNode1.should.have.property("loaded",true);
// With disableEditor true, the types property is not populated by the
// html file - but instead is populated as nodes register themselves.
// But for this test, we have stubbed out registerType, so we won't get any types
// module.nodes.TestNode1.should.have.property("types");
// module.nodes.TestNode1.types.should.have.a.length(1);
// module.nodes.TestNode1.types[0].should.eql('test-node-1');
// With disableEditor set, config should be blank
module.nodes.TestNode1.should.have.property("config");
module.nodes.TestNode1.config.should.eql("");
// help should be an empty object
module.nodes.TestNode1.should.have.property("help");
module.nodes.TestNode1.help.should.eql({})
module.nodes.TestNode1.should.have.property("namespace","node-red");
nodes.registerType.calledOnce.should.be.true();
nodes.registerType.lastCall.args[0].should.eql('node-red/TestNode1');
nodes.registerType.lastCall.args[1].should.eql('test-node-1');
done();
}).catch(function(err) {
done(err);
});
});
it("load core node files scanned by lfs - multiple nodes single file", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
var result = {};
result["node-red"] = {
"name": "node-red",
"version": "4.5.6",
"nodes": {
"MultipleNodes1": {
"file": path.join(resourcesDir,"MultipleNodes1","MultipleNodes1.js"),
"module": "node-red",
"name": "MultipleNodes1"
}
}
};
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) {
registry.addModule.called.should.be.true();
var module = registry.addModule.lastCall.args[0];
module.should.have.property("name","node-red");
module.should.have.property("version","4.5.6");
module.should.have.property("nodes");
module.nodes.should.have.property("MultipleNodes1");
module.nodes.MultipleNodes1.should.have.property("id","node-red/MultipleNodes1");
module.nodes.MultipleNodes1.should.have.property("module","node-red");
module.nodes.MultipleNodes1.should.have.property("name","MultipleNodes1");
module.nodes.MultipleNodes1.should.have.property("file");
module.nodes.MultipleNodes1.should.have.property("template");
module.nodes.MultipleNodes1.should.have.property("enabled",true);
module.nodes.MultipleNodes1.should.have.property("loaded",true);
module.nodes.MultipleNodes1.should.have.property("types");
module.nodes.MultipleNodes1.types.should.have.a.length(2);
module.nodes.MultipleNodes1.types[0].should.eql('test-node-multiple-1a');
module.nodes.MultipleNodes1.types[1].should.eql('test-node-multiple-1b');
module.nodes.MultipleNodes1.should.have.property("config");
module.nodes.MultipleNodes1.should.have.property("help");
module.nodes.MultipleNodes1.should.have.property("namespace","node-red");
nodes.registerType.calledTwice.should.be.true();
nodes.registerType.firstCall.args[0].should.eql('node-red/MultipleNodes1');
nodes.registerType.firstCall.args[1].should.eql('test-node-multiple-1a');
nodes.registerType.secondCall.args[0].should.eql('node-red/MultipleNodes1');
nodes.registerType.secondCall.args[1].should.eql('test-node-multiple-1b');
done();
}).catch(function(err) {
done(err);
});
});
it("load core node files scanned by lfs - node with promise", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
var result = {};
result["node-red"] = {
"name": "node-red",
"version":"2.4.6",
"nodes": {
"TestNode2": {
"file": path.join(resourcesDir,"TestNode2","TestNode2.js"),
"module": "node-red",
"name": "TestNode2"
}
}
};
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) {
registry.addModule.called.should.be.true();
var module = registry.addModule.lastCall.args[0];
module.should.have.property("name","node-red");
module.should.have.property("version","2.4.6");
module.should.have.property("nodes");
module.nodes.should.have.property("TestNode2");
module.nodes.TestNode2.should.have.property("id","node-red/TestNode2");
module.nodes.TestNode2.should.have.property("module","node-red");
module.nodes.TestNode2.should.have.property("name","TestNode2");
module.nodes.TestNode2.should.have.property("file");
module.nodes.TestNode2.should.have.property("template");
module.nodes.TestNode2.should.have.property("enabled",true);
module.nodes.TestNode2.should.have.property("loaded",true);
module.nodes.TestNode2.should.have.property("types");
module.nodes.TestNode2.types.should.have.a.length(1);
module.nodes.TestNode2.types[0].should.eql('test-node-2');
module.nodes.TestNode2.should.have.property("config");
module.nodes.TestNode2.should.have.property("help");
module.nodes.TestNode2.should.have.property("namespace","node-red");
module.nodes.TestNode2.should.not.have.property('err');
nodes.registerType.calledOnce.should.be.true();
nodes.registerType.lastCall.args[0].should.eql('node-red/TestNode2');
nodes.registerType.lastCall.args[1].should.eql('test-node-2');
done();
}).catch(function(err) {
done(err);
});
});
it("load core node files scanned by lfs - node with rejecting promise", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
var result = {};
result["node-red"] = {
"name": "node-red",
"version":"1.2.3",
"nodes": {
"TestNode3": {
"file": path.join(resourcesDir,"TestNode3","TestNode3.js"),
"module": "node-red",
"name": "TestNode3"
}
}
};
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) {
registry.addModule.called.should.be.true();
var module = registry.addModule.lastCall.args[0];
module.should.have.property("name","node-red");
module.should.have.property("version","1.2.3");
module.should.have.property("nodes");
module.nodes.should.have.property("TestNode3");
module.nodes.TestNode3.should.have.property("id","node-red/TestNode3");
module.nodes.TestNode3.should.have.property("module","node-red");
module.nodes.TestNode3.should.have.property("name","TestNode3");
module.nodes.TestNode3.should.have.property("file");
module.nodes.TestNode3.should.have.property("template");
module.nodes.TestNode3.should.have.property("enabled",true);
module.nodes.TestNode3.should.have.property("loaded",false);
module.nodes.TestNode3.should.have.property("types");
module.nodes.TestNode3.types.should.have.a.length(1);
module.nodes.TestNode3.types[0].should.eql('test-node-3');
module.nodes.TestNode3.should.have.property("config");
module.nodes.TestNode3.should.have.property("help");
module.nodes.TestNode3.should.have.property("namespace","node-red");
module.nodes.TestNode3.should.have.property('err','fail');
nodes.registerType.called.should.be.false();
done();
}).catch(function(err) {
done(err);
});
});
it("load core node files scanned by lfs - missing file", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
var result = {};
result["node-red"] = {
"name": "node-red",
"version":"1.2.3",
"nodes": {
"DoesNotExist": {
"file": path.join(resourcesDir,"doesnotexist"),
"module": "node-red",
"name": "DoesNotExist"
}
}
};
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) {
registry.addModule.called.should.be.true();
var module = registry.addModule.lastCall.args[0];
module.should.have.property("name","node-red");
module.should.have.property("version","1.2.3");
module.should.have.property("nodes");
module.nodes.should.have.property("DoesNotExist");
module.nodes.DoesNotExist.should.have.property("id","node-red/DoesNotExist");
module.nodes.DoesNotExist.should.have.property("module","node-red");
module.nodes.DoesNotExist.should.have.property("name","DoesNotExist");
module.nodes.DoesNotExist.should.have.property("file");
module.nodes.DoesNotExist.should.have.property("template");
module.nodes.DoesNotExist.should.have.property("enabled",true);
module.nodes.DoesNotExist.should.have.property("loaded",false);
module.nodes.DoesNotExist.should.have.property("types");
module.nodes.DoesNotExist.types.should.have.a.length(0);
module.nodes.DoesNotExist.should.have.property("config","");
module.nodes.DoesNotExist.should.have.property("help",{});
module.nodes.DoesNotExist.should.have.property("namespace","node-red");
module.nodes.DoesNotExist.should.have.property('err');
nodes.registerType.called.should.be.false();
done();
}).catch(function(err) {
done(err);
});
});
// it("load core node files scanned by lfs - missing html file", function(done) {
// // This is now an okay situation
// stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
// var result = {};
// result["node-red"] = {
// "name": "node-red",
// "version": "1.2.3",
// "nodes": {
// "DuffNode": {
// "file": path.join(resourcesDir,"DuffNode","DuffNode.js"),
// "module": "node-red",
// "name": "DuffNode"
// }
// }
// };
// return result;
// }));
//
// stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
// stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
// // This module isn't already loaded
// stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
//
// stubs.push(sinon.stub(nodes,"registerType"));
// loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
// loader.load().then(function(result) {
//
// registry.addModule.called.should.be.true();
// var module = registry.addModule.lastCall.args[0];
// module.should.have.property("name","node-red");
// module.should.have.property("version","1.2.3");
// module.should.have.property("nodes");
// module.nodes.should.have.property("DuffNode");
// module.nodes.DuffNode.should.have.property("id","node-red/DuffNode");
// module.nodes.DuffNode.should.have.property("module","node-red");
// module.nodes.DuffNode.should.have.property("name","DuffNode");
// module.nodes.DuffNode.should.have.property("file");
// module.nodes.DuffNode.should.have.property("template");
// module.nodes.DuffNode.should.have.property("enabled",true);
// module.nodes.DuffNode.should.have.property("loaded",false);
// module.nodes.DuffNode.should.have.property("types");
// module.nodes.DuffNode.types.should.have.a.length(0);
// module.nodes.DuffNode.should.have.property("config","");
// module.nodes.DuffNode.should.have.property("help",{});
// module.nodes.DuffNode.should.have.property("namespace","node-red");
// module.nodes.DuffNode.should.have.property('err');
// module.nodes.DuffNode.err.should.endWith("DuffNode.html does not exist");
//
// nodes.registerType.called.should.be.false();
//
// done();
// }).catch(function(err) {
// done(err);
// });
// });
});
describe("#addModule",function() {
it("throws error if settings unavailable", function() {
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return false;}}});
/*jshint immed: false */
(function(){
loader.addModule("test-module");
}).should.throw("Settings unavailable");
});
it("returns rejected error if module already loaded", function(done) {
stubs.push(sinon.stub(registry,"getModuleInfo").callsFake(function(){return{}}));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.addModule("test-module").catch(function(err) {
err.code.should.eql("module_already_loaded");
done();
});
});
it("returns rejected error if module not found", function(done) {
stubs.push(sinon.stub(registry,"getModuleInfo").callsFake(function(){return null}));
stubs.push(sinon.stub(localfilesystem,"getModuleFiles").callsFake(function() {
throw new Error("failure");
}));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.addModule("test-module").catch(function(err) {
err.message.should.eql("failure");
done();
});
});
it("loads module by name", function(done) {
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getModuleInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(localfilesystem,"getModuleFiles").callsFake(function(){
var result = {};
result["TestNodeModule"] = {
"name": "TestNodeModule",
"version": "1.2.3",
"nodes": {
"TestNode1": {
"file": path.join(resourcesDir,"TestNodeModule","node_modules","TestNodeModule","TestNodeModule.js"),
"module": "TestNodeModule",
"name": "TestNode1",
"version": "1.2.3"
}
}
};
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return "a node list" }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.addModule("TestNodeModule").then(function(result) {
result.should.eql("TestNodeModule");
registry.addModule.called.should.be.true();
var module = registry.addModule.lastCall.args[0];
module.should.have.property("name","TestNodeModule");
module.should.have.property("version","1.2.3");
module.should.have.property("nodes");
module.nodes.should.have.property("TestNode1");
module.nodes.TestNode1.should.have.property("id","TestNodeModule/TestNode1");
module.nodes.TestNode1.should.have.property("module","TestNodeModule");
module.nodes.TestNode1.should.have.property("name","TestNode1");
module.nodes.TestNode1.should.have.property("file");
module.nodes.TestNode1.should.have.property("template");
module.nodes.TestNode1.should.have.property("enabled",true);
module.nodes.TestNode1.should.have.property("loaded",true);
module.nodes.TestNode1.should.have.property("types");
module.nodes.TestNode1.types.should.have.a.length(1);
module.nodes.TestNode1.types[0].should.eql('test-node-mod-1');
module.nodes.TestNode1.should.have.property("config");
module.nodes.TestNode1.should.have.property("help");
module.nodes.TestNode1.should.have.property("namespace","TestNodeModule");
module.nodes.TestNode1.should.not.have.property('err');
nodes.registerType.calledOnce.should.be.true();
done();
}).catch(function(err) {
done(err);
});
});
it("skips module that fails version check", function(done) {
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getModuleInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(localfilesystem,"getModuleFiles").callsFake(function(){
var result = {};
result["TestNodeModule"] = {
"name": "TestNodeModule",
"version": "1.2.3",
"redVersion":"999.0.0",
"nodes": {
"TestNode1": {
"file": path.join(resourcesDir,"TestNodeModule","node_modules","TestNodeModule","TestNodeModule.js"),
"module": "TestNodeModule",
"name": "TestNode1",
"version": "1.2.3"
}
}
};
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return "a node list" }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({log:{"_":function(){},warn:function(){}},nodes:nodes,version: function() { return "0.12.0"}, settings:{available:function(){return true;}}});
loader.addModule("TestNodeModule").then(function(result) {
result.should.eql("TestNodeModule");
registry.addModule.called.should.be.false();
nodes.registerType.called.should.be.false();
done();
}).catch(function(err) {
done(err);
});
});
it.skip('registers a message catalog');
});
describe("#loadNodeSet",function() {
it("no-ops the load if node is not enabled", function(done) {
stubs.push(sinon.stub(nodes,"registerType"));
loader.loadNodeSet({
"file": path.join(resourcesDir,"TestNode1","TestNode1.js"),
"module": "node-red",
"name": "TestNode1",
"enabled": false
}).then(function(node) {
node.enabled.should.be.false();
nodes.registerType.called.should.be.false();
done();
}).catch(function(err) {
done(err);
});
});
it("handles node that errors on require", function(done) {
stubs.push(sinon.stub(nodes,"registerType"));
loader.loadNodeSet({
"file": path.join(resourcesDir,"TestNode4","TestNode4.js"),
"module": "node-red",
"name": "TestNode4",
"enabled": true
}).then(function(node) {
node.enabled.should.be.true();
nodes.registerType.called.should.be.false();
node.should.have.property('err');
node.err.toString().should.eql("Error: fail to require (line:1)");
done();
}).catch(function(err) {
done(err);
});
});
});
describe("#getNodeHelp",function() {
it("returns preloaded help", function() {
loader.getNodeHelp({
help:{
en:"foo"
}
},"en").should.eql("foo");
});
it("loads help, caching result", function() {
stubs.push(sinon.stub(fs,"readFileSync").callsFake(function(path) {
return 'bar';
}))
var node = {
template: "/tmp/node/directory/file.html",
help:{
en:"foo"
}
};
loader.getNodeHelp(node,"fr").should.eql("bar");
node.help['fr'].should.eql("bar");
fs.readFileSync.calledOnce.should.be.true();
fs.readFileSync.lastCall.args[0].should.eql(path.normalize("/tmp/node/directory/locales/fr/file.html"));
loader.getNodeHelp(node,"fr").should.eql("bar");
fs.readFileSync.calledOnce.should.be.true();
});
it("loads help, defaulting to en-US content", function() {
stubs.push(sinon.stub(fs,"readFileSync").callsFake(function(path) {
throw new Error("not found");
}))
var node = {
template: "/tmp/node/directory/file.html",
help:{}
};
node.help['en-US'] = 'foo';
loader.getNodeHelp(node,"fr").should.eql("foo");
node.help['fr'].should.eql("foo");
fs.readFileSync.calledOnce.should.be.true();
fs.readFileSync.lastCall.args[0].should.eql(path.normalize("/tmp/node/directory/locales/fr/file.html"));
loader.getNodeHelp(node,"fr").should.eql("foo");
fs.readFileSync.calledOnce.should.be.true();
});
it("loads help, defaulting to en-US content for extra nodes", function() {
stubs.push(sinon.stub(fs,"readFileSync").callsFake(function(path) {
if (path.indexOf("en-US") >= 0) {
return 'bar';
}
throw new Error("not found");
}));
var node = {
template: "/tmp/node/directory/file.html",
help:{}
};
delete node.help['en-US'];
loader.getNodeHelp(node,"fr").should.eql("bar");
node.help['fr'].should.eql("bar");
fs.readFileSync.calledTwice.should.be.true();
fs.readFileSync.firstCall.args[0].should.eql(path.normalize("/tmp/node/directory/locales/fr/file.html"));
fs.readFileSync.lastCall.args[0].should.eql(path.normalize("/tmp/node/directory/locales/en-US/file.html"));
loader.getNodeHelp(node,"fr").should.eql("bar");
fs.readFileSync.calledTwice.should.be.true();
});
it("fails to load en-US help content", function() {
stubs.push(sinon.stub(fs,"readFileSync").callsFake(function(path) {
throw new Error("not found");
}));
var node = {
template: "/tmp/node/directory/file.html",
help:{}
};
delete node.help['en-US'];
should.not.exist(loader.getNodeHelp(node,"en-US"));
should.not.exist(node.help['en-US']);
fs.readFileSync.calledTwice.should.be.true();
fs.readFileSync.firstCall.args[0].should.eql(path.normalize("/tmp/node/directory/locales/en-US/file.html"));
fs.readFileSync.lastCall.args[0].should.eql(path.normalize("/tmp/node/directory/locales/en/file.html"));
should.not.exist(loader.getNodeHelp(node,"en-US"));
fs.readFileSync.callCount.should.eql(4);
});
});
});

View File

@@ -1,276 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* 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 path = require("path");
var NR_TEST_UTILS = require("nr-test-utils");
var localfilesystem = NR_TEST_UTILS.require("@node-red/registry/lib/localfilesystem");
var resourcesDir = path.resolve(path.join(__dirname,"resources","local"));
var userDir = path.resolve(path.join(__dirname,"resources","userDir"));
var moduleDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule"));
var i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
describe("red/nodes/registry/localfilesystem",function() {
beforeEach(function() {
stubs.push(sinon.stub(i18n,"registerMessageCatalog").callsFake(function() { return Promise.resolve(); }));
})
var stubs = [];
afterEach(function() {
while(stubs.length) {
stubs.pop().restore();
}
})
function checkNodes(nodes,shouldHaveNodes,shouldNotHaveNodes,module) {
for (var i=0;i<shouldHaveNodes.length;i++) {
nodes.should.have.a.property(shouldHaveNodes[i]);
nodes[shouldHaveNodes[i]].should.have.a.property('file');
nodes[shouldHaveNodes[i]].file.should.equal(path.resolve(nodes[shouldHaveNodes[i]].file));
nodes[shouldHaveNodes[i]].should.have.a.property('module',module||'node-red');
nodes[shouldHaveNodes[i]].should.have.a.property('name',shouldHaveNodes[i]);
}
for (i=0;i<shouldNotHaveNodes.length;i++) {
nodes.should.not.have.a.property(shouldNotHaveNodes[i]);
}
}
describe("#getNodeFiles",function() {
it("Finds all the node files in the resources tree",function(done) {
localfilesystem.init({coreNodesDir:resourcesDir});
var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red'];
nm.should.have.a.property('name','node-red');
nm.should.have.a.property("nodes");
var nodes = nm.nodes;
checkNodes(nm.nodes,['TestNode1','MultipleNodes1','NestedNode','TestNode2','TestNode3','TestNode4'],['TestNodeModule']);
i18n.registerMessageCatalog.called.should.be.true();
i18n.registerMessageCatalog.lastCall.args[0].should.eql('node-red');
i18n.registerMessageCatalog.lastCall.args[1].should.eql(path.resolve(path.join(resourcesDir,"locales")));
i18n.registerMessageCatalog.lastCall.args[2].should.eql('messages.json');
done();
});
it("Includes node files from settings",function(done) {
localfilesystem.init({nodesIncludes:['TestNode1.js'],coreNodesDir:resourcesDir});
var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red'];
nm.should.have.a.property('name','node-red');
nm.should.have.a.property("nodes");
checkNodes(nm.nodes,['TestNode1'],['MultipleNodes1','NestedNode','TestNode2','TestNode3','TestNode4','TestNodeModule']);
done();
});
it("Excludes node files from settings",function(done) {
localfilesystem.init({nodesExcludes:['TestNode1.js'],coreNodesDir:resourcesDir});
var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red'];
nm.should.have.a.property('name','node-red');
nm.should.have.a.property("nodes");
checkNodes(nm.nodes,['MultipleNodes1','NestedNode','TestNode2','TestNode3','TestNode4'],['TestNode1','TestNodeModule']);
done();
});
it("Finds nodes in userDir/nodes",function(done) {
localfilesystem.init({userDir:userDir});
var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red'];
nm.should.have.a.property('name','node-red');
nm.should.have.a.property("nodes");
checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
done();
});
it("Finds nodes in settings.nodesDir (string)",function(done) {
localfilesystem.init({nodesDir:userDir});
var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red'];
nm.should.have.a.property('name','node-red');
nm.should.have.a.property("nodes");
checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
done();
});
it("Finds nodes in settings.nodesDir (string,relative path)",function(done) {
var relativeUserDir = path.join("test","unit","@node-red","registry","lib","resources","userDir");
localfilesystem.init({nodesDir:relativeUserDir});
var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red'];
nm.should.have.a.property('name','node-red');
nm.should.have.a.property("nodes");
checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
done();
});
it("Finds nodes in settings.nodesDir (array)",function(done) {
localfilesystem.init({nodesDir:[userDir]});
var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red'];
nm.should.have.a.property('name','node-red');
nm.should.have.a.property("nodes");
checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
done();
});
it("Finds nodes module path",function(done) {
var _join = path.join;
stubs.push(sinon.stub(path,"join").callsFake(function() {
if (arguments[0] == resourcesDir) {
// This stops the module tree scan from going any higher
// up the tree than resourcesDir.
return arguments[0];
}
return _join.apply(null,arguments);
}));
localfilesystem.init({coreNodesDir:moduleDir});
var nodeList = localfilesystem.getNodeFiles();
nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red'];
// The `node-red` module is loaded differently to those scanned for
// It doesn't get the `path` property set. Maybe it should.
nm.should.have.a.property('name','node-red');
nm.should.have.a.property("nodes");
checkNodes(nm.nodes,[],['TestNode1']);
nm = nodeList['TestNodeModule'];
nm.should.have.a.property('path')
nm.should.have.a.property('name','TestNodeModule');
nm.should.have.a.property("nodes");
checkNodes(nm.nodes,['TestNodeMod1','TestNodeMod2'],[],'TestNodeModule');
nm = nodeList['VersionMismatchModule'];
nm.should.have.a.property('path')
nm.should.have.a.property('name','VersionMismatchModule');
nm.should.have.a.property("nodes");
checkNodes(nm.nodes,['VersionMismatchMod1','VersionMismatchMod2'],[],'VersionMismatchModule');
i18n.registerMessageCatalog.called.should.be.true();
i18n.registerMessageCatalog.lastCall.args[0].should.eql('node-red');
i18n.registerMessageCatalog.lastCall.args[1].should.eql(path.resolve(path.join(moduleDir,"locales")));
i18n.registerMessageCatalog.lastCall.args[2].should.eql('messages.json');
done();
});
it.skip("finds locales directory");
it.skip("finds icon path directory");
it("scans icon files in the resources tree",function(done) {
var count = 0;
localfilesystem.init({
coreNodesDir: resourcesDir
});
var list = localfilesystem.getNodeFiles(true);
list.should.have.property("node-red");
list["node-red"].should.have.property("icons");
list["node-red"].icons.should.have.length(1);
list["node-red"].icons[0].should.have.property("path",path.join(__dirname,"resources/local/NestedDirectoryNode/NestedNode/icons"))
list["node-red"].icons[0].should.have.property("icons");
list["node-red"].icons[0].icons.should.have.length(1);
list["node-red"].icons[0].icons[0].should.eql("arrow-in.png");
done();
});
it("scans icons dir in library",function(done) {
var count = 0;
localfilesystem.init({
userDir: userDir
});
var list = localfilesystem.getNodeFiles(true);
list.should.have.property("node-red");
list["node-red"].should.have.property("icons");
list["node-red"].icons.should.have.length(1);
list["node-red"].icons[0].should.have.property("path",path.join(__dirname,"resources/userDir/lib/icons"))
list["node-red"].icons[0].should.have.property("icons");
list["node-red"].icons[0].icons.should.have.length(1);
list["node-red"].icons[0].icons[0].should.eql("test_icon.png");
done();
});
});
describe("#getModuleFiles",function() {
it("gets a nodes module files",function(done) {
var _join = path.join;
stubs.push(sinon.stub(path,"join").callsFake(function() {
if (arguments[0] == resourcesDir) {
// This stops the module tree scan from going any higher
// up the tree than resourcesDir.
return arguments[0];
}
return _join.apply(null,arguments);
}));
localfilesystem.init({coreNodesDir:moduleDir});
var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
nodeModule.should.have.a.property('TestNodeModule');
nodeModule['TestNodeModule'].should.have.a.property('name','TestNodeModule');
nodeModule['TestNodeModule'].should.have.a.property('version','0.0.1');
nodeModule['TestNodeModule'].should.have.a.property('nodes');
nodeModule['TestNodeModule'].should.have.a.property('path');
checkNodes(nodeModule['TestNodeModule'].nodes,['TestNodeMod1','TestNodeMod2'],[],'TestNodeModule');
nodeModule = localfilesystem.getModuleFiles('VersionMismatchModule');
nodeModule.should.have.a.property('VersionMismatchModule');
nodeModule['VersionMismatchModule'].should.have.a.property('redVersion','100.0.0');
done();
});
it("throws an error if a node isn't found",function(done) {
var _join = path.join;
stubs.push(sinon.stub(path,"join").callsFake(function() {
if (arguments[0] == resourcesDir) {
// This stops the module tree scan from going any higher
// up the tree than resourcesDir.
return arguments[0];
}
return _join.apply(null,arguments);
}));
localfilesystem.init({coreNodesDir:moduleDir});
/*jshint immed: false */
(function(){
localfilesystem.getModuleFiles('WontExistModule');
}).should.throw();
done();
});
it.skip("finds locales directory");
it.skip("finds icon path directory");
it("scans icon files with a module file",function(done) {
var _join = path.join;
stubs.push(sinon.stub(path,"join").callsFake(function() {
if (arguments[0] == resourcesDir) {
// This stops the module tree scan from going any higher
// up the tree than resourcesDir.
return arguments[0];
}
return _join.apply(null,arguments);
}));
localfilesystem.init({
coreNodesDir: moduleDir
});
var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
nodeModule.should.have.property("TestNodeModule");
nodeModule.TestNodeModule.should.have.property('icons');
nodeModule.TestNodeModule.icons.should.have.length(1);
nodeModule.TestNodeModule.icons[0].should.have.property("path");
nodeModule.TestNodeModule.icons[0].should.have.property("icons");
nodeModule.TestNodeModule.icons[0].icons[0].should.eql("arrow-in.png");
done();
});
});
});

View File

@@ -1,200 +0,0 @@
const should = require("should");
const sinon = require("sinon");
const path = require("path");
const NR_TEST_UTILS = require("nr-test-utils");
const plugins = NR_TEST_UTILS.require("@node-red/registry/lib/plugins");
const registry = NR_TEST_UTILS.require("@node-red/registry/lib/registry");
const { events } = NR_TEST_UTILS.require("@node-red/util");
describe("red/nodes/registry/plugins",function() {
let receivedEvents = [];
let modules;
function handleEvent(evnt) {
receivedEvents.push(evnt);
}
beforeEach(function() {
plugins.init({});
receivedEvents = [];
modules = {
"test-module": {
plugins: {
"test-set": {
id: "test-module/test-set",
enabled: true,
config: "test-module-config",
plugins: []
},
"test-disabled-set": {
id: "test-module/test-disabled-set",
enabled: false,
config: "disabled-plugin-config",
plugins: []
}
}
}
}
events.on("registry:plugin-added",handleEvent);
sinon.stub(registry,"getModule").callsFake(moduleId => modules[moduleId]);
sinon.stub(registry,"getModuleList").callsFake(() => modules)
});
afterEach(function() {
events.removeListener("registry:plugin-added",handleEvent);
registry.getModule.restore();
registry.getModuleList.restore();
})
describe("registerPlugin", function() {
it("registers a plugin", function() {
let pluginDef = {}
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
receivedEvents.length.should.eql(1);
receivedEvents[0].should.eql("a-plugin");
should.exist(modules['test-module'].plugins['test-set'].plugins[0])
modules['test-module'].plugins['test-set'].plugins[0].should.equal(pluginDef)
})
it("calls a plugins onadd function", function() {
let pluginDef = { onadd: sinon.stub() }
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
pluginDef.onadd.called.should.be.true();
})
})
describe("getPlugin", function() {
it("returns a registered plugin", function() {
let pluginDef = {}
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
pluginDef.should.equal(plugins.getPlugin("a-plugin"));
})
})
describe("getPluginsByType", function() {
it("returns a plugins of a given type", function() {
let pluginDef = {type: "foo"}
let pluginDef2 = {type: "bar"}
let pluginDef3 = {type: "foo"}
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
plugins.registerPlugin("test-module/test-set","a-plugin2",pluginDef2);
plugins.registerPlugin("test-module/test-set","a-plugin3",pluginDef3);
let fooPlugins = plugins.getPluginsByType("foo");
let barPlugins = plugins.getPluginsByType("bar");
let noPlugins = plugins.getPluginsByType("none");
noPlugins.should.be.of.length(0);
fooPlugins.should.be.of.length(2);
fooPlugins.should.containEql(pluginDef);
fooPlugins.should.containEql(pluginDef3);
barPlugins.should.be.of.length(1);
barPlugins.should.containEql(pluginDef2);
})
})
describe("getPluginConfigs", function() {
it("gets all plugin configs", function() {
let configs = plugins.getPluginConfigs("en-US");
configs.should.eql(`
<!-- --- [red-plugin:test-module/test-set] --- -->
test-module-config`)
})
})
describe("getPluginList", function() {
it("returns a plugins of a given type", function() {
let pluginDef = {type: "foo"}
let pluginDef2 = {type: "bar"}
let pluginDef3 = {type: "foo"}
plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
plugins.registerPlugin("test-module/test-set","a-plugin2",pluginDef2);
plugins.registerPlugin("test-module/test-set","a-plugin3",pluginDef3);
let pluginList = plugins.getPluginList();
JSON.stringify(pluginList).should.eql(JSON.stringify(
[
{
"id": "test-module/test-set",
"enabled": true,
"local": false,
"user": false,
"plugins": [
{
"type": "foo",
"id": "a-plugin",
"module": "test-module"
},
{
"type": "bar",
"id": "a-plugin2",
"module": "test-module"
},
{
"type": "foo",
"id": "a-plugin3",
"module": "test-module"
}
]
},
{
"id": "test-module/test-disabled-set",
"enabled": false,
"local": false,
"user": false,
"plugins": []
}
]
))
})
})
describe("exportPluginSettings", function() {
it("exports plugin settings - default false", function() {
plugins.init({ "a-plugin": { a: 123, b:234, c: 345} });
plugins.registerPlugin("test-module/test-set","a-plugin",{
settings: {
a: { exportable: true },
b: {exportable: false },
d: { exportable: true, value: 456}
}
});
var exportedSet = {};
plugins.exportPluginSettings(exportedSet);
exportedSet.should.have.property("a-plugin");
// a is exportable
exportedSet["a-plugin"].should.have.property("a",123);
// b is explicitly not exportable
exportedSet["a-plugin"].should.not.have.property("b");
// c isn't listed and default false
exportedSet["a-plugin"].should.not.have.property("c");
// d has a default value
exportedSet["a-plugin"].should.have.property("d",456);
})
it("exports plugin settings - default true", function() {
plugins.init({ "a-plugin": { a: 123, b:234, c: 345} });
plugins.registerPlugin("test-module/test-set","a-plugin",{
settings: {
'*': { exportable: true },
a: { exportable: true },
b: {exportable: false },
d: { exportable: true, value: 456}
}
});
var exportedSet = {};
plugins.exportPluginSettings(exportedSet);
exportedSet.should.have.property("a-plugin");
// a is exportable
exportedSet["a-plugin"].should.have.property("a",123);
// b is explicitly not exportable
exportedSet["a-plugin"].should.not.have.property("b");
// c isn't listed, but default true
exportedSet["a-plugin"].should.have.property("c");
// d has a default value
exportedSet["a-plugin"].should.have.property("d",456);
})
});
});

View File

@@ -1,614 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* 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 path = require("path");
var NR_TEST_UTILS = require("nr-test-utils");
var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry");
const { events } = NR_TEST_UTILS.require("@node-red/util");
describe("red/nodes/registry/registry",function() {
afterEach(function() {
typeRegistry.clear();
});
function stubSettings(s,available,initialConfig) {
s.available = function() {return available;};
s.set = sinon.spy(function(s,v) { return Promise.resolve();});
s.get = function(s) { return initialConfig;};
return s;
}
var settings = stubSettings({},false,null);
var settingsWithStorageAndInitialConfig = stubSettings({},true,{"node-red":{module:"testModule",name:"testName",version:"testVersion",nodes:{"node":{id:"node-red/testName",name:"test",types:["a","b"],enabled:true}}}});
var testNodeSet1 = {
id: "test-module/test-name",
module: "test-module",
name: "test-name",
enabled: true,
loaded: false,
config: "configA",
types: [ "test-a","test-b"]
};
var testNodeSet2 = {
id: "test-module/test-name-2",
module: "test-module",
name: "test-name-2",
enabled: true,
loaded: false,
config: "configB",
types: [ "test-c","test-d"]
};
var testNodeSet2WithError = {
id: "test-module/test-name-2",
module: "test-module",
name: "test-name-2",
enabled: true,
loaded: false,
err: "I have an error",
config: "configC",
types: [ "test-c","test-d"]
};
var testNodeSet3 = {
id: "test-module-2/test-name-3",
module: "test-module-2",
name: "test-name-3",
enabled: true,
loaded: false,
config: "configB",
types: [ "test-a","test-e"]
};
describe('#init/load', function() {
it('loads initial config', function(done) {
typeRegistry.init(settingsWithStorageAndInitialConfig,null);
typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.load();
typeRegistry.getNodeList().should.have.lengthOf(1);
done();
});
it('migrates legacy format', function(done) {
var legacySettings = {
available: function() { return true; },
set: sinon.stub().returns(Promise.resolve()),
get: function() { return {
"123": {
"name": "72-sentiment.js",
"types": [
"sentiment"
],
"enabled": true
},
"456": {
"name": "20-inject.js",
"types": [
"inject"
],
"enabled": true
},
"789": {
"name": "testModule:a-module.js",
"types": [
"example"
],
"enabled":true,
"module":"testModule"
}
}}
};
var expected = JSON.parse('{"node-red":{"name":"node-red","nodes":{"sentiment":{"name":"sentiment","types":["sentiment"],"enabled":true,"module":"node-red"},"inject":{"name":"inject","types":["inject"],"enabled":true,"module":"node-red"}}},"testModule":{"name":"testModule","nodes":{"a-module.js":{"name":"a-module.js","types":["example"],"enabled":true,"module":"testModule"}}}}');
typeRegistry.init(legacySettings,null);
typeRegistry.load();
legacySettings.set.calledOnce.should.be.true();
legacySettings.set.args[0][1].should.eql(expected);
done();
});
});
describe.skip('#addNodeSet', function() {
it('adds a node set for an unknown module', function() {
typeRegistry.init(settings,null);
typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.getModuleList().should.eql({});
typeRegistry.addNodeSet("test-module/test-name",testNodeSet1, "0.0.1");
typeRegistry.getNodeList().should.have.lengthOf(1);
var moduleList = typeRegistry.getModuleList();
moduleList.should.have.a.property("test-module");
moduleList["test-module"].should.have.a.property("name","test-module");
moduleList["test-module"].should.have.a.property("version","0.0.1");
moduleList["test-module"].should.have.a.property("nodes");
moduleList["test-module"].nodes.should.have.a.property("test-name");
moduleList["test-module"].nodes["test-name"].should.eql({
config: 'configA',
id: 'test-module/test-name',
module: 'test-module',
name: 'test-name',
enabled: true,
loaded: false,
types: [ 'test-a', 'test-b' ]
});
});
it('adds a node set to an existing module', function() {
typeRegistry.init(settings,null);
typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.getModuleList().should.eql({});
typeRegistry.addNodeSet("test-module/test-name",testNodeSet1, "0.0.1");
typeRegistry.getNodeList().should.have.lengthOf(1);
var moduleList = typeRegistry.getModuleList();
Object.keys(moduleList).should.have.a.lengthOf(1);
moduleList.should.have.a.property("test-module");
moduleList["test-module"].should.have.a.property("name","test-module");
moduleList["test-module"].should.have.a.property("version","0.0.1");
moduleList["test-module"].should.have.a.property("nodes");
Object.keys(moduleList["test-module"].nodes).should.have.a.lengthOf(1);
moduleList["test-module"].nodes.should.have.a.property("test-name");
typeRegistry.addNodeSet("test-module/test-name-2",testNodeSet2);
typeRegistry.getNodeList().should.have.lengthOf(2);
moduleList = typeRegistry.getModuleList();
Object.keys(moduleList).should.have.a.lengthOf(1);
Object.keys(moduleList["test-module"].nodes).should.have.a.lengthOf(2);
moduleList["test-module"].nodes.should.have.a.property("test-name");
moduleList["test-module"].nodes.should.have.a.property("test-name-2");
});
it('doesnt add node set types if node set has an error', function() {
typeRegistry.init(settings,null);
typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.getModuleList().should.eql({});
typeRegistry.addNodeSet("test-module/test-name",testNodeSet1, "0.0.1");
typeRegistry.getTypeId("test-a").should.eql("test-module/test-name");
should.not.exist(typeRegistry.getTypeId("test-c"));
typeRegistry.addNodeSet("test-module/test-name-2",testNodeSet2WithError, "0.0.1");
should.not.exist(typeRegistry.getTypeId("test-c"));
});
it('doesnt add node set if type already exists', function() {
typeRegistry.init(settings,null);
typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.getModuleList().should.eql({});
should.not.exist(typeRegistry.getTypeId("test-e"));
typeRegistry.addNodeSet("test-module/test-name",testNodeSet1, "0.0.1");
typeRegistry.getNodeList().should.have.lengthOf(1);
should.exist(typeRegistry.getTypeId("test-a"));
typeRegistry.addNodeSet(testNodeSet3.id,testNodeSet3, "0.0.1");
typeRegistry.getNodeList().should.have.lengthOf(2);
// testNodeSet3 registers a duplicate test-a and unique test-e
// as test-a is a duplicate, test-e should not get registered
should.not.exist(typeRegistry.getTypeId("test-e"));
var testNodeSet3Result = typeRegistry.getNodeList()[1];
should.exist(testNodeSet3Result.err);
testNodeSet3Result.err.code.should.equal("type_already_registered");
testNodeSet3Result.err.details.type.should.equal("test-a");
testNodeSet3Result.err.details.moduleA.should.equal("test-module");
testNodeSet3Result.err.details.moduleB.should.equal("test-module-2");
//
// typeRegistry.addNodeSet("test-module/test-name-2",testNodeSet2WithError, "0.0.1");
//
// should.not.exist(typeRegistry.getTypeId("test-c"));
});
});
describe("#enableNodeSet", function() {
it('throws error if settings unavailable', function() {
typeRegistry.init(settings,null);
/*jshint immed: false */
(function(){
typeRegistry.enableNodeSet("test-module/test-name");
}).should.throw("Settings unavailable");
});
it('throws error if module unknown', function() {
typeRegistry.init(settingsWithStorageAndInitialConfig,null);
/*jshint immed: false */
(function(){
typeRegistry.enableNodeSet("test-module/unknown");
}).should.throw("Unrecognised id: test-module/unknown");
});
it.skip('enables the node',function(){})
});
describe("#disableNodeSet", function() {
it('throws error if settings unavailable', function() {
typeRegistry.init(settings,null);
/*jshint immed: false */
(function(){
typeRegistry.disableNodeSet("test-module/test-name");
}).should.throw("Settings unavailable");
});
it('throws error if module unknown', function() {
typeRegistry.init(settingsWithStorageAndInitialConfig,null);
/*jshint immed: false */
(function(){
typeRegistry.disableNodeSet("test-module/unknown");
}).should.throw("Unrecognised id: test-module/unknown");
});
it.skip('disables the node',function(){})
});
describe('#getNodeConfig', function() {
it('returns nothing for an unregistered type config', function(done) {
typeRegistry.init(settings,null);
var config = typeRegistry.getNodeConfig("imaginary-shark");
(config === null).should.be.true();
done();
});
});
describe('#saveNodeList',function() {
it('rejects when settings unavailable',function(done) {
typeRegistry.init(stubSettings({},false,{}),null);
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {"test-name":{module:"test-module",name:"test-name",types:[]}}});
typeRegistry.saveNodeList().catch(function(err) {
done();
});
});
it('saves the list',function(done) {
var s = stubSettings({},true,{});
typeRegistry.init(s,null);
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":testNodeSet1,
"test-name-2":testNodeSet2WithError
}});
typeRegistry.saveNodeList().then(function() {
s.set.called.should.be.true();
s.set.lastCall.args[0].should.eql('nodes');
var nodes = s.set.lastCall.args[1];
nodes.should.have.property('test-module');
for (var n in nodes['test-module'].nodes) {
if (nodes['test-module'].nodes.hasOwnProperty(n)) {
var nn = nodes['test-module'].nodes[n];
nn.should.not.have.property('err');
nn.should.not.have.property('id');
}
}
done();
}).catch(function(err) {
done(err);
});
});
});
describe('#removeModule',function() {
it('throws error for unknown module', function() {
var s = stubSettings({},true,{});
typeRegistry.init(s,null);
/*jshint immed: false */
(function(){
typeRegistry.removeModule("test-module/unknown");
}).should.throw("Unrecognised module: test-module/unknown");
});
it('throws error for unavaiable settings', function() {
var s = stubSettings({},false,{});
typeRegistry.init(s,null);
/*jshint immed: false */
(function(){
typeRegistry.removeModule("test-module/unknown");
}).should.throw("Settings unavailable");
});
it('removes a known module', function() {
var s = stubSettings({},true,{});
typeRegistry.init(s,null);
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":testNodeSet1
}});
var moduleList = typeRegistry.getModuleList();
moduleList.should.have.a.property("test-module");
typeRegistry.getNodeList().should.have.lengthOf(1);
var info = typeRegistry.removeModule('test-module');
moduleList = typeRegistry.getModuleList();
moduleList.should.not.have.a.property("test-module");
typeRegistry.getNodeList().should.have.lengthOf(0);
});
});
describe('#get[All]NodeConfigs', function() {
it('returns node config', function() {
typeRegistry.init(settings,{
getNodeHelp: function(config) { return "HE"+config.name+"LP" }
});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{
id: "test-module/test-name",
module: "test-module",
name: "test-name",
enabled: true,
loaded: false,
config: "configA",
types: [ "test-a","test-b"]
},
"test-name-2":{
id: "test-module/test-name-2",
module: "test-module",
name: "test-name-2",
enabled: true,
loaded: false,
config: "configB",
types: [ "test-c","test-d"]
}
}});
typeRegistry.getNodeConfig("test-module/test-name").should.eql('<!-- --- [red-module:test-module/test-name] --- -->\nconfigAHEtest-nameLP');
typeRegistry.getNodeConfig("test-module/test-name-2").should.eql('<!-- --- [red-module:test-module/test-name-2] --- -->\nconfigBHEtest-name-2LP');
typeRegistry.getAllNodeConfigs().should.eql('\n<!-- --- [red-module:test-module/test-name] --- -->\nconfigAHEtest-nameLP\n<!-- --- [red-module:test-module/test-name-2] --- -->\nconfigBHEtest-name-2LP');
});
});
describe('#getModuleInfo', function() {
it('returns module info', function() {
typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{
id: "test-module/test-name",
module: "test-module",
name: "test-name",
enabled: true,
loaded: false,
config: "configA",
types: [ "test-a","test-b"],
file: "abc"
}
}});
var moduleInfo = typeRegistry.getModuleInfo("test-module");
moduleInfo.should.have.a.property('name','test-module');
moduleInfo.should.have.a.property('version','0.0.1');
moduleInfo.should.have.a.property('nodes');
moduleInfo.nodes.should.have.a.lengthOf(1);
moduleInfo.nodes[0].should.have.a.property('id','test-module/test-name');
moduleInfo.nodes[0].should.not.have.a.property('file');
});
});
describe('#getNodeInfo', function() {
it('returns node info', function() {
typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{
id: "test-module/test-name",
module: "test-module",
name: "test-name",
enabled: true,
loaded: false,
config: "configA",
types: [ "test-a","test-b"],
file: "abc"
}
}});
var nodeSetInfo = typeRegistry.getNodeInfo("test-module/test-name");
nodeSetInfo.should.have.a.property('id',"test-module/test-name");
nodeSetInfo.should.not.have.a.property('config');
nodeSetInfo.should.not.have.a.property('file');
});
});
describe('#getFullNodeInfo', function() {
it('returns node info', function() {
typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{
id: "test-module/test-name",
module: "test-module",
name: "test-name",
enabled: true,
loaded: false,
config: "configA",
types: [ "test-a","test-b"],
file: "abc"
}
}});
var nodeSetInfo = typeRegistry.getFullNodeInfo("test-module/test-name");
nodeSetInfo.should.have.a.property('id',"test-module/test-name");
nodeSetInfo.should.have.a.property('config');
nodeSetInfo.should.have.a.property('file');
});
});
describe('#cleanModuleList', function() {
it.skip("cleans the module list");
});
describe('#getNodeList', function() {
it("returns a filtered list", function() {
typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{
id: "test-module/test-name",
module: "test-module",
name: "test-name",
enabled: true,
loaded: false,
config: "configA",
types: [ "test-a","test-b"],
file: "abc"
},
"test-name-2":{
id: "test-module/test-name-2",
module: "test-module",
name: "test-name-2",
enabled: true,
loaded: false,
config: "configB",
types: [ "test-c","test-d"],
file: "def"
}
}});
var filterCallCount = 0;
var filteredList = typeRegistry.getNodeList(function(n) { filterCallCount++; return n.name === 'test-name-2';});
filterCallCount.should.eql(2);
filteredList.should.have.a.lengthOf(1);
filteredList[0].should.have.a.property('id',"test-module/test-name-2");
});
});
describe('#registerNodeConstructor', function() {
var TestNodeConstructor;
beforeEach(function() {
TestNodeConstructor = function TestNodeConstructor() {};
sinon.stub(events,'emit');
});
afterEach(function() {
events.emit.restore();
});
it('registers a node constructor', function() {
typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor);
events.emit.calledOnce.should.be.true();
events.emit.lastCall.args[0].should.eql('type-registered');
events.emit.lastCall.args[1].should.eql('node-type');
})
it('throws error on duplicate node registration', function() {
typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor);
events.emit.calledOnce.should.be.true();
events.emit.lastCall.args[0].should.eql('type-registered');
events.emit.lastCall.args[1].should.eql('node-type');
/*jshint immed: false */
(function(){
typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor);
}).should.throw("node-type already registered");
events.emit.calledOnce.should.be.true();
});
});
describe('#getNodeIconPath', function() {
it('returns the null when getting an unknown icon', function() {
var iconPath = typeRegistry.getNodeIconPath('random-module','youwonthaveme.png');
should.not.exist(iconPath);
});
it('returns a registered icon' , function() {
var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/');
typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{
id: "test-module/test-name",
module: "test-module",
name: "test-name",
enabled: true,
loaded: false,
config: "configA",
types: [ "test-a","test-b"],
file: "abc"
}
},icons: [{path:testIcon,icons:['test_icon.png']}]});
var iconPath = typeRegistry.getNodeIconPath('test-module','test_icon.png');
iconPath.should.eql(path.resolve(testIcon+"/test_icon.png"));
});
it('returns null when getting an unknown module', function() {
var debugIcon = path.resolve(__dirname+'/../../../public/icons/debug.png');
var iconPath = typeRegistry.getNodeIconPath('unknown-module', 'debug.png');
should.not.exist(iconPath);
});
});
describe('#getNodeIcons', function() {
it('returns empty icon list when no modules are registered', function() {
var iconList = typeRegistry.getNodeIcons();
iconList.should.eql({});
});
it('returns an icon list of registered node module', function() {
var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/');
typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{
id: "test-module/test-name",
module: "test-module",
name: "test-name",
enabled: true,
loaded: false,
config: "configA",
types: [ "test-a","test-b"],
file: "abc"
}
},icons: [{path:testIcon,icons:['test_icon.png']}]});
var iconList = typeRegistry.getNodeIcons();
iconList.should.eql({"test-module":["test_icon.png"]});
});
});
describe('#getModuleResource', function() {
beforeEach(function() {
typeRegistry.init(settings,{});
typeRegistry.addModule({
name: "test-module",version:"0.0.1",nodes: {
"test-name":{
id: "test-module/test-name",
module: "test-module",
name: "test-name",
enabled: true,
loaded: false,
config: "configA",
types: [ "test-a","test-b"],
file: "abc"
}
},
resources: {
path: path.join(__dirname, "resources","examples")
}
});
});
it('Returns valid resource path', function() {
const result = typeRegistry.getModuleResource("test-module","one.json");
should.exist(result);
result.should.eql(path.join(__dirname, "resources","examples","one.json"))
});
it('Returns null for path that tries to break out', function() {
// Note - this path exists, but we don't allow .. in the resolved path to
// avoid breaking out of the resources dir
const result = typeRegistry.getModuleResource("test-module","../../index_spec.js");
should.not.exist(result);
});
it('Returns null for path that does not exist', function() {
const result = typeRegistry.getModuleResource("test-module","two.json");
should.not.exist(result);
});
});
});

View File

@@ -1,5 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function DuffNode(n) {}
RED.nodes.registerType("duff-node",DuffNode);
}

View File

@@ -1,3 +0,0 @@
<script type="text/x-red" data-template-name="test-node-1"></script>
<script type="text/x-red" data-help-name="test-node-1"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-1',{});</script>

View File

@@ -1,5 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function DuplicateTestNode(n) {}
RED.nodes.registerType("test-node-1",DuplicateTestNode);
}

View File

@@ -1,6 +0,0 @@
<script type="text/x-red" data-template-name="test-node-multiple-1a"></script>
<script type="text/x-red" data-help-name="test-node-multiple-1a"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-multiple-1a',{});</script>
<script type="text/x-red" data-template-name="test-node-multiple-1b"></script>
<script type="text/x-red" data-help-name="test-node-multiple-1b"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-multiple-1b',{});</script>

View File

@@ -1,7 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function TestNode1(n) {}
RED.nodes.registerType("test-node-multiple-1a",TestNode1);
function TestNode2(n) {}
RED.nodes.registerType("test-node-multiple-1b",TestNode2);
}

View File

@@ -1,4 +0,0 @@
<script type="text/x-red" data-template-name="nested-node-1"></script>
<script type="text/x-red" data-help-name="nested-node-1"></script>
<script type="text/javascript">RED.nodes.registerType('nested-node-1',{});</script>
<style></style>

View File

@@ -1,5 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function TestNode(n) {}
RED.nodes.registerType("nested-node-1",TestNode);
}

View File

@@ -1,4 +0,0 @@
<script type="text/x-red" data-template-name="should-not-load-1"></script>
<script type="text/x-red" data-help-name="should-not-load-1"></script>
<script type="text/javascript">RED.nodes.registerType('should-not-load-1',{});</script>
<style></style>

View File

@@ -1,5 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function TestNode(n) {}
RED.nodes.registerType("should-not-load-1",TestNode);
}

View File

@@ -1,4 +0,0 @@
<script type="text/x-red" data-template-name="should-not-load-2"></script>
<script type="text/x-red" data-help-name="should-not-load-2"></script>
<script type="text/javascript">RED.nodes.registerType('should-not-load-2',{});</script>
<style></style>

View File

@@ -1,5 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function TestNode(n) {}
RED.nodes.registerType("should-not-load-2",TestNode);
}

View File

@@ -1,4 +0,0 @@
<script type="text/x-red" data-template-name="should-not-load-3"></script>
<script type="text/x-red" data-help-name="should-not-load-3"></script>
<script type="text/javascript">RED.nodes.registerType('should-not-load-3',{});</script>
<style></style>

View File

@@ -1,5 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function TestNode(n) {}
RED.nodes.registerType("should-not-load-3",TestNode);
}

View File

@@ -1,5 +0,0 @@
<script type="text/x-red" data-template-name="test-node-1"></script>
<script type="text/x-red" data-help-name="test-node-1"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-1',{});</script>
<style></style>
<p>this should be filtered out</p>

View File

@@ -1,5 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function TestNode(n) {}
RED.nodes.registerType("test-node-1",TestNode);
}

View File

@@ -1,4 +0,0 @@
<script type="text/x-red" data-template-name="test-node-2"></script>
<script type="text/x-red" data-help-name="test-node-2"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-2',{});</script>
<style></style>

View File

@@ -1,9 +0,0 @@
// A test node that exports a function which returns a resolving promise
module.exports = function(RED) {
return new Promise(function(resolve,reject) {
function TestNode(n) {}
RED.nodes.registerType("test-node-2",TestNode);
resolve();
});
}

View File

@@ -1,3 +0,0 @@
<script type="text/x-red" data-template-name="test-node-3"></script>
<script type="text/x-red" data-help-name="test-node-3"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-3',{});</script>

View File

@@ -1,7 +0,0 @@
// A test node that exports a function which returns a rejecting promise
module.exports = function(RED) {
return new Promise(function(resolve,reject) {
reject("fail");
});
}

View File

@@ -1,3 +0,0 @@
<script type="text/x-red" data-template-name="test-node-3"></script>
<script type="text/x-red" data-help-name="test-node-3"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-3',{});</script>

View File

@@ -1 +0,0 @@
throw new Error("fail to require");

View File

@@ -1 +0,0 @@
This file exists just to ensure the parent directory is in the repository.

View File

@@ -1,5 +0,0 @@
<script type="text/x-red" data-template-name="test-node-mod-1"></script>
<script type="text/x-red" data-help-name="test-node-mod-1"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-mod-1',{});</script>
<style></style>
<p>this should be filtered out</p>

View File

@@ -1,5 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function TestNode(n) {}
RED.nodes.registerType("test-node-mod-1",TestNode);
}

View File

@@ -1,5 +0,0 @@
<script type="text/x-red" data-template-name="test-node-mod-2"></script>
<script type="text/x-red" data-help-name="test-node-mod-2"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-mod-2',{});</script>
<style></style>
<p>this should be filtered out</p>

View File

@@ -1,4 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
throw new Error("fail to load");
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 B

View File

@@ -1,3 +0,0 @@
This file exists just to ensure the 'icons' directory is in the repository.
TODO: a future test needs to ensure the right icon files are loaded - this
directory can be used for that

View File

@@ -1,11 +0,0 @@
{
"name" : "TestNodeModule",
"version" : "0.0.1",
"description" : "A test node module",
"node-red" : {
"nodes": {
"TestNodeMod1": "TestNodeModule.js",
"TestNodeMod2": "TestNodeModule2.js"
}
}
}

View File

@@ -1,5 +0,0 @@
<script type="text/x-red" data-template-name="test-node-mod-1"></script>
<script type="text/x-red" data-help-name="test-node-mod-1"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-mod-1',{});</script>
<style></style>
<p>this should be filtered out</p>

View File

@@ -1,5 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
function TestNode(n) {}
RED.nodes.registerType("test-node-mod-1",TestNode);
}

View File

@@ -1,5 +0,0 @@
<script type="text/x-red" data-template-name="test-node-mod-2"></script>
<script type="text/x-red" data-help-name="test-node-mod-2"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-mod-2',{});</script>
<style></style>
<p>this should be filtered out</p>

View File

@@ -1,4 +0,0 @@
// A test node that exports a function
module.exports = function(RED) {
throw new Error("fail to load");
}

View File

@@ -1,3 +0,0 @@
This file exists just to ensure the 'icons' directory is in the repository.
TODO: a future test needs to ensure the right icon files are loaded - this
directory can be used for that

View File

@@ -1,12 +0,0 @@
{
"name" : "VersionMismatchModule",
"version" : "0.0.1",
"description" : "A test node module",
"node-red" : {
"version": "100.0.0",
"nodes": {
"VersionMismatchMod1": "TestNodeModule.js",
"VersionMismatchMod2": "TestNodeModule2.js"
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 B

View File

@@ -1,5 +0,0 @@
<script type="text/x-red" data-template-name="test-node-5"></script>
<script type="text/x-red" data-help-name="test-node-5"></script>
<script type="text/javascript">RED.nodes.registerType('test-node-5',{});</script>
<style></style>
<p>this should be filtered out</p>

View File

@@ -1 +0,0 @@
throw new Error("fail to require");

View File

@@ -1,3 +0,0 @@
describe("red/nodes/registry/subflow",function() {
it.skip("NEEDS TESTS");
});

View File

@@ -1,115 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* 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.
**/
const should = require("should");
const sinon = require("sinon");
const NR_TEST_UTILS = require("nr-test-utils");
const registryUtil = NR_TEST_UTILS.require("@node-red/registry/lib/util");
// Get the internal runtime api
const runtime = NR_TEST_UTILS.require("@node-red/runtime")._;
const i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
describe("red/nodes/registry/util",function() {
describe("createNodeApi", function() {
let i18n_;
let registerType;
let registerSubflow;
before(function() {
i18n_ = sinon.stub(i18n,"_").callsFake(function() {
return Array.prototype.slice.call(arguments,0);
})
registerType = sinon.stub(runtime.nodes,"registerType");
registerSubflow = sinon.stub(runtime.nodes,"registerSubflow");
});
after(function() {
i18n_.restore();
registerType.restore();
registerSubflow.restore();
})
it("builds node-specific view of runtime api", function() {
registryUtil.init(runtime);
var result = registryUtil.createNodeApi({id: "my-node", namespace: "my-namespace"})
// Need a better strategy here.
// For now, validate the node-custom functions
var message = result._("message");
// This should prepend the node's namespace to the message
message.should.eql([ 'my-namespace:message' ]);
var nodeConstructor = () => {};
var nodeOpts = {};
result.nodes.registerType("type",nodeConstructor, nodeOpts);
registerType.called.should.be.true();
registerType.lastCall.args[0].should.eql("my-node")
registerType.lastCall.args[1].should.eql("type")
registerType.lastCall.args[2].should.eql(nodeConstructor)
registerType.lastCall.args[3].should.eql(nodeOpts)
var subflowDef = {};
result.nodes.registerSubflow(subflowDef);
registerSubflow.called.should.be.true();
registerSubflow.lastCall.args[0].should.eql("my-node")
registerSubflow.lastCall.args[1].should.eql(subflowDef)
});
});
describe("checkModuleAllowed", function() {
function checkList(module, version, allowList, denyList) {
return registryUtil.checkModuleAllowed(
module,
version,
registryUtil.parseModuleList(allowList),
registryUtil.parseModuleList(denyList)
)
}
it("allows module with no allow/deny list provided", function() {
checkList("abc","1.2.3",[],[]).should.be.true();
})
it("defaults allow to * when only deny list is provided", function() {
checkList("abc","1.2.3",["*"],["def"]).should.be.true();
checkList("def","1.2.3",["*"],["def"]).should.be.false();
})
it("uses most specific matching rule", function() {
checkList("abc","1.2.3",["ab*"],["a*"]).should.be.true();
checkList("def","1.2.3",["d*"],["de*"]).should.be.false();
})
it("checks version string using semver rules", function() {
// Deny
checkList("abc","1.2.3",["abc@1.2.2"],["*"]).should.be.false();
checkList("abc","1.2.3",["abc@1.2.4"],["*"]).should.be.false();
checkList("abc","1.2.3",["abc@>1.2.3"],["*"]).should.be.false();
checkList("abc","1.2.3",["abc@>=1.2.3"],["abc"]).should.be.false();
checkList("node-red-contrib-foo","1.2.3",["*"],["*contrib*"]).should.be.false();
// Allow
checkList("abc","1.2.3",["abc@1.2.3"],["*"]).should.be.true();
checkList("abc","1.2.3",["abc@<1.2.4"],["*"]).should.be.true();
checkList("abc","1.2.3",["abc"],["abc@>1.2.3"]).should.be.true();
checkList("abc","1.2.3",["abc"],["abc@<1.2.3||>1.2.3"]).should.be.true();
checkList("node-red-contrib-foo","1.2.3",["*contrib*"],["*"]).should.be.true();
})
})
});