Permalink
Browse files

Initial take.

  • Loading branch information...
0 parents commit cdb3ff8bed396596c84e13b70e63f5fe66fc33f8 Chakrit Wichian committed Sep 5, 2012
Showing with 263 additions and 0 deletions.
  1. +1 −0 dummy-store.js
  2. +35 −0 index.js
  3. +38 −0 memory-store.js
  4. +43 −0 memory-store.test.js
  5. +28 −0 mock-store.js
  6. +24 −0 package.json
  7. +9 −0 redis-store.js
  8. +85 −0 test.js
@@ -0,0 +1 @@
+
@@ -0,0 +1,35 @@
+
+// index.js - Main interface file
+module.exports = (function() {
+
+ var acl = { };
+
+ acl.MemoryStore = require('./memory-store');
+ acl.RedisStore = require('./redis-store');
+ acl.MockStore = require('./mock-store');
+
+ // bound wrapper
+ var bind = function(func, obj) {
+ return function() { func.apply(obj, arguments); };
+ };
+
+ // store management.
+ acl.store = null;
+ acl.use = function(store) {
+ acl.store = store;
+
+ acl.grant = bind(store.grant, store);
+ acl.assert = bind(store.assert, store);
+ acl.revoke = bind(store.revoke, store);
+ };
+
+ // dud function (replaced by .use)
+ acl.grant = function(grantee, resource, callback) { };
+ acl.assert = function(grantee, resource, callback) { };
+ acl.revoke = function(grantee, resource, callback) { };
+
+ // defaults to MemoryStore on first use
+ acl.use(new acl.MemoryStore());
+ return acl;
+
+})();
@@ -0,0 +1,38 @@
+
+// memory-store.js - A memory-backed store for simple-acl
+module.exports = (function() {
+
+ var defer = process.nextTick;
+
+ var MemoryStore = function() {
+ this.rights = { };
+ };
+
+ MemoryStore.prototype =
+ { 'grant':
+ function(grantee, resource, callback) {
+ if (!(grantee in this.rights))
+ this.rights[grantee] = [];
+
+ this.rights[grantee].push(resource);
+ defer(callback);
+ }
+
+ , 'assert':
+ function(grantee, resource, callback) {
+ var list = this.rights[grantee]
+ , ok = (list && list.indexOf(resource) != -1);
+
+ defer(function() { callback(null, ok); });
+ }
+
+ , 'revoke':
+ function(grantee, resource, callback) {
+ defer(callback);
+ }
+ };
+
+
+ return MemoryStore;
+
+})();
@@ -0,0 +1,43 @@
+
+// memory-store.test.js - Tests for the MemoryStore
+(function() {
+
+ var assert = require('assert')
+ , acl = require('./')
+ , MemoryStore = acl.MemoryStore;
+
+ // temp string
+ var G = 'grantee', R = 'resource';
+
+ // tests
+ describe('MemoryStore', function() {
+ before(function() {
+ this.store = new MemoryStore();
+ acl.use(this.store);
+ });
+
+ describe('asserting right away', function() {
+ before(function(done) { var me = this;
+ acl.assert(G, R, function(e, success) {
+ done(e, me.success = success);
+ });
+ });
+
+ it('should returns false', function() {
+ assert(this.success === false);
+ });
+ });
+
+ describe('granting permission', function() {
+ before(function(done) { acl.grant(G, R, done); });
+ after(function(done) { acl.revoke(G, R, done); });
+
+ it('should causes assert() to succeeds', function(done) {
+ acl.assert(G, R, function(e, success) {
+ done(e, assert(success === true));
+ });
+ });
+ });
+ });
+
+})();
@@ -0,0 +1,28 @@
+
+// mock-store.js - Mock store for testing simple-acl
+module.exports = (function() {
+
+ var MockStore = function() {
+ this.lastFunc = null;
+ this.lastArgs = null;
+ };
+
+ var spy = function(name) {
+ return function() {
+ this.lastFunc = name;
+ this.lastArgs = Array.prototype.slice.call(arguments);
+
+ var lastArg = this.lastArgs[this.lastArgs.length - 1];
+ if (typeof lastArg === 'function') { // assume last arg is a callback
+ process.nextTick(lastArg);
+ };
+ };
+ };
+
+ MockStore.prototype.grant = spy('grant');
+ MockStore.prototype.assert = spy('assert');
+ MockStore.prototype.revoke = spy('revoke');
+
+ return MockStore;
+
+})();
@@ -0,0 +1,24 @@
+{
+ "name": "simple-acl",
+ "version": "0.1.0",
+ "description": "Simple ACL. 'nuff said.",
+ "main": "index.js",
+ "scripts": {
+ "test": "mocha --reporter spec"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/chakrit/simple-acl.git"
+ },
+ "optionalDependencies": {
+ "redis": "latest"
+ },
+ "devDependencies": {
+ "mocha": "latest"
+ },
+ "keywords": [
+ "acl"
+ ],
+ "author": "Chakrit Wichian (http://chakrit.net) <service@chakrit.net>",
+ "license": "BSD"
+}
@@ -0,0 +1,9 @@
+
+// redis-store.js - A redis-backed store for simple-acl
+module.exports = (function() {
+
+ var RedisStore = function() { };
+
+ return RedisStore;
+
+})();
85 test.js
@@ -0,0 +1,85 @@
+
+// test.js - Test the simple-acl package
+(function() {
+
+ var assert = require('assert');
+
+ // interface info
+ var stores = 'MemoryStore,RedisStore,MockStore'.split(',')
+ , funcs = 'grant,revoke,assert'.split(',');
+
+ // tests
+ describe('acl', function() {
+ before(function() { this.acl = require('./'); });
+
+ for (var i in stores) (function(store) {
+ it('should exports the ' + store, function() {
+ assert(store in this.acl);
+ assert(typeof this.acl[store] === 'function');
+ });
+ })(stores[i]);
+
+ for (var i in funcs) (function(func) {
+ it('should exports the ' + func + '() function', function() {
+ assert(func in this.acl);
+ assert(typeof this.acl[func] === 'function');
+ });
+ })(funcs[i]);
+
+ it('should exports an `store` property', function() {
+ assert('store' in this.acl);
+ });
+
+ it('should defaults to the MemoryStore', function() {
+ assert(this.acl.store);
+ assert(this.acl.store instanceof this.acl.MemoryStore);
+ });
+
+ it('should exports a `use` function', function() {
+ assert('use' in this.acl);
+ assert(typeof this.acl.use === 'function');
+ });
+
+
+ describe('using another store', function() {
+ before(function() {
+ this.oldStore = this.acl.store;
+ this.newStore = new this.acl.MockStore();
+
+ this.acl.use(this.newStore);
+ });
+
+ after(function() {
+ this.acl.use(this.oldStore);
+ delete this['oldStore'];
+ delete this['newStore'];
+ });
+
+ it('should changes the acl.store value', function() {
+ assert(this.acl.store instanceof this.acl.MockStore);
+ assert(this.acl.store === this.newStore);
+ });
+
+
+ for (var i in funcs) (function(func) {
+ describe('calling acl.' + func + '() function', function() {
+ before(function(done) {
+ this.acl[func]('grantee', 'resource', done);
+ this.lastFunc = this.newStore.lastFunc;
+ this.lastArgs = this.newStore.lastArgs;
+ });
+
+ it('should calls the store\'s ' + func + '() function', function() {
+ assert(this.lastFunc === func);
+ assert(this.lastArgs.length === 3);
+ assert(this.lastArgs[0] === 'grantee');
+ assert(this.lastArgs[1] === 'resource');
+ });
+ });
+ })(funcs[i]);
+
+ }); // using another store
+
+ }); // acl
+
+})();

0 comments on commit cdb3ff8

Please sign in to comment.