From c126fd762e320bc4b836c725b541e4d6c924825e Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Sat, 10 Jul 2021 11:50:40 -0700 Subject: [PATCH 1/8] Dependency update part 1 - gulp + jshint, transition from jscs to eslint --- .eslintrc | 30 + device/index.js | 4 +- examples/browser/lifecycle/index.js | 22 +- examples/browser/mqtt-explorer/index.js | 20 +- examples/browser/mqtt-webpack/entry.js | 14 +- .../browser/mqtt-webpack/webpack.config.js | 4 +- examples/browser/temperature-monitor/index.js | 26 +- examples/jobs-agent.js | 60 +- examples/jobs-example.js | 16 +- examples/lib/cmdline.js | 2 +- examples/lib/copy-file.js | 6 +- examples/lib/download-file.js | 2 +- .../temperature-control.js | 4 +- examples/thing-example.js | 12 +- examples/thing-passthrough-example.js | 12 +- gulpfile.js | 7 +- jobs/index.js | 50 +- package.json | 11 +- test/device-unit-tests.js | 544 +++++++++--------- test/jobs-agent-unit-tests.js | 162 +++--- test/jobs-unit-tests.js | 78 +-- test/thing-unit-tests.js | 254 ++++---- thing/index.js | 22 +- 23 files changed, 696 insertions(+), 666 deletions(-) create mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..ef41ad0 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,30 @@ +{ + "env": { + "browser": true, + "node": true, + "es6": true + }, + "globals": { + "Buffer": true, + "escape": true + }, + "rules": { + "quotes": [2, "single"], + "strict": 0, + "eol-last": ["error", "always"], + "curly": 0, + "no-empty": 0, + "no-underscore-dangle": 0, + "new-cap": 0, + "dot-notation": 0, + "no-use-before-define": 0, + "semi": [2, "always"], + "keyword-spacing": [2, {"before": true, "after": true}], + "space-before-blocks": [2, "always"], + "no-trailing-spaces": 2, + "space-unary-ops": 0 + }, + "parserOptions": { + "ecmaVersion": 2017 + } +} \ No newline at end of file diff --git a/device/index.js b/device/index.js index 4fcd96f..e143b1d 100644 --- a/device/index.js +++ b/device/index.js @@ -360,7 +360,7 @@ function DeviceClient(options) { // // Validate options, set default reconnect period if not specified. // - var metricPrefix = "?SDK=JavaScript&Version="; + var metricPrefix = '?SDK=JavaScript&Version='; var pjson = require('../package.json'); var sdkVersion = pjson.version; var defaultUsername = metricPrefix + sdkVersion; @@ -375,7 +375,7 @@ function DeviceClient(options) { // // Metrics will be enabled by default unless the user explicitly disables it // - if (isUndefined(options.enableMetrics) || options.enableMetrics === true){ + if (isUndefined(options.enableMetrics) || options.enableMetrics === true) { if (isUndefined(options.username)) { options.username = defaultUsername; } else { diff --git a/examples/browser/lifecycle/index.js b/examples/browser/lifecycle/index.js index 3bf40ce..4725c4f 100644 --- a/examples/browser/lifecycle/index.js +++ b/examples/browser/lifecycle/index.js @@ -14,11 +14,11 @@ */ // -// Instantiate the AWS SDK and configuration objects. The AWS SDK for -// JavaScript (aws-sdk) is used for Cognito Identity/Authentication, and +// Instantiate the AWS SDK and configuration objects. The AWS SDK for +// JavaScript (aws-sdk) is used for Cognito Identity/Authentication, and // the AWS IoT SDK for JavaScript (aws-iot-device-sdk) is used for the // WebSocket connection to AWS IoT and device shadow APIs. -// +// var AWS = require('aws-sdk'); var AWSIoTData = require('aws-iot-device-sdk'); var AWSConfiguration = require('./aws-configuration.js'); @@ -50,7 +50,7 @@ AWS.config.credentials = new AWS.CognitoIdentityCredentials({ }); // -// Create the AWS IoT device object. Note that the credentials must be +// Create the AWS IoT device object. Note that the credentials must be // initialized with empty strings; when we successfully authenticate to // the Cognito Identity Pool, the credentials will be dynamically updated. // @@ -82,7 +82,7 @@ const mqttClient = AWSIoTData.device({ // debug: true, // - // IMPORTANT: the AWS access key ID, secret key, and sesion token must be + // IMPORTANT: the AWS access key ID, secret key, and sesion token must be // initialized with empty strings. // accessKeyId: '', @@ -92,7 +92,7 @@ const mqttClient = AWSIoTData.device({ // // Attempt to authenticate to the Cognito Identity Pool. Note that this -// example only supports use of a pool which allows unauthenticated +// example only supports use of a pool which allows unauthenticated // identities. // var cognitoIdentity = new AWS.CognitoIdentity(); @@ -167,8 +167,8 @@ AWS.config.credentials.get(function(err, data) { // window.mqttClientConnectHandler = function() { console.log('connect'); - document.getElementById("connecting-div").style.visibility = 'hidden'; - document.getElementById("clients-div").style.visibility = 'visible'; + document.getElementById('connecting-div').style.visibility = 'hidden'; + document.getElementById('clients-div').style.visibility = 'visible'; // // We only subscribe to lifecycle events once. @@ -184,8 +184,8 @@ window.mqttClientConnectHandler = function() { // window.mqttClientReconnectHandler = function() { console.log('reconnect'); - document.getElementById("connecting-div").style.visibility = 'visible'; - document.getElementById("clients-div").style.visibility = 'hidden'; + document.getElementById('connecting-div').style.visibility = 'visible'; + document.getElementById('clients-div').style.visibility = 'hidden'; }; // @@ -225,7 +225,7 @@ window.mqttClientMessageHandler = function(topic, payload) { // clientDiv.parentNode.removeChild(clientDiv); // - // Forget this client + // Forget this client // delete clients[divName]; } diff --git a/examples/browser/mqtt-explorer/index.js b/examples/browser/mqtt-explorer/index.js index c96980a..a07af34 100644 --- a/examples/browser/mqtt-explorer/index.js +++ b/examples/browser/mqtt-explorer/index.js @@ -14,11 +14,11 @@ */ // -// Instantiate the AWS SDK and configuration objects. The AWS SDK for -// JavaScript (aws-sdk) is used for Cognito Identity/Authentication, and +// Instantiate the AWS SDK and configuration objects. The AWS SDK for +// JavaScript (aws-sdk) is used for Cognito Identity/Authentication, and // the AWS IoT SDK for JavaScript (aws-iot-device-sdk) is used for the // WebSocket connection to AWS IoT and device shadow APIs. -// +// var AWS = require('aws-sdk'); var AWSIoTData = require('aws-iot-device-sdk'); var AWSConfiguration = require('./aws-configuration.js'); @@ -50,7 +50,7 @@ AWS.config.credentials = new AWS.CognitoIdentityCredentials({ }); // -// Create the AWS IoT device object. Note that the credentials must be +// Create the AWS IoT device object. Note that the credentials must be // initialized with empty strings; when we successfully authenticate to // the Cognito Identity Pool, the credentials will be dynamically updated. // @@ -81,7 +81,7 @@ const mqttClient = AWSIoTData.device({ // debug: true, // - // IMPORTANT: the AWS access key ID, secret key, and sesion token must be + // IMPORTANT: the AWS access key ID, secret key, and sesion token must be // initialized with empty strings. // accessKeyId: '', @@ -91,7 +91,7 @@ const mqttClient = AWSIoTData.device({ // // Attempt to authenticate to the Cognito Identity Pool. Note that this -// example only supports use of a pool which allows unauthenticated +// example only supports use of a pool which allows unauthenticated // identities. // var cognitoIdentity = new AWS.CognitoIdentity(); @@ -127,8 +127,8 @@ AWS.config.credentials.get(function(err, data) { // window.mqttClientConnectHandler = function() { console.log('connect'); - document.getElementById("connecting-div").style.visibility = 'hidden'; - document.getElementById("explorer-div").style.visibility = 'visible'; + document.getElementById('connecting-div').style.visibility = 'hidden'; + document.getElementById('explorer-div').style.visibility = 'visible'; document.getElementById('subscribe-div').innerHTML = '


'; messageHistory = ''; @@ -143,8 +143,8 @@ window.mqttClientConnectHandler = function() { // window.mqttClientReconnectHandler = function() { console.log('reconnect'); - document.getElementById("connecting-div").style.visibility = 'visible'; - document.getElementById("explorer-div").style.visibility = 'hidden'; + document.getElementById('connecting-div').style.visibility = 'visible'; + document.getElementById('explorer-div').style.visibility = 'hidden'; }; // diff --git a/examples/browser/mqtt-webpack/entry.js b/examples/browser/mqtt-webpack/entry.js index 49f2fce..45ce855 100644 --- a/examples/browser/mqtt-webpack/entry.js +++ b/examples/browser/mqtt-webpack/entry.js @@ -29,7 +29,7 @@ AWS.config.credentials = new AWS.CognitoIdentityCredentials({ }); // -// Create the AWS IoT device object. Note that the credentials must be +// Create the AWS IoT device object. Note that the credentials must be // initialized with empty strings; when we successfully authenticate to // the Cognito Identity Pool, the credentials will be dynamically updated. // @@ -58,7 +58,7 @@ const mqttClient = AWSIoTData.device({ // debug: true, // - // IMPORTANT: the AWS access key ID, secret key, and sesion token must be + // IMPORTANT: the AWS access key ID, secret key, and sesion token must be // initialized with empty strings. // accessKeyId: '', @@ -68,7 +68,7 @@ const mqttClient = AWSIoTData.device({ // // Attempt to authenticate to the Cognito Identity Pool. Note that this -// example only supports use of a pool which allows unauthenticated +// example only supports use of a pool which allows unauthenticated // identities. // var cognitoIdentity = new AWS.CognitoIdentity(); @@ -104,8 +104,8 @@ AWS.config.credentials.get(function(err, data) { // window.mqttClientConnectHandler = function() { console.log('connect'); - document.getElementById("connecting-div").style.visibility = 'hidden'; - document.getElementById("explorer-div").style.visibility = 'visible'; + document.getElementById('connecting-div').style.visibility = 'hidden'; + document.getElementById('explorer-div').style.visibility = 'visible'; document.getElementById('subscribe-div').innerHTML = '


'; messageHistory = ''; @@ -120,8 +120,8 @@ window.mqttClientConnectHandler = function() { // window.mqttClientReconnectHandler = function() { console.log('reconnect'); - document.getElementById("connecting-div").style.visibility = 'visible'; - document.getElementById("explorer-div").style.visibility = 'hidden'; + document.getElementById('connecting-div').style.visibility = 'visible'; + document.getElementById('explorer-div').style.visibility = 'hidden'; }; // diff --git a/examples/browser/mqtt-webpack/webpack.config.js b/examples/browser/mqtt-webpack/webpack.config.js index f6469cf..dd19a07 100644 --- a/examples/browser/mqtt-webpack/webpack.config.js +++ b/examples/browser/mqtt-webpack/webpack.config.js @@ -1,8 +1,8 @@ module.exports = { - entry: "./entry.js", + entry: './entry.js', output: { path: __dirname, - filename: "bundle.js" + filename: 'bundle.js' }, node: { fs: 'empty', diff --git a/examples/browser/temperature-monitor/index.js b/examples/browser/temperature-monitor/index.js index 3e54443..b27d75d 100644 --- a/examples/browser/temperature-monitor/index.js +++ b/examples/browser/temperature-monitor/index.js @@ -14,11 +14,11 @@ */ // -// Instantiate the AWS SDK and configuration objects. The AWS SDK for -// JavaScript (aws-sdk) is used for Cognito Identity/Authentication, and +// Instantiate the AWS SDK and configuration objects. The AWS SDK for +// JavaScript (aws-sdk) is used for Cognito Identity/Authentication, and // the AWS IoT SDK for JavaScript (aws-iot-device-sdk) is used for the // WebSocket connection to AWS IoT and device shadow APIs. -// +// var AWS = require('aws-sdk'); var AWSIoTData = require('aws-iot-device-sdk'); var AWSConfiguration = require('./aws-configuration.js'); @@ -41,7 +41,7 @@ AWS.config.credentials = new AWS.CognitoIdentityCredentials({ var shadowsRegistered = false; // -// Create the AWS IoT shadows object. Note that the credentials must be +// Create the AWS IoT shadows object. Note that the credentials must be // initialized with empty strings; when we successfully authenticate to // the Cognito Identity Pool, the credentials will be dynamically updated. // @@ -52,7 +52,7 @@ const shadows = AWSIoTData.thingShadow({ region: AWS.config.region, // //Set the AWS IoT Host Endpoint - // + // host:AWSConfiguration.host, // // Use a random client ID. @@ -73,7 +73,7 @@ const shadows = AWSIoTData.thingShadow({ // debug: true, // - // IMPORTANT: the AWS access key ID, secret key, and sesion token must be + // IMPORTANT: the AWS access key ID, secret key, and sesion token must be // initialized with empty strings. // accessKeyId: '', @@ -129,7 +129,7 @@ shadows.on('status', function(name, statusType, clientToken, stateObject) { // // Attempt to authenticate to the Cognito Identity Pool. Note that this -// example only supports use of a pool which allows unauthenticated +// example only supports use of a pool which allows unauthenticated // identities. // var cognitoIdentity = new AWS.CognitoIdentity(); @@ -165,9 +165,9 @@ AWS.config.credentials.get(function(err, data) { // window.shadowConnectHandler = function() { console.log('connect'); - document.getElementById("connecting-div").style.visibility = 'hidden'; - document.getElementById("temperature-monitor-div").style.visibility = 'visible'; - document.getElementById("temperature-control-div").style.visibility = 'visible'; + document.getElementById('connecting-div').style.visibility = 'hidden'; + document.getElementById('temperature-monitor-div').style.visibility = 'visible'; + document.getElementById('temperature-control-div').style.visibility = 'visible'; // // We only register our shadows once. @@ -202,9 +202,9 @@ window.shadowConnectHandler = function() { // window.shadowReconnectHandler = function() { console.log('reconnect'); - document.getElementById("connecting-div").style.visibility = 'visible'; - document.getElementById("temperature-monitor-div").style.visibility = 'hidden'; - document.getElementById("temperature-control-div").style.visibility = 'hidden'; + document.getElementById('connecting-div').style.visibility = 'visible'; + document.getElementById('temperature-monitor-div').style.visibility = 'hidden'; + document.getElementById('temperature-control-div').style.visibility = 'hidden'; }; // diff --git a/examples/jobs-agent.js b/examples/jobs-agent.js index d276abe..0b6e0b0 100644 --- a/examples/jobs-agent.js +++ b/examples/jobs-agent.js @@ -76,12 +76,12 @@ const maxStatusDetailLength = 64; // ... // ] // -var installedPackages = []; +var installedPackages = []; // // Track information about running state of packages // -var packageRuntimes = {}; +var packageRuntimes = {}; // // Private function to show jobs errors @@ -158,7 +158,7 @@ function backupFiles(job, iFile, cb) { if (iFile === job.document.files.length) { cb(); return; - } + } var file = job.document.files[iFile]; if (isUndefined(file)) { @@ -202,7 +202,7 @@ function rollbackFiles(job, iFile, cb) { if (iFile === job.document.files.length) { cb(); return; - } + } var file = job.document.files[iFile]; var filePath = path.resolve(job.document.workingDirectory || '', file.fileName); @@ -234,7 +234,7 @@ function downloadFiles(job, iFile, cb) { if (iFile === job.document.files.length) { cb(); return; - } + } var file = job.document.files[iFile]; var filePath = path.resolve(job.document.workingDirectory || '', file.fileName); @@ -270,8 +270,8 @@ function downloadFiles(job, iFile, cb) { // Private function to update installed package // function updateInstalledPackage(updatedPackage) { - var packageIndex = installedPackages.findIndex(function(element) { - return (element.packageName === updatedPackage.packageName); + var packageIndex = installedPackages.findIndex(function(element) { + return (element.packageName === updatedPackage.packageName); }); if (packageIndex < 0) { @@ -308,7 +308,7 @@ function stopPackage(packageName, cb) { packageRuntime.killedCallback = cb; packageRuntime.killTimer = setTimeout(function() { - packageRuntime.killedCallback = null; + packageRuntime.killedCallback = null; packageRuntime.killTimer = null; cb(new Error('unable to stop package ' + packageName)); }, killTimout * 1000); @@ -350,7 +350,7 @@ function startPackage(package, cb) { return; } - packageRuntime.startupTimer = setTimeout(function() { + packageRuntime.startupTimer = setTimeout(function() { packageRuntime.startupTimer = null; cb(); }, startupTimout * 1000); @@ -376,8 +376,8 @@ function startPackage(package, cb) { // function startPackageFromJob(job) { if (!isUndefined(job.document.packageName)) { - var package = installedPackages.find(function(element) { - return (element.packageName === job.document.packageName); + var package = installedPackages.find(function(element) { + return (element.packageName === job.document.packageName); }); if (isUndefined(package)) { @@ -385,7 +385,7 @@ function startPackageFromJob(job) { return; } - job.inProgress({ operation: job.operation, step: 'starting package, checking stability' }, function(err) { + job.inProgress({ operation: job.operation, step: 'starting package, checking stability' }, function(err) { showJobsError(err); startPackage(package, function(err) { if (isUndefined(err)) { @@ -406,7 +406,7 @@ function startPackageFromJob(job) { // function restartPackage(job) { if (!isUndefined(job.document.packageName)) { - job.inProgress({ operation: job.operation, step: 'stopping running package' }, function(err) { + job.inProgress({ operation: job.operation, step: 'stopping running package' }, function(err) { showJobsError(err); stopPackage(job.document.packageName, function (err) { if (isUndefined(err)) { @@ -443,7 +443,7 @@ function installHandler(job) { downloadFiles(job, function(downloadError) { if (isUndefined(downloadError)) { if (!isUndefined(job.document.launchCommand) && job.document.autoStart) { - job.inProgress({ operation: job.operation, step: 'restarting package' }, function(err) { + job.inProgress({ operation: job.operation, step: 'restarting package' }, function(err) { showJobsError(err); stopPackage(job.document.packageName, function (err) { if (isUndefined(err)) { @@ -454,8 +454,8 @@ function installHandler(job) { } else { rollbackFiles(job, function(rollbackError) { if (isUndefined(rollbackError)) { - var package = installedPackages.find(function(element) { - return (element.packageName === job.document.packageName); + var package = installedPackages.find(function(element) { + return (element.packageName === job.document.packageName); }); if (isUndefined(package) || isUndefined(package.autoStart) || !package.autoStart) { @@ -466,7 +466,7 @@ function installHandler(job) { }); } } else { - job.failed({ operation: job.operation, errorCode: 'ERR_UNEXPECTED_PACKAGE_EXIT', + job.failed({ operation: job.operation, errorCode: 'ERR_UNEXPECTED_PACKAGE_EXIT', errorMessage: errorToString(err), rollbackError: errorToString(rollbackError) }, showJobsError); } }); @@ -474,7 +474,7 @@ function installHandler(job) { }); } else { rollbackFiles(job, function(rollbackError) { - job.failed({ operation: job.operation, errorCode: 'ERR_UNABLE_TO_STOP_PACKAGE', + job.failed({ operation: job.operation, errorCode: 'ERR_UNABLE_TO_STOP_PACKAGE', errorMessage: 'unable to stop package for restart,' + (isUndefined(rollbackError) ? 'rollback successful' : 'rollback failed'), rollbackError: errorToString(rollbackError) }, showJobsError); }); @@ -506,7 +506,7 @@ function installHandler(job) { // function shutdownHandler(job) { // Change status to IN_PROGRESS - job.inProgress({ operation: job.operation, step: 'attempting' }, function(err) { + job.inProgress({ operation: job.operation, step: 'attempting' }, function(err) { showJobsError(err); var delay = (isUndefined(job.document.delay) ? '0' : job.document.delay.toString()); @@ -515,9 +515,9 @@ function shutdownHandler(job) { // // User account running node.js agent must have passwordless sudo access on /sbin/shutdown // Recommended online search for permissions setup instructions https://www.google.com/search?q=passwordless+sudo+access+instructions - exec('sudo /sbin/shutdown -k +' + delay, function (err) { + exec('sudo /sbin/shutdown -k +' + delay, function (err) { if (!isUndefined(err)) { - job.failed({ operation: job.operation, errorCode: 'ERR_SYSTEM_CALL_FAILED', errorMessage: 'unable to execute shutdown, check passwordless sudo permissions on agent', + job.failed({ operation: job.operation, errorCode: 'ERR_SYSTEM_CALL_FAILED', errorMessage: 'unable to execute shutdown, check passwordless sudo permissions on agent', error: errorToString(err) }, showJobsError); } else { job.succeeded({ operation: job.operation, step: 'initiated' }, function (err) { @@ -535,21 +535,21 @@ function shutdownHandler(job) { // function rebootHandler(job) { // Check if the reboot job has not yet been initiated - if (job.status.status === 'QUEUED' || - isUndefined(job.status.statusDetails) || + if (job.status.status === 'QUEUED' || + isUndefined(job.status.statusDetails) || isUndefined(job.status.statusDetails.step)) { // Change status to IN_PROGRESS - job.inProgress({ operation: job.operation, step: 'initiated' }, function(err) { + job.inProgress({ operation: job.operation, step: 'initiated' }, function(err) { showJobsError(err); var delay = (isUndefined(job.document.delay) ? '0' : job.document.delay.toString()); // User account running node.js agent must have passwordless sudo access on /sbin/shutdown // Recommended online search for permissions setup instructions https://www.google.com/search?q=passwordless+sudo+access+instructions - exec('sudo /sbin/shutdown -r +' + delay, function (err) { + exec('sudo /sbin/shutdown -r +' + delay, function (err) { if (!isUndefined(err)) { - job.failed({ operation: job.operation, errorCode: 'ERR_SYSTEM_CALL_FAILED', errorMessage: 'unable to execute reboot, check passwordless sudo permissions on agent', + job.failed({ operation: job.operation, errorCode: 'ERR_SYSTEM_CALL_FAILED', errorMessage: 'unable to execute reboot, check passwordless sudo permissions on agent', error: errorToString(err) }, showJobsError); } }); @@ -560,7 +560,7 @@ function rebootHandler(job) { job.succeeded({ operation: job.operation, step: 'rebooted' }, showJobsError); } else { job.failed({ operation: job.operation, errorCode: 'ERR_UNEXPECTED', errorMessage: 'reboot job execution in unexpected state' }, showJobsError); - } + } } @@ -662,8 +662,8 @@ function jobsAgent(args) { subscribeToJobsWithRetryOnError(args.thingName, 'install', installHandler); subscribeToJobsWithRetryOnError(args.thingName, 'systemStatus', systemStatusHandler); subscribeToJobsWithRetryOnError(args.thingName, 'stop', stopPackageFromJob); - subscribeToJobsWithRetryOnError(args.thingName, 'start', startPackageFromJob); - subscribeToJobsWithRetryOnError(args.thingName, 'restart', restartPackage); + subscribeToJobsWithRetryOnError(args.thingName, 'start', startPackageFromJob); + subscribeToJobsWithRetryOnError(args.thingName, 'restart', restartPackage); jobs.startJobNotifications(args.thingName, function(err) { if (isUndefined(err)) { @@ -685,7 +685,7 @@ function jobsAgent(args) { } for (var i = 0; i < installedPackages.length; i++) { - if (!isUndefined(installedPackages[i].launchCommand) && + if (!isUndefined(installedPackages[i].launchCommand) && (isUndefined(installedPackages[i].autoStart) || installedPackages[i].autoStart)) { startPackage(installedPackages[i], console.error); } diff --git a/examples/jobs-example.js b/examples/jobs-example.js index 3649f98..ca1ab00 100644 --- a/examples/jobs-example.js +++ b/examples/jobs-example.js @@ -72,16 +72,16 @@ function processTest(args) { jobs.subscribe('testTopic'); - if (args.thingName) { - jobs.subscribeToJobs(args.thingName, 'customJob', function(err, job) { + if (args.thingName) { + jobs.subscribeToJobs(args.thingName, 'customJob', function(err, job) { if (isUndefined(err)) { console.log('customJob operation handler invoked, jobId: ' + job.id.toString()); - // - // Indicate to AWS IoT Jobs manager that the job execution is in progress of being processed // - job.inProgress({ operation: 'customJob', step: 'step 1 of customJob' }, function(err) { - // + // Indicate to AWS IoT Jobs manager that the job execution is in progress of being processed + // + job.inProgress({ operation: 'customJob', step: 'step 1 of customJob' }, function(err) { + // // Do some work... // @@ -96,9 +96,9 @@ function processTest(args) { } }); - jobs.subscribeToJobs(args.thingName, function(err, job) { + jobs.subscribeToJobs(args.thingName, function(err, job) { if (isUndefined(err)) { - console.log('default job handler invoked, jobId: ' + job.id.toString()); + console.log('default job handler invoked, jobId: ' + job.id.toString()); // // Indicate to AWS IoT Jobs manager that the job execution failed diff --git a/examples/lib/cmdline.js b/examples/lib/cmdline.js index 1d1038c..bacd75a 100644 --- a/examples/lib/cmdline.js +++ b/examples/lib/cmdline.js @@ -135,7 +135,7 @@ module.exports = function(description, args, processFunction, argumentHelp) { } // // If the configuration file is defined, read it in and set the parameters based - // on the values inside; these will override any other arguments specified on + // on the values inside; these will override any other arguments specified on // the command line. // if (!isUndefined(args.configFile)) { diff --git a/examples/lib/copy-file.js b/examples/lib/copy-file.js index 279e867..7dfa494 100644 --- a/examples/lib/copy-file.js +++ b/examples/lib/copy-file.js @@ -35,18 +35,18 @@ module.exports = function(fileSrc, fileDest, cb) { var cbCalled = false; var rd = fs.createReadStream(fileSrc); - rd.on("error", function(err) { + rd.on('error', function(err) { err.fileName = fileSrc; done(err); }); var wr = fs.createWriteStream(fileDest); - wr.on("error", function(err) { + wr.on('error', function(err) { err.fileName = fileDest; done(err); }); - wr.on("close", function(ex) { + wr.on('close', function(ex) { done(); }); rd.pipe(wr); diff --git a/examples/lib/download-file.js b/examples/lib/download-file.js index b887dad..a67043e 100644 --- a/examples/lib/download-file.js +++ b/examples/lib/download-file.js @@ -27,7 +27,7 @@ var copyFile = require('./copy-file'); //begin module var supportedProtocols = { - "https:": https + 'https:': https }; /** diff --git a/examples/temperature-control/temperature-control.js b/examples/temperature-control/temperature-control.js index 8247174..6f90a4f 100644 --- a/examples/temperature-control/temperature-control.js +++ b/examples/temperature-control/temperature-control.js @@ -274,7 +274,7 @@ function processTest(args) { lcd5.setDisplay(networkStatus); log.log('network ' + (networkEnabled ? 'connected' : 'disconnected')); // - // Simulate a network connection/disconnection + // Simulate a network connection/disconnection // if (networkEnabled) { thingShadows.setConnectionStatus(true); @@ -368,7 +368,7 @@ function processTest(args) { // // Simulate the interaction of a mobile application and a remote device via the // AWS IoT service. The simulated remote device is a temperature controller. - // Two thing shadows are used: one for control properties (setpoint and on/off) + // Two thing shadows are used: one for control properties (setpoint and on/off) // and the other for monitoring properties (interior/exterior temperature, current // state). // diff --git a/examples/thing-example.js b/examples/thing-example.js index 138f4d3..f418206 100644 --- a/examples/thing-example.js +++ b/examples/thing-example.js @@ -27,8 +27,8 @@ const isUndefined = require('../common/lib/is-undefined'); // // Simulate the interaction of a mobile device and a remote thing via the // AWS IoT service. The remote thing will be a dimmable color lamp, where -// the individual RGB channels can be set to an intensity between 0 and 255. -// One process will simulate each side, with testMode being used to distinguish +// the individual RGB channels can be set to an intensity between 0 and 255. +// One process will simulate each side, with testMode being used to distinguish // between the mobile app (1) and the remote thing (2). The remote thing // will update its state periodically using an 'update thing shadow' operation, // and the mobile device will listen to delta events to receive the updated @@ -63,10 +63,10 @@ function processTest(args) { var currentTimeout = null; // - // For convenience, use a stack to keep track of the current client - // token; in this example app, this should never reach a depth of more + // For convenience, use a stack to keep track of the current client + // token; in this example app, this should never reach a depth of more // than a single element, but if your application uses multiple thing - // shadows simultaneously, you'll need some data structure to correlate + // shadows simultaneously, you'll need some data structure to correlate // client tokens with their respective thing shadows. // var stack = []; @@ -77,7 +77,7 @@ function processTest(args) { if (clientToken === null) { // // The thing shadow operation can't be performed because another one - // is pending; if no other operation is pending, reschedule it after an + // is pending; if no other operation is pending, reschedule it after an // interval which is greater than the thing shadow operation timeout. // if (currentTimeout !== null) { diff --git a/examples/thing-passthrough-example.js b/examples/thing-passthrough-example.js index ea0ffa0..18a8955 100644 --- a/examples/thing-passthrough-example.js +++ b/examples/thing-passthrough-example.js @@ -25,7 +25,7 @@ const isUndefined = require('../common/lib/is-undefined'); //begin module // -// This test demonstrates the use of thing shadows along with +// This test demonstrates the use of thing shadows along with // non-thing topics. One process updates a thing shadow and // subscribes to a non-thing topic; the other receives delta // updates on the thing shadow on publishes to the non-thing @@ -64,10 +64,10 @@ function processTest(args) { var currentTimeout = null; // - // For convenience, use a stack to keep track of the current client - // token; in this example app, this should never reach a depth of more + // For convenience, use a stack to keep track of the current client + // token; in this example app, this should never reach a depth of more // than a single element, but if your application uses multiple thing - // shadows simultaneously, you'll need some data structure to correlate + // shadows simultaneously, you'll need some data structure to correlate // client tokens with their respective thing shadows. // var stack = []; @@ -77,7 +77,7 @@ function processTest(args) { if (clientToken === null) { // // The thing shadow operation can't be performed because another one - // is pending; if no other operation is pending, reschedule it after an + // is pending; if no other operation is pending, reschedule it after an // interval which is greater than the thing shadow operation timeout. // if (currentTimeout !== null) { @@ -123,7 +123,7 @@ function processTest(args) { // thingShadows.register(thingName, { ignoreDeltas: true - }, function(err, failedTopics){ + }, function(err, failedTopics) { if (isUndefined(err) && isUndefined(failedTopics)) { genericOperation('update', generateState()); thingShadows.subscribe(nonThingName); diff --git a/gulpfile.js b/gulpfile.js index b319f15..0a70766 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -17,10 +17,9 @@ var gulp = require('gulp'), jshint = require('gulp-jshint'), - concat = require('gulp-concat'), mocha = require('gulp-mocha'), cover = require('gulp-coverage'), - jscs = require('gulp-jscs'), + eslint = require('gulp-eslint'), beautify = require('gulp-beautify'); gulp.task('default', ['test']); @@ -51,7 +50,9 @@ gulp.task('jshint', function() { .pipe(jshint()) .pipe(jshint.reporter('jshint-stylish', {verbose: true})) .pipe(jshint.reporter('fail')) - .pipe(jscs()); + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); }); gulp.task('beautify', function() { diff --git a/jobs/index.js b/jobs/index.js index 0ea1a6f..39519cd 100644 --- a/jobs/index.js +++ b/jobs/index.js @@ -72,10 +72,10 @@ function jobsClient(options) { // Track job subscriptions // // [ - // { + // { // "thingName": "string", // "operations": [ - // { + // { // "operationName": "string", // if null then treat as default // "currentJob": job, // "callback": callback @@ -96,7 +96,7 @@ function jobsClient(options) { // this._updateJobStatus = function(thingName, job, status, statusDetails, callback) { // Check for omitted statusDetails and update parameters - if (typeof statusDetails === "function") { + if (typeof statusDetails === 'function') { callback = statusDetails; statusDetails = undefined; } @@ -105,7 +105,7 @@ function jobsClient(options) { console.log('updateJobStatus:', { thingName: thingName, jobId: job.id, status: status, statusDetails: statusDetails }); } - device.publish(buildJobTopic(thingName, job.id, 'update'), JSON.stringify({ status: status, statusDetails: statusDetails}), null, function(err){ + device.publish(buildJobTopic(thingName, job.id, 'update'), JSON.stringify({ status: status, statusDetails: statusDetails}), null, function(err) { if (isUndefined(err)) { job.status = { status: status, statusDetails: statusDetails }; } @@ -114,7 +114,7 @@ function jobsClient(options) { callback(err); } }); - } + }; // // Private function to build job object for passing to callback supplied in subscribeToJobs @@ -133,18 +133,18 @@ function jobsClient(options) { job.inProgress = function(statusDetails, callback) { that._updateJobStatus(thingName, job, 'IN_PROGRESS', statusDetails, callback); - } + }; job.failed = function(statusDetails, callback) { that._updateJobStatus(thingName, job, 'FAILED', statusDetails, callback); - } + }; job.succeeded = function(statusDetails, callback) { that._updateJobStatus(thingName, job, 'SUCCEEDED', statusDetails, callback); - } + }; return job; - } + }; // // Private function to handle job messages and process them accordingly @@ -160,11 +160,11 @@ function jobsClient(options) { var thingName = topicTokens[2]; - var thing = jobSubscriptions.find(function(elem) { - return elem.thingName === thingName; + var thing = jobSubscriptions.find(function(elem) { + return elem.thingName === thingName; }); - // Do nothing if thing not found in job subscriptions + // Do nothing if thing not found in job subscriptions if (isUndefined(thing)) { return; } @@ -180,15 +180,15 @@ function jobsClient(options) { return; } - if (isUndefined(jobExecutionData.execution) || - isUndefined(jobExecutionData.execution.jobId) || + if (isUndefined(jobExecutionData.execution) || + isUndefined(jobExecutionData.execution.jobId) || isUndefined(jobExecutionData.execution.jobDocument)) { return; } var operationName = jobExecutionData.execution.jobDocument.operation; - var operation = thing.operations.find(function(elem) { - return (isUndefined(operationName) ? isUndefined(elem.operationName) : operationName === elem.operationName); + var operation = thing.operations.find(function(elem) { + return (isUndefined(operationName) ? isUndefined(elem.operationName) : operationName === elem.operationName); }); // If operation subscription not found by operation name then look for default operation subscription @@ -201,7 +201,7 @@ function jobsClient(options) { } operation.callback(null, that._buildJobObject(thingName, jobExecutionData.execution)); - } + }; this.subscribeToJobs = function(thingName, operationName, callback) { // Check for omitted optional operationName and fixup parameters @@ -214,8 +214,8 @@ function jobsClient(options) { console.log('subscribeToJobs:', { thingName: thingName, operationName: operationName }); } - var thing = jobSubscriptions.find(function(elem) { - return elem.thingName === thingName; + var thing = jobSubscriptions.find(function(elem) { + return elem.thingName === thingName; }); // Check for previously unseen thing and add to job subscriptions @@ -231,8 +231,8 @@ function jobsClient(options) { } // Find existing subscription for the given operationName - var operation = thing.operations.find(function(elem) { - return (isUndefined(operationName) ? isUndefined(elem.operationName) : operationName === elem.operationName); + var operation = thing.operations.find(function(elem) { + return (isUndefined(operationName) ? isUndefined(elem.operationName) : operationName === elem.operationName); }); // If existing subscription found then update callback, otherwise create new entry in the thing's operations array @@ -242,7 +242,7 @@ function jobsClient(options) { operation = { operationName: operationName, callback: callback }; thing.operations.push(operation); } - } + }; this.unsubscribeFromJobs = function(thingName, operationName, callback) { // Check for omitted optional operationName and fixup parameters @@ -255,7 +255,7 @@ function jobsClient(options) { console.log('unsubscribeFromJobs:', { thingName: thingName, operationName: operationName }); } - var iThing = jobSubscriptions.findIndex(function(elem) { + var iThing = jobSubscriptions.findIndex(function(elem) { return elem.thingName === thingName; }); @@ -285,7 +285,7 @@ function jobsClient(options) { } callback(); - } + }; this.startJobNotifications = function(thingName, callback) { if ((!isUndefined(options)) && (options.debug === true)) { @@ -293,7 +293,7 @@ function jobsClient(options) { } device.publish(buildJobTopic(thingName, '$next', 'get'), '{}', callback); - } + }; device.on('connect', function() { that.emit('connect'); diff --git a/package.json b/package.json index 79796d3..45f7c85 100644 --- a/package.json +++ b/package.json @@ -28,20 +28,19 @@ "mqtt" ], "dependencies": { - "crypto-js": "4.0.0", + "crypto-js": "^4.0.0", "minimist": "1.2.5", - "mqtt": "4.2.8", + "mqtt": "^4.2.8", "websocket-stream": "^5.5.2" }, "devDependencies": { "gulp": "^3.9.0", "gulp-beautify": "^2.0.0", - "gulp-concat": "^2.6.0", "gulp-coverage": "^0.3.38", - "gulp-jscs": "^4.0.0", - "gulp-jshint": "^2.0.0", + "gulp-eslint": "^6.0.0", + "gulp-jshint": "^2.1.0", "gulp-mocha": "^3.0.1", - "jshint": "^2.9.1", + "jshint": "^2.13.0", "jshint-stylish": "^2.2.1", "rewire": "^2.5.1", "sinon": "^1.17.3" diff --git a/test/device-unit-tests.js b/test/device-unit-tests.js index c700556..4291dc0 100644 --- a/test/device-unit-tests.js +++ b/test/device-unit-tests.js @@ -26,8 +26,8 @@ var myTls = rewire('../device/lib/tls'); var mockTls = require('./mock/mockTls'); var mockMQTTClient = require('./mock/mockMQTTClient'); -describe( "device class unit tests", function() { - var deviceModule = require('../').device; +describe( 'device class unit tests', function() { + var deviceModule = require('../').device; var mockMQTTClientObject; var fakeConnect; @@ -50,8 +50,8 @@ describe( "device class unit tests", function() { mqttSave = sinon.stub(mqtt, 'MqttClient', fakeConnect); - mockTlsRevert = myTls.__set__("tls", mockTlsObject); - mockMqttRevert = myTls.__set__("mqtt", mockMqttObject); + mockTlsRevert = myTls.__set__('tls', mockTlsObject); + mockMqttRevert = myTls.__set__('mqtt', mockMqttObject); }); afterEach( function () { mqttSave.restore(); @@ -59,169 +59,169 @@ describe( "device class unit tests", function() { mockMqttRevert(); }); - describe("TLS handler calls the correct functions", function() { - it("calls the correct functions", function() { + describe('TLS handler calls the correct functions', function() { + it('calls the correct functions', function() { mockTlsObject.reInitCommandCalled(); myTls(mockMqttObject, { 'testOption': true } ); assert.equal(mockTlsObject.commandCalled['connect'], 1); assert.equal(mockTlsObject.commandCalled['on'], 2); assert.equal(mockTlsObject.commandCalled['emit'], 1); assert.equal(mockMqttObject.commandCalled['emit'], 1); - }) + }); }); - describe( "device is instantiated with empty parameters", function() { + describe( 'device is instantiated with empty parameters', function() { // // Verify that the device module throws an exception when all // parameters are empty. // - it("throws an exception", function() { - assert.throws( function( err ) { + it('throws an exception', function() { + assert.throws( function( err ) { var device = deviceModule( { } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device is instantiated with no private key", function() { + describe( 'device is instantiated with no private key', function() { // // Verify that the device module throws an exception when there is // no valid private key file. // - it("throws an exception", function() { - assert.throws( function( err ) { - var device = deviceModule( { + it('throws an exception', function() { + assert.throws( function( err ) { + var device = deviceModule( { certPath:'test/data/certificate.pem.crt', caPath:'test/data/root-CA.crt', clientId:'dummy-client-1', host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device is instantiated with no CA certificate", function() { + describe( 'device is instantiated with no CA certificate', function() { // // Verify that the device module throws an exception when there is // no valid CA certificate file. // - it("throws an exception", function() { - assert.throws( function( err ) { - var device = deviceModule( { - keyPath:'test/data/private.pem.key', - certPath:'test/data/certificate.pem.crt', + it('throws an exception', function() { + assert.throws( function( err ) { + var device = deviceModule( { + keyPath:'test/data/private.pem.key', + certPath:'test/data/certificate.pem.crt', clientId:'dummy-client-1', host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device is instantiated with no client certificate", function() { + describe( 'device is instantiated with no client certificate', function() { // // Verify that the device module throws an exception when there is // no valid client certificate file. // - it("throws an exception", function() { - assert.throws( function( err ) { - var device = deviceModule( { - keyPath:'test/data/private.pem.key', + it('throws an exception', function() { + assert.throws( function( err ) { + var device = deviceModule( { + keyPath:'test/data/private.pem.key', caPath:'test/data/root-CA.crt', clientId:'dummy-client-1', host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device is instantiated with invalid key path", function() { + describe( 'device is instantiated with invalid key path', function() { +// +// Verify that the device module throws an exception when key is not valid. // -// Verify that the device module throws an exception when key is not valid. -// // - it("throws an exception", function() { - assert.throws( function( err ) { - var device = deviceModule( { - keyPath:'test/data/private.pem.key-1', - certPath:'test/data/certificate.pem.crt', + it('throws an exception', function() { + assert.throws( function( err ) { + var device = deviceModule( { + keyPath:'test/data/private.pem.key-1', + certPath:'test/data/certificate.pem.crt', caPath:'test/data/root-CA.crt', clientId:'dummy-client-1', host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device is instantiated with invalid cert path", function() { + describe( 'device is instantiated with invalid cert path', function() { // // Verify that the device module throws an exception when certificate is not valid. -// // - it("throws an exception", function() { - assert.throws( function( err ) { - var device = deviceModule( { - keyPath:'test/data/private.pem.key', - certPath:'test/data/certificate.pem.crt-1', +// + it('throws an exception', function() { + assert.throws( function( err ) { + var device = deviceModule( { + keyPath:'test/data/private.pem.key', + certPath:'test/data/certificate.pem.crt-1', caPath:'test/data/root-CA.crt', clientId:'dummy-client-1', host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device is instantiated with invalid CA path", function() { + describe( 'device is instantiated with invalid CA path', function() { // // Verify that the device module throws an exception when CA is not valid. -// // - it("throws an exception", function() { - assert.throws( function( err ) { - var device = deviceModule( { - keyPath:'test/data/private.pem.key', - certPath:'test/data/certificate.pem.crt', +// + it('throws an exception', function() { + assert.throws( function( err ) { + var device = deviceModule( { + keyPath:'test/data/private.pem.key', + certPath:'test/data/certificate.pem.crt', caPath:'test/data/root-CA.crt-1', clientId:'dummy-client-1', host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device is instantiated with required parameters", function() { + describe( 'device is instantiated with required parameters', function() { // -// Verify that the device module doesn't throw an exception when all +// Verify that the device module doesn't throw an exception when all // parameters are specified correctly. // - it("does not throw an exception", function() { - assert.doesNotThrow( function( err ) { - var device = deviceModule( { - keyPath:'test/data/private.pem.key', - certPath:'test/data/certificate.pem.crt', + it('does not throw an exception', function() { + assert.doesNotThrow( function( err ) { + var device = deviceModule( { + keyPath:'test/data/private.pem.key', + certPath:'test/data/certificate.pem.crt', caPath:'test/data/root-CA.crt', clientId:'dummy-client-1', host:'XXXX.iot.us-east-1.amazonaws.com', servername:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device accepts certificate data in buffer", function() { + describe( 'device accepts certificate data in buffer', function() { // // Verify that the device module accepts certificate and key data in buffers // when using the properties generated by the AWS Console. // - it("does not throw an exception", function() { + it('does not throw an exception', function() { var buffers = {}; buffers.privateKey = filesys.readFileSync('test/data/private.pem.key'); buffers.certificate = filesys.readFileSync('test/data/certificate.pem.crt'); buffers.rootCA = filesys.readFileSync('test/data/root-CA.crt'); - assert.doesNotThrow( function( err ) { - var device = deviceModule( { + assert.doesNotThrow( function( err ) { + var device = deviceModule( { clientCert: buffers.certificate, privateKey: buffers.privateKey, caCert:buffers.rootCA, @@ -229,23 +229,23 @@ describe( "device class unit tests", function() { host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device accepts certificate data in buffers+files", function() { + describe( 'device accepts certificate data in buffers+files', function() { // // Verify that the device module accepts certificate and key data in files -// as well as buffers when using the properties generated by the AWS Iot -// Console. +// as well as buffers when using the properties generated by the AWS Iot +// Console. // - it("does not throw an exception", function() { + it('does not throw an exception', function() { var buffers = {}; buffers.privateKey = filesys.readFileSync('test/data/private.pem.key'); buffers.rootCA = filesys.readFileSync('test/data/root-CA.crt'); - assert.doesNotThrow( function( err ) { - var device = deviceModule( { + assert.doesNotThrow( function( err ) { + var device = deviceModule( { clientCert:'test/data/certificate.pem.crt', privateKey: buffers.privateKey, caCert:buffers.rootCA, @@ -253,22 +253,22 @@ describe( "device class unit tests", function() { host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device accepts certificate data in buffers+files", function() { + describe( 'device accepts certificate data in buffers+files', function() { // // Verify that the device module accepts certificate and key data in files -// as well as buffers when using the properties generated by the AWS Iot -// Console. +// as well as buffers when using the properties generated by the AWS Iot +// Console. // - it("does not throw an exception", function() { + it('does not throw an exception', function() { var buffers = {}; buffers.rootCA = filesys.readFileSync('test/data/root-CA.crt'); - assert.doesNotThrow( function( err ) { - var device = deviceModule( { + assert.doesNotThrow( function( err ) { + var device = deviceModule( { clientCert:'test/data/certificate.pem.crt', privateKey: 'test/data/private.pem.key', caCert:buffers.rootCA, @@ -276,18 +276,18 @@ describe( "device class unit tests", function() { host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device accepts certificate data in buffers+files", function() { + describe( 'device accepts certificate data in buffers+files', function() { // // Verify that the device module accepts certificate and key data in files // using the properties generated by the AWS Iot Console. // - it("does not throw an exception", function() { + it('does not throw an exception', function() { - assert.doesNotThrow( function( err ) { - var device = deviceModule( { + assert.doesNotThrow( function( err ) { + var device = deviceModule( { clientCert:'test/data/certificate.pem.crt', privateKey: 'test/data/private.pem.key', caCert: 'test/data/root-CA.crt', @@ -295,18 +295,18 @@ describe( "device class unit tests", function() { host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device ensures AWS Console clientCert property is a buffer or file", function() { + describe( 'device ensures AWS Console clientCert property is a buffer or file', function() { // // Verify that the device module will not accept a client certificate property // which is neither a file nor a buffer. // - it("throws an exception", function() { + it('throws an exception', function() { - assert.throws( function( err ) { - var device = deviceModule( { + assert.throws( function( err ) { + var device = deviceModule( { clientCert: { }, privateKey: 'test/data/private.pem.key', caCert: 'test/data/root-CA.crt', @@ -314,18 +314,18 @@ describe( "device class unit tests", function() { host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device ensures AWS Console privateKey property is a buffer or file", function() { + describe( 'device ensures AWS Console privateKey property is a buffer or file', function() { // // Verify that the device module will not accept a private key property // which is neither a file nor a buffer. // - it("throws an exception", function() { + it('throws an exception', function() { - assert.throws( function( err ) { - var device = deviceModule( { + assert.throws( function( err ) { + var device = deviceModule( { clientCert:'test/data/certificate.pem.crt', privateKey: { }, caCert: 'test/data/root-CA.crt', @@ -333,18 +333,18 @@ describe( "device class unit tests", function() { host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device ensures AWS Console caCert property is a buffer or file", function() { + describe( 'device ensures AWS Console caCert property is a buffer or file', function() { // // Verify that the device module will not accept a CA certificate property // which is neither a file nor a buffer. // - it("throws an exception", function() { + it('throws an exception', function() { - assert.throws( function( err ) { - var device = deviceModule( { + assert.throws( function( err ) { + var device = deviceModule( { clientCert:'test/data/certificate.pem.crt', privateKey: 'test/data/private.pem.key', caCert: { }, @@ -352,158 +352,158 @@ describe( "device class unit tests", function() { host:'XXXX.iot.us-east-1.amazonaws.com' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device throws an exception if using websocket protocol without IAM credentials", function() { + describe( 'device throws an exception if using websocket protocol without IAM credentials', function() { // // Verify that the device module throws an exception when incorrectly // configured for websocket operation. // - it("throws exception", function() { + it('throws exception', function() { delete process.env.AWS_ACCESS_KEY_ID; delete process.env.AWS_SECRET_ACCESS_KEY; - assert.throws( function( err ) { + assert.throws( function( err ) { var device = deviceModule( { host:'XXXX.iot.us-east-1.amazonaws.com', protocol: 'wss', filename: '' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device throws an exception if using websocket protocol with invalid credential files", function() { + describe( 'device throws an exception if using websocket protocol with invalid credential files', function() { // // Verify that the device module throws an exception when incorrectly // configured for websocket operation. // - it("throws exception", function() { + it('throws exception', function() { delete process.env.AWS_ACCESS_KEY_ID; delete process.env.AWS_SECRET_ACCESS_KEY; - assert.throws( function( err ) { + assert.throws( function( err ) { var device = deviceModule( { host:'XXXX.iot.us-east-1.amazonaws.com', protocol: 'wss', filename: './test/data/invalid_credentials' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device not throw an exception if using websocket protocol with filename specified in options", function() { + describe( 'device not throw an exception if using websocket protocol with filename specified in options', function() { // // Verify that the device module does not throw an exception when loading -// credentials from credential file// +// credentials from credential file// // - it("does not throws exception", function() { + it('does not throws exception', function() { delete process.env.AWS_ACCESS_KEY_ID; delete process.env.AWS_SECRET_ACCESS_KEY; delete process.env.AWS_PROFILE; - assert.doesNotThrow( function( err ) { + assert.doesNotThrow( function( err ) { var device = deviceModule( { host:'XXXX.iot.us-east-1.amazonaws.com', protocol: 'wss', filename: './test/data/credentials' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device not throw an exception if using websocket protocol with filename specified in options as well as set in environment", function() { + describe( 'device not throw an exception if using websocket protocol with filename specified in options as well as set in environment', function() { // // Verify that the device module does not throw an exception when provided -// both options and environment variables -// +// both options and environment variables +// // - it("does not throws exception", function() { + it('does not throws exception', function() { process.env.AWS_ACCESS_KEY_ID='not a valid access key id'; process.env.AWS_SECRET_ACCESS_KEY='not a valid secret access key'; - assert.doesNotThrow( function( err ) { + assert.doesNotThrow( function( err ) { var device = deviceModule( { host:'XXXX.iot.us-east-1.amazonaws.com', protocol: 'wss', filename: './test/data/credentials' } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device throws an exception if using websocket protocol with no host specified", function() { + describe( 'device throws an exception if using websocket protocol with no host specified', function() { // // Verify that the device module throws an exception when configured for // websocket operation with no host specified. // - it("throws exception", function() { + it('throws exception', function() { - assert.throws( function( err ) { + assert.throws( function( err ) { process.env.AWS_ACCESS_KEY_ID='not a valid access key id'; process.env.AWS_SECRET_ACCESS_KEY='not a valid secret access key'; - var device = deviceModule( { + var device = deviceModule( { protocol: 'wss', debug: true } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device throws an exception if using websocket protocol with incorrect host specified", function() { + describe( 'device throws an exception if using websocket protocol with incorrect host specified', function() { // // Verify that the device module throws an exception when configured for // websocket operation with incorrect host specified. // - it("throws exception", function() { + it('throws exception', function() { - assert.throws( function( err ) { + assert.throws( function( err ) { process.env.AWS_ACCESS_KEY_ID='not a valid access key id'; process.env.AWS_SECRET_ACCESS_KEY='not a valid secret access key'; var device = deviceModule( { - host:'not-a-valid-host.com', + host:'not-a-valid-host.com', protocol: 'wss', debug: true } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device does not throw exception if using websocket protocol with IAM credentials in environment", function() { + describe( 'device does not throw exception if using websocket protocol with IAM credentials in environment', function() { // // Verify that the device module will not throw an exception when correctly // configured for websocket operation. // - it("does not throw an exception", function() { + it('does not throw an exception', function() { assert.doesNotThrow( function( err ) { process.env.AWS_ACCESS_KEY_ID='not a valid access key id'; process.env.AWS_SECRET_ACCESS_KEY='not a valid secret access key'; - var device = deviceModule( { + var device = deviceModule( { host:'XXXX.iot.us-east-1.amazonaws.com', protocol: 'wss', debug: true } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "device does not throw exception if using websocket protocol with IAM credentials in class options", function() { + describe( 'device does not throw exception if using websocket protocol with IAM credentials in class options', function() { // // Verify that the device module will not throw an exception when correctly // configured for websocket operation. // - it("does not throw an exception", function() { + it('does not throw an exception', function() { assert.doesNotThrow( function( err ) { - var device = deviceModule( { + var device = deviceModule( { host:'XXXX.iot.us-east-1.amazonaws.com', protocol: 'wss', debug: true, @@ -512,15 +512,15 @@ describe( "device class unit tests", function() { sessionToken: 'not a valid session token', } ); }, function(err) { console.log('\t['+err+']'); return true;} - ); + ); }); }); - describe( "coverage: device doesn't throw exception if using websocket protocol with IAM credentials", function() { + describe( 'coverage: device doesn\'t throw exception if using websocket protocol with IAM credentials', function() { // // Verify that the device module will not throw an exception when correctly // configured for websocket operation. // - it("does not throw an exception", function() { + it('does not throw an exception', function() { assert.doesNotThrow( function( err ) { @@ -530,8 +530,8 @@ describe( "device class unit tests", function() { ); }); }); - describe("device does not throw exception if using CustomAuth with valid headers", function () { - it("does not throw an exception", function () { + describe('device does not throw exception if using CustomAuth with valid headers', function () { + it('does not throw an exception', function () { assert.doesNotThrow(function (err) { var device = deviceModule({ host: 'XXXX.iot.us-east-1.amazonaws.com', @@ -546,8 +546,8 @@ describe( "device class unit tests", function() { ); }); }); - describe("device throws exception if using CustomAuth over websocket without headers or querystring", function () { - it("throws exception", function () { + describe('device throws exception if using CustomAuth over websocket without headers or querystring', function () { + it('throws exception', function () { assert.throws(function (err) { var device = deviceModule({ host: 'XXXX.iot.us-east-1.amazonaws.com', @@ -557,8 +557,8 @@ describe( "device class unit tests", function() { ); }); }); - describe("device does not throw exception if using CustomAuth over websocket with headers", function () { - it("does not throw an exception", function () { + describe('device does not throw exception if using CustomAuth over websocket with headers', function () { + it('does not throw an exception', function () { assert.doesNotThrow(function (err) { var device = deviceModule({ host: 'XXXX.iot.us-east-1.amazonaws.com', @@ -569,8 +569,8 @@ describe( "device class unit tests", function() { ); }); }); - describe("device does not throw exception if using CustomAuth over websocket with querystring", function () { - it("does not throw an exception", function () { + describe('device does not throw exception if using CustomAuth over websocket with querystring', function () { + it('does not throw an exception', function () { assert.doesNotThrow(function (err) { var device = deviceModule({ host: 'XXXX.iot.us-east-1.amazonaws.com', @@ -581,8 +581,8 @@ describe( "device class unit tests", function() { ); }); }); - describe("device does not throw exception if using CustomAuth over websocket with non-standard headers", function () { - it("does not throw an exception", function () { + describe('device does not throw exception if using CustomAuth over websocket with non-standard headers', function () { + it('does not throw an exception', function () { assert.doesNotThrow(function (err) { var device = deviceModule({ host: 'XXXX.iot.us-east-1.amazonaws.com', @@ -596,8 +596,8 @@ describe( "device class unit tests", function() { ); }); }); - describe( "device doesn't accept invalid timing parameters: baseReconnectTimeMs<1", function() { - it("throws an exception", function() { + describe( 'device doesn\'t accept invalid timing parameters: baseReconnectTimeMs<1', function() { + it('throws an exception', function() { assert.throws( function( err ) { var device = deviceModule( { certPath:'test/data/certificate.pem.crt', @@ -611,8 +611,8 @@ describe( "device class unit tests", function() { ); }); }); - describe( "device doesn't accept invalid timing parameters: minimumConnectionTimeMs= thingShadows[thingName].version)) { @@ -235,7 +235,7 @@ function ThingShadowsClient(deviceOptions, thingShadowOptions) { // 2) The message has arrived out-of-order. // // For case 1) we can look at the operation to determine that this - // is the case and notify the client if appropriate. For case 2, + // is the case and notify the client if appropriate. For case 2, // we will not process it unless the client has specifically expressed // an interested in these messages by setting 'discardStale' to false. // @@ -383,8 +383,8 @@ function ThingShadowsClient(deviceOptions, thingShadowOptions) { // thingShadows[thingName].pending = true; // - // If not provided, construct a clientToken from the clientId and a rolling - // operation count. The clientToken is transmitted in any published stateObject + // If not provided, construct a clientToken from the clientId and a rolling + // operation count. The clientToken is transmitted in any published stateObject // and is returned to the caller for each operation. Applications can use // clientToken values to correlate received responses or timeouts with // the original operations. @@ -416,7 +416,7 @@ function ThingShadowsClient(deviceOptions, thingShadowOptions) { operation); // // Subscribe to the 'accepted' and 'rejected' sub-topics for this get - // operation and set a timeout beyond which they will be unsubscribed if + // operation and set a timeout beyond which they will be unsubscribed if // no messages have been received for either of them. // thingShadows[thingName].timeout = setTimeout( @@ -472,7 +472,7 @@ function ThingShadowsClient(deviceOptions, thingShadowOptions) { // if (!isUndefined(stateObject)) { // - // Add the version # (if known and versioning is enabled) and + // Add the version # (if known and versioning is enabled) and // 'clientToken' properties to the stateObject. // if (!isUndefined(thingShadows[thingName].version) && @@ -494,7 +494,7 @@ function ThingShadowsClient(deviceOptions, thingShadowOptions) { }); } else { // - // Add the version # (if known and versioning is enabled) and + // Add the version # (if known and versioning is enabled) and // 'clientToken' properties to the stateObject. // if (!isUndefined(thingShadows[thingName].version) && @@ -530,8 +530,8 @@ function ThingShadowsClient(deviceOptions, thingShadowOptions) { if (!thingShadows.hasOwnProperty(thingName)) { // - // Initialize the registration entry for this thing; because the version # is - // not yet known, do not add the property for it yet. The version number + // Initialize the registration entry for this thing; because the version # is + // not yet known, do not add the property for it yet. The version number // property will be added after the first accepted update from AWS IoT. // var ignoreDeltas = false; @@ -619,7 +619,7 @@ function ThingShadowsClient(deviceOptions, thingShadowOptions) { // // If an operation is outstanding, it will have a timeout set; when it - // expires any accept/reject sub-topic subscriptions for the thing will be + // expires any accept/reject sub-topic subscriptions for the thing will be // deleted. If any messages arrive after the thing has been deleted, they // will simply be ignored as it no longer exists in the thing registrations. // The only sub-topic we need to unsubscribe from is the delta sub-topic, From 5d16e39022fce8505e1290957fe135783f1700ce Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Sat, 10 Jul 2021 13:49:14 -0700 Subject: [PATCH 2/8] Everything but sinon --- gulpfile.js | 64 +++++++++++++++++++--------------------------------- package.json | 8 +++---- 2 files changed, 26 insertions(+), 46 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 0a70766..835b99c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -18,50 +18,32 @@ var gulp = require('gulp'), jshint = require('gulp-jshint'), mocha = require('gulp-mocha'), - cover = require('gulp-coverage'), - eslint = require('gulp-eslint'), - beautify = require('gulp-beautify'); + eslint = require('gulp-eslint'); -gulp.task('default', ['test']); +function lint() { + console.log('Analyzing source with JSHint and JSCS'); + return gulp + .src(['common/lib/*.js','examples/**/*.js', 'device/**/*.js','thing/*.js','index.js', '!node_modules/**/*.js', '!examples/**/node_modules/**/*.js', '!examples/**/aws-configuration.js', '!browser/**/*bundle.js', '!examples/browser/**/*bundle.js']) + .pipe(jshint()) + .pipe(jshint.reporter('jshint-stylish', {verbose: true})) + .pipe(jshint.reporter('fail')) + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); +} -gulp.task('test', ['jshint'], function() { +exports.lint = lint; + +function test() { console.log('Running unit tests'); return gulp.src(['test/*unit-tests.js'], {read: false}) - .pipe(cover.instrument({ - pattern: ['common/lib/*.js','device/**/*.js','thing/*.js','index.js'], - debugDirectory: 'debug' - })) - .pipe(mocha({ - reporter: 'spec', - globals: {} - })) - .pipe(cover.gather()) - .pipe(cover.format()) - .pipe(gulp.dest('reports')) - .once('end', function() { - process.exit(); - }); -}); + .pipe(mocha({ + reporter: 'spec' + })); +} + +exports.test = gulp.series(exports.lint, test); + +exports.default = exports.test; -gulp.task('jshint', function() { - console.log('Analyzing source with JSHint and JSCS'); - return gulp - .src(['common/lib/*.js','examples/**/*.js', 'device/**/*.js','thing/*.js','index.js', '!node_modules/**/*.js', '!examples/**/node_modules/**/*.js', '!examples/**/aws-configuration.js', '!browser/**/*bundle.js', '!examples/browser/**/*bundle.js']) - .pipe(jshint()) - .pipe(jshint.reporter('jshint-stylish', {verbose: true})) - .pipe(jshint.reporter('fail')) - .pipe(eslint()) - .pipe(eslint.format()) - .pipe(eslint.failAfterError()); -}); -gulp.task('beautify', function() { - console.log('Beautifying source with indent level 3'); - return gulp - .src(['!browser/**/*bundle.js', '!examples/**/*bundle.js', 'browser/**/*.js','common/**/*.js','examples/**/*.js', 'device/**/*.js','thing/*.js','index.js', '!node_modules/**/*.js', '!examples/**/node_modules/**/*.js', '!browser/**/*bundle.js', '!examples/browser/**/*bundle.js']) - .pipe(beautify({'indent_size':3, 'indent_char': ' ', 'end_with_newline': true})) -// -// Replace the files in-place with the beautified versions. -// - .pipe(gulp.dest( function(vinylFile) { console.log('Beautifying \''+vinylFile.path+'\'...'); return vinylFile.base; })); -}); diff --git a/package.json b/package.json index 45f7c85..38a5140 100644 --- a/package.json +++ b/package.json @@ -34,15 +34,13 @@ "websocket-stream": "^5.5.2" }, "devDependencies": { - "gulp": "^3.9.0", - "gulp-beautify": "^2.0.0", - "gulp-coverage": "^0.3.38", + "gulp": "^4.0.2", "gulp-eslint": "^6.0.0", "gulp-jshint": "^2.1.0", - "gulp-mocha": "^3.0.1", + "gulp-mocha": "^8.0.0", "jshint": "^2.13.0", "jshint-stylish": "^2.2.1", - "rewire": "^2.5.1", + "rewire": "^5.0.0", "sinon": "^1.17.3" }, "scripts": { From a20b04046c57128f85250bdf1fd3a9567ec2794d Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Sat, 10 Jul 2021 14:02:17 -0700 Subject: [PATCH 3/8] Sinon to 3.x --- package.json | 2 +- test/device-unit-tests.js | 8 ++++---- test/jobs-unit-tests.js | 2 +- test/thing-unit-tests.js | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 38a5140..1aa00a0 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "jshint": "^2.13.0", "jshint-stylish": "^2.2.1", "rewire": "^5.0.0", - "sinon": "^1.17.3" + "sinon": "^3.3.0" }, "scripts": { "test": "node ./node_modules/gulp/bin/gulp.js test --verbose", diff --git a/test/device-unit-tests.js b/test/device-unit-tests.js index 4291dc0..657607b 100644 --- a/test/device-unit-tests.js +++ b/test/device-unit-tests.js @@ -48,7 +48,7 @@ describe( 'device class unit tests', function() { return mockMQTTClientObject; }; - mqttSave = sinon.stub(mqtt, 'MqttClient', fakeConnect); + mqttSave = sinon.stub(mqtt, 'MqttClient').callsFake(fakeConnect); mockTlsRevert = myTls.__set__('tls', mockTlsObject); mockMqttRevert = myTls.__set__('mqtt', mockMqttObject); @@ -1852,7 +1852,7 @@ describe( 'device class unit tests', function() { // Fix the date at a known value so that the URL preparation code will always produce // the same result. // - before( function() { clock = sinon.useFakeTimers( (new Date('11/15/86 PST')).getTime(), 'Date' ); } ); + before( function() { clock = sinon.useFakeTimers( (new Date('11/15/86 PST'))); } ); after( function() { clock.restore(); } ); it('calculates the url correctly', function() { @@ -1872,7 +1872,7 @@ describe( 'device class unit tests', function() { // Fix the date at a known value so that the URL preparation code will always produce // the same result. // - before( function() { clock = sinon.useFakeTimers( (new Date('11/15/86 PST')).getTime(), 'Date' ); } ); + before( function() { clock = sinon.useFakeTimers( (new Date('11/15/86 PST'))); } ); after( function() { clock.restore(); } ); it('calculates the url correctly', function() { @@ -1894,7 +1894,7 @@ describe( 'device class unit tests', function() { // Fix the date at a known value so that the URL preparation code will always produce // the same result. // - before( function() { clock = sinon.useFakeTimers( (new Date('11/15/86 PST')).getTime(), 'Date' ); } ); + before( function() { clock = sinon.useFakeTimers( (new Date('11/15/86 PST'))); } ); after( function() { clock.restore(); } ); it('calculates the url correctly', function() { diff --git a/test/jobs-unit-tests.js b/test/jobs-unit-tests.js index b8448b3..e7baaa8 100644 --- a/test/jobs-unit-tests.js +++ b/test/jobs-unit-tests.js @@ -47,7 +47,7 @@ describe( 'jobs class unit tests', function() { return mockMQTTClientObject; }; - mqttSave = sinon.stub(mqtt, 'MqttClient', fakeConnect); + mqttSave = sinon.stub(mqtt, 'MqttClient').callsFake(fakeConnect); mockTlsRevert = myTls.__set__('tls', mockTlsObject); mockMqttRevert = myTls.__set__('mqtt', mockMqttObject); diff --git a/test/thing-unit-tests.js b/test/thing-unit-tests.js index d2a5e14..4f2c2f2 100644 --- a/test/thing-unit-tests.js +++ b/test/thing-unit-tests.js @@ -38,7 +38,7 @@ describe( 'thing shadow class unit tests', function() { return mockMQTTClientObject; }; - mqttSave = sinon.stub(device, 'DeviceClient', fakeConnect); + mqttSave = sinon.stub(device, 'DeviceClient').callsFake(fakeConnect); }); afterEach( function () { mqttSave.restore(); @@ -85,7 +85,7 @@ describe( 'thing shadow class unit tests', function() { it('should trigger error when a subscription fails', function () { - var stubTriggerError = sinon.stub(mockMQTTClient, 'triggerError', function() {return true;}); + var stubTriggerError = sinon.stub(mockMQTTClient, 'triggerError').callsFake(function() {return true;}); var thingShadows = thingShadow(thingShadowsConfig); thingShadows.register('testShadow1', { ignoreDeltas: true, persistentSubscribe: true }, function (err, granted) { @@ -904,7 +904,7 @@ describe( 'thing shadow class unit tests', function() { myPayload = '{"state":{"desired":{"color":"RED"},"reported":{"color":"BLUE"}},"clientToken":"CoolToken1"}'; myStateObject = JSON.parse(myPayload); // cause subscribe error on update (we subscribe because we have elected to not be persistently subscribed) - var stubTriggerError = sinon.stub(mockMQTTClient, 'triggerError', function() {return true;}); + var stubTriggerError = sinon.stub(mockMQTTClient, 'triggerError').callsFake(function() {return true;}); // Update thingShadows.update('testShadow4', myStateObject); // Publish will not be called (error before updating state) From 77ad389838c272903e8ca59d6a58e8992a6f58d5 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Sat, 10 Jul 2021 14:09:59 -0700 Subject: [PATCH 4/8] Upgrade to sinon 7.x --- package.json | 2 +- test/jobs-agent-unit-tests.js | 90 +++++++++++++++++------------------ test/thing-unit-tests.js | 8 ++-- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index 1aa00a0..12c9ac5 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "jshint": "^2.13.0", "jshint-stylish": "^2.2.1", "rewire": "^5.0.0", - "sinon": "^3.3.0" + "sinon": "^7.5.0" }, "scripts": { "test": "node ./node_modules/gulp/bin/gulp.js test --verbose", diff --git a/test/jobs-agent-unit-tests.js b/test/jobs-agent-unit-tests.js index b8f7fba..7bdb782 100644 --- a/test/jobs-agent-unit-tests.js +++ b/test/jobs-agent-unit-tests.js @@ -125,9 +125,9 @@ describe( 'jobs agent unit tests', function() { var fakeCallbackSucceeded = sinon.spy(); it('invalid status calls failed callback', function() { - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'INVALID' }, null, fakeCallbackInProgress, function (statusDetails) { fakeCallbackFailed(); console.log(statusDetails); @@ -140,9 +140,9 @@ describe( 'jobs agent unit tests', function() { }); it('missing packageName calls failed callback', function() { - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { files: [ { fileName: 'testFileName' } ] }, fakeCallbackInProgress, function (statusDetails) { fakeCallbackFailed(); console.log(statusDetails); @@ -155,9 +155,9 @@ describe( 'jobs agent unit tests', function() { }); it('missing files list calls failed callback', function() { - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName' }, fakeCallbackInProgress, function (statusDetails) { fakeCallbackFailed(); console.log(statusDetails); @@ -170,9 +170,9 @@ describe( 'jobs agent unit tests', function() { }); it('empty files list calls failed callback', function() { - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', files: [] }, fakeCallbackInProgress, function (statusDetails) { fakeCallbackFailed(); console.log(statusDetails); @@ -185,9 +185,9 @@ describe( 'jobs agent unit tests', function() { }); it('invalid file in files list calls failed callback', function() { - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', files: [ null, { fileName: 'testFileName.txt' } ] }, @@ -209,9 +209,9 @@ describe( 'jobs agent unit tests', function() { it('missing url in file in files calls failed callback, rolls back', function(done) { fs.reset(); fs.writeFileSync('/testFileName.txt', 'This is a test.'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, files: [ { fileName: 'testFileName.txt' } ] }, @@ -235,9 +235,9 @@ describe( 'jobs agent unit tests', function() { it('invalid url in file in files calls failed callback, rolls back', function(done) { fs.reset(); fs.writeFileSync('/testFileName.txt', 'This is a test.'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, files: [ { fileName: 'testFileName.txt', fileSource: { url: 'https://bogus.not.a.url' } } ] }, @@ -262,9 +262,9 @@ describe( 'jobs agent unit tests', function() { fs.reset(); fs.writeFileSync('/testFileName.txt', 'This is a test.'); fs.writeFileSync('/testNewFile.txt', 'This is an updated test.'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, files: [ { fileName: 'testFileName.txt', fileSource: { url: 'file:///testNewFile.txt' } } ] }, @@ -290,9 +290,9 @@ describe( 'jobs agent unit tests', function() { fs.reset(); fs.writeFileSync('/testFileName.txt', 'This is a test.'); fs.writeFileSync('/testNewFile.txt', 'This is an updated test.'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, files: [ { fileName: 'testFileName.txt', fileSource: { url: 'file:///testNewFile.txt' }, @@ -319,9 +319,9 @@ describe( 'jobs agent unit tests', function() { fs.reset(); fs.writeFileSync('/testFileName.txt', 'This is a test.'); fs.writeFileSync('/testNewFile.txt', 'This is an updated test.'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, files: [ { fileName: 'testFileName.txt', fileSource: { url: 'file:///testNewFile.txt' }, @@ -348,9 +348,9 @@ describe( 'jobs agent unit tests', function() { fs.reset(); fs.writeFileSync('/testFileName.txt', 'This is a test.'); fs.writeFileSync('/testNewFile.txt', 'This is an updated test.'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, files: [ { fileName: 'testFileName.txt', fileSource: { url: 'file:///testNewFile.txt' }, @@ -379,9 +379,9 @@ describe( 'jobs agent unit tests', function() { fs.writeFileSync('/testNewFile1.txt', 'This is an updated test 1.'); fs.writeFileSync('/testFileName2.txt', 'This is a test 2.'); fs.writeFileSync('/testNewFile2.txt', 'This is an updated test 2.'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, files: [ { fileName: 'testFileName1.txt', fileSource: { url: 'file:///testNewFile1.txt' } }, @@ -412,9 +412,9 @@ describe( 'jobs agent unit tests', function() { fs.writeFileSync('/testNewFile1.txt', 'This is an updated test 1.'); fs.writeFileSync('/testFileName2.txt', 'This is a test 2.'); fs.writeFileSync('/testNewFile2.txt', 'This is an updated test 2.'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, files: [ { fileName: 'testFileName1.txt', fileSource: { url: 'file:///testNewFile1.txt' } }, @@ -443,9 +443,9 @@ describe( 'jobs agent unit tests', function() { fs.reset(); fs.writeFileSync('/program.js', 'previous program version'); fs.writeFileSync('/badNewProgram.js', 'this is an invalid node program to install'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, launchCommand: 'node -e "this is an invalid node program to install"', autoStart: true, @@ -471,9 +471,9 @@ describe( 'jobs agent unit tests', function() { fs.reset(); fs.writeFileSync('/program.js', 'previous program version'); fs.writeFileSync('/newProgram.js', 'function done() {}; setTimeout(done, 3000);'); - fakeCallbackInProgress.reset(); - fakeCallbackFailed.reset(); - fakeCallbackSucceeded.reset(); + fakeCallbackInProgress.resetHistory(); + fakeCallbackFailed.resetHistory(); + fakeCallbackSucceeded.resetHistory(); var job = buildJobObject('install', { status: 'QUEUED' }, { packageName: 'testPackageName', workingDirectory: tempDir, launchCommand: 'node -e "function done() {}; setTimeout(done, 3000);"', autoStart: true, diff --git a/test/thing-unit-tests.js b/test/thing-unit-tests.js index 4f2c2f2..3b8258a 100644 --- a/test/thing-unit-tests.js +++ b/test/thing-unit-tests.js @@ -705,7 +705,7 @@ describe( 'thing shadow class unit tests', function() { // Get thingShadows.get('testShadow3', 'CoolToken1'); mockMQTTClientObject.emit('message', '$aws/things/testShadow3/shadow/get/accepted', '{"clientToken":"CoolToken1", "version":3}'); - fakeCallback.reset(); // Reset spy + fakeCallback.resetHistory(); // Reset spy thingShadows.get('testShadow3', 'CoolToken2'); mockMQTTClientObject.emit('message', '$aws/things/testShadow3/shadow/get/accepted', '{"clientToken":"CoolToken2", "version":1}'); // old version // Delete @@ -809,7 +809,7 @@ describe( 'thing shadow class unit tests', function() { // Check assert(fakeCallback.calledOnce); // Reset - fakeCallback.reset(); + fakeCallback.resetHistory(); // Update rejected thingShadows.update('testShadow4', myStateObject); mockMQTTClientObject.emit('message', '$aws/things/testShadow4/shadow/update/rejected', '{"clientToken":"CoolToken1","version":2}'); @@ -1070,8 +1070,8 @@ describe( 'thing shadow class unit tests', function() { clock.tick(3000); assert(fakeCallbackStatus.calledOnce); sinon.assert.notCalled(fakeCallbackTimeout); - fakeCallbackStatus.reset(); // Reset spy status - fakeCallbackTimeout.reset(); // Reset spy timeout + fakeCallbackStatus.resetHistory(); // Reset spy status + fakeCallbackTimeout.resetHistory(); // Reset spy timeout thingShadows.update('testShadow4', myStateObject); mockMQTTClientObject.emit('message', '$aws/things/testShadow4/shadow/update/accepted', '{"clientToken":"CoolToken1", "version":1}'); // old version clock.tick(3000); From 945e81874968dca03399928f5d39fa806d24b1a4 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Sat, 10 Jul 2021 14:15:37 -0700 Subject: [PATCH 5/8] Sinon to latest --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 12c9ac5..0ff2f70 100644 --- a/package.json +++ b/package.json @@ -41,11 +41,10 @@ "jshint": "^2.13.0", "jshint-stylish": "^2.2.1", "rewire": "^5.0.0", - "sinon": "^7.5.0" + "sinon": "^11.1.1" }, "scripts": { "test": "node ./node_modules/gulp/bin/gulp.js test --verbose", - "browserize": "./scripts/browserize.sh", - "beautify": "node ./node_modules/gulp/bin/gulp.js beautify" + "browserize": "./scripts/browserize.sh" } } From dd0c4d4c2e2f5a35a31e87a75b05c710db9b656d Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Sat, 10 Jul 2021 14:20:50 -0700 Subject: [PATCH 6/8] Does this let us build on node 12? --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3e0eb8..155152b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [10.x] + node-version: [10.x, 12.x] steps: - uses: actions/checkout@v2 From dcfd1a0d0f6ca0cfbb1cae50dc8446d00b19e872 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Sat, 10 Jul 2021 14:23:03 -0700 Subject: [PATCH 7/8] Looking good for node 12+ --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 155152b..c1e5f74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [10.x, 12.x] + node-version: [10.x, 12.x, 14.x] steps: - uses: actions/checkout@v2 @@ -35,7 +35,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [10.x] + node-version: [10.x, 12.x, 14.x] test-type: [websocket, certificate, custom-auth] steps: From ee59c244605e36448938fd108ba946851043a123 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Sat, 10 Jul 2021 14:47:57 -0700 Subject: [PATCH 8/8] Drop 14 for now --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1e5f74..a9719cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [10.x, 12.x, 14.x] + node-version: [10.x, 12.x] test-type: [websocket, certificate, custom-auth] steps: