mirror of
https://github.com/bower/bower.git
synced 2026-01-13 00:08:13 -05:00
706 lines
24 KiB
JavaScript
706 lines
24 KiB
JavaScript
var expect = require('expect.js');
|
|
var Q = require('q');
|
|
var path = require('path');
|
|
var mout = require('mout');
|
|
var fs = require('../../lib/util/fs');
|
|
var rimraf = require('../../lib/util/rimraf');
|
|
var RegistryClient = require('bower-registry-client');
|
|
var Logger = require('bower-logger');
|
|
var proxyquire = require('proxyquire');
|
|
var defaultConfig = require('../../lib/config');
|
|
var ResolveCache = require('../../lib/core/ResolveCache');
|
|
var resolvers = require('../../lib/core/resolvers');
|
|
var copy = require('../../lib/util/copy');
|
|
var helpers = require('../helpers');
|
|
|
|
describe('PackageRepository', function() {
|
|
var packageRepository;
|
|
var resolver;
|
|
var resolverFactoryHook;
|
|
var resolverFactoryClearHook;
|
|
var testPackage = path.resolve(__dirname, '../assets/package-a');
|
|
var tempPackage = path.resolve(__dirname, '../tmp/temp-package');
|
|
var packagesCacheDir = path.join(__dirname, '../tmp/temp-resolve-cache');
|
|
var registryCacheDir = path.join(__dirname, '../tmp/temp-registry-cache');
|
|
var mockSource = helpers.localSource(testPackage);
|
|
|
|
var forceCaching = true;
|
|
|
|
after(function() {
|
|
rimraf.sync(registryCacheDir);
|
|
rimraf.sync(packagesCacheDir);
|
|
});
|
|
|
|
beforeEach(function(next) {
|
|
var PackageRepository;
|
|
var config;
|
|
var logger = new Logger();
|
|
|
|
// Config
|
|
config = defaultConfig({
|
|
storage: {
|
|
packages: packagesCacheDir,
|
|
registry: registryCacheDir
|
|
}
|
|
});
|
|
|
|
// Mock the resolver factory to always return a resolver for the test package
|
|
function resolverFactory(decEndpoint, options, _registryClient) {
|
|
var _config = options.config;
|
|
var _logger = options.logger;
|
|
|
|
expect(_config).to.eql(config);
|
|
expect(_logger).to.be.an(Logger);
|
|
expect(_registryClient).to.be.an(RegistryClient);
|
|
|
|
decEndpoint = mout.object.deepMixIn({}, decEndpoint);
|
|
decEndpoint.source = mockSource;
|
|
|
|
resolver = new resolvers.GitRemote(decEndpoint, _config, _logger);
|
|
|
|
if (forceCaching) {
|
|
// Force to use cache even for local resources
|
|
resolver.isCacheable = function() {
|
|
return true;
|
|
};
|
|
}
|
|
|
|
resolverFactoryHook(resolver);
|
|
|
|
return Q.resolve(resolver);
|
|
}
|
|
resolverFactory.getConstructor = function() {
|
|
return Q.resolve([
|
|
resolvers.GitRemote,
|
|
{
|
|
source: helpers.localSource(testPackage)
|
|
}
|
|
]);
|
|
};
|
|
resolverFactory.clearRuntimeCache = function() {
|
|
resolverFactoryClearHook();
|
|
};
|
|
|
|
PackageRepository = proxyquire('../../lib/core/PackageRepository', {
|
|
'./resolverFactory': resolverFactory
|
|
});
|
|
packageRepository = new PackageRepository(config, logger);
|
|
|
|
// Reset hooks
|
|
resolverFactoryHook = resolverFactoryClearHook = function() {};
|
|
|
|
// Remove temp package
|
|
rimraf.sync(tempPackage);
|
|
|
|
// Clear the repository
|
|
packageRepository.clear().then(next.bind(next, null), next);
|
|
});
|
|
|
|
describe('.constructor', function() {
|
|
it('should pass the config correctly to the registry client, including its cache folder', function() {
|
|
expect(packageRepository._registryClient._config.cache).to.equal(
|
|
registryCacheDir
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('.fetch', function() {
|
|
it('should call the resolver factory to get the appropriate resolver', function(next) {
|
|
var called;
|
|
|
|
resolverFactoryHook = function() {
|
|
called = true;
|
|
};
|
|
|
|
packageRepository
|
|
.fetch({ name: '', source: 'foo', target: '~0.1.0' })
|
|
.spread(function(canonicalDir, pkgMeta) {
|
|
expect(called).to.be(true);
|
|
expect(fs.existsSync(canonicalDir)).to.be(true);
|
|
expect(pkgMeta).to.be.an('object');
|
|
expect(pkgMeta.name).to.be('package-a');
|
|
expect(pkgMeta.version).to.be('0.1.1');
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should just call the resolver resolve method if force was specified', function(next) {
|
|
var called = [];
|
|
|
|
resolverFactoryHook = function(resolver) {
|
|
var originalResolve = resolver.resolve;
|
|
|
|
resolver.resolve = function() {
|
|
called.push('resolve');
|
|
return originalResolve.apply(this, arguments);
|
|
};
|
|
|
|
resolver.hasNew = function() {
|
|
called.push('hasNew');
|
|
return Q.resolve(false);
|
|
};
|
|
};
|
|
|
|
packageRepository._resolveCache.retrieve = function() {
|
|
called.push('retrieve');
|
|
return Q.resolve([]);
|
|
};
|
|
|
|
packageRepository._config.force = true;
|
|
packageRepository
|
|
.fetch({ name: '', source: 'foo', target: ' ~0.1.0' })
|
|
.spread(function(canonicalDir, pkgMeta) {
|
|
expect(called).to.eql(['resolve']);
|
|
expect(fs.existsSync(canonicalDir)).to.be(true);
|
|
expect(pkgMeta).to.be.an('object');
|
|
expect(pkgMeta.name).to.be('package-a');
|
|
expect(pkgMeta.version).to.be('0.1.1');
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should attempt to retrieve a resolved package from the resolve package', function(next) {
|
|
var called = false;
|
|
var originalRetrieve = packageRepository._resolveCache.retrieve;
|
|
|
|
packageRepository._resolveCache.retrieve = function(source) {
|
|
called = true;
|
|
expect(source).to.be(mockSource);
|
|
return originalRetrieve.apply(this, arguments);
|
|
};
|
|
|
|
packageRepository
|
|
.fetch({ name: '', source: 'foo', target: '~0.1.0' })
|
|
.spread(function(canonicalDir, pkgMeta) {
|
|
expect(called).to.be(true);
|
|
expect(fs.existsSync(canonicalDir)).to.be(true);
|
|
expect(pkgMeta).to.be.an('object');
|
|
expect(pkgMeta.name).to.be('package-a');
|
|
expect(pkgMeta.version).to.be('0.1.1');
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should avoid using cache for local resources', function(next) {
|
|
forceCaching = false;
|
|
|
|
var called = false;
|
|
var originalRetrieve = packageRepository._resolveCache.retrieve;
|
|
|
|
packageRepository._resolveCache.retrieve = function(source) {
|
|
called = true;
|
|
expect(source).to.be(mockSource);
|
|
return originalRetrieve.apply(this, arguments);
|
|
};
|
|
|
|
packageRepository
|
|
.fetch({
|
|
name: '',
|
|
source: helpers.localSource(testPackage),
|
|
target: '~0.1.0'
|
|
})
|
|
.spread(function(canonicalDir, pkgMeta) {
|
|
expect(called).to.be(false);
|
|
expect(fs.existsSync(canonicalDir)).to.be(true);
|
|
expect(pkgMeta).to.be.an('object');
|
|
expect(pkgMeta.name).to.be('package-a');
|
|
expect(pkgMeta.version).to.be('0.1.1');
|
|
forceCaching = true;
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should just call the resolver resolve method if no appropriate package was found in the resolve cache', function(next) {
|
|
var called = [];
|
|
|
|
resolverFactoryHook = function(resolver) {
|
|
var originalResolve = resolver.resolve;
|
|
|
|
resolver.resolve = function() {
|
|
called.push('resolve');
|
|
return originalResolve.apply(this, arguments);
|
|
};
|
|
|
|
resolver.hasNew = function() {
|
|
called.push('hasNew');
|
|
};
|
|
};
|
|
|
|
packageRepository._resolveCache.retrieve = function() {
|
|
return Q.resolve([]);
|
|
};
|
|
|
|
packageRepository
|
|
.fetch({ name: '', source: 'foo', target: ' ~0.1.0' })
|
|
.spread(function(canonicalDir, pkgMeta) {
|
|
expect(called).to.eql(['resolve']);
|
|
expect(fs.existsSync(canonicalDir)).to.be(true);
|
|
expect(pkgMeta).to.be.an('object');
|
|
expect(pkgMeta.name).to.be('package-a');
|
|
expect(pkgMeta.version).to.be('0.1.1');
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should call the resolver hasNew method if an appropriate package was found in the resolve cache', function(next) {
|
|
var json = {
|
|
name: 'a',
|
|
version: '0.2.1'
|
|
};
|
|
var called;
|
|
|
|
resolverFactoryHook = function(resolver) {
|
|
var originalHasNew = resolver.hasNew;
|
|
|
|
resolver.hasNew = function(pkgMeta) {
|
|
expect(pkgMeta).to.eql(json);
|
|
called = true;
|
|
return originalHasNew.apply(this, arguments);
|
|
};
|
|
};
|
|
|
|
packageRepository._resolveCache.retrieve = function() {
|
|
return Q.resolve([tempPackage, json]);
|
|
};
|
|
|
|
copy.copyDir(testPackage, tempPackage, { ignore: ['.git'] })
|
|
.then(function() {
|
|
fs.writeFileSync(
|
|
path.join(tempPackage, '.bower.json'),
|
|
JSON.stringify(json)
|
|
);
|
|
|
|
return packageRepository
|
|
.fetch({ name: '', source: 'foo', target: '~0.1.0' })
|
|
.spread(function(canonicalDir, pkgMeta) {
|
|
expect(called).to.be(true);
|
|
expect(fs.existsSync(canonicalDir)).to.be(true);
|
|
expect(pkgMeta).to.be.an('object');
|
|
expect(pkgMeta.name).to.be('package-a');
|
|
expect(pkgMeta.version).to.be('0.1.1');
|
|
next();
|
|
});
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should call the resolver resolve method if hasNew resolved to true', function(next) {
|
|
var json = {
|
|
name: 'a',
|
|
version: '0.2.0'
|
|
};
|
|
var called = [];
|
|
|
|
resolverFactoryHook = function(resolver) {
|
|
var originalResolve = resolver.resolve;
|
|
|
|
resolver.resolve = function() {
|
|
called.push('resolve');
|
|
return originalResolve.apply(this, arguments);
|
|
};
|
|
|
|
resolver.hasNew = function(pkgMeta) {
|
|
expect(pkgMeta).to.eql(json);
|
|
called.push('hasNew');
|
|
return Q.resolve(true);
|
|
};
|
|
};
|
|
|
|
packageRepository._resolveCache.retrieve = function() {
|
|
return Q.resolve([tempPackage, json]);
|
|
};
|
|
|
|
copy.copyDir(testPackage, tempPackage, { ignore: ['.git'] })
|
|
.then(function() {
|
|
fs.writeFileSync(
|
|
path.join(tempPackage, '.bower.json'),
|
|
JSON.stringify(json)
|
|
);
|
|
|
|
return packageRepository
|
|
.fetch({ name: '', source: 'foo', target: '~0.2.0' })
|
|
.spread(function(canonicalDir, pkgMeta) {
|
|
expect(called).to.eql(['hasNew', 'resolve']);
|
|
expect(fs.existsSync(canonicalDir)).to.be(true);
|
|
expect(pkgMeta).to.be.an('object');
|
|
expect(pkgMeta.name).to.be('a');
|
|
expect(pkgMeta.version).to.be('0.2.2');
|
|
next();
|
|
});
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should resolve to the cached package if hasNew resolve to false', function(next) {
|
|
var json = {
|
|
name: 'a',
|
|
version: '0.2.0'
|
|
};
|
|
var called = [];
|
|
|
|
resolverFactoryHook = function(resolver) {
|
|
var originalResolve = resolver.resolve;
|
|
|
|
resolver.resolve = function() {
|
|
called.push('resolve');
|
|
return originalResolve.apply(this, arguments);
|
|
};
|
|
|
|
resolver.hasNew = function(pkgMeta) {
|
|
expect(pkgMeta).to.eql(json);
|
|
called.push('hasNew');
|
|
return Q.resolve(false);
|
|
};
|
|
};
|
|
|
|
packageRepository._resolveCache.retrieve = function() {
|
|
return Q.resolve([tempPackage, json]);
|
|
};
|
|
|
|
copy.copyDir(testPackage, tempPackage, { ignore: ['.git'] })
|
|
.then(function() {
|
|
fs.writeFileSync(
|
|
path.join(tempPackage, '.bower.json'),
|
|
JSON.stringify(json)
|
|
);
|
|
|
|
return packageRepository
|
|
.fetch({ name: '', source: 'foo', target: '~0.2.0' })
|
|
.spread(function(canonicalDir, pkgMeta) {
|
|
expect(called).to.eql(['hasNew']);
|
|
expect(canonicalDir).to.equal(tempPackage);
|
|
expect(pkgMeta).to.eql(json);
|
|
next();
|
|
});
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should just use the cached package if offline was specified', function(next) {
|
|
var json = {
|
|
name: 'a',
|
|
version: '0.2.0'
|
|
};
|
|
var called = [];
|
|
|
|
resolverFactoryHook = function(resolver) {
|
|
var originalResolve = resolver.resolve;
|
|
|
|
resolver.hasNew = function(pkgMeta) {
|
|
expect(pkgMeta).to.eql(json);
|
|
called.push('resolve');
|
|
return originalResolve.apply(this, arguments);
|
|
};
|
|
|
|
resolver.hasNew = function() {
|
|
called.push('hasNew');
|
|
return Q.resolve(false);
|
|
};
|
|
};
|
|
|
|
packageRepository._resolveCache.retrieve = function() {
|
|
return Q.resolve([tempPackage, json]);
|
|
};
|
|
|
|
copy.copyDir(testPackage, tempPackage, { ignore: ['.git'] })
|
|
.then(function() {
|
|
fs.writeFileSync(
|
|
path.join(tempPackage, '.bower.json'),
|
|
JSON.stringify(json)
|
|
);
|
|
|
|
packageRepository._config.offline = true;
|
|
return packageRepository
|
|
.fetch({ name: '', source: 'foo', target: '~0.2.0' })
|
|
.spread(function(canonicalDir, pkgMeta) {
|
|
expect(called.length).to.be(0);
|
|
expect(canonicalDir).to.equal(tempPackage);
|
|
expect(pkgMeta).to.eql(json);
|
|
next();
|
|
});
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should error out if there is no appropriate package in the resolve cache and offline was specified', function(next) {
|
|
packageRepository._config.offline = true;
|
|
packageRepository
|
|
.fetch({ name: '', source: 'foo', target: '~0.2.0' })
|
|
.then(
|
|
function() {
|
|
throw new Error('Should have failed');
|
|
},
|
|
function(err) {
|
|
expect(err).to.be.an(Error);
|
|
expect(err.code).to.equal('ENOCACHE');
|
|
|
|
next();
|
|
}
|
|
)
|
|
.done();
|
|
});
|
|
});
|
|
|
|
describe('.versions', function() {
|
|
it('should call the versions method on the concrete resolver', function(next) {
|
|
var called = [];
|
|
var originalVersions = resolvers.GitRemote.versions;
|
|
|
|
resolvers.GitRemote.versions = function(source) {
|
|
expect(source).to.equal(mockSource);
|
|
called.push('resolver');
|
|
return Q.resolve([]);
|
|
};
|
|
|
|
packageRepository._resolveCache.versions = function() {
|
|
called.push('resolve-cache');
|
|
return Q.resolve([]);
|
|
};
|
|
|
|
packageRepository
|
|
.versions('foo')
|
|
.then(function(versions) {
|
|
expect(called).to.eql(['resolver']);
|
|
expect(versions).to.be.an('array');
|
|
expect(versions.length).to.be(0);
|
|
|
|
next();
|
|
})
|
|
.fin(function() {
|
|
resolvers.GitRemote.versions = originalVersions;
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should call the versions method on the resolve cache if offline was specified', function(next) {
|
|
var called = [];
|
|
var originalVersions = resolvers.GitRemote.versions;
|
|
|
|
resolvers.GitRemote.versions = function() {
|
|
called.push('resolver');
|
|
return Q.resolve([]);
|
|
};
|
|
|
|
packageRepository._resolveCache.versions = function(source) {
|
|
expect(source).to.equal(mockSource);
|
|
called.push('resolve-cache');
|
|
return Q.resolve([]);
|
|
};
|
|
|
|
packageRepository._config.offline = true;
|
|
packageRepository
|
|
.versions('foo')
|
|
.then(function(versions) {
|
|
expect(called).to.eql(['resolve-cache']);
|
|
expect(versions).to.be.an('array');
|
|
expect(versions.length).to.be(0);
|
|
|
|
next();
|
|
})
|
|
.fin(function() {
|
|
resolvers.GitRemote.versions = originalVersions;
|
|
})
|
|
.done();
|
|
});
|
|
});
|
|
|
|
describe('.eliminate', function() {
|
|
it('should call the eliminate method from the resolve cache', function(next) {
|
|
var called;
|
|
var json = {
|
|
name: 'a',
|
|
version: '0.2.0',
|
|
_source: 'foo'
|
|
};
|
|
|
|
packageRepository._resolveCache.eliminate = function(pkgMeta) {
|
|
expect(pkgMeta).to.eql(json);
|
|
called = true;
|
|
return Q.resolve();
|
|
};
|
|
|
|
packageRepository
|
|
.eliminate(json)
|
|
.then(function() {
|
|
expect(called).to.be(true);
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should call the clearCache method with the name from the registry client', function(next) {
|
|
var called;
|
|
var json = {
|
|
name: 'a',
|
|
version: '0.2.0',
|
|
_source: 'foo'
|
|
};
|
|
|
|
packageRepository._registryClient.clearCache = function(
|
|
name,
|
|
callback
|
|
) {
|
|
expect(name).to.eql(json.name);
|
|
called = true;
|
|
callback();
|
|
};
|
|
|
|
packageRepository
|
|
.eliminate(json)
|
|
.then(function() {
|
|
expect(called).to.be(true);
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
});
|
|
|
|
describe('.list', function() {
|
|
it('should proxy to the resolve cache list method', function(next) {
|
|
var called;
|
|
var originalList = packageRepository._resolveCache.list;
|
|
|
|
packageRepository._resolveCache.list = function() {
|
|
called = true;
|
|
return originalList.apply(this, arguments);
|
|
};
|
|
|
|
packageRepository
|
|
.list()
|
|
.then(function(entries) {
|
|
expect(called).to.be(true);
|
|
expect(entries).to.be.an('array');
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
});
|
|
|
|
describe('.clear', function() {
|
|
it('should call the clear method from the resolve cache', function(next) {
|
|
var called;
|
|
|
|
packageRepository._resolveCache.clear = function() {
|
|
called = true;
|
|
return Q.resolve();
|
|
};
|
|
|
|
packageRepository
|
|
.clear()
|
|
.then(function() {
|
|
expect(called).to.be(true);
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
|
|
it('should call the clearCache method without name from the registry client', function(next) {
|
|
var called;
|
|
|
|
packageRepository._registryClient.clearCache = function(callback) {
|
|
called = true;
|
|
callback();
|
|
};
|
|
|
|
packageRepository
|
|
.clear()
|
|
.then(function() {
|
|
expect(called).to.be(true);
|
|
next();
|
|
})
|
|
.done();
|
|
});
|
|
});
|
|
|
|
describe('.reset', function() {
|
|
it('should call the reset method from the resolve cache', function() {
|
|
var called;
|
|
|
|
packageRepository._resolveCache.reset = function() {
|
|
called = true;
|
|
return packageRepository._resolveCache;
|
|
};
|
|
|
|
packageRepository.reset();
|
|
expect(called).to.be(true);
|
|
});
|
|
|
|
it('should call the resetCache method without name from the registry client', function() {
|
|
var called;
|
|
|
|
packageRepository._registryClient.resetCache = function() {
|
|
called = true;
|
|
return packageRepository._registryClient;
|
|
};
|
|
|
|
packageRepository.reset();
|
|
expect(called).to.be(true);
|
|
});
|
|
});
|
|
|
|
describe('.getRegistryClient', function() {
|
|
it('should return the underlying registry client', function() {
|
|
expect(packageRepository.getRegistryClient()).to.be.an(
|
|
RegistryClient
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('.getResolveCache', function() {
|
|
it('should return the underlying resolve cache', function() {
|
|
expect(packageRepository.getResolveCache()).to.be.an(ResolveCache);
|
|
});
|
|
});
|
|
|
|
describe('#clearRuntimeCache', function() {
|
|
it('should clear the resolve cache runtime cache', function() {
|
|
var called;
|
|
var originalClearRuntimeCache = ResolveCache.clearRuntimeCache;
|
|
|
|
// No need to restore the original method since the constructor
|
|
// gets re-assigned every time in beforeEach
|
|
ResolveCache.clearRuntimeCache = function() {
|
|
called = true;
|
|
return originalClearRuntimeCache.apply(ResolveCache, arguments);
|
|
};
|
|
|
|
packageRepository.constructor.clearRuntimeCache();
|
|
expect(called).to.be(true);
|
|
});
|
|
|
|
it('should clear the resolver factory runtime cache', function() {
|
|
var called;
|
|
|
|
resolverFactoryClearHook = function() {
|
|
called = true;
|
|
};
|
|
|
|
packageRepository.constructor.clearRuntimeCache();
|
|
expect(called).to.be(true);
|
|
});
|
|
|
|
it('should clear the registry runtime cache', function() {
|
|
var called;
|
|
var originalClearRuntimeCache = RegistryClient.clearRuntimeCache;
|
|
|
|
// No need to restore the original method since the constructor
|
|
// gets re-assigned every time in beforeEach
|
|
RegistryClient.clearRuntimeCache = function() {
|
|
called = true;
|
|
return originalClearRuntimeCache.apply(
|
|
RegistryClient,
|
|
arguments
|
|
);
|
|
};
|
|
|
|
packageRepository.constructor.clearRuntimeCache();
|
|
expect(called).to.be(true);
|
|
});
|
|
});
|
|
});
|