Skip to content

Commit

Permalink
[api test] Added the dependencies.of() method for determining if a …
Browse files Browse the repository at this point in the history
…system is within a given dependency tree.
  • Loading branch information
indexzero committed Mar 6, 2013
1 parent 0f7b571 commit 8c890cb
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 36 deletions.
29 changes: 29 additions & 0 deletions lib/dependencies.js
Expand Up @@ -119,6 +119,35 @@ var dependencies = module.exports = function (options, callback) {
});
};

//
// ### function of (system, tree)
// #### @system {Object|string} System to check if it is a dependency of.
// #### @tree {Object} Dependency tree to check `system` against.
// Returns a list of systems in `dependencies` which depend on the
// specified `system`.
//
dependencies.of = function (system, tree) {
var target = system.name || system,
dependent;

dependent = Object.keys(tree).filter(function (name) {
var dep = tree[name],
children = Object.keys(dep.dependencies || {});

if (!children.length) {
return false;
}

return !~children.indexOf(target)
? dependencies.of(target, dep.dependencies)
: true;
});

return dependent.length
? dependent
: false;
};

//
// ### function maxSatisfying (callback)
// #### @options {Object} Options for calculating maximum satisfying set.
Expand Down
36 changes: 34 additions & 2 deletions test/dependencies-test.js
Expand Up @@ -15,6 +15,10 @@ var assert = require('assert'),
mock = require('./helpers/mock'),
systemJson = require('../lib');

var shouldAnalyzeDeps = macros.shouldAnalyzeDeps,
shouldBeDependent = macros.shouldBeDependent,
shouldNotBeDependent = macros.shouldNotBeDependent;

//
// Asserts the remote runlist for `hello-remote-deps`.
//
Expand Down Expand Up @@ -60,10 +64,38 @@ function shouldMakeRemoteRunlist(assertFn) {

vows.describe('system.json/dependencies').addBatch({
"When using system.json": {
"calculating dependencies": macros.shouldAnalyzeAllDeps(),
"the remote.runlist() method": {
"calculating dependencies": {
"with a no dependencies": shouldAnalyzeDeps('no-deps'),
"with a single dependency (implicit runlist)": shouldAnalyzeDeps('single-dep'),
"with a single dependency (empty runlist)": shouldAnalyzeDeps('empty-runlist'),
"with multiple dependencies": shouldAnalyzeDeps('depends-on-a-b'),
"with remoteDependencies": shouldAnalyzeDeps('hello-remote-deps'),
"with indirect remoteDependencies": shouldAnalyzeDeps('indirect-remote-deps'),
"with duplicate nested dependencies": shouldAnalyzeDeps('dep-in-dep'),
"with nested dependencies"shouldAnalyzeDeps('nested-dep'),
"with a single OS dependency": shouldAnalyzeDeps('single-ubuntu-dep', 'ubuntu')
},
"remote.runlist()": {
"hello-remote-deps": shouldMakeRemoteRunlist(assertHelloRemoteDeps),
"indirect-remote-deps": shouldMakeRemoteRunlist(assertHelloRemoteDeps)
},
"dependencies.of()": {
"when dependedent:": {
"fixture-one": shouldBeDependent(
'hello-world',
{ name: 'ubuntu-dep', os: 'ubuntu' }
),
"b": shouldBeDependent(
'dep-in-dep', 'c', 'nested-dep',
{ name: 'single-ubuntu-dep', os: 'ubuntu' }
)
},
"when not dependent": {
"fixture-one": shouldNotBeDependent(
'a', 'b', 'c',
{ name: 'ubuntu-dep', os: 'smartos' }
)
}
}
}
}).export(module);
35 changes: 35 additions & 0 deletions test/fixtures/index.js
Expand Up @@ -27,6 +27,18 @@ var systems = module.exports = [
}
}
},
{
name: 'hello-world',
version: '0.0.0',
versions: {
'0.0.0': {
dependencies: {
'fixture-one': '0.0.x',
'fixture-two': '0.0.x'
}
}
}
},
{
name: 'indirect-remote-deps',
version: '0.0.0',
Expand Down Expand Up @@ -102,6 +114,29 @@ var systems = module.exports = [
}
}
},
{
name: 'nested-dep',
version: '1.0.2',
versions: {
'1.0.2': {
runlist: ['c', 'b', 'a'],
dependencies: {
a: '0.0.1',
c: '0.3.0'
}
}
}
},
{
name: 'ubuntu-dep',
version: '0.0.0',
versions: {
'0.0.0': {}
},
os: {
ubuntu: { 'fixture-one': '0.0.0' }
}
},
{
name: 'single-ubuntu-dep',
version: '0.0.1',
Expand Down
40 changes: 40 additions & 0 deletions test/fixtures/trees.js
Expand Up @@ -132,6 +132,7 @@ trees['depends-on-a-b'] = {

//
// Dependency tree with dependency in a dependency
// that is also required by the top-level
//
trees['dep-in-dep'] = {
tree: {
Expand Down Expand Up @@ -176,6 +177,45 @@ trees['dep-in-dep'] = {
list: ['b@0.2.0', 'c@0.3.0', 'a@0.0.1', 'dep-in-dep@1.0.2']
};

//
// Dependency tree with dependency in a dependency
//
trees['nested-dep'] = {
tree: {
'nested-dep': {
name: 'nested-dep',
runlist: [ 'c', 'b', 'a' ],
dependencies: {
a: {
name: 'a',
runlist: [],
required: '0.0.1',
dependencies: {},
version: '0.0.1'
},
c: {
name: 'c',
runlist: [ 'b' ],
dependencies: {
b: {
name: 'b',
runlist: [],
required: '0.2.0',
dependencies: {},
version: '0.2.0'
}
},
required: '0.3.0',
version: '0.3.0'
}
},
required: '*',
version: '1.0.2'
}
},
list: ['b@0.2.0', 'c@0.3.0', 'a@0.0.1', 'nested-dep@1.0.2']
};

//
// Dependency with an implied runlist
//
Expand Down
36 changes: 36 additions & 0 deletions test/helpers/index.js
@@ -0,0 +1,36 @@
/*
* index.js: Test helpers for `system.json`.
*
* (C) 2010, Nodejitsu Inc.
*
*/

var assert = require('assert'),
fs = require('fs'),
path = require('path'),
conservatory = require('conservatory-api'),
nock = require('nock'),
utile = require('utile'),
mock = require('./mock'),
systemJson = require('../../lib'),
trees = require('../fixtures/trees');

//
// Helper function that fetches all dependencies for
// `system` and `os` using a mocked `conservatory-api` client.
//
exports.dependencies = function (system, os, callback) {
var api = nock('http://api.testquill.com');

mock.systems.all(api);
systemJson.dependencies({
client: conservatory.createClient('composer', {
protocol: 'http',
host: 'api.testquill.com',
port: 80,
auth: {}
}).systems,
systems: system,
os: os
}, callback);
};
115 changes: 82 additions & 33 deletions test/helpers/macros.js
@@ -1,69 +1,50 @@
/*
* macros.js: Test macros for `system.json`.
*
* (C) 2010, Nodejitsu Inc.
*
*/

var assert = require('assert'),
fs = require('fs'),
path = require('path'),
conservatory = require('conservatory-api'),
nock = require('nock'),
utile = require('utile'),
mock = require('./mock'),
helpers = require('./index'),
systemJson = require('../../lib'),
trees = require('../fixtures/trees');

exports.shouldAnalyzeAllDeps = function () {
var shouldAnalyzeDeps = exports.shouldAnalyzeDeps;

return {
"with a no dependencies": shouldAnalyzeDeps('no-deps'),
"with a single dependency (implicit runlist)": shouldAnalyzeDeps('single-dep'),
"with a single dependency (empty runlist)": shouldAnalyzeDeps('empty-runlist'),
"with multiple dependencies": shouldAnalyzeDeps('depends-on-a-b'),
"with remoteDependencies": shouldAnalyzeDeps('hello-remote-deps'),
"with indirect remoteDependencies": shouldAnalyzeDeps('indirect-remote-deps'),
"with a dependency in a dependency": shouldAnalyzeDeps('dep-in-dep'),
"with a single OS dependency": shouldAnalyzeDeps('single-ubuntu-dep', 'ubuntu')
};
};

//
// ### function shouldFindDeps (system, os)
//
// Setups mock API endpoints for the `systems`, invokes
// Setups mock API endpoints for the `systems`, invokes
// `systemJson.dependencies()` and asserts the result
// is equal to `tree`.
//
exports.shouldAnalyzeDeps = function (system, os) {
var api = nock('http://api.testquill.com'),
fixture = trees[system],
var fixture = trees[system],
tree = fixture.tree;

mock.systems.all(api);


return {
"the dependencies() method": {
topic: function () {
systemJson.dependencies({
client: conservatory.createClient('composer', {
protocol: 'http',
host: 'api.testquill.com',
port: 80,
auth: {}
}).systems,
systems: system,
os: os
}, this.callback);
helpers.dependencies(system, os, this.callback);
},
"should respond with the correct dependency tree": function (err, actual) {
assert.isNull(err);
assert.deepEqual(actual, tree);
},
"the runlist() method": exports.shouldMakeRunlist(system, os)
"when used by runlist()": exports.shouldMakeRunlist(system, os)
}
};
};

//
// ### function shouldMakeRunlist (system, os)
//
// Setups mock API endpoints for the `systems`, invokes
// Setups mock API endpoints for the `systems`, invokes
// `systemJson.runlist()` and asserts the result
// is equal to `list`.
//
Expand All @@ -87,4 +68,72 @@ exports.shouldMakeRunlist = function (system, os) {
);
}
}
};

//
// ### function shouldBeDependent (system0, system1, ...)
// Asserts that all arguments depend on the
// context name.
//
exports.shouldBeDependent = function () {
return exports.shouldHaveRelationship(
'should be dependent',
function (tree) {
assert.include(
systemJson.dependencies.of(this.target, tree),
this.system
);
}
).apply(null, arguments);
};

//
// ### function shouldNotBeDependent (system0, system1, ...)
// Asserts that all arguments do not depend on the
// context name.
//
exports.shouldNotBeDependent = function () {
return exports.shouldHaveRelationship(
'should not be dependent',
function (tree) {
assert.isFalse(
systemJson.dependencies.of(this.target, tree)
);
}
).apply(null, arguments);
};

//
// ### function shouldHaveRelationship (msg, assertFn)
// Asserts that all arguments have the `assertFn` relationship
// with the context name.
//
exports.shouldHaveRelationship = function (msg, assertFn) {
return function () {
return Array.prototype.slice.call(arguments)
.reduce(function (tests, system) {
var name = system,
os;

if (typeof system === 'object') {
name = system.name;
os = system.os
}

tests['by ' + name] = {
topic: function (target) {
this.target = target;
this.system = name;
helpers.dependencies(name, os, this.callback);
}
};

tests['by ' + name][msg] = assertFn;
return tests;
}, {
topic: function () {
return this.context.name;
}
});
};
};
2 changes: 1 addition & 1 deletion test/helpers/mock.js
@@ -1,5 +1,5 @@
/*
* mock.js: Mock helpers for `quill`.
* mock.js: Mock helpers for `system.json`.
*
* (C) 2010, Nodejitsu Inc.
*
Expand Down

0 comments on commit 8c890cb

Please sign in to comment.