Skip to content

Commit

Permalink
Merge pull request #431 from particle-iot/feature/function-fix
Browse files Browse the repository at this point in the history
Fix issue with function and variable commands
  • Loading branch information
monkbroc authored Jun 25, 2018
2 parents 5cec784 + f3958fa commit 8f8d04a
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 9 deletions.
2 changes: 0 additions & 2 deletions src/cmd/cloud.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
const _ = require('lodash');
const VError = require('verror');
const whenNode = require('when/node');
const prompt = require('inquirer').prompt;
const temp = require('temp').track();

const settings = require('../../settings.js');
const specs = require('../lib/deviceSpecs');
Expand Down
6 changes: 1 addition & 5 deletions src/cmd/function.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ const VError = require('verror');
const ensureError = require('../lib/utilities').ensureError;

class FunctionCommand {
constructor(options) {
this.options = options;
}

listFunctions() {
const api = new ApiClient();
api.ensureToken();
Expand Down Expand Up @@ -42,7 +38,7 @@ class FunctionCommand {
api.ensureToken();

return api.callFunction(deviceId, functionName, funcParam).then(result => {
if (result && result.return_value) {
if (result && result.hasOwnProperty('return_value')) {
console.log(result.return_value);
} else {
throw api.normalizedApiError(result);
Expand Down
4 changes: 2 additions & 2 deletions src/cmd/variable.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class VariableCommand {
return when.map(deviceId, (deviceId) => {
return api.getVariable(deviceId, variableName);
}).then((results) => {
const time = moment().format();
const now = moment().format();
let hasErrors = false;
for (let i = 0; i < results.length; i++) {
const parts = [];
Expand All @@ -82,7 +82,7 @@ class VariableCommand {
parts.push(result.coreInfo.deviceID);
}
if (time) {
parts.push(time);
parts.push(now);
}
parts.push(result.result);

Expand Down
109 changes: 109 additions & 0 deletions test/cmd/function.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
const expect = require('chai').expect;
const proxyquire = require('proxyquire');
const sandbox = require('sinon').createSandbox();

const stubs = {
api: {
ensureToken: () => {},
callFunction: () => {},
normalizedApiError: (resp) => new Error(resp.error),
},
ApiClient: function ApiClient(){
return stubs.api;
}
};

const FunctionCommand = proxyquire('../../src/cmd/function', {
'../lib/ApiClient.js': stubs.ApiClient
});


describe('Function Command', () => {

let deviceId, functionName, functionParam;

beforeEach(() => {
deviceId = 'test-device';
functionName = 'fn';
functionParam = 'param';
});

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

describe('when the function succeeds', () => {
it('prints the return value', withConsoleStubs(() => {
const { func, api } = stubForFunction(new FunctionCommand(), stubs);
api.callFunction.resolves({ ok: true, return_value: 42 });

return func.callFunction(deviceId, functionName, functionParam).then(() => {
expectSuccessMessage(42);
});
}));

it('prints the return value of 0', withConsoleStubs(() => {
const { func, api } = stubForFunction(new FunctionCommand(), stubs);
api.callFunction.resolves({ ok: true, return_value: 0 });

return func.callFunction(deviceId, functionName, functionParam).then(() => {
expectSuccessMessage(0);
});
}));
});

describe('when the function does not exist', () => {
it('rejects with an error',() => {
const { func, api } = stubForFunction(new FunctionCommand(), stubs);
api.callFunction.resolves({
ok: false,
error: `Function ${functionName} not found`
});

return func.callFunction(deviceId, functionName, functionParam).then(() => {
throw new Error('expected promise to be rejected');
}).catch(error => {
expect(error).to.have.property('message', `Function call failed: Function ${functionName} not found`);
});
});
});

function expectSuccessMessage(value){
expect(process.stdout.write).to.have.property('callCount', 1);
expect(process.stdout.write.firstCall.args[0])
.to.match(new RegExp(`${value}\\n$`));
}

function stubForFunction(func, stubs){
const { api } = stubs;
sandbox.stub(api, 'ensureToken');
sandbox.stub(api, 'callFunction');
return { func, api };
}

// TODO (mirande): figure out a better approach. this allows us to verify
// log output without supressing mocha's success / error messages but is a
// bit awkward
function withConsoleStubs(fn){

return () => {
let result;

sandbox.stub(process.stdout, 'write');
sandbox.stub(process.stderr, 'write');

try {
result = fn();
} catch (error) {
sandbox.restore();
throw error;
}

if (result && typeof result.finally === 'function'){
return result.finally(() => sandbox.restore());
}
sandbox.restore();
return result;
};
}
});

0 comments on commit 8f8d04a

Please sign in to comment.