cylon/spec/lib/robot.spec.js

540 lines
14 KiB
JavaScript
Raw Normal View History

2014-12-15 07:21:28 +08:00
/* jshint expr:true */
2014-03-05 05:03:31 +08:00
"use strict";
2014-02-28 06:52:25 +08:00
2014-12-15 07:21:28 +08:00
var Driver = source("driver"),
Adaptor = source("adaptor"),
2014-12-16 01:37:52 +08:00
Robot = source("robot");
2014-05-07 10:18:13 +08:00
2014-05-08 23:57:20 +08:00
describe("Robot", function() {
2014-10-01 03:22:00 +08:00
var work, extraFunction, robot;
2014-02-28 06:52:25 +08:00
2014-10-01 03:22:00 +08:00
beforeEach(function() {
work = spy();
extraFunction = spy();
2014-02-28 09:39:02 +08:00
2014-10-01 03:22:00 +08:00
robot = new Robot({
name: "Robby",
work: work,
2014-02-28 06:52:25 +08:00
2014-10-01 03:22:00 +08:00
extraFunction: extraFunction,
extraValue: "Hello World",
master: { master: true }
});
2013-10-25 05:25:42 +08:00
});
2014-03-05 05:03:31 +08:00
describe("constructor", function() {
describe("name", function() {
context("if provided", function() {
it("is set to the passed value", function() {
2014-12-16 01:37:52 +08:00
expect(robot.name).to.be.eql("Robby");
2014-03-05 05:03:31 +08:00
});
});
2014-02-28 06:52:25 +08:00
2014-03-05 05:03:31 +08:00
context("if not provided", function() {
2014-07-05 00:49:29 +08:00
beforeEach(function() {
2014-12-15 07:21:28 +08:00
stub(Robot, "randomName").returns("New Robot");
2014-03-05 05:03:31 +08:00
});
2014-02-28 06:52:25 +08:00
2014-07-05 00:49:29 +08:00
afterEach(function() {
2014-05-08 23:57:20 +08:00
Robot.randomName.restore();
2014-03-05 05:03:31 +08:00
});
2014-02-28 06:52:25 +08:00
2014-03-05 05:03:31 +08:00
it("is set to a random name", function() {
2014-05-08 23:57:20 +08:00
var bot = new Robot({});
2014-03-05 05:03:31 +08:00
expect(bot.name).to.be.eql("New Robot");
});
});
});
it("sets @master to the passed Master object", function() {
expect(robot.master).to.be.eql({ master: true });
});
it("sets @connections to an empty object by default", function() {
expect(robot.connections).to.be.eql({});
});
2014-02-28 06:52:25 +08:00
2014-03-05 05:03:31 +08:00
it("sets @devices to an empty object by default", function() {
expect(robot.devices).to.be.eql({});
});
it("sets @work to the passed work function", function() {
expect(robot.work).to.be.eql(work);
});
it("sets other obj params as values on the robot", function() {
expect(robot.extraFunction).to.be.eql(extraFunction);
expect(robot.extraValue).to.be.eql("Hello World");
2014-02-28 06:52:25 +08:00
});
context("if there are devices but no connections", function() {
2014-12-15 07:21:28 +08:00
it("throws an error", function() {
var fn = function() {
return new Robot({
2014-12-15 07:21:28 +08:00
name: "BrokenBot",
devices: {
2014-12-15 07:21:28 +08:00
ping: { driver: "ping" }
}
});
};
expect(fn).to.throw(Error, "No connections specified");
});
});
2014-08-06 09:41:57 +08:00
context("if no commands are provided", function() {
var robot;
beforeEach(function() {
robot = new Robot({
2014-12-15 07:21:28 +08:00
name: "NewBot",
otherThings: { more: "details" },
2014-12-16 01:37:52 +08:00
sayHello: function() { return "Hello!"; }
2014-08-06 09:41:57 +08:00
});
});
it("sets #commands to the additionally provided functions", function() {
expect(robot.commands).to.be.eql({ sayHello: robot.sayHello });
});
});
context("if a commands function is provided", function() {
var robot;
beforeEach(function() {
robot = new Robot({
2014-12-15 07:21:28 +08:00
name: "NewBot",
2014-08-06 09:41:57 +08:00
2014-12-16 01:37:52 +08:00
sayHello: function() { return this.name + " says hello"; },
2014-08-06 09:41:57 +08:00
commands: function() {
return {
say_hello: this.sayHello
2014-12-16 01:37:52 +08:00
};
2014-08-06 09:41:57 +08:00
}
});
});
it("sets #commands to the returned object", function() {
expect(robot.commands.say_hello).to.be.eql(robot.sayHello);
});
context("if the function doesn't return an object", function() {
var fn;
beforeEach(function() {
fn = function() {
2014-12-16 01:37:52 +08:00
var bot = new Robot({
2014-12-15 07:21:28 +08:00
name: "NewBot",
2014-08-06 09:41:57 +08:00
commands: function() {
return [];
}
});
2014-12-16 01:37:52 +08:00
return bot;
};
2014-08-06 09:41:57 +08:00
});
it("throws an error", function() {
2014-12-16 01:37:52 +08:00
expect(fn).to.throw(
Error,
"#commands must be an object or a function that returns an object"
2014-12-16 01:37:52 +08:00
);
2014-08-06 09:41:57 +08:00
});
2014-12-16 01:37:52 +08:00
});
2014-08-06 09:41:57 +08:00
});
context("if a commands object is provided", function() {
var robot;
beforeEach(function() {
robot = new Robot({
2014-12-15 07:21:28 +08:00
name: "NewBot",
2014-08-06 09:41:57 +08:00
2014-12-16 01:37:52 +08:00
sayHello: function() { return this.name + " says hello"; },
2014-08-06 09:41:57 +08:00
commands: {
say_hello: function() {}
}
});
});
it("sets #commands to the provided object", function() {
2014-12-15 07:21:28 +08:00
expect(robot.commands.say_hello).to.be.a("function");
2014-08-06 09:41:57 +08:00
});
});
context("arbitrary arguments", function() {
beforeEach(function() {
robot = new Robot({
2014-12-15 07:21:28 +08:00
name: "NewBot",
2014-12-15 07:21:28 +08:00
hiThere: "hi there",
sayHi: function() {
2014-12-15 07:21:28 +08:00
return "hi";
},
start: "start"
2014-12-16 01:37:52 +08:00
});
});
2014-12-16 01:37:52 +08:00
context("if they don't conflict with built-ins", function() {
it("passes them through", function() {
expect(robot.hiThere).to.be.eql("hi there");
expect(robot.sayHi()).to.be.eql("hi");
});
});
2014-12-16 01:37:52 +08:00
context("if they do conflict with built-ins", function() {
it("doesn't pass them through", function() {
expect(robot.start).to.be.a("function");
});
});
});
2014-02-28 06:52:25 +08:00
});
2014-03-01 12:27:05 +08:00
describe("all work and no play", function() {
var play = spy();
var playBot = new Robot({
play: play
});
2014-12-15 07:21:28 +08:00
it("makes Jack a dull boy", function() {
expect(playBot.work).to.be.eql(play);
2014-12-16 01:37:52 +08:00
});
2014-08-06 09:41:57 +08:00
});
describe("#toJSON", function() {
2014-05-08 23:57:20 +08:00
var bot = new Robot({
connections: {
2014-12-15 07:21:28 +08:00
loopback: { adaptor: "loopback" }
},
devices: {
2014-12-15 07:21:28 +08:00
ping: { driver: "ping" }
}
2014-03-01 12:27:05 +08:00
});
var json = bot.toJSON();
2014-03-01 12:27:05 +08:00
it("returns an object", function() {
2014-12-15 07:21:28 +08:00
expect(json).to.be.a("object");
2014-03-01 12:27:05 +08:00
});
it("contains the robot's name", function() {
expect(json.name).to.eql(bot.name);
2014-03-01 12:27:05 +08:00
});
it("contains the robot's commands", function() {
2014-08-06 09:41:57 +08:00
expect(json.commands).to.eql(Object.keys(bot.commands));
2014-03-01 12:27:05 +08:00
});
it("contains the robot's devices", function() {
2014-11-12 03:41:18 +08:00
expect(json.devices).to.eql([bot.devices.ping.toJSON()]);
2014-03-01 12:27:05 +08:00
});
it("contains the robot's connections", function() {
2014-11-12 03:41:18 +08:00
expect(json.connections).to.eql([bot.connections.loopback.toJSON()]);
2014-03-01 12:27:05 +08:00
});
});
2014-03-05 05:03:31 +08:00
describe("#connection", function() {
var opts, bot;
beforeEach(function() {
bot = new Robot();
2014-12-15 07:21:28 +08:00
opts = { adaptor: "loopback" };
});
it("creates and adds a new Connection", function() {
expect(bot.connections.loopback).to.be.eql(undefined);
2014-12-15 07:21:28 +08:00
bot.connection("loopback", opts);
expect(bot.connections.loopback).to.be.an.instanceOf(Adaptor);
2014-12-16 01:37:52 +08:00
});
2014-12-16 01:37:52 +08:00
it("sets connection.robot on to the Robot initializing it", function() {
2014-12-15 07:21:28 +08:00
bot.connection("loopback", opts);
expect(bot.connections.loopback.robot).to.be.eql(bot);
2014-12-16 01:37:52 +08:00
});
it("avoids name collisions", function() {
2014-12-15 07:21:28 +08:00
bot.connection("loopback", opts);
bot.connection("loopback", opts);
2014-12-16 01:37:52 +08:00
var conns = Object.keys(bot.connections);
expect(conns).to.be.eql(["loopback", "loopback-1"]);
});
});
2014-03-05 05:03:31 +08:00
describe("initConnections", function() {
var bot;
beforeEach(function() {
bot = new Robot();
});
2014-03-05 05:03:31 +08:00
context("when not passed anything", function() {
it("does not modify the bot's connections", function() {
bot.initConnections({});
expect(bot.connections).to.be.eql({});
2014-03-05 05:03:31 +08:00
});
});
context("when passed a connection object", function() {
it("instantiates a new connection with the provided object", function() {
2014-12-15 07:21:28 +08:00
var connection = { name: "loopback", adaptor: "loopback" };
bot.initConnections({ connection: connection });
2014-12-15 07:21:28 +08:00
expect(bot.connections["loopback"]).to.be.instanceOf(Adaptor);
2014-03-05 05:03:31 +08:00
});
});
context("when passed an object containing connection details", function() {
it("creates new connections with each of the ones provided", function() {
var connections = {
loopback: { adaptor: "loopback" }
};
bot.initConnections({ connections: connections });
expect(bot.connections.loopback).to.be.instanceOf(Adaptor);
});
});
2014-03-05 05:03:31 +08:00
context("when passed an array of connection objects", function() {
2014-12-16 01:37:52 +08:00
it("creates new connections with each of the ones provided", function() {
var connections = [{ name: "loopback", adaptor: "loopback" }];
bot.initConnections({ connections: connections });
2014-12-15 07:21:28 +08:00
expect(bot.connections["loopback"]).to.be.instanceOf(Adaptor);
});
it("avoids name collisions", function() {
var opts = {
connections: [
2014-12-15 07:21:28 +08:00
{ name: "loopback", adaptor: "loopback" },
{ name: "loopback", adaptor: "loopback" }
]
};
bot.initConnections(opts);
var keys = Object.keys(bot.connections);
expect(keys).to.be.eql(["loopback", "loopback-1"]);
2014-03-05 05:03:31 +08:00
});
});
});
describe("#device", function() {
var opts, bot;
beforeEach(function() {
bot = new Robot();
2014-12-15 07:21:28 +08:00
opts = { driver: "ping" };
});
it("creates and adds a new Device", function() {
expect(bot.devices.ping).to.be.eql(undefined);
2014-12-15 07:21:28 +08:00
bot.device("ping", opts);
expect(bot.devices.ping).to.be.an.instanceOf(Driver);
2014-12-16 01:37:52 +08:00
});
it("sets @robot on the Device to be the Robot initializing it", function() {
2014-12-15 07:21:28 +08:00
bot.device("ping", opts);
expect(bot.devices.ping.robot).to.be.eql(bot);
2014-12-16 01:37:52 +08:00
});
it("avoids name collisions", function() {
2014-12-15 07:21:28 +08:00
bot.device("ping", opts);
bot.device("ping", opts);
expect(Object.keys(bot.devices)).to.be.eql(["ping", "ping-1"]);
});
});
2014-03-05 05:03:31 +08:00
describe("initDevices", function() {
var bot;
beforeEach(function() {
2014-11-01 04:48:05 +08:00
bot = new Robot({
connections: {
2014-12-15 07:21:28 +08:00
loopback: { adaptor: "loopback" }
}
2014-11-01 04:48:05 +08:00
});
});
2014-03-05 05:03:31 +08:00
context("when not passed anything", function() {
it("does not modify the bot's devices", function() {
bot.initDevices({});
expect(bot.devices).to.be.eql({});
2014-03-05 05:03:31 +08:00
});
});
2014-11-12 03:41:18 +08:00
context("when passed a device object", function() {
it("instantiates a new driver with the provided object", function() {
2014-12-15 07:21:28 +08:00
var device = { name: "ping", driver: "ping" };
bot.initDevices({ device: device });
2014-12-15 07:21:28 +08:00
expect(bot.devices["ping"]).to.be.instanceOf(Driver);
2014-03-05 05:03:31 +08:00
});
});
context("when passed an object containing device details", function() {
it("creates new devices with each of the ones provided", function() {
var devices = {
ping: { driver: "ping" }
};
bot.initDevices({ devices: devices });
expect(bot.devices.ping).to.be.instanceOf(Driver);
});
});
2014-03-05 05:03:31 +08:00
context("when passed an array of device objects", function() {
2014-12-16 01:37:52 +08:00
it("instantiates new drivers with provided objects", function() {
var devices = [{ name: "ping", driver: "ping" }];
bot.initDevices({ devices: devices});
2014-12-15 07:21:28 +08:00
expect(bot.devices["ping"]).to.be.instanceOf(Driver);
});
it("avoids name collisions collisions", function() {
bot.initDevices({
devices: [
2014-12-15 07:21:28 +08:00
{ name: "ping", driver: "ping" },
{ name: "ping", driver: "ping" }
]
});
2014-05-07 10:18:13 +08:00
var keys = Object.keys(bot.devices);
expect(keys).to.be.eql(["ping", "ping-1"]);
2014-03-05 05:03:31 +08:00
});
});
});
describe("#start", function() {
2014-07-05 00:49:29 +08:00
beforeEach(function() {
2014-12-15 07:21:28 +08:00
stub(robot, "startConnections").callsArg(0);
stub(robot, "startDevices").callsArg(0);
stub(robot, "emit").returns(null);
2014-03-05 05:03:31 +08:00
robot.start();
});
2014-07-05 00:49:29 +08:00
afterEach(function() {
2014-03-05 05:03:31 +08:00
robot.startConnections.restore();
robot.startDevices.restore();
robot.emit.restore();
});
it("starts the robot's connections", function() {
expect(robot.startConnections).to.be.called;
});
it("starts the robot's devices", function() {
expect(robot.startDevices).to.be.called;
});
it("starts the robot's work", function() {
expect(robot.work).to.be.called;
});
2014-09-30 01:27:52 +08:00
it("emits the 'ready' event", function() {
2014-12-16 01:37:52 +08:00
expect(robot.emit).to.be.calledWith("ready", robot);
2014-03-05 05:03:31 +08:00
});
it("returns the robot", function() {
expect(robot.start()).to.be.eql(robot);
});
2014-03-05 05:03:31 +08:00
});
describe("#startConnections", function() {
var bot;
beforeEach(function() {
2014-05-08 23:57:20 +08:00
bot = new Robot({
connections: {
2014-12-15 07:21:28 +08:00
alpha: { adaptor: "loopback" },
bravo: { adaptor: "loopback" }
}
2014-03-05 05:03:31 +08:00
});
2014-12-15 07:21:28 +08:00
stub(bot.connections.alpha, "connect").returns(true);
stub(bot.connections.bravo, "connect").returns(true);
2014-03-05 05:03:31 +08:00
});
it("runs #connect on each connection", function() {
bot.startConnections();
expect(bot.connections.alpha.connect).to.be.called;
expect(bot.connections.bravo.connect).to.be.called;
});
});
describe("#startDevices", function() {
var bot;
beforeEach(function() {
2014-05-08 23:57:20 +08:00
bot = new Robot({
connections: {
2014-12-15 07:21:28 +08:00
loopback: { adaptor: "loopback" }
},
devices: {
2014-12-15 07:21:28 +08:00
alpha: { driver: "ping" },
bravo: { driver: "ping" }
}
2014-03-05 05:03:31 +08:00
});
2014-12-15 07:21:28 +08:00
stub(bot.devices.alpha, "start").returns(true);
stub(bot.devices.bravo, "start").returns(true);
2014-03-05 05:03:31 +08:00
});
it("runs #start on each device", function() {
bot.startDevices();
expect(bot.devices.alpha.start).to.be.called;
expect(bot.devices.bravo.start).to.be.called;
});
});
describe("#halt", function() {
2014-07-05 00:49:29 +08:00
var bot, device, connection;
beforeEach(function() {
bot = new Robot({
devices: {
2014-12-15 07:21:28 +08:00
ping: { driver: "ping" }
},
connections: {
2014-12-15 07:21:28 +08:00
loopback: { adaptor: "loopback" }
}
2014-07-05 00:49:29 +08:00
});
2014-03-05 05:03:31 +08:00
2014-07-05 00:49:29 +08:00
device = bot.devices.ping;
connection = bot.connections.loopback;
2014-03-05 05:03:31 +08:00
2014-12-15 07:21:28 +08:00
stub(device, "halt").yields(true);
stub(connection, "disconnect").yields(true);
2014-03-05 05:03:31 +08:00
});
2014-07-05 00:49:29 +08:00
afterEach(function() {
device.halt.restore();
connection.disconnect.restore();
2014-03-05 05:03:31 +08:00
});
it("calls #halt on all devices and connections", function() {
bot.halt();
2014-03-05 05:03:31 +08:00
expect(device.halt).to.be.called;
expect(connection.disconnect).to.be.called;
2014-03-05 05:03:31 +08:00
});
});
describe("#toString", function() {
it("returns basic information about the robot", function() {
expect(robot.toString()).to.be.eql("[Robot name='Robby']");
});
});
2014-02-28 06:52:25 +08:00
});