Skip to content

Commit

Permalink
add update cli coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
hugomontero committed May 20, 2024
1 parent 4783c05 commit 957c6f9
Show file tree
Hide file tree
Showing 2 changed files with 268 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/cmd/update-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class UpdateCliCommand {
logAndReject(error, reject, version) {
const baseMessage = 'We were unable to check for updates';
const message = version ? `${baseMessage}: Version ${version} not found` : `${baseMessage} Please try again later`;
log.error(error);
log.error(error.message || error);
reject(message);
}

Expand Down
267 changes: 267 additions & 0 deletions src/cmd/update-cli.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
const { expect, sinon } = require('../../test/setup');
const UpdateCLI = require('./update-cli');
const settings = require('../../settings');
const fs = require('fs-extra');
const path = require('path');
const nock = require('nock');
const log = require('../lib/log');
const pkg = require('../../package');
const os = require('os');

describe('Update CLI Command', () => {
beforeEach(() => {
sinon.stub(settings, 'saveProfileData');
settings.profile_json = { enableUpdates: false };
});

afterEach(() => {
sinon.restore();
});

describe('updateCli', () => {
beforeEach(() => {
sinon.stub(log, 'info');
});
afterEach(() => {
sinon.restore();
});
it('skip update if the CLI is up to date', async () => {
const update = new UpdateCLI();
const manifest = { version: '1.2.3' };
sinon.stub(update, 'downloadManifest').resolves(manifest);
sinon.stub(pkg, 'version').value('1.2.3');
await update.updateCli();
expect(log.info).to.have.been.calledWith('CLI is already up to date');
});

it('update the CLI to the latest version', async () => {
const update = new UpdateCLI();
const manifest = { version: '1.2.3' };
sinon.stub(update, 'downloadManifest').resolves(manifest);
sinon.stub(pkg, 'version').value('1.2.2');
sinon.stub(update, 'downloadCLI').resolves('/path/to/cli/particle-cli-1.2.3-linux-x64.gz');
sinon.stub(update, 'replaceCLI').resolves();
await update.updateCli();
expect(log.info).to.have.been.calledWith('CLI updated successfully');
expect(settings.saveProfileData).to.have.property('callCount', 1);
expect(settings.profile_json.last_version_check).to.gt(0);
expect(update.downloadCLI).to.have.been.calledWith(manifest);
expect(update.replaceCLI).to.have.been.calledWith('/path/to/cli/particle-cli-1.2.3-linux-x64.gz');
});
});
describe('enable/disable updates', () => {
it('should enable updates', async () => {
const update = new UpdateCLI();
await update.update({ 'enable-updates': true });
expect(settings.saveProfileData).to.have.property('callCount', 1);
expect(settings.profile_json.enableUpdates).to.equal(true);
});

it('should disable updates', async () => {
settings.profile_json.enableUpdates = true;
const update = new UpdateCLI();
await update.update({ 'disable-updates': true });
expect(settings.saveProfileData).to.have.property('callCount', 1);
expect(settings.profile_json.enableUpdates).to.equal(false);
});
});

describe('downloadManifest', () => {
const manifestData = JSON.stringify({
'version': '4.1.0',
'builds': {
'linux': { 'x64': { 'url': 'https://binaries.particle.io/cli/manifest/4.1.0/particle-cli-4.1.0-linux-x64.tar.gz' }
}
}
});
beforeEach(() => {
sinon.stub(log, 'info');
sinon.stub(log, 'error');
});
afterEach(() => {
sinon.restore();
});
it('downloads the latest manifest version', async () => {
nock('https://binaries.particle.io')
.intercept('/particle-cli/manifest.json', 'GET')
.reply(200, manifestData);
const update = new UpdateCLI();
const manifest = await update.downloadManifest();
expect(manifest).to.deep.equal(JSON.parse(manifestData));
});

it('downloads a specific manifest version', async () => {
nock('https://binaries.particle.io')
.intercept('/particle-cli/manifest-4.1.0.json', 'GET')
.reply(200, manifestData);
const update = new UpdateCLI();
const manifest = await update.downloadManifest('4.1.0');
expect(manifest).to.deep.equal(JSON.parse(manifestData));
});
it('throws an error if the manifest download fails', async () => {
nock('https://binaries.particle.io')
.intercept('/particle-cli/manifest.json', 'GET')
.reply(404);
const update = new UpdateCLI();
await expect(update.downloadManifest()).to.be.rejectedWith('We were unable to check for updates Please try again later');
expect(log.error).to.have.been.calledWith('Failed to download manifest: Status Code 404');
});
it('throws an error if the manifest is invalid', async () => {
nock('https://binaries.particle.io')
.intercept('/particle-cli/manifest.json', 'GET')
.reply(200, 'invalid json');
const update = new UpdateCLI();
await expect(update.downloadManifest()).to.be.rejectedWith('We were unable to check for updates Please try again later');
expect(log.error).to.have.been.calledWith('Unexpected token i in JSON at position 0');
});
});

describe('downloadCLI', () => {
beforeEach(() => {
sinon.stub(log, 'error');
sinon.stub(log, 'debug');
});
afterEach(() => {
sinon.restore();
});
it('downloads the CLI binary', async () => {
const update = new UpdateCLI();
const buildDetails = {
url: 'https://binaries.particle.io/cli/manifest/1.2.3/particle-cli-1.2.3-linux-x64.gz',
sha256: '9cb63cb779e8c571db3199b783a36cc43cd9e7c076beeb496c39e9cc06196dc5'
};
sinon.stub(update, 'getBuildDetailsFromManifest').returns(buildDetails);
sinon.stub(update, 'unzipFile').resolves('/path/to/cli/particle-cli-1.2.3-linux-x64.gz');

nock('https://binaries.particle.io')
.intercept('/cli/manifest/1.2.3/particle-cli-1.2.3-linux-x64.gz', 'GET')
.reply(200, 'binary data');
const cliPath = await update.downloadCLI(buildDetails);
expect(cliPath).to.contain('particle-cli-1.2.3-linux-x64.gz');
expect(log.error).to.not.have.been.called;
});

it('throws an error if the CLI download fails', async () => {
const update = new UpdateCLI();
const buildDetails = {
url: 'https://binaries.particle.io/cli/manifest/1.2.3/particle-cli-1.2.3-linux-x64.gz',
sha256: '9cb63cb779e8c571db3199b783a36cc43cd9e7c076beeb496c39e9cc06196dc5'
};
sinon.stub(update, 'getBuildDetailsFromManifest').returns(buildDetails);
sinon.stub(update, 'unzipFile').resolves('/path/to/cli/particle-cli-1.2.3-linux-x64.gz');

nock('https://binaries.particle.io')
.intercept('/cli/manifest/1.2.3/particle-cli-1.2.3-linux-x64.gz', 'GET')
.reply(404);
await expect(update.downloadCLI(buildDetails)).to.be.rejectedWith('Failed to download or verify the CLI, please try again later');
expect(log.debug).to.have.been.calledWith('Failed during download or verification: Error: No file found to download');
});

it('throws an error if the CLI hash does not match', async () => {
const update = new UpdateCLI();
const buildDetails = {
url: 'https://binaries.particle.io/cli/manifest/1.2.3/particle-cli-1.2.3-linux-x64.gz',
sha256: 'invalid-hash'
};
sinon.stub(update, 'getBuildDetailsFromManifest').returns(buildDetails);
sinon.stub(update, 'unzipFile').resolves('/path/to/cli/particle-cli-1.2.3-linux-x64.gz');

nock('https://binaries.particle.io')
.intercept('/cli/manifest/1.2.3/particle-cli-1.2.3-linux-x64.gz', 'GET')
.reply(200, 'binary data');
await expect(update.downloadCLI(buildDetails)).to.be.rejectedWith('Failed to download or verify the CLI, please try again later');
expect(log.debug).to.have.been.calledWith('Failed during download or verification: Error: Hash mismatch');
});
});

describe('getBuildDetailsFromManifest', () => {
const manifest = {
builds: {
linux: {
x64: {
url: 'https://binaries.particle.io/cli/manifest/1.2.3/particle-cli-1.2.3-linux-x64.tar.gz'
}
}
}
};

afterEach(() => {
sinon.restore();
});
it('returns the manifest details from current platform/architecture', () => {
sinon.stub(os, 'platform').returns('linux');
sinon.stub(os, 'arch').returns('x64');
const update = new UpdateCLI();
const buildDetails = update.getBuildDetailsFromManifest(manifest);
expect(buildDetails).to.equal(manifest.builds.linux.x64);
});

it('throws an error if the platform is not found in the manifest', () => {
sinon.stub(os, 'platform').returns('darwin');
sinon.stub(os, 'arch').returns('x64');
const update = new UpdateCLI();
expect(() => update.getBuildDetailsFromManifest(manifest)).to.throw('No CLI build found for darwin x64');
});

it('throws an error if the platform is not found in the manifest', () => {
const update = new UpdateCLI();
expect(() => update.getBuildDetailsFromManifest({})).to.throw('No CLI build found for darwin x64');
});

});

describe('replaceCLI', () => {
let processExecPathTmp;
beforeEach(() => {
processExecPathTmp = process.execPath;
process.execPath = '/usr/bin/particle';
});

afterEach(() => {
process.execPath = processExecPathTmp;
});


it('replace the cli for a new one', async () => {
const update = new UpdateCLI();
const newCliPath = path.join('path', 'to', 'new', 'cli');
const execPath = path.join(path.sep,'usr', 'bin', 'particle');
const binPath = path.join(path.sep,'usr', 'bin');
const fileName = 'particle';


const getBinaryPathStub = sinon.spy(update, 'getBinaryPath');
const moveStub = sinon.stub(fs, 'move').resolves();
const chmodStub = sinon.stub(fs, 'chmod').resolves();
const cliPath = execPath;
const oldCliPath = path.join(binPath, `${fileName}.old`);
await update.replaceCLI(newCliPath);
expect(getBinaryPathStub).to.have.been.calledOnce;
expect(moveStub).to.have.been.calledWith(execPath, oldCliPath, { overwrite: true });
expect(moveStub).to.have.been.calledWith(newCliPath, cliPath);
expect(chmodStub).to.have.been.calledWith(cliPath, 0o755);
});
});

describe('configureProfileSettings', () => {
it ('disable updates if version is provided', async() => {
const update = new UpdateCLI();
settings.profile_json.last_version_check = 0;
settings.profile_json.enableUpdates = true;
await update.configureProfileSettings('1.2.3');
expect(settings.profile_json.last_version_check).to.gt(0);
expect(settings.profile_json.enableUpdates).to.equal(false);
expect(settings.saveProfileData).to.have.property('callCount', 2);
});

it ('update last_version_check but will not change enableUpdates data if version is undefined', async () => {
const update = new UpdateCLI();
settings.profile_json.last_version_check = 0;
settings.profile_json.enableUpdates = true;
await update.configureProfileSettings();
expect(settings.profile_json.last_version_check).to.gt(0);
expect(settings.profile_json.enableUpdates).to.equal(true);
expect(settings.saveProfileData).to.have.property('callCount', 1);
});
});
});

0 comments on commit 957c6f9

Please sign in to comment.