bricks-cli
Version:
Command line tool for developing ambitious ember.js apps
1,050 lines (870 loc) • 38.7 kB
JavaScript
var path = require('path');
var mout = require('mout');
var rimraf = require('rimraf');
var fs = require('graceful-fs');
var Q = require('q');
var expect = require('expect.js');
var mkdirp = require('mkdirp');
var ResolveCache = require('../../lib/core/ResolveCache');
var defaultConfig = require('../../lib/config');
var cmd = require('../../lib/util/cmd');
var copy = require('../../lib/util/copy');
var md5 = require('../../lib/util/md5');
describe('ResolveCache', function () {
var resolveCache;
var testPackage = path.resolve(__dirname, '../assets/package-a');
var tempPackage = path.resolve(__dirname, '../tmp/temp-package');
var tempPackage2 = path.resolve(__dirname, '../tmp/temp2-package');
var cacheDir = path.join(__dirname, '../tmp/temp-resolve-cache');
before(function (next) {
// Delete cache folder
rimraf.sync(cacheDir);
// Instantiate resolver cache
resolveCache = new ResolveCache(mout.object.deepMixIn(defaultConfig, {
storage: {
packages: cacheDir
}
}));
// Checkout test package version 0.2.0
cmd('git', ['checkout', '0.2.0'], { cwd: testPackage })
.then(next.bind(next, null), next);
});
beforeEach(function () {
// Reset in memory cache for each test
resolveCache.reset();
});
after(function () {
// Remove cache folder afterwards
rimraf.sync(cacheDir);
});
describe('.constructor', function () {
beforeEach(function () {
// Delete temp folder
rimraf.sync(tempPackage);
});
after(function () {
// Delete temp folder
rimraf.sync(tempPackage);
});
function initialize(cacheDir) {
return new ResolveCache(mout.object.deepMixIn(defaultConfig, {
storage: {
packages: cacheDir
}
}));
}
it('should create the cache folder if it doesn\'t exists', function () {
initialize(tempPackage);
expect(fs.existsSync(tempPackage)).to.be(true);
});
it('should not error out if the cache folder already exists', function () {
mkdirp.sync(tempPackage);
initialize(tempPackage);
});
});
describe('.store', function () {
var oldFsRename = fs.rename;
beforeEach(function (next) {
// Restore oldFsRename
fs.rename = oldFsRename;
// Create a fresh copy of the test package into temp
rimraf.sync(tempPackage);
copy.copyDir(testPackage, tempPackage, { ignore: ['.git'] })
.then(next.bind(next, null), next);
});
it('should move the canonical dir to source-md5/version/ folder if package meta has a version', function (next) {
resolveCache.store(tempPackage, {
name: 'foo',
version: '1.0.0',
_source: 'foo',
_target: '*'
})
.then(function (dir) {
expect(dir).to.equal(path.join(cacheDir, md5('foo'), '1.0.0'));
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);
next();
})
.done();
});
it('should move the canonical dir to source-md5/target/ folder if package meta has no version', function (next) {
resolveCache.store(tempPackage, {
name: 'foo',
_source: 'foo',
_target: 'some-branch'
})
.then(function (dir) {
expect(dir).to.equal(path.join(cacheDir, md5('foo'), 'some-branch'));
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);
next();
})
.done();
});
it('should move the canonical dir to source-md5/_wildcard/ folder if package meta has no version and target is *', function (next) {
resolveCache.store(tempPackage, {
name: 'foo',
_source: 'foo',
_target: '*'
})
.then(function (dir) {
expect(dir).to.equal(path.join(cacheDir, md5('foo'), '_wildcard'));
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);
next();
})
.done();
});
it('should read the package meta if not present', function (next) {
var pkgMeta = path.join(tempPackage, '.bower.json');
// Copy bower.json to .bower.json and add some props
copy.copyFile(path.join(tempPackage, 'component.json'), pkgMeta)
.then(function () {
return Q.nfcall(fs.readFile, pkgMeta)
.then(function (contents) {
var json = JSON.parse(contents.toString());
json._target = '~0.2.0';
json._source = 'git://github.com/bower/test-package.git';
return Q.nfcall(fs.writeFile, pkgMeta, JSON.stringify(json, null, ' '));
});
})
// Store as usual
.then(function () {
return resolveCache.store(tempPackage);
})
.then(function (dir) {
expect(dir).to.equal(path.join(cacheDir, md5('git://github.com/bower/test-package.git'), '0.2.0'));
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);
next();
})
.done();
});
it('should error out when reading the package meta if the file does not exist', function (next) {
resolveCache.store(tempPackage)
.then(function () {
next(new Error('Should have failed'));
}, function (err) {
expect(err).to.be.an(Error);
expect(err.code).to.equal('ENOENT');
expect(err.message).to.contain(path.join(tempPackage, '.bower.json'));
next();
})
.done();
});
it('should error out when reading an invalid package meta', function (next) {
var pkgMeta = path.join(tempPackage, '.bower.json');
return Q.nfcall(fs.writeFile, pkgMeta, 'w00t')
.then(function () {
return resolveCache.store(tempPackage)
.then(function () {
next(new Error('Should have failed'));
}, function (err) {
expect(err).to.be.an(Error);
expect(err.code).to.equal('EMALFORMED');
expect(err.message).to.contain(path.join(tempPackage, '.bower.json'));
next();
});
})
.done();
});
it('should move the canonical dir, even if it is in a different drive', function (next) {
var hittedMock = false;
fs.rename = function (src, dest, cb) {
hittedMock = true;
setTimeout(function () {
var err = new Error();
err.code = 'EXDEV';
cb(err);
}, 10);
};
resolveCache.store(tempPackage, {
name: 'foo',
_source: 'foobar',
_target: 'some-branch'
})
.then(function (dir) {
// Ensure mock was called
expect(hittedMock).to.be(true);
expect(dir).to.equal(path.join(cacheDir, md5('foobar'), 'some-branch'));
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);
next();
})
.done();
});
it('should update the in-memory cache', function (next) {
// Feed the cache
resolveCache.versions('test-in-memory')
// Copy temp package to temp package 2
.then(function () {
return copy.copyDir(tempPackage, tempPackage2, { ignore: ['.git'] });
})
// Store the two packages
.then(function () {
return resolveCache.store(tempPackage, {
name: 'foo',
version: '1.0.0',
_source: 'test-in-memory',
_target: '*'
});
})
.then(function () {
return resolveCache.store(tempPackage2, {
name: 'foo',
version: '1.0.1',
_source: 'test-in-memory',
_target: '*'
});
})
// Cache should have been updated
.then(function () {
return resolveCache.versions('test-in-memory')
.then(function (versions) {
expect(versions).to.eql(['1.0.1', '1.0.0']);
next();
});
})
.done();
});
it('should url encode target when storing to the fs', function (next) {
resolveCache.store(tempPackage, {
name: 'foo',
_source: 'foo',
_target: 'foo/bar'
})
.then(function (dir) {
expect(dir).to.equal(path.join(cacheDir, md5('foo'), 'foo%2Fbar'));
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);
next();
})
.done();
});
it('should be possible to store two package at same time', function (next) {
var store = resolveCache.store.bind(resolveCache, tempPackage, {
name: 'foo',
_source: 'foo',
_target: 'foo/bar'
});
var store2 = resolveCache.store.bind(resolveCache, tempPackage2, {
name: 'foo',
_source: 'foo',
_target: 'foo/bar'
});
Q.all([store(), store2()]).then(function (dirs) {
var dir = dirs[0];
expect(dir).to.equal(path.join(cacheDir, md5('foo'), 'foo%2Fbar'));
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);
expect(fs.existsSync(tempPackage2)).to.be(false);
next();
}).done();
});
});
describe('.versions', function () {
it('should resolve to an array', function (next) {
resolveCache.versions(String(Math.random()))
.then(function (versions) {
expect(versions).to.be.an('array');
next();
})
.done();
});
it('should ignore non-semver folders of the source', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(path.join(sourceDir, '0.1.0'));
fs.mkdirSync(path.join(sourceDir, 'foo'));
resolveCache.versions(source)
.then(function (versions) {
expect(versions).to.not.contain('foo');
expect(versions).to.contain('0.0.1');
expect(versions).to.contain('0.1.0');
next();
})
.done();
});
it('should order the versions', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(path.join(sourceDir, '0.1.0'));
fs.mkdirSync(path.join(sourceDir, '0.1.0-rc.1'));
resolveCache.versions(source)
.then(function (versions) {
expect(versions).to.eql(['0.1.0', '0.1.0-rc.1', '0.0.1']);
next();
})
.done();
});
it('should cache versions to speed-up subsequent calls', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
resolveCache.versions(source)
.then(function () {
// Remove folder
rimraf.sync(sourceDir);
return resolveCache.versions(source);
})
.then(function (versions) {
expect(versions).to.eql(['0.0.1']);
next();
})
.done();
});
});
describe('.retrieve', function () {
it('should resolve to empty if there are no packages for the requested source', function (next) {
resolveCache.retrieve(String(Math.random()))
.spread(function () {
expect(arguments.length).to.equal(0);
next();
})
.done();
});
it('should resolve to empty if there are no suitable packages for the requested target', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(path.join(sourceDir, '0.1.0'));
fs.mkdirSync(path.join(sourceDir, '0.1.9'));
fs.mkdirSync(path.join(sourceDir, '0.2.0'));
resolveCache.retrieve(source, '~0.3.0')
.spread(function () {
expect(arguments.length).to.equal(0);
return resolveCache.retrieve(source, 'some-branch');
})
.spread(function () {
expect(arguments.length).to.equal(0);
next();
})
.done();
});
it('should remove invalid packages from the cache if their package meta is missing or invalid', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(path.join(sourceDir, '0.1.0'));
fs.mkdirSync(path.join(sourceDir, '0.1.9'));
fs.mkdirSync(path.join(sourceDir, '0.2.0'));
// Create an invalid package meta
fs.writeFileSync(path.join(sourceDir, '0.2.0', '.bower.json'), 'w00t');
resolveCache.retrieve(source, '~0.1.0')
.spread(function () {
var dirs = fs.readdirSync(sourceDir);
expect(arguments.length).to.equal(0);
expect(dirs).to.contain('0.0.1');
expect(dirs).to.contain('0.2.0');
next();
})
.done();
});
it('should resolve to the highest package that matches a range target, ignoring pre-releases', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
var json = { name: 'foo' };
// Create some versions
fs.mkdirSync(sourceDir);
json.version = '0.0.1';
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.writeFileSync(path.join(sourceDir, '0.0.1', '.bower.json'), JSON.stringify(json, null, ' '));
json.version = '0.1.0';
fs.mkdirSync(path.join(sourceDir, '0.1.0'));
fs.writeFileSync(path.join(sourceDir, '0.1.0', '.bower.json'), JSON.stringify(json, null, ' '));
json.version = '0.1.0-rc.1';
fs.mkdirSync(path.join(sourceDir, '0.1.0-rc.1'));
fs.writeFileSync(path.join(sourceDir, '0.1.0-rc.1', '.bower.json'), JSON.stringify(json, null, ' '));
json.version = '0.1.9';
fs.mkdirSync(path.join(sourceDir, '0.1.9'));
fs.writeFileSync(path.join(sourceDir, '0.1.9', '.bower.json'), JSON.stringify(json, null, ' '));
json.version = '0.2.0';
fs.mkdirSync(path.join(sourceDir, '0.2.0'));
fs.writeFileSync(path.join(sourceDir, '0.2.0', '.bower.json'), JSON.stringify(json, null, ' '));
resolveCache.retrieve(source, '~0.1.0')
.spread(function (canonicalDir, pkgMeta) {
expect(pkgMeta).to.be.an('object');
expect(pkgMeta.version).to.equal('0.1.9');
expect(canonicalDir).to.equal(path.join(sourceDir, '0.1.9'));
return resolveCache.retrieve(source, '*');
})
.spread(function (canonicalDir, pkgMeta) {
expect(pkgMeta).to.be.an('object');
expect(pkgMeta.version).to.equal('0.2.0');
expect(canonicalDir).to.equal(path.join(sourceDir, '0.2.0'));
next();
})
.done();
});
it('should resolve to the highest package that matches a range target, not ignoring pre-releases if they are the only versions', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
var json = { name: 'foo' };
// Create some versions
fs.mkdirSync(sourceDir);
json.version = '0.1.0-rc.1';
fs.mkdirSync(path.join(sourceDir, '0.1.0-rc.1'));
fs.writeFileSync(path.join(sourceDir, '0.1.0-rc.1', '.bower.json'), JSON.stringify(json, null, ' '));
json.version = '0.1.0-rc.2';
fs.mkdirSync(path.join(sourceDir, '0.1.0-rc.2'));
fs.writeFileSync(path.join(sourceDir, '0.1.0-rc.2', '.bower.json'), JSON.stringify(json, null, ' '));
resolveCache.retrieve(source, '~0.1.0')
.spread(function (canonicalDir, pkgMeta) {
expect(pkgMeta).to.be.an('object');
expect(pkgMeta.version).to.equal('0.1.0-rc.2');
expect(canonicalDir).to.equal(path.join(sourceDir, '0.1.0-rc.2'));
next();
})
.done();
});
it('should resolve to exact match (including build metadata) if available', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
var json = { name: 'foo' };
var encoded;
// Create some versions
fs.mkdirSync(sourceDir);
json.version = '0.1.0';
fs.mkdirSync(path.join(sourceDir, '0.1.0'));
fs.writeFileSync(path.join(sourceDir, '0.1.0', '.bower.json'), JSON.stringify(json, null, ' '));
json.version = '0.1.0+build.4';
encoded = encodeURIComponent('0.1.0+build.4');
fs.mkdirSync(path.join(sourceDir, encoded));
fs.writeFileSync(path.join(sourceDir, encoded, '.bower.json'), JSON.stringify(json, null, ' '));
json.version = '0.1.0+build.5';
encoded = encodeURIComponent('0.1.0+build.5');
fs.mkdirSync(path.join(sourceDir, encoded));
fs.writeFileSync(path.join(sourceDir, encoded, '.bower.json'), JSON.stringify(json, null, ' '));
json.version = '0.1.0+build.6';
encoded = encodeURIComponent('0.1.0+build.6');
fs.mkdirSync(path.join(sourceDir, encoded));
fs.writeFileSync(path.join(sourceDir, encoded, '.bower.json'), JSON.stringify(json, null, ' '));
resolveCache.retrieve(source, '0.1.0+build.5')
.spread(function (canonicalDir, pkgMeta) {
expect(pkgMeta).to.be.an('object');
expect(pkgMeta.version).to.equal('0.1.0+build.5');
expect(canonicalDir).to.equal(path.join(sourceDir, encodeURIComponent('0.1.0+build.5')));
next();
})
.done();
});
it('should resolve to the _wildcard package if target is * and there are no semver versions', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
var json = { name: 'foo' };
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '_wildcard'));
fs.writeFileSync(path.join(sourceDir, '_wildcard', '.bower.json'), JSON.stringify(json, null, ' '));
resolveCache.retrieve(source, '*')
.spread(function (canonicalDir, pkgMeta) {
expect(pkgMeta).to.be.an('object');
expect(canonicalDir).to.equal(path.join(sourceDir, '_wildcard'));
next();
})
.done();
});
it('should resolve to the exact target it\'s not a semver range', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
var json = { name: 'foo' };
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, 'some-branch'));
fs.writeFileSync(path.join(sourceDir, 'some-branch', '.bower.json'), JSON.stringify(json, null, ' '));
fs.mkdirSync(path.join(sourceDir, 'other-branch'));
fs.writeFileSync(path.join(sourceDir, 'other-branch', '.bower.json'), JSON.stringify(json, null, ' '));
resolveCache.retrieve(source, 'some-branch')
.spread(function (canonicalDir, pkgMeta) {
expect(pkgMeta).to.be.an('object');
expect(pkgMeta).to.not.have.property('version');
next();
})
.done();
});
});
describe('.eliminate', function () {
beforeEach(function () {
mkdirp.sync(cacheDir);
});
it('should delete the source-md5/version folder', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(path.join(sourceDir, '0.1.0'));
resolveCache.eliminate({
name: 'foo',
version: '0.0.1',
_source: source,
_target: '*'
})
.then(function () {
expect(fs.existsSync(path.join(sourceDir, '0.0.1'))).to.be(false);
expect(fs.existsSync(path.join(sourceDir, '0.1.0'))).to.be(true);
next();
})
.done();
});
it('should delete the source-md5/target folder', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(path.join(sourceDir, 'some-branch'));
resolveCache.eliminate({
name: 'foo',
_source: source,
_target: 'some-branch'
})
.then(function () {
expect(fs.existsSync(path.join(sourceDir, 'some-branch'))).to.be(false);
expect(fs.existsSync(path.join(sourceDir, '0.0.1'))).to.be(true);
next();
})
.done();
});
it('should delete the source-md5/_wildcard folder', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(path.join(sourceDir, '_wildcard'));
resolveCache.eliminate({
name: 'foo',
_source: source,
_target: '*'
})
.then(function () {
expect(fs.existsSync(path.join(sourceDir, '_wildcard'))).to.be(false);
expect(fs.existsSync(path.join(sourceDir, '0.0.1'))).to.be(true);
next();
})
.done();
});
it('should delete the source-md5 folder if empty', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
resolveCache.eliminate({
name: 'foo',
version: '0.0.1',
_source: source,
_target: '*'
})
.then(function () {
expect(fs.existsSync(path.join(sourceDir, '0.0.1'))).to.be(false);
expect(fs.existsSync(path.join(sourceDir))).to.be(false);
next();
})
.done();
});
it('should remove entry from in memory cache if the source-md5 folder was deleted', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
// Feed up the cache
resolveCache.versions(source)
// Eliminate
.then(function () {
return resolveCache.eliminate({
name: 'foo',
version: '0.0.1',
_source: source,
_target: '*'
});
})
.then(function () {
// At this point the parent folder should be deleted
// To test against the in-memory cache, we create a folder
// manually and request the versions
mkdirp.sync(path.join(sourceDir, '0.0.2'));
resolveCache.versions(source)
.then(function (versions) {
expect(versions).to.eql(['0.0.2']);
next();
});
})
.done();
});
});
describe('.clear', function () {
beforeEach(function () {
mkdirp.sync(cacheDir);
});
it('should empty the whole cache folder', function (next) {
resolveCache.clear()
.then(function () {
var files;
expect(fs.existsSync(cacheDir)).to.be(true);
files = fs.readdirSync(cacheDir);
expect(files.length).to.be(0);
next();
})
.done();
});
it('should erase the in-memory cache', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
// Feed the in-memory cache
resolveCache.versions(source)
// Clear
.then(function () {
return resolveCache.clear();
})
.then(function () {
// To test against the in-memory cache, we create a folder
// manually and request the versions
mkdirp.sync(path.join(sourceDir, '0.0.2'));
resolveCache.versions(source)
.then(function (versions) {
expect(versions).to.eql(['0.0.2']);
next();
});
})
.done();
});
});
describe('.reset', function () {
it('should erase the in-memory cache', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
// Feed the in-memory cache
resolveCache.versions(source)
.then(function () {
// Delete 0.0.1 and create 0.0.2
fs.rmdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(path.join(sourceDir, '0.0.2'));
// Reset cache
resolveCache.reset();
// Get versions
return resolveCache.versions(source);
})
.then(function (versions) {
expect(versions).to.eql(['0.0.2']);
next();
})
.done();
});
});
describe('.list', function () {
beforeEach(function () {
rimraf.sync(cacheDir);
mkdirp.sync(cacheDir);
});
it('should resolve to an empty array if the cache is empty', function (next) {
resolveCache.list()
.then(function (entries) {
expect(entries).to.be.an('array');
expect(entries.length).to.be(0);
next();
})
.done();
});
it('should resolve to an ordered array of entries (name ASC, release ASC)', function (next) {
var source = 'list-package-1';
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
var source2 = 'list-package-2';
var sourceId2 = md5(source2);
var sourceDir2 = path.join(cacheDir, sourceId2);
var json = {
name: 'foo'
};
// Create some versions for different sources
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
json.version = '0.0.1';
fs.writeFileSync(path.join(sourceDir, '0.0.1', '.bower.json'), JSON.stringify(json, null, ' '));
fs.mkdirSync(path.join(sourceDir, '0.1.0'));
json.version = '0.1.0';
fs.writeFileSync(path.join(sourceDir, '0.1.0', '.bower.json'), JSON.stringify(json, null, ' '));
delete json.version;
fs.mkdirSync(path.join(sourceDir, 'foo'));
json._target = 'foo';
fs.writeFileSync(path.join(sourceDir, 'foo', '.bower.json'), JSON.stringify(json, null, ' '));
fs.mkdirSync(path.join(sourceDir, 'bar'));
json._target = 'bar';
fs.writeFileSync(path.join(sourceDir, 'bar', '.bower.json'), JSON.stringify(json, null, ' '));
fs.mkdirSync(path.join(sourceDir, 'aa'));
json._target = 'aa';
fs.writeFileSync(path.join(sourceDir, 'aa', '.bower.json'), JSON.stringify(json, null, ' '));
delete json._target;
fs.mkdirSync(sourceDir2);
fs.mkdirSync(path.join(sourceDir2, '0.2.1'));
json.version = '0.2.1';
fs.writeFileSync(path.join(sourceDir2, '0.2.1', '.bower.json'), JSON.stringify(json, null, ' '));
fs.mkdirSync(path.join(sourceDir2, '0.2.0'));
json.name = 'abc';
json.version = '0.2.0';
fs.writeFileSync(path.join(sourceDir2, '0.2.0', '.bower.json'), JSON.stringify(json, null, ' '));
resolveCache.list()
.then(function (entries) {
var expectedJson;
var bowerDir = path.join(__dirname, '../..');
expect(entries).to.be.an('array');
expectedJson = fs.readFileSync(path.join(__dirname, '../assets/resolve-cache/list-json-1.json'));
expectedJson = expectedJson.toString().trim();
mout.object.forOwn(entries, function (entry) {
// Trim absolute bower path from json
entry.canonicalDir = entry.canonicalDir.substr(bowerDir.length);
// Convert windows \ paths to /
entry.canonicalDir = entry.canonicalDir.replace(/\\/g, '/');
});
json = JSON.stringify(entries, null, ' ');
expect(json).to.equal(expectedJson);
next();
})
.done();
});
it('should ignore lurking files where dirs are expected', function (next) {
var source = 'list-package-1';
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
var json = {
name: 'foo'
};
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
json.version = '0.0.1';
fs.writeFileSync(path.join(sourceDir, '0.0.1', '.bower.json'), JSON.stringify(json, null, ' '));
// Create lurking files
fs.writeFileSync(path.join(cacheDir, 'foo'), 'w00t');
fs.writeFileSync(path.join(cacheDir, '.DS_Store'), '');
fs.writeFileSync(path.join(sourceDir, 'foo'), 'w00t');
fs.writeFileSync(path.join(sourceDir, '.DS_Store'), '');
// It should not error out
resolveCache.list()
.then(function (entries) {
expect(entries).to.be.an('array');
expect(entries.length).to.be(1);
expect(entries[0].pkgMeta).to.eql(json);
// Lurking file should have been removed
expect(fs.existsSync(path.join(cacheDir, 'foo'))).to.be(false);
expect(fs.existsSync(path.join(cacheDir, '.DS_Store'))).to.be(false);
expect(fs.existsSync(path.join(sourceDir, 'foo'))).to.be(false);
expect(fs.existsSync(path.join(sourceDir, '.DS_Store'))).to.be(false);
next();
})
.done();
});
it('should delete entries if failed to read package meta', function (next) {
var source = 'list-package-1';
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
var json = {
name: 'foo'
};
// Create invalid versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(path.join(sourceDir, '0.0.2'));
fs.writeFileSync(path.join(sourceDir, '0.0.2', '.bower.json'), 'w00t');
// Create valid version
fs.mkdirSync(path.join(sourceDir, '0.0.3'));
json.version = '0.0.3';
fs.writeFileSync(path.join(sourceDir, '0.0.3', '.bower.json'), JSON.stringify(json, null, ' '));
// It should not error out
resolveCache.list()
.then(function (entries) {
expect(entries).to.be.an('array');
expect(entries.length).to.be(1);
expect(entries[0].pkgMeta).to.eql(json);
// Packages with invalid metas should have been removed
expect(fs.existsSync(path.join(sourceDir, '0.0.1'))).to.be(false);
expect(fs.existsSync(path.join(sourceDir, '0.0.2'))).to.be(false);
next();
})
.done();
});
});
describe('#clearRuntimeCache', function () {
it('should clear the in-memory cache for all sources', function (next) {
var source = String(Math.random());
var sourceId = md5(source);
var sourceDir = path.join(cacheDir, sourceId);
var source2 = String(Math.random());
var sourceId2 = md5(source2);
var sourceDir2 = path.join(cacheDir, sourceId2);
// Create some versions
fs.mkdirSync(sourceDir);
fs.mkdirSync(path.join(sourceDir, '0.0.1'));
fs.mkdirSync(sourceDir2);
fs.mkdirSync(path.join(sourceDir2, '0.0.2'));
// Feed the cache
resolveCache.versions(source)
.then(function () {
return resolveCache.versions(source2);
})
.then(function () {
// Create some more
fs.mkdirSync(path.join(sourceDir, '0.0.3'));
fs.mkdirSync(path.join(sourceDir2, '0.0.4'));
// Reset cache
ResolveCache.clearRuntimeCache();
})
.then(function () {
return resolveCache.versions(source)
.then(function (versions) {
expect(versions).to.eql(['0.0.3', '0.0.1']);
return resolveCache.versions(source2);
})
.then(function (versions) {
expect(versions).to.eql(['0.0.4', '0.0.2']);
next();
});
})
.done();
});
});
});