From e4e8c0f8523f5cf85959d995252c30bffbdbb2de Mon Sep 17 00:00:00 2001 From: johnnyman727 Date: Thu, 1 Oct 2015 22:02:23 -0700 Subject: [PATCH] Uses LAN and USB flags properly --- lib/controller.js | 32 ++++--- lib/discover.js | 34 +++++-- test/unit/controller.js | 12 +-- test/unit/discover.js | 193 ++++++++++++++++++++++++++++++++-------- 4 files changed, 212 insertions(+), 59 deletions(-) diff --git a/lib/controller.js b/lib/controller.js index bb1e0318..a04772a3 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -18,15 +18,19 @@ Tessel.list = function(opts) { // Keep a list of all the Tessels we discovered var foundTessels = []; + + // Options for Tessel discovery + var seekerOpts = { + timeout: opts.timeout * 1000, + usb: opts.usb, + lan: opts.lan + }; + // Start looking for Tessels - var seeker = new discover.TesselSeeker().start(opts.timeout * 1000); + var seeker = new discover.TesselSeeker().start(seekerOpts); // When a Tessel is found seeker.on('tessel', function displayResults(tessel) { - if ((tessel.connection.connectionType === 'LAN' && opts.usb && !opts.lan) || - (tessel.connection.connectionType === 'USB' && opts.lan && !opts.usb)) { - return; - } var note = ''; @@ -68,7 +72,7 @@ Tessel.list = function(opts) { // Report that selected Tessel to the user logs.info('Multiple Tessels found.'); if (tessel) { - logs.info('Will default to', tessel.name, '.'); + logs.info('Will default to %s.', tessel.name); } // Helpful instructions on how to switch logs.info('Set default Tessel with environment variable (e.g. \'export TESSEL=bulbasaur\') or use the --name flag.'); @@ -94,12 +98,18 @@ Tessel.list = function(opts) { Tessel.get = function(opts) { return new Promise(function(resolve, reject) { logs.info('Looking for your Tessel...'); - // Store the amount of time to look for Tessel in seconds - var timeout = (opts.timeout || 2) * 1000; // Collection variable as more Tessels are found var tessels = []; + + // Store the amount of time to look for Tessel in seconds + var seekerOpts = { + timeout: (opts.timeout || 2) * 1000, + usb: opts.usb, + lan: opts.lan + }; + // Create a seeker object and start detecting any Tessels - var seeker = new discover.TesselSeeker().start(timeout); + var seeker = new discover.TesselSeeker().start(seekerOpts); function searchComplete() { // If we found no Tessels @@ -425,6 +435,9 @@ controller.provisionTessel = function(opts) { } }) .then(function executeProvision() { + // We should only be using a USB connection + opts.usb = true; + // Fetch a Tessel return controller.standardTesselCommand(opts, function(tessel) { // Provision Tessel with SSH keys return tessel.provisionTessel(opts); @@ -455,7 +468,6 @@ controller.eraseScript = function(opts) { controller.renameTessel = function(opts) { opts = opts || {}; - // Grab the preferred tessel return new Promise(function(resolve, reject) { if (!opts.reset && !opts.newName) { diff --git a/lib/discover.js b/lib/discover.js index b83511eb..617674e5 100644 --- a/lib/discover.js +++ b/lib/discover.js @@ -14,19 +14,37 @@ function TesselSeeker() { util.inherits(TesselSeeker, EventEmitter); -TesselSeeker.prototype.start = function(timeout) { +TesselSeeker.prototype.start = function(opts) { var self = this; + // Initialize the opts if it wasn't provided + opts = opts || {}; // An array of pending open connections var pendingOpen = []; - self.lanScan = lan.startScan(); - - self.lanScan.on('connection', connectionHandler.bind(self)); + // If no connection preference was supplied + if (!opts.usb && !opts.lan) { + // Default to all connections + opts.usb = opts.lan = true; + } - self.usbScan = usb.startScan(); + // If the user has specifically requested lan devices + if (opts.lan) { + debug('Will scan for LAN devices'); + // Start the scan + self.lanScan = lan.startScan(); + // When we get a connection, handle it + self.lanScan.on('connection', connectionHandler.bind(self)); + } - self.usbScan.on('connection', connectionHandler.bind(self)); + // If the user has explicitly requested a USB search + if (opts.usb) { + debug('Will scan for USB devices'); + // Start the scan + self.usbScan = usb.startScan(); + // When we get a connection, handle it + self.usbScan.on('connection', connectionHandler.bind(self)); + } function connectionHandler(conn) { var tessel = new Tessel(conn); @@ -54,7 +72,7 @@ TesselSeeker.prototype.start = function(timeout) { } // If a timeout was provided - if (timeout && typeof timeout === 'number') { + if (opts.timeout && typeof opts.timeout === 'number') { // Set a timeout function self.scanTimeout = setTimeout(function() { debug('Timeout hit! Waiting for pending to finish...'); @@ -65,7 +83,7 @@ TesselSeeker.prototype.start = function(timeout) { debug('Done! Stopping.'); self.stop(); }); - }, timeout); + }, opts.timeout); } return self; diff --git a/test/unit/controller.js b/test/unit/controller.js index 7a3e7dcf..f6cee7d8 100644 --- a/test/unit/controller.js +++ b/test/unit/controller.js @@ -126,10 +126,10 @@ exports['Tessel.list'] = { this.processOn = this.sandbox.stub(process, 'on'); this.activeSeeker = undefined; this.seeker = this.sandbox.stub(Seeker, 'TesselSeeker', function Seeker() { - this.start = function(timeout) { + this.start = function(opts) { self.activeSeeker = this; - if (timeout && typeof timeout === 'number') { - setTimeout(this.stop, timeout); + if (opts.timeout && typeof opts.timeout === 'number') { + setTimeout(this.stop, opts.timeout); } return this; }; @@ -274,10 +274,10 @@ exports['Tessel.get'] = { this.processOn = this.sandbox.stub(process, 'on'); this.activeSeeker = undefined; this.seeker = this.sandbox.stub(Seeker, 'TesselSeeker', function Seeker() { - this.start = function(timeout) { + this.start = function(opts) { self.activeSeeker = this; - if (timeout && typeof timeout === 'number') { - setTimeout(this.stop, timeout); + if (opts.timeout && typeof opts.timeout === 'number') { + setTimeout(this.stop, opts.timeout); } return this; }; diff --git a/test/unit/discover.js b/test/unit/discover.js index 61484729..0c4587b0 100644 --- a/test/unit/discover.js +++ b/test/unit/discover.js @@ -180,6 +180,8 @@ exports['TesselSeeker Scan Time'] = { return new FakeScanner(); }); this.seeker = new TesselSeeker(); + // The default amount of time to scan for connections + this.scanTime = 100; done(); }, @@ -194,9 +196,11 @@ exports['TesselSeeker Scan Time'] = { oneUnauthorizedLANPending: function(test) { test.expect(1); // Scan for new connections for this period - var scanTime = 100; + var seekerOpts = { + timeout: this.scanTime + }; - standardSeekerSetup(this.seeker, scanTime) + standardSeekerSetup(this.seeker, seekerOpts) // When all Tessels have completed opening .then(function(found) { // Make sure we only have the one Tessel we created @@ -212,9 +216,9 @@ exports['TesselSeeker Scan Time'] = { // Give it a name lan.connection.host = 'Tessel-Test_Subject'; // Create it's open function - lan.connection.open = resolveOpenInMs.bind(this, scanTime * 2); + lan.connection.open = resolveOpenInMs.bind(this, this.scanTime * 2); // Once half of the scan time has elapsed, emit a new connection - emitConnectionInMs(this.seeker, lan.connection, scanTime / 2); + emitConnectionInMs(this.seeker, lan.connection, this.scanTime / 2); }, oneAuthorizedLANPending: function(test) { @@ -230,9 +234,11 @@ exports['TesselSeeker Scan Time'] = { }); // Scan for this period - var scanTime = 100; - // When all Tessels have completed opening - standardSeekerSetup(this.seeker, scanTime) + var seekerOpts = { + timeout: this.scanTime + }; + + standardSeekerSetup(this.seeker, seekerOpts) .then(function discoveryComplete(found) { // Make sure we only have the one Tessel we created test.equal(found.length, 1); @@ -248,24 +254,25 @@ exports['TesselSeeker Scan Time'] = { }); // Create it's open function - lan.connection.open = resolveOpenInMs.bind(this, scanTime * 2); + lan.connection.open = resolveOpenInMs.bind(this, this.scanTime * 2); // Emit the connection halfway through the scan - emitConnectionInMs(this.seeker, lan.connection, scanTime / 2); + emitConnectionInMs(this.seeker, lan.connection, this.scanTime / 2); }, oneAuthorizedLANPendingFails: function(test) { test.expect(1); - // Scan for new connections for this period - var scanTime = 100; // Error on name fetch this.getName = this.sandbox.stub(Tessel.prototype, 'getName', function() { return Promise.reject('Could not get name for some reason...'); }); - // Start scan - standardSeekerSetup(this.seeker, scanTime) + var seekerOpts = { + timeout: this.scanTime + }; + + standardSeekerSetup(this.seeker, seekerOpts) // When all Tessels have completed opening .then(function(found) { // Make sure we don't find any Tessels @@ -280,17 +287,15 @@ exports['TesselSeeker Scan Time'] = { }); // Create it's open function - lan.connection.open = resolveOpenInMs.bind(this, scanTime * 2); + lan.connection.open = resolveOpenInMs.bind(this, this.scanTime * 2); // Emit the connection halfway through the scan - emitConnectionInMs(this.seeker, lan.connection, scanTime / 2); + emitConnectionInMs(this.seeker, lan.connection, this.scanTime / 2); }, // A test with multiple kinds of connections emitted at different times usbAndLANConnections: function(test) { test.expect(1); - // Scan for new connections for one second - var scanTime = 100; // Give it a name this.getName = this.sandbox.stub(Tessel.prototype, 'getName', function() { @@ -298,7 +303,9 @@ exports['TesselSeeker Scan Time'] = { }); // When all Tessels have completed opening - standardSeekerSetup(this.seeker, scanTime) + standardSeekerSetup(this.seeker, { + timeout: this.scanTime + }) .then(function(found) { // Make sure we only have the one Tessel we created test.equal(found.length, 4); @@ -318,10 +325,10 @@ exports['TesselSeeker Scan Time'] = { // Create open functions authorized Tessel opens after scan has // complete but unauthorized opens before scan completes - lan1.connection.open = resolveOpenInMs.bind(this, scanTime + 1); + lan1.connection.open = resolveOpenInMs.bind(this, this.scanTime + 1); // Give it a name lan1.connection.host = 'Tessel-TroubleMaker'; - lan2.connection.open = resolveOpenInMs.bind(this, scanTime + 2); + lan2.connection.open = resolveOpenInMs.bind(this, this.scanTime + 2); var usb1 = TesselSimulator({ type: 'USB' @@ -330,28 +337,30 @@ exports['TesselSeeker Scan Time'] = { type: 'USB' }); - usb1.connection.open = resolveOpenInMs.bind(this, scanTime + 3); - usb2.connection.open = resolveOpenInMs.bind(this, scanTime + 4); + usb1.connection.open = resolveOpenInMs.bind(this, this.scanTime + 3); + usb2.connection.open = resolveOpenInMs.bind(this, this.scanTime + 4); - emitConnectionInMs(this.seeker, lan1.connection, scanTime / 4); - emitConnectionInMs(this.seeker, usb1.connection, scanTime / 3); - emitConnectionInMs(this.seeker, lan2.connection, scanTime / 2); - emitConnectionInMs(this.seeker, usb2.connection, scanTime / 1.1); + emitConnectionInMs(this.seeker, lan1.connection, this.scanTime / 4); + emitConnectionInMs(this.seeker, usb1.connection, this.scanTime / 3); + emitConnectionInMs(this.seeker, lan2.connection, this.scanTime / 2); + emitConnectionInMs(this.seeker, usb2.connection, this.scanTime / 1.1); }, // A test where seeker.stop is explicitly called instead of waiting for timeout explicitStop: function(test) { test.expect(1); - // Scan for new connections for this period - var scanTime = 100; // Error on name fetch this.getName = this.sandbox.stub(Tessel.prototype, 'getName', function() { return Promise.resolve('Frank'); }); - // Start scan - standardSeekerSetup(this.seeker, scanTime) + // Scan for new connections for this period + var seekerOpts = { + timeout: this.scanTime + }; + + standardSeekerSetup(this.seeker, seekerOpts) // When all Tessels have completed opening .then(function(found) { // Make sure we don't find any Tessels because we stopped the scan @@ -366,21 +375,135 @@ exports['TesselSeeker Scan Time'] = { }); // Create it's open function - lan.connection.open = resolveOpenInMs.bind(this, scanTime * 2); + lan.connection.open = resolveOpenInMs.bind(this, this.scanTime * 2); // Emit the connection halfway through the scan - emitConnectionInMs(this.seeker, lan.connection, scanTime / 2); + emitConnectionInMs(this.seeker, lan.connection, this.scanTime / 2); + + setTimeout(function stopScan() { + this.seeker.stop(); + }.bind(this), this.scanTime); + }, + onlyFindUSBConnections: function(test) { + test.expect(2); + // Scan for new connections for this period + var seekerOpts = { + timeout: this.scanTime, + usb: true + }; + + // Error on name fetch + this.getName = this.sandbox.stub(Tessel.prototype, 'getName', function() { + return Promise.resolve('Frank'); + }); + + // Start scan + standardSeekerSetup(this.seeker, seekerOpts) + // When all Tessels have completed opening + .then(function(found) { + // Make sure we don't find any Tessels because we stopped the scan + test.equal(found.length, 1); + test.equal(found[0].connection.connectionType, 'USB'); + test.done(); + }.bind(this)); + + // Create a Simulated LAN Tessel (authorized) + var lan = TesselSimulator({ + type: 'LAN', + authorized: true + }); + + var usb = TesselSimulator({ + type: 'USB' + }); + + // Make the open function resolve immediately + lan.connection.open = function() { + return Promise.resolve(); + }; + usb.connection.open = function() { + return Promise.resolve(); + }; + + // Emit the connections immediately + if (this.seeker.lanScan) { + this.seeker.lanScan.emit('connection', lan.connection); + } + if (this.seeker.usbScan) { + this.seeker.usbScan.emit('connection', usb.connection); + } + + setTimeout(function stopScan() { + this.seeker.stop(); + }.bind(this), this.scanTime); + }, + onlyFindLANConnections: function(test) { + test.expect(3); + // Scan for new connections for this period + var seekerOpts = { + timeout: this.scanTime, + lan: true + }; + + // Error on name fetch + this.getName = this.sandbox.stub(Tessel.prototype, 'getName', function() { + return Promise.resolve('Frank'); + }); + + // Start scan + standardSeekerSetup(this.seeker, seekerOpts) + // When all Tessels have completed opening + .then(function(found) { + // Make sure we don't find any Tessels because we stopped the scan + test.equal(found.length, 2); + test.equal(found[0].connection.connectionType, 'LAN'); + test.equal(found[1].connection.connectionType, 'LAN'); + test.done(); + }.bind(this)); + + // Create a Simulated LAN Tessel (authorized) + var lan1 = TesselSimulator({ + type: 'LAN', + authorized: true + }); + + // Create a Simulated LAN Tessel (authorized) + var lan2 = TesselSimulator({ + type: 'LAN', + authorized: true + }); + + var usb = TesselSimulator({ + type: 'USB' + }); + + // Make the open function resolve immediately + lan1.connection.open = lan2.connection.open = function() { + return Promise.resolve(); + }; + usb.connection.open = function() { + return Promise.resolve(); + }; + + // Emit the connections immediately + if (this.seeker.lanScan) { + this.seeker.lanScan.emit('connection', lan1.connection); + this.seeker.lanScan.emit('connection', lan2.connection); + } + if (this.seeker.usbScan) { + this.seeker.usbScan.emit('connection', usb.connection); + } setTimeout(function stopScan() { this.seeker.stop(); - }.bind(this), scanTime); + }.bind(this), this.scanTime); } }; -function standardSeekerSetup(seeker, scanTime) { +function standardSeekerSetup(seeker, opts) { return new Promise(function(resolve) { // Start scan - seeker.start(scanTime); + seeker.start(opts); // Array to save found Tessels in var found = [];