Skip to content

Commit

Permalink
add timeout to command to catch if device isn't listening
Browse files Browse the repository at this point in the history
  • Loading branch information
wraithan committed Oct 30, 2019
1 parent 20d02af commit 46fd1de
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 16 deletions.
40 changes: 26 additions & 14 deletions src/cmd/serial.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ const ensureError = require('../lib/utilities').ensureError;
const cmd = path.basename(process.argv[1]);
const arrow = chalk.green('>');
const alert = chalk.yellow('!');
const timeoutError = 'Serial timed out';

function protip(){
const args = Array.prototype.slice.call(arguments);
args.unshift(chalk.cyan('!'), chalk.bold.white('PROTIP:'));
console.log.apply(null, args);
}

const TIMEOUT_ERROR_MESSAGE = 'Serial timed out';

// An LTE device may take up to 18 seconds to power up the modem
const MODULE_INFO_COMMAND_TIMEOUT = 20000;
const IDENTIFY_COMMAND_TIMEOUT = 20000;
Expand Down Expand Up @@ -616,7 +617,7 @@ module.exports = class SerialCommand {
return !!matches;
})
.catch((err) => {
if (err !== timeoutError){
if (err !== TIMEOUT_ERROR_MESSAGE){
throw err;
}
return false;
Expand Down Expand Up @@ -897,7 +898,7 @@ module.exports = class SerialCommand {
}

function startTimeout(to){
self._serialTimeout = setTimeout(() => reject('Serial timed out'), to);
self._serialTimeout = setTimeout(() => reject(TIMEOUT_ERROR_MESSAGE), to);
}

function resetTimeout(){
Expand All @@ -919,8 +920,22 @@ module.exports = class SerialCommand {
return promise.finally(cleanUpFn);
}

/**
* This is a wrapper function created so _serialWifiConfig can return the
* true promise state, but the wrapper can still act like it handled any
* failures gracefully as it acted before testing was attempted.
*/
serialWifiConfig(...args) {
return this._serialWifiConfig.apply(this, args)
.then(() => {
console.log('Done! Your device should now restart.');
}, (err) => {
log.error('Something went wrong:', err);
});
}

/* eslint-disable max-statements */
serialWifiConfig(device, opts = {}){
_serialWifiConfig(device, opts = {}){
if (!device){
return Promise.reject('No serial port available');
}
Expand Down Expand Up @@ -1204,15 +1219,18 @@ module.exports = class SerialCommand {
serialTrigger.start(true);
serialPort.write('w');
serialPort.drain();

// In case device is not in listening mode.
startTimeout(5000, 'Serial timed out while initially listening to device, please ensure device is in listening mode with particle usb start-listening');
});

function serialClosedEarly(){
reject('Serial port closed early');
}

function startTimeout(to){
function startTimeout(to, message = TIMEOUT_ERROR_MESSAGE){
self._serialTimeout = setTimeout(() => {
reject('Serial timed out');
reject(message);
}, to);
}

Expand Down Expand Up @@ -1275,13 +1293,7 @@ module.exports = class SerialCommand {
}
});

return promise
.then(() => {
console.log('Done! Your device should now restart.');
}, (err) => {
log.error('Something went wrong:', err);
})
.finally(cleanUpFn);
return promise.finally(cleanUpFn);
}
/* eslint-enable max-statements */

Expand All @@ -1307,7 +1319,7 @@ module.exports = class SerialCommand {
serialPort.pipe(parser);

const failTimer = setTimeout(() => {
reject(timeoutError);
reject(TIMEOUT_ERROR_MESSAGE);
}, failDelay);

parser.on('data', (data) => {
Expand Down
24 changes: 23 additions & 1 deletion src/cmd/serial.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
const MockSerial = require('../../test/__mocks__/serial.mock');
const { expect } = require('../../test/setup');
const { expect, sinon } = require('../../test/setup');
const SerialCommand = require('./serial');


describe('Serial Command', () => {
let serial;
let clock;

beforeEach(() => {
serial = new SerialCommand({ params: {} });
});

afterEach(() => {
if (clock !== undefined) {
clock.restore();
clock = undefined;
}
});

describe('supportsClaimCode', () => {
it('can check if a device supports claiming', () => {
var device = { port: 'vintage' };
Expand Down Expand Up @@ -53,5 +61,19 @@ describe('Serial Command', () => {
});
});
});

describe('serialWifiConfig', () => {
it('can reject with timeout after 5000ms if not getting any serial data', () => {
clock = sinon.useFakeTimers();
const device = { port: 'baltimore' };
const mockSerial = new MockSerial();
serial.serialPort = mockSerial;
const wifiPromise = serial._serialWifiConfig(device);
process.nextTick(() => {
clock.tick(5010);
});
return expect(wifiPromise).to.be.rejected;
});
});
});

2 changes: 1 addition & 1 deletion test/__mocks__/serial.mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ MockSerial.prototype.write = function write(chunk) {
this.data += chunk;
};

MockSerial.prototype.drain = function drain(cb) {
MockSerial.prototype.drain = function drain(cb = () => {}) {
this.emit('drain');
process.nextTick(cb);
};
Expand Down

0 comments on commit 46fd1de

Please sign in to comment.