Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
@klevn/assumejs
Advanced tools
Assume your node.js production server won't fail. And get notified if you were wrong.
![Gitter](https://badges.gitter.im/Join Chat.svg)
tl;dr: Weave assumptions - like asserts in unit tests - into your production code and get notified once they are violated. And no, it is no excuse for lazy testers.
~~~
Frankly, some functionality cannot be sufficiently tested before moving to production: Will we always meet our service level agreements? Our load tests certainly won't cover all real-world scenarios! What if a third party API changes suddenly? We couldn't possibly predict the exact change and write a test for it! This means, we will have production failures and there is nothing we can do to prevent those.
Assume.js provides a solution to close the gap between "We tested this." and "We just cannot test that." The idea is to weave assumptions - like asserts in unit tests - into the production code. If an assumption is violated the developers in charge will e.g. receive an e-mail so they can do something about it, hopefully even before the user notices the error or gets annoyed.
I did not reinvent the wheel. Assume.js is a clever combination of Chai's "expect" syntax to formulate assumptions and a hook to handle the notification on violated assumptions. With this hook you can go as far as integrating error management cloud services.
Available today:
In the future:
Will the assumptions slow down your system? I wrote a test and executed it on my MacBook Air with node.js v0.10.32:
Executing 40000 assumptions took 669 ms. That is 16.725 µs per assumption.
The module for node.js is installed via npm:
$ npm install assumejs --save
Assume.js is basically a renaming of Chai's expect()
. That means you can apply your working knowledge or read the docs and just use "assume" instead of "expect". E.g.:
var expect = require('chai').expect;
expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(foo).to.have.length(3);
expect(tea).to.have.property('flavors')
.with.length(3);
var assume = require('assumejs');
assume(foo).to.be.a('string');
assume(foo).to.equal('bar');
assume(foo).to.have.length(3);
assume(tea).to.have.property('flavors')
.with.length(3);
The main difference, however, is that assume.js does not throw an error if an assumption is violated. Instead it invokes the notification on violated assumptions.
Additionally, the signature of assume()
was extended:
assume(foo, 'my message').to.equal('bar');
// is identical to:
expect(foo, 'my message').to.equal('bar');
// which adds the message to the error if the expectation fails.
assume(foo, { data: 'Hello world!' }).to.equal('bar');
// forwards { data: 'Hello world!' } to the notification handler if the assumption is violated
// and invokes:
expect(foo).to.equal('bar');
// All can be combined:
assume(foo, 'my message', { data: 'Hello world!' }).to.equal('bar');
Chai was designed with high extensibility in mind and many plugins are already available.
Assume.js exposes Chai's plugin hook:
// Chai users are used to:
var chai = require('chai');
chai.use(function (_chai, utils) {
// Write your plugin code here.
});
// This is identical in assume.js:
var assume = require('assumejs');
assume.chaiUse(function (_chai, utils) {
// Write your plugin code here.
});
To get started read Chai's docs on the core concepts and how to build a helper.
Caution: If you install an existing plugin or write your own you have to obey one rule: Any assertion must be executed through chai.Assertion.assert(...)
. Assume.js overwrites this method in order to not throw an error if an assumption is violated and to invoke the notification handler instead. If the plugin throws its own errors instead of calling the assert method the production code will crash!
Out-of-the-box assume.js just logs a violated assumption to the console. You can easily write your own handler that gets called for each violated assumption like this:
var assume = require('assumejs');
assume.overwriteNotify(function (_super) {
// The function returned will be called once an assumption gets violated.
// err - The error that Chai throws
// context - The object/array that is optionally passed to assume()
return function (err, context) {
// You may or may not call the previously registered handler.
// This allows stacking multiple handlers on top of each other if you wish to do so.
_super(err, context);
// Do whatever you like.
// E.g. calling on of the services listed in the next section.
};
});
The error that Chai throws is caught by assume.js and passed to the handler. It actually is a standardized AssertionError
. For details see the 'assertion-error' module.
The first time a certain assumption is violated you want to get notified immediately. However, if it occurs repeatedly you don't want to get spammed by those notifications until you fix your code. Also, you might tolerate a certain violation to occur from time to time but want to get notified if the violation suddenly occurs more frequently. For that you may ask for a sophisticated error management system. Here is a list of those I know of:
Service | No money? | Integration | Getting Started |
---|---|---|---|
Airbrake | npm install airbrake | Gists welcome | |
App Enlight | offers a free plan | call their REST API or use their Airbrake compatible endpoint | Gist for using the Airbrake compatible endpoint |
Bugsnag | npm install bugsnag | Gists welcome | |
Errbit | host yourself | service endpoint is Airbrake-compatible | Gists welcome |
Honeybadger | npm install honeybadger | Gists welcome | |
Raygun | npm install raygun | Gists welcome | |
Rollbar | offers a free plan | npm install rollbar | Gist |
Sentry | npm install raven | Gists welcome | |
Stackify | call their REST api | Gists welcome |
Assume you want to store your data in your MongoDB:
collection.update(
{ id: 42 },
{ soda: 'and what not' },
{ upsert: true },
function (err, doc) {
if (err) {
// ???
}
});
Now assume you properly tested your code and it is working. The only reasons I can think of that an error occurs is (1) your code contains a bug - which is kinda unlikely because you wrote enough tests - and (2) MongoDB is down - which is also unlikely because you chose a reliable hoster. This means it would make no sense to write extensive error recovery code at this point. It is more effective to get notified if an error actually occurs and then decide if it is worth the effort to implement some intelligent error handling.
Of course one assume.js call will make your day:
function (err, doc) {
if (err) {
assume.notify(err); // This is the same hook that assumptions use.
}
}
Assume.js is just one safety net of many you shall apply. Writing assumptions does not let you off the hook implementing proper error handling. I highly recommend Joyent's article about error handling in node.js. Speaking in their terms it is best to focus on writing assumptions for "operational errors". For those of which you understand well you can and should write code to recover from them. Those of which you don't understand well you should write assumptions that help you get a better understanding through their notifications - but in the meantime it is probably a good choice to intentionally crash your server as you would do for "programmer errors".
When intentionally crashing your system because of an error you can't handle, you probably will want to get notified like for violated assumptions. Therefore add the following code to your main file:
var assume = require('assumejs');
process.on('uncaughtException', function (err) {
var context = { type: 'uncaughtException' }; // Or whatever you would like to pass with the notification.
assume.notify(err, context); // This is the same hook that assumptions use.
throw err; // So that you actually crash your server.
});
If you use one of the modules for the services listed above please look into their API. Some already provide a mechanism for handling uncaught exceptions that might be preferable.
What would you like to contribute?
cd
to the main folder,npm install
,npm install gulp -g
if you haven't installed gulp globally yet, andgulp dev
. (Or run node ./node_modules/.bin/gulp dev
if you don't want to install gulp globally.)gulp dev
watches all source files and if you save some changes it will lint the code and execute all tests. The test coverage report can be viewed from ./coverage/lcov-report/index.html
.
If you want to debug a test you should use gulp test-without-coverage
to run all tests without obscuring the code by the test coverage instrumentation.
assume.notify(...)
when passing a non-Error parameterexpect(true).to.be.true;
can also be written as expect(true).to.be.true();
.assume.notify(...)
does not alter the error anymore.assume.overwriteHandleViolation(...)
into assume.overwriteNotify(...)
assume.handleViolation(...)
into assume.notify(...)
In case you never heard about the ISC license it is functionally equivalent to the MIT license.
See the LICENSE file for details.
FAQs
Assume your node.js production server won't fail. And get notified if you were wrong.
We found that @klevn/assumejs demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.