add unit test for uci.js

This commit is contained in:
Martin Schröder 2016-12-13 14:16:20 +01:00
parent 284ef14400
commit a7234b93bf
8 changed files with 156 additions and 458 deletions

3
juci/src/js/runtests.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
istanbul cover _mocha -- -u exports -R tap

View File

@ -0,0 +1,134 @@
/*global.JSON = require("JSON");
global.async = require("async");
global.$ = global.jQuery = require("jquery-deferred");
global.$.ajax = require("najax");
global.async = require("async");
global.watch = require("watchjs").watch;
global.expect = require("expect.js");
*/
global.assert = require("assert");
global.async = require("async");
global.$ = global.jQuery = require("jquery-deferred");
global.UBUS = {
uci: {
get: function(params){
console.log("UCI get");
var def = $.Deferred();
setTimeout(function(){
def.resolve({
values: {
".name": "mysection",
".type": "test",
field: "foo"
}
});
}, 0);
return def.promise();
},
set: function(params){
console.log("UCI add");
var def = $.Deferred();
setTimeout(function(){
def.resolve({
});
}, 0);
return def.promise();
},
add: function(params){
console.log("UCI add");
var def = $.Deferred();
setTimeout(function(){
def.resolve({
section: params["name"] || "unknown"
});
}, 0);
return def.promise();
}
}
};
var uci = require("../uci");
UCI.$registerConfig("test");
UCI.test.$registerSectionType("test", {
"field": { dvalue: "test", type: String }
});
describe("Basic test", function(){
it("tests the basic function of loading a config", function(done){
UCI.$sync("test").done(function(){
done();
}).fail(function(){
done(new Error("unable to sync config"));
});
});
});
describe("Section operations", function(){
it("add a new section", function(done){
UCI.test.$create({
".name": "mysection",
".type": "test",
"field": "value"
}).done(function(){
var s = UCI.test["@test"][0];
assert.equal(s.field.value, "value");
assert.equal(UCI.test.mysection.field.value, "value");
done();
}).fail(function(){
done(new Error("unable to create section"));
});
});
it("add a new section with invalid type", function(done){
try {
UCI.test.$create({
".name": "mysection",
".type": "noexist"
}).done(function(){
done(new Error("Able to create invlid sections"));
}).fail(function(){
done(new Error("unable to create section"));
});
} catch(err){
done();
}
});
it("saves a section", function(done){
UCI.$save().done(function(){
done();
});
});
it("modifies a field and then saves a section", function(done){
UCI.test.mysection.field.value = "newstuff";
UCI.$save().done(function(){
done();
});
});
});
describe("Field operations", function(){
it("try setting different values", function(done){
UCI.test.$create({
".name": "another",
".type": "test",
"field": "value"
}).done(function(){
var s = UCI.test["@test"][1];
assert.equal(s.field.value, "value");
s.field.value = "me";
assert.equal(s.field.value, "me");
assert.equal(s.field.uvalue, "me");
assert.equal(s.field.dvalue, "test");
assert.equal(s.field.ovalue, "value");
done();
}).fail(function(){
done(new Error("unable to create section"));
});
});
});

View File

@ -318,6 +318,9 @@
$commit: function(){
this.$update(this.uvalue, false);
},
get dvalue(){
return this.schema.dvalue;
},
get value(){
if(this.schema.type == Boolean){
var uvalue = (this.uvalue == undefined)?this.ovalue:this.uvalue;
@ -767,7 +770,10 @@
if(!$rpc.uci) {
// this will happen if there is no router connection!
setTimeout(function(){ deferred.reject(); }, 0);
setTimeout(function(){
console.error("uci is not defined!");
deferred.reject();
}, 0);
return deferred.promise();
}

View File

@ -1,68 +0,0 @@
//! Author: Martin K. Schröder <mkschreder.uk@gmail.com>
#!javascript
var assert = require("assert");
var JSON = require("juci/json");
//global.XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
global.$ = global.jQuery = require("jquery-deferred");
global.$.ajax = require("najax");
var async = require("async");
require("../htdocs/lib/js/jquery-jsonrpc");
//global.request = require("../htdocs/lib/js/request").request;
require("../htdocs/js/rpc");
require("../htdocs/js/uci");
var $rpc = global.UBUS;
var $uci = global.UCI;
var username;
var password;
for(var i = 0; i < process.argv.length; i++){
switch(process.argv[i]){
case "--pass": password = process.argv[++i]; break;
case "--user": username = process.argv[++i]; break;
};
}
if(!username || !password){
console.error("Please specify -u <rpcuser> and -p <rpcpassword> arguments!");
process.exit();
}
function init(){
var deferred = $.Deferred();
async.series([
function(next){
$rpc.$init({host: "http://192.168.1.4"}).done(function(){
console.log("Initialized rpc: "+Object.keys($rpc));
next();
});
},
function(next){
$rpc.$login({username: username, password: password}).done(function(){
next();
});
},
function(next){
$uci.$init().done(function(){
console.log("Initialized uci: "+Object.keys($uci));
next();
});
}
], function(){
deferred.resolve();
});
return deferred.promise();
}
exports.test = function(){
console.log("test");
}
describe("test", function(){
it("should pass", function(done){
init().done(function(){
assert.equal(0, 0);
done();
});
});
});

View File

@ -1,208 +0,0 @@
global.assert = require("assert");
global.JSON = require("juci/json");
global.async = require("async");
global.$ = global.jQuery = require("jquery-deferred");
global.$.ajax = require("najax");
global.async = require("async");
global.watch = require("watchjs").watch;
global.expect = require("expect.js");
require("../htdocs/lib/js/jquery-jsonrpc");
require("../htdocs/js/localStorage");
require("../htdocs/js/rpc");
require("../htdocs/js/uci");
var $rpc = global.$rpc = global.UBUS;
var $uci = global.$uci = global.UCI;
Object.prototype.assign = require("object-assign");
global.annotate = function annotate(fn) {
var $inject,
fnText,
argDecl,
last;
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
if (typeof fn == 'function') {
if (!($inject = fn.$inject)) {
$inject = [];
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg){
arg.replace(FN_ARG, function(all, underscore, name){
$inject.push(name);
});
});
fn.$inject = $inject;
}
} else if (isArray(fn)) {
last = fn.length - 1;
assertArgFn(fn[last], 'fn')
$inject = fn.slice(0, last);
} else {
assertArgFn(fn, 'fn', true);
}
return $inject;
}
function JUCIMock(){
var _controllers = {};
var self = this;
self.app = {
directive: function(name, fn){
console.log("JUCI.app.directive("+name+")");
return self.app;
},
controller: function(name, fn){
console.log("JUCI.app.controller("+name+")");
_controllers[name] = fn;
return self.app;
},
config: function(){}
}
self.redirect = function(url){
console.log("JUCIMock redirect: "+url);
}
function LocalStorageMock(){
var _items = {};
this.getItem = function(name){
return _items[name];
}
this.setItem = function(name, value){
_items[name] = value;
}
}
function MockWindow(){
var _location = "";
this.location = {
set href(value){
console.log("window.location.href="+value);
_location = value;
},
get href(){
return _location;
}
}
}
global.window = new MockWindow();
function MockLanguages(){
var _currentLanguage;
this.getLanguages = function(){
return ["se", "en"];
},
this.setLanguage = function(short_code){
_currentLanguage = short_code;
}
}
var mocks = {
"$window": global.window,
"$state": { },
"$session": global.UBUS.$session,
"$localStorage": new LocalStorageMock(),
"$rpc": global.UBUS,
"$uci": global.UCI,
"gettext": function(str) { return str; },
"$tr": function(str) { return str; },
"$languages": new MockLanguages()
};
global.controller = function(name, scope){
if(_controllers[name] !== undefined){
var ctrl = _controllers[name];
scope.$apply = function(){
console.log("$scope.apply");
}
scope.$watch = function(name, fn){
global.watch(this, name, function(){
fn(this[name]);
});
}
var args = annotate(ctrl).map(function(x){
switch(x){
case "$scope":
return scope;
default:
if(x in mocks) return mocks[x];
else if(x in global) return global[x];
else{
console.error("Missing mock for "+x);
return undefined;
}
}
});
ctrl.apply(ctrl, args);
}
else throw new Error("Controller "+name+" was not found!");
}
}
global.JUCI = new JUCIMock();
var PARAMS = {
host: "localhost",
username: "",
password: ""
};
for(var i = 0; i < process.argv.length; i++){
switch(process.argv[i]){
case "--pass": PARAMS.password = process.argv[++i]; break;
case "--user": PARAMS.username = process.argv[++i]; break;
case "--host": PARAMS.host = process.argv[++i]; break;
};
}
if(!PARAMS.username || !PARAMS.password ){
console.error("Please specify --user <rpcuser> and --pass <rpcpassword> arguments!");
process.exit();
}
global.PARAMS = PARAMS;
function init(){
var deferred = $.Deferred();
async.series([
function(next){
console.log("Trying to connect to RPC host '"+PARAMS.host+"'...");
$rpc.$init({host: "http://"+PARAMS.host}).done(function(){
//console.log("Initialized rpc: "+Object.keys($rpc));
next();
}).fail(function(){
throw new Error("Could not connect to rpc host!");
});
},
function(next){
$rpc.$login({username: PARAMS.username, password: PARAMS.password}).done(function(){
next();
}).fail(function(){
throw new Error("Could not login over RPC using specified username and password!");
});
},
function(next){
$uci.$init().done(function(){
//console.log("Initialized uci: "+Object.keys($uci));
next();
});
}
], function(){
deferred.resolve();
});
return deferred.promise();
}
before(function(done){
init().done(function(){
done();
});
});
exports.$uci = $uci;
exports.$init = init;
exports.$rpc = $rpc;
exports.app = {
config: function(func){
//func();
}
}

View File

@ -1,15 +0,0 @@
//! Author: Martin K. Schröder <mkschreder.uk@gmail.com>
#!javascript
require("./lib-juci");
describe("JUCI", function(){
it("should have questd installed on router", function(){
expect($rpc.router).to.be.an(Object);
expect($rpc.router.info).to.be.a(Function);
});
it("should have juci installed on the router", function(){
// TODO: rename juci stuff to juci
expect($rpc.juci).to.be.an(Object);
expect($rpc.juci.ui.menu).to.be.a(Function);
});
});

View File

@ -1,156 +0,0 @@
//! Author: Martin K. Schröder <mkschreder.uk@gmail.com>
#!javascript
require("./lib-juci");
describe("UCI", function(){
beforeEach(function(done){
$uci.$sync().done(function(){
expect($uci).to.have.property("juci");
var to_delete = $uci.juci["@test"].map(function(x){
return x;
});
// have to use a copy of the array because deletion modifies the array
async.eachSeries(to_delete, function(section, next){
section.$delete().done(function(){
next();
}).fail(function(){
throw new Error("Was unable to delete section "+section[".name"]+" from config juci!");
});
}, function(){
$uci.save().done(function(){
done();
});
});
});
});
it("should have schema definition for each data field found in each defined uci config", function(done){
//$uci.sync().done(function(){
// get all configs that have been successfully loaded
var configs_map = {} ;
$uci.$eachConfig(function(cf){
configs_map[cf[".name"]] = cf;
});
// for each config, retreive the raw data using rpc and compare that all fields in rpc data are present in the uci data
async.eachSeries(Object.keys(configs_map), function(k, next){
console.log("Testing config "+k);
var cf = configs_map[k];
$rpc.uci.state({config: k}).done(function(result){
Object.keys(result.values).filter(function(x){
return x in cf;
}).map(function(name){
var values = result.values[name];
var section = cf[name];
console.log(".. testing section "+name+" of type "+section[".type"]);
expect(section).to.be.ok();
var type = section[".section_type"];
expect(type).to.be.ok();
Object.keys(values).filter(function(x){
return x.indexOf(".") != 0; // filter out hidden values
}).map(function(x){
expect(Object.keys(type)).to.contain(x);
});
});
next();
}).fail(function(){
throw new Error("Have not been able to retreive state for config "+k);
});
}, function(){
done();
});
//});
});
// will create an anonymous 'test' section and then delete it, commiting the changes
it("should be able to add and delete an anonymous section", function(done){
expect($uci.juci["@test"]).to.be.empty();
$uci.juci.create({".type": "test"}).done(function(section){
expect($uci.juci["@test"]).to.be.ok();
expect($uci.juci["@test"].length).not.to.be(0);
expect($uci.juci["@test"]).to.contain(section);
section.str.value = "test";
$uci.save().done(function(){
$uci.$sync("juci").done(function(){
expect($uci.juci["@test"]).to.contain(section);
expect($uci.juci[section[".name"]]).to.be.ok();
expect($uci.juci[section[".name"]].str.value).to.eql("test");
section.$delete().done(function(){
expect(section[".name"]).to.be.ok();
expect($uci.juci[section[".name"]]).not.to.be.ok();
expect($uci.juci["@test"]).to.be.empty();
$uci.save().done(function(){
done();
}).fail(function(){
throw new Error("Was unable to save uci config after deleting section!");
});
}).fail(function(){
throw new Error("Deleting section has failed!");
});
}).fail(function(){
throw new Error("Was unable to sync config juci. Check that acl list on the server allows access to juci config!");
});
}).fail(function(){
throw new Error("Was unable to save newly created section in juci config!");
});
}).fail(function(){
throw new Error("Was unable to create section 'test' in config juci");
});
});
// will try to resync (old changes should be reverted also on the server)
it("should remove previously created section if resync is done without saving", function(done){
expect($uci.juci["@test"]).to.be.empty();
$uci.juci.create({".type": "test"}).done(function(section){
expect($uci.juci["@test"]).to.contain(section);
expect($uci.juci["@test"].length).to.be(1);
$uci.$sync("juci").done(function(){
expect($uci.juci["@test"]).to.be.empty();
expect($uci.juci["@test"]).not.to.contain(section);
$uci.save().done(function(){ // this should not commit previulsy added section!
$uci.$sync("juci").done(function(){
expect($uci.juci["@test"]).to.be.empty();
expect($uci.juci["@test"]).not.to.contain(section);
done();
});
});
}).fail(function(){
throw new Error("Was unable to sync config juci. Check that acl list on the server allows access to juci config!");
});
}).fail(function(){
throw new Error("Was unable to create section 'test' in config juci");
});
});
it("should be able to add a named section", function(done){
expect($uci.juci["@test"]).to.be.empty();
$uci.juci.create({".type": "test", ".name": "testname"}).done(function(section){
expect($uci.juci.testname).to.be.ok();
$uci.save().done(function(){
$uci.$sync("juci").done(function(){
expect($uci.juci.testname).to.be.ok();
expect($uci.juci["@test"]).to.contain(section);
expect($uci.juci["@test"].length).to.be(1);
section.$delete().done(function(){
$uci.save().done(function(){
done();
});
});
});
});
}).fail(function(){
throw new Error("Could not create named section in juci config!");
});
});
it("should not be able to add a section that already exists", function(done){
expect($uci.juci["@test"]).to.be.empty();
$uci.juci.create({".type": "test", ".name": "testname"}).done(function(section){
$uci.juci.create({".type": "test", ".name": "testname"}).done(function(section2){
throw new Error("Creating a section that already exists returned success when it should fail!");
}).fail(function(){
section.$delete().done(function(){
$uci.save().done(function(){
done();
});
});
});
}).fail(function(){
throw new Error("Failed to create section testname when it was supposed to work fine!");
});
});
});

View File

@ -12,24 +12,26 @@
"object-assign": "*",
"jquery-deferred": "*",
"watchjs": "*",
"uglify-js": "*",
"uglify-js": "*",
"array.prototype.find": "*",
"node-getopt": "*",
"gettext-parser": "*",
"underscore": "*",
"ws": "*",
"jquery-deferred": "*",
"express-ws": "*"
"node-getopt": "*",
"gettext-parser": "*",
"underscore": "*",
"ws": "*",
"express-ws": "*"
},
"engines": {
"node": "0.10.x",
"npm": "1.2.x"
},
"devDependencies": {
"grunt": "^1.0.1",
"istanbul": "^0.4.5",
"jasmine-core": "~2.3.3",
"karma-jasmine": "~0.3.5",
"karma": "^1.3.0",
"karma-firefox-launcher": "~0.1.6",
"mocha": "~2.2.5",
"karma-mocha": "~0.1.10"
"karma-jasmine": "~0.3.5",
"karma-mocha": "~0.1.10",
"mocha": "~2.2.5"
}
}