etcher/tests/shared/robot.spec.js
2017-04-21 17:41:20 -04:00

369 lines
11 KiB
JavaScript

/*
* Copyright 2016 resin.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
const m = require('mochainon');
const _ = require('lodash');
const robot = require('../../lib/shared/robot');
describe('Shared: Robot', function() {
describe('.COMMAND', function() {
it('should be a plain object', function() {
m.chai.expect(_.isPlainObject(robot.COMMAND)).to.be.true;
});
it('should only contain string values', function() {
m.chai.expect(_.every(_.values(robot.COMMAND), _.isString)).to.be.true;
});
it('should contain only unique values', function() {
const numberOfKeys = _.size(_.keys(robot.COMMAND));
m.chai.expect(_.size(_.uniq(_.values(robot.COMMAND)))).to.equal(numberOfKeys);
});
});
describe('.isEnabled()', function() {
it('should return false if ETCHER_CLI_ROBOT is not set', function() {
m.chai.expect(robot.isEnabled({})).to.be.false;
});
it('should return true if ETCHER_CLI_ROBOT=1', function() {
m.chai.expect(robot.isEnabled({
ETCHER_CLI_ROBOT: 1
})).to.be.true;
});
it('should return false if ETCHER_CLI_ROBOT=0', function() {
m.chai.expect(robot.isEnabled({
ETCHER_CLI_ROBOT: 0
})).to.be.false;
});
it('should return true if ETCHER_CLI_ROBOT="true"', function() {
m.chai.expect(robot.isEnabled({
ETCHER_CLI_ROBOT: 'true'
})).to.be.true;
});
it('should return false if ETCHER_CLI_ROBOT="false"', function() {
m.chai.expect(robot.isEnabled({
ETCHER_CLI_ROBOT: 'false'
})).to.be.false;
});
it('should return true if ETCHER_CLI_ROBOT=true', function() {
m.chai.expect(robot.isEnabled({
ETCHER_CLI_ROBOT: true
})).to.be.true;
});
it('should return false if ETCHER_CLI_ROBOT=false', function() {
m.chai.expect(robot.isEnabled({
ETCHER_CLI_ROBOT: false
})).to.be.false;
});
});
describe('.buildMessage()', function() {
it('should build a message without data', function() {
const message = robot.buildMessage('hello');
const result = '{"command":"hello","data":{}}';
m.chai.expect(message).to.equal(result);
});
it('should build a message with data', function() {
const message = robot.buildMessage('hello', {
foo: 1,
bar: 2
});
const result = '{"command":"hello","data":{"foo":1,"bar":2}}';
m.chai.expect(message).to.equal(result);
});
it('should throw if data is defined but it not an object', function() {
m.chai.expect(() => {
robot.buildMessage('hello', 'world');
}).to.throw('Invalid data: world');
});
});
describe('.isMessage()', function() {
it('should return true if message is an empty object', function() {
m.chai.expect(robot.isMessage('{}')).to.be.true;
});
it('should return true if message is an object', function() {
m.chai.expect(robot.isMessage('{"command":"foo"}')).to.be.true;
});
it('should return false if message is an invalid object', function() {
m.chai.expect(robot.isMessage('{"command":\\foo"}')).to.be.false;
});
it('should return false if message is an unquoted string', function() {
m.chai.expect(robot.isMessage('foo')).to.be.false;
});
it('should return false if message is an quoted string', function() {
m.chai.expect(robot.isMessage('"foo"')).to.be.false;
});
it('should return false if message is an empty string', function() {
m.chai.expect(robot.isMessage('')).to.be.false;
});
it('should return false if message is undefined', function() {
m.chai.expect(robot.isMessage(undefined)).to.be.false;
});
it('should return false if message is null', function() {
m.chai.expect(robot.isMessage(null)).to.be.false;
});
it('should return false if message is a positive integer string', function() {
m.chai.expect(robot.isMessage('5')).to.be.false;
});
it('should return false if message is a negative integer string', function() {
m.chai.expect(robot.isMessage('-3')).to.be.false;
});
it('should return false if message is a zero string', function() {
m.chai.expect(robot.isMessage('0')).to.be.false;
});
it('should return false if message is a positive float string', function() {
m.chai.expect(robot.isMessage('5.3')).to.be.false;
});
it('should return false if message is a negative float string', function() {
m.chai.expect(robot.isMessage('-2.1')).to.be.false;
});
it('should return false if message is a positive integer', function() {
m.chai.expect(robot.isMessage(5)).to.be.false;
});
it('should return false if message is a negative integer', function() {
m.chai.expect(robot.isMessage(-3)).to.be.false;
});
it('should return false if message is zero', function() {
m.chai.expect(robot.isMessage(0)).to.be.false;
});
it('should return false if message is a positive float', function() {
m.chai.expect(robot.isMessage(5.3)).to.be.false;
});
it('should return false if message is a negative float', function() {
m.chai.expect(robot.isMessage(-2.1)).to.be.false;
});
it('should return false if message is an array', function() {
m.chai.expect(robot.isMessage([ 'foo' ])).to.be.false;
});
it('should return false if message is an array string', function() {
m.chai.expect(robot.isMessage('["foo"]')).to.be.false;
});
it('should return true for a message built with .buildMessage()', function() {
m.chai.expect(robot.isMessage(robot.buildMessage('foo', {
message: 'bar'
}))).to.be.true;
});
it('should return true for a message built with .buildErrorMessage()', function() {
const error = new Error('foo');
m.chai.expect(robot.isMessage(robot.buildErrorMessage(error))).to.be.true;
});
});
describe('.buildErrorMessage()', function() {
it('should build a message from a simple error', function() {
const error = new Error('foo');
const message = robot.buildErrorMessage(error);
m.chai.expect(JSON.parse(message)).to.deep.equal({
command: robot.COMMAND.ERROR,
data: {
message: 'foo',
stack: error.stack
}
});
});
it('should save the error description', function() {
const error = new Error('foo');
error.description = 'error description';
const message = robot.buildErrorMessage(error);
m.chai.expect(JSON.parse(message)).to.deep.equal({
command: robot.COMMAND.ERROR,
data: {
message: 'foo',
description: 'error description',
stack: error.stack
}
});
});
it('should save the error code', function() {
const error = new Error('foo');
error.code = 'MYERROR';
const message = robot.buildErrorMessage(error);
m.chai.expect(JSON.parse(message)).to.deep.equal({
command: robot.COMMAND.ERROR,
data: {
message: 'foo',
code: 'MYERROR',
stack: error.stack
}
});
});
it('should handle a string error', function() {
const message = JSON.parse(robot.buildErrorMessage('foo'));
m.chai.expect(message.data.message).to.equal('foo');
m.chai.expect(message.data.stack).to.be.a.string;
m.chai.expect(_.isEmpty(message.data.stack)).to.be.false;
});
});
describe('.parseMessage()', function() {
it('should parse a valid message', function() {
const message = robot.buildMessage('foo', {
bar: 1
});
m.chai.expect(robot.parseMessage(message)).to.deep.equal({
command: 'foo',
data: {
bar: 1
}
});
});
it('should parse a valid without data', function() {
const message = robot.buildMessage('foo');
m.chai.expect(robot.parseMessage(message)).to.deep.equal({
command: 'foo',
data: {}
});
});
it('should throw if input is not valid JSON', function() {
m.chai.expect(() => {
robot.parseMessage('Hello world\nFoo Bar');
}).to.throw('Invalid message');
});
it('should throw if input has no command', function() {
m.chai.expect(() => {
robot.parseMessage('{"data":{"foo":"bar"}}');
}).to.throw('Invalid message');
});
it('should throw if input has no data', function() {
m.chai.expect(() => {
robot.parseMessage('{"command":"foo"}');
}).to.throw('Invalid message');
});
});
describe('.getCommand()', function() {
it('should get the command of a message', function() {
const message = robot.parseMessage(robot.buildMessage('hello', {
foo: 1,
bar: 2
}));
m.chai.expect(robot.getCommand(message)).to.equal('hello');
});
});
describe('.getData()', function() {
it('should get the data of a message', function() {
const message = robot.parseMessage(robot.buildMessage('hello', {
foo: 1,
bar: 2
}));
m.chai.expect(robot.getData(message)).to.deep.equal({
foo: 1,
bar: 2
});
});
it('should return an empty object if the message has no data', function() {
m.chai.expect(robot.getData({
command: 'foo'
})).to.deep.equal({});
});
});
describe('.recomposeErrorMessage()', function() {
it('should return an instance of Error', function() {
const error = new Error('Foo bar');
const message = robot.parseMessage(robot.buildErrorMessage(error));
m.chai.expect(robot.recomposeErrorMessage(message)).to.be.an.instanceof(Error);
});
it('should be able to recompose an error object', function() {
const error = new Error('Foo bar');
const message = robot.parseMessage(robot.buildErrorMessage(error));
m.chai.expect(robot.recomposeErrorMessage(message)).to.deep.equal(error);
});
it('should be able to recompose an error object with a code', function() {
const error = new Error('Foo bar');
error.code = 'FOO';
const message = robot.parseMessage(robot.buildErrorMessage(error));
m.chai.expect(robot.recomposeErrorMessage(message)).to.deep.equal(error);
});
it('should be able to recompose an error object with a description', function() {
const error = new Error('Foo bar');
error.description = 'My description';
const message = robot.parseMessage(robot.buildErrorMessage(error));
m.chai.expect(robot.recomposeErrorMessage(message)).to.deep.equal(error);
});
});
});