veendor
Version:
a tool for stroing your npm dependencies in arbitraty storage
368 lines (292 loc) • 14 kB
JavaScript
const {describe, it, beforeEach, afterEach} = require('mocha');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const sinon = require('sinon');
const mockfs = require('mock-fs');
const path = require('path');
const assert = chai.assert;
chai.use(chaiAsPromised);
const gitLfs = require('../../../lib/backends/git-lfs');
const gitWrapper = require('../../../lib/commandWrappers/gitWrapper');
const tarWrapper = require('../../../lib/commandWrappers/tarWrapper');
const errors = require('../../../lib/errors');
const {notifyAssert} = require('../helpers');
let fakeRepo;
let sandbox;
let fakeHash;
let defaultOptions;
describe('git-lfs', () => {
beforeEach(() => {
mockfs({
'.veendor': {
'git-lfs.0': {}
},
});
fakeRepo = 'git://fakehub.com/test/test.git';
fakeHash = '1234567890deadbeef1234567890';
sandbox = sinon.sandbox.create();
defaultOptions = {
repo: fakeRepo,
compression: 'gzip',
defaultBranch: 'defaultBranchaster'
};
gitLfs._remoteIsFresh = false;
sandbox.stub(gitWrapper, 'clone').resolves();
sandbox.stub(gitWrapper, 'fetch').resolves();
sandbox.stub(gitWrapper, 'checkout').resolves();
sandbox.stub(gitWrapper, 'add').resolves();
sandbox.stub(gitWrapper, 'commit').resolves();
sandbox.stub(gitWrapper, 'tag').resolves();
sandbox.stub(gitWrapper, 'push').resolves();
sandbox.stub(gitWrapper, 'isGitRepo').resolves();
sandbox.stub(gitWrapper, 'resetToRemote').resolves();
sandbox.stub(gitWrapper, 'isGitLfsAvailable').resolves();
sandbox.stub(gitWrapper, 'lfsPull').resolves();
sandbox.stub(tarWrapper, 'createArchive').resolves();
sandbox.stub(tarWrapper, 'extractArchive').resolves();
});
afterEach(() => {
mockfs.restore();
sandbox.restore();
});
describe('.pull', () => {
it('clones repo to cache directory if isn\'t already there', done => {
gitWrapper.isGitRepo.restore();
sandbox.stub(gitWrapper, 'isGitRepo').rejects(gitWrapper.NotAGitRepoError);
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.clone,
args: [fakeRepo, sinon.match('.veendor/git-lfs.0/repo')]
}], done);
gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('runs `fetch` if repo already exist', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.fetch,
args: [sinon.match('.veendor/git-lfs.0/repo')]
}], done);
gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('checks out tag by passed hash', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.checkout,
args: [sinon.match('.veendor/git-lfs.0/repo'), 'veendor-' + fakeHash]
}], done);
gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('rejects with BundleNotFoundError if tag not found', done => {
gitWrapper.checkout.restore();
sandbox.stub(gitWrapper, 'checkout').rejects(new Error);
assert
.isRejected(gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0'), errors.BundleNotFoundError)
.notify(done);
});
it('does not run tar if tag not found', done => {
gitWrapper.checkout.restore();
sandbox.stub(gitWrapper, 'checkout').rejects(new Error);
const checkResult = () => {
setTimeout(() => {
if (tarWrapper.extractArchive.notCalled) {
return done();
}
done(new Error('Expected `tarWrapper.extractArchive` not to be called'));
}, 1); // Yep, async world. Setting timeouts just to be sure.
};
gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('unpacks the archive to $(pwd)', done => {
const checkResult = expectCalls.bind(null, [{
spy: tarWrapper.extractArchive,
args: [sinon.match(`.veendor/git-lfs.0/repo/${fakeHash}.tar.gz`)]
}], done);
gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('should run git fetch only once in a run', done => {
const checkResult = () => {
const calls = gitWrapper.fetch.getCalls();
notifyAssert(assert.equal.bind(
null,
calls.length,
1,
`Expected 'gitWrapper.fetch' to be called once`
), done);
};
gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0')
.then(() => {
return gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0');
})
.then(() => {
return gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0');
})
.then(checkResult, checkResult);
});
it('should run git lfs pull if git lfs is available', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.lfsPull,
args: [sinon.match('.veendor/git-lfs.0/repo')]
}], done);
gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('should not run git lfs pull if git lfs is not available', done => {
gitWrapper.isGitLfsAvailable.restore();
sandbox.stub(gitWrapper, 'isGitLfsAvailable').rejects(new gitWrapper.GitLfsNotAvailableError);
const checkResult = () => {
const calls = gitWrapper.lfsPull.getCalls();
notifyAssert(assert.equal.bind(
null,
calls.length,
0,
`Expected 'gitWrapper.lfsPull' not to be called`
), done);
};
gitLfs.pull(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
});
describe('.push', () => {
it('clones repo to cache directory if isn\'t already there', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.clone,
args: [fakeRepo, sinon.match('.veendor/git-lfs.0/repo')]
}], done);
gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('runs `fetch` if repo already exist', done => {
mockfs({
'.veendor': {
'git-lfs.0': {
repo: {
'.git': {}
}
}
},
});
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.fetch,
args: [sinon.match('.veendor/git-lfs.0/repo')]
}], done);
gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('checks out default branch', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.checkout,
args: [sinon.match('.veendor/git-lfs.0/repo'), defaultOptions.defaultBranch]
}], done);
gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('resets branch to remote state', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.resetToRemote,
args: [sinon.match('.veendor/git-lfs.0/repo'), defaultOptions.defaultBranch]
}], done);
gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('archives node_modules', done => {
const checkResult = expectCalls.bind(null, [{
spy: tarWrapper.createArchive,
args: [
sinon.match(`.veendor/git-lfs.0/repo/${fakeHash}`),
[path.resolve(process.cwd(), 'node_modules')],
defaultOptions.compression
]
}], done);
gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('adds archive to staging', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.add,
args: [
sinon.match('.veendor/git-lfs.0/repo'),
[sinon.match(`.veendor/git-lfs.0/repo/${fakeHash}.tar.gz`)]
]
}], done);
gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('creates commit', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.commit,
args: [sinon.match('.veendor/git-lfs.0/repo'), sinon.match.any]
}], done);
gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('creates tag with hash name', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.tag,
args: [sinon.match('.veendor/git-lfs.0/repo'), `veendor-${fakeHash}`]
}], done);
gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('pushes tag', done => {
const checkResult = expectCalls.bind(null, [{
spy: gitWrapper.push,
args: [sinon.match('.veendor/git-lfs.0/repo'), `veendor-${fakeHash}`]
}], done);
gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0').then(checkResult, checkResult);
});
it('throws BundleAlreadyExistsError if git tag rejected with RefAlreadyExistsError', done => {
gitWrapper.tag.restore();
sandbox.stub(gitWrapper, 'tag').rejects(new gitWrapper.RefAlreadyExistsError);
const result = gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0');
assert.isRejected(result, errors.BundleAlreadyExistsError).notify(done);
});
it('throws BundleAlreadyExistsError if git push rejected with RefAlreadyExistsError', done => {
gitWrapper.push.restore();
sandbox.stub(gitWrapper, 'push').rejects(new gitWrapper.RefAlreadyExistsError);
const result = gitLfs.push(fakeHash, defaultOptions, '.veendor/git-lfs.0');
assert.isRejected(result, errors.BundleAlreadyExistsError).notify(done);
});
});
describe('.validateOptions', done => {
it('throws error if `repo` hasn\'t been passed', done => {
delete defaultOptions.repo;
assert.isRejected(gitLfs.validateOptions(defaultOptions), errors.InvalidOptionsError).notify(done);
});
it('checks valid compression', done => {
defaultOptions.compression = 'lsda';
assert.isRejected(gitLfs.validateOptions(defaultOptions), errors.InvalidOptionsError).notify(done);
});
it('sets default compression type to `gzip`', done => {
delete defaultOptions.compression;
gitLfs
.validateOptions(defaultOptions)
.then(() => {
assert.equal(defaultOptions.compression, 'gzip');
done();
}, done);
});
it('sets default default branch to `master`', done => {
delete defaultOptions.defaultBranch;
gitLfs
.validateOptions(defaultOptions)
.then(() => {
notifyAssert(assert.equal.bind(null, defaultOptions.defaultBranch, 'master'), done);
}, done);
});
it('checks if checkLfsAvailability is boolean', done => {
defaultOptions.checkLfsAvailability = 'test';
assert.isRejected(gitLfs.validateOptions(defaultOptions), errors.InvalidOptionsError).notify(done);
});
it('sets default checkLfsAvailability to `false`', done => {
gitLfs
.validateOptions(defaultOptions)
.then(() => {
notifyAssert(assert.equal.bind(null, defaultOptions.checkLfsAvailability, false), done);
}, done);
});
it('rejects with `GitLfsNotAvailableError` if git lfs is not available ' +
'and `checkLfsAvailability` was set to \'true\'', done => {
defaultOptions.checkLfsAvailability = true;
gitWrapper.isGitLfsAvailable.restore();
sandbox.stub(gitWrapper, 'isGitLfsAvailable').rejects(new gitWrapper.GitLfsNotAvailableError);
assert.isRejected(gitLfs.validateOptions(defaultOptions), gitWrapper.GitLfsNotAvailableError).notify(done);
})
})
});
function expectCalls(expectPairs, done) {
for (const expect of expectPairs) {
if (!expect.spy.calledWith(...expect.args)) {
return done(new Error(`Expected spy "${expect.spy.displayName}" ` +
`to be called with [${expect.args.join(', ')}]\n` +
`Actual calls were: [${expect.spy.getCalls().join(', ')}]`))
}
}
done();
}