86.36% Coverage. Moving on to SQL re-integration
This commit is contained in:
parent
36542501ea
commit
8fd8cf103f
|
@ -2,7 +2,7 @@ require_relative 'abstract_controller'
|
|||
require_relative '../sequence_factory'
|
||||
class ExecSequenceController < AbstractController
|
||||
def call
|
||||
sequence = SequenceFactory.run!(@message.payload["command"])
|
||||
sequence = SequenceFactory.run!(Hash(@message.payload["command"]))
|
||||
sequence.steps.each do |step|
|
||||
step.call(bot)
|
||||
end
|
||||
|
|
|
@ -7,10 +7,10 @@ require 'pry'
|
|||
class FarmBotPi
|
||||
attr_accessor :mesh, :bot, :credentials, :handler
|
||||
|
||||
def initialize(env = :development)
|
||||
def initialize(bot: FB::Arduino.new)
|
||||
@credentials = Credentials.new
|
||||
@mesh = EM::MeshRuby.new(@credentials.uuid, @credentials.token)
|
||||
@bot = FB::Arduino.new
|
||||
@bot = bot
|
||||
end
|
||||
|
||||
def start
|
||||
|
@ -34,5 +34,7 @@ class FarmBotPi
|
|||
|
||||
bot.onclose { EM.stop }
|
||||
end
|
||||
rescue => error
|
||||
binding.pry
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'json'
|
||||
require 'time'
|
||||
require_relative 'mesh_message'
|
||||
Dir["lib/controllers/*.rb"].each { |f| load(f) }
|
||||
Dir["lib/controllers/**/*.rb"].each { |f| load(f) }
|
||||
|
||||
# Get the JSON command, received through skynet, and send it to the farmbot
|
||||
# command queue Parses JSON messages received through SkyNet.
|
||||
|
|
|
@ -9,52 +9,60 @@ require 'ostruct'
|
|||
# |__| \___/ |_____| \___/ |__| * Find a way to re-use single_command controller?
|
||||
|
||||
class SequenceStep < OpenStruct
|
||||
attr_accessor :bot
|
||||
|
||||
def initialize(hash = nil)
|
||||
super
|
||||
self[:command] = OpenStruct.new(self[:command])
|
||||
end
|
||||
|
||||
def call(bot)
|
||||
botcmd, cmd = bot.commands, command
|
||||
case message_type
|
||||
when "move_relative"
|
||||
coords = {x: (cmd.x || 0), y: (cmd.y || 0), z: (cmd.z || 0)}
|
||||
bot.commands.move_relative coords
|
||||
when "move_absolute"
|
||||
coords = { x: cmd.x || bot.current_position.x,
|
||||
y: cmd.y || bot.current_position.y,
|
||||
z: cmd.z || bot.current_position.z }
|
||||
botcmd.move_absolute(coords)
|
||||
when "pin_write"
|
||||
botcmd.pin_write(pin: cmd.pin, value: cmd.value, mode: cmd.mode)
|
||||
else
|
||||
bot.log "Unknown message #{message_type}"
|
||||
@bot = bot
|
||||
route_me = { "move_relative" => -> { move_relative },
|
||||
"move_absolute" => -> { move_absolute },
|
||||
"pin_write" => -> { pin_write }, }
|
||||
route_me[message_type][] || bot.log("Unknown message #{message_type}")
|
||||
end
|
||||
|
||||
def move_relative
|
||||
coords = {x: (command.x || 0), y: (command.y || 0), z: (command.z || 0)}
|
||||
bot.commands.move_relative coords
|
||||
end
|
||||
|
||||
def move_absolute
|
||||
coords = { x: command.x || bot.current_position.x,
|
||||
y: command.y || bot.current_position.y,
|
||||
z: command.z || bot.current_position.z, }
|
||||
bot.commands.move_absolute(coords)
|
||||
end
|
||||
|
||||
def pin_write
|
||||
bot.commands.pin_write(pin: command.pin, value: command.value, mode: command.mode)
|
||||
end
|
||||
end
|
||||
|
||||
class StepValidator < Mutations::Command
|
||||
COMMANDS = %w(emergency_stop home_all home_x home_y home_z move_absolute
|
||||
move_relative pin_write read_parameter read_status write_parameter)
|
||||
|
||||
required do
|
||||
string :message_type, in: COMMANDS
|
||||
hash :command do
|
||||
optional do
|
||||
[:x, :y, :z, :speed, :pin, :value, :mode].each do |f|
|
||||
integer f, default: nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def execute
|
||||
SequenceStep.new(inputs)
|
||||
end
|
||||
end
|
||||
|
||||
# Builds a validated sequence (and collection of steps)
|
||||
class SequenceFactory < Mutations::Command
|
||||
class StepValidator < Mutations::Command
|
||||
COMMANDS = %w(emergency_stop home_all home_x home_y home_z move_absolute
|
||||
move_relative pin_write read_parameter read_status write_parameter)
|
||||
|
||||
required do
|
||||
string :message_type, in: COMMANDS
|
||||
hash :command do
|
||||
optional do
|
||||
[:x, :y, :z, :speed, :pin, :value, :mode].each do |f|
|
||||
integer f, default: nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def execute
|
||||
SequenceStep.new(inputs)
|
||||
end
|
||||
end
|
||||
|
||||
required do
|
||||
string :name
|
||||
array(:steps) { model :sequence_step, builder: StepValidator }
|
||||
|
|
37
spec/controllers/exec_sequence_controller_spec.rb
Normal file
37
spec/controllers/exec_sequence_controller_spec.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ExecSequenceController do
|
||||
let(:bot) { FakeBot.new }
|
||||
let(:mesh) { FakeMesh.new }
|
||||
let(:example_hash) do
|
||||
{
|
||||
"message_type" => "exec_sequence",
|
||||
"command" => {
|
||||
"name" =>"Yowza!",
|
||||
"steps" => [
|
||||
{"message_type"=>"move_relative", "command"=> {"x"=>"500"}},
|
||||
{"message_type"=>"move_absolute", "command"=> {"y"=>"1200"}},
|
||||
{"message_type" => "pin_write",
|
||||
"command" => {"pin" => 1, "value" => 1, "mode" => 0}},
|
||||
]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
let(:message) do
|
||||
MeshMessage.new(from: '1234567890',
|
||||
type: 'exec_sequence',
|
||||
payload: example_hash)
|
||||
end
|
||||
let(:controller) { ExecSequenceController.new(message, bot, mesh) }
|
||||
|
||||
it "initializes" do
|
||||
controller.call
|
||||
expect(mesh.last.type).to eq("exec_sequence")
|
||||
within_event_loop { bot.execute_command_next_tick }
|
||||
results = bot.outbound_queue.map(&:to_s)
|
||||
["F41 P1 V1 M0", "G0 X0 Y1200 Z0", "G0 X500 Y0 Z0"].each do |gcode|
|
||||
expect(results).to include(gcode)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,11 +1,12 @@
|
|||
class FakeBot
|
||||
require_relative "fake_logger"
|
||||
require_relative "fake_serial_port"
|
||||
require 'farmbot-serial'
|
||||
|
||||
class FakeBot < FB::Arduino
|
||||
attr_reader :logs, :last_log
|
||||
|
||||
def initialize
|
||||
def initialize(serial_port: FakeSerialPort.new, logger: FakeLogger.new)
|
||||
@logs = []
|
||||
end
|
||||
|
||||
def log(msg)
|
||||
@last_log = @logs.push(msg).last
|
||||
super
|
||||
end
|
||||
end
|
||||
|
|
10
spec/fakes/fake_logger.rb
Normal file
10
spec/fakes/fake_logger.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
class FakeLogger < StringIO
|
||||
def initialize(input = "")
|
||||
super
|
||||
end
|
||||
|
||||
def message
|
||||
rewind
|
||||
read.chomp
|
||||
end
|
||||
end
|
12
spec/fakes/fake_serial_port.rb
Normal file
12
spec/fakes/fake_serial_port.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
## SERIAL PORT SIMULATION
|
||||
## **********************
|
||||
class FakeSerialPort < StringIO
|
||||
def initialize(*)
|
||||
super("")
|
||||
end
|
||||
|
||||
def message
|
||||
rewind
|
||||
read.chomp
|
||||
end
|
||||
end
|
11
spec/farmbot-pi_spec.rb
Normal file
11
spec/farmbot-pi_spec.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe FarmBotPi do
|
||||
let(:bot) { FakeBot.new }
|
||||
|
||||
it 'starts the event loop' do
|
||||
pending 'Will circle back to this one later.
|
||||
Possible issues in Farmbot-serial'.strip
|
||||
expect(true).to be_falsey
|
||||
end
|
||||
end
|
|
@ -18,8 +18,6 @@ describe Credentials do
|
|||
expect(cred.credentials_file).to eq(temp_file)
|
||||
end
|
||||
|
||||
it 'loads credentials'
|
||||
|
||||
it 'creates credentials' do
|
||||
old_uuid = cred.uuid
|
||||
old_token = cred.token
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
require 'simplecov'
|
||||
SimpleCov.start do
|
||||
add_filter "/spec/"
|
||||
root = './lib'
|
||||
end
|
||||
|
||||
require 'pry'
|
||||
Dir['spec/fakes/**/*.rb'].each {|file| load file }
|
||||
Dir['spec/fakes/**/*.rb'].each { |file| load file }
|
||||
require_relative '../lib/farmbot-pi'
|
||||
|
||||
require_relative '../lib/controllers/exec_sequence_controller'
|
||||
require_relative '../lib/sequence_factory.rb'
|
||||
RSpec.configure do |config|
|
||||
config.expect_with :rspec do |expectations|
|
||||
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
||||
|
@ -16,3 +17,12 @@ RSpec.configure do |config|
|
|||
mocks.verify_partial_doubles = true
|
||||
end
|
||||
end
|
||||
|
||||
# This is used for testing things that require an event loop. Once run, you can
|
||||
# observe / make assertions on side effects.
|
||||
def within_event_loop
|
||||
EM.run do
|
||||
EventMachine::PeriodicTimer.new(0.1) { EM.stop }
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue