Merge pull request #1758 from FarmBot/mark_as

Phase 0: Ability to pass variables to MARK AS step
pull/1759/head
Rick Carlino 2020-04-16 13:27:52 -05:00 committed by GitHub
commit 643bcb1a37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 166 additions and 133 deletions

View File

@ -16,9 +16,9 @@ module CeleryScriptSettingsBag
end
PIN_TYPE_MAP = { "Peripheral" => Peripheral,
"Sensor" => Sensor,
"BoxLed3" => BoxLed,
"BoxLed4" => BoxLed }
"Sensor" => Sensor,
"BoxLed3" => BoxLed,
"BoxLed4" => BoxLed }
ALLOWED_AXIS = %w(x y z all)
ALLOWED_ASSERTION_TYPES = %w(abort recover abort_recover continue)
ALLOWED_CHANGES = %w(add remove update)
@ -38,7 +38,7 @@ module CeleryScriptSettingsBag
factory_reset find_home flash_firmware home
install_farmware install_first_party_farmware _if
move_absolute move_relative power_off read_pin
read_status reboot remove_farmware resource_update
read_status reboot remove_farmware update_resource
send_message set_servo_angle set_user_env sync
take_photo toggle_pin update_farmware wait
write_pin zero)
@ -74,7 +74,6 @@ module CeleryScriptSettingsBag
"as input. Please change your selection to a single" \
" location."
PLANT_STAGES = %w(planned planted harvested sprouted)
RESOURCE_UPDATE_ARGS = [:resource_type, :resource_id, :label, :value]
SCOPE_DECLARATIONS = [:variable_declaration, :parameter_declaration]
MISC_ENUM_ERR = '"%s" is not valid. Allowed values: %s'
MAX_WAIT_MS = 1000 * 60 * 3 # Three Minutes
@ -82,6 +81,13 @@ module CeleryScriptSettingsBag
"A single wait node cannot exceed #{MAX_WAIT_MS / 1000 / 60} minutes. " +
"Consider lowering the wait time or using multiple WAIT blocks."
Corpus = CeleryScript::Corpus.new
THIS_IS_DEPRECATED = {
args: [:resource_type, :resource_id, :label, :value],
tags: [:function, :api_writer, :network_user],
blk: ->(n) do
n.invalidate!("Deprecated `mark_as` detected. Delete it and re-add")
end,
}
CORPUS_VALUES = {
boolean: [TrueClass, FalseClass],
@ -278,6 +284,9 @@ module CeleryScriptSettingsBag
lua: {
defn: [v(:string)],
},
resource: {
defn: [n(:identifier), n(:resource)],
},
}.map do |(name, conf)|
blk = conf[:blk]
defn = conf.fetch(:defn)
@ -513,15 +522,22 @@ module CeleryScriptSettingsBag
tags: [:function, :firmware_user, :rpi_user],
blk: ->(n) { no_rpi_analog(n) },
},
resource_update: {
args: RESOURCE_UPDATE_ARGS,
tags: [:function, :api_writer, :network_user],
# DEPRECATED- Get rid of this node ASAP -RC 15 APR 2020
resource_update: THIS_IS_DEPRECATED,
resource: {
args: [:resource_type, :resource_id],
tags: [:network_user],
blk: ->(n) do
resource_type = n.args.fetch(:resource_type).value
resource_id = n.args.fetch(:resource_id).value
check_resource_type(n, resource_type, resource_id, Device.current)
end,
},
update_resource: {
args: [:resource],
body: [:pair],
tags: [:function, :api_writer, :network_user],
},
point_group: {
args: [:point_group_id],
tags: [:data, :list_like],
@ -529,7 +545,7 @@ module CeleryScriptSettingsBag
resource_id = n.args.fetch(:point_group_id).value
check_resource_type(n, "PointGroup", resource_id, Device.current)
end,
}
},
}.map { |(name, list)| Corpus.node(name, **list) }
HASH = Corpus.as_json

View File

@ -6,68 +6,68 @@ describe CeleryScript::Corpus do
it "handles valid move_absolute blocks" do
ok1 = CeleryScript::AstNode.new(**{
kind: "move_absolute",
args: {
location: {
kind: "coordinate",
args: {
x: 1,
y: 2,
z: 3,
},
},
offset: {
kind: "coordinate",
args: {
"x": 0,
"y": 0,
"z": 0,
},
},
speed: 100,
},
})
kind: "move_absolute",
args: {
location: {
kind: "coordinate",
args: {
x: 1,
y: 2,
z: 3,
},
},
offset: {
kind: "coordinate",
args: {
"x": 0,
"y": 0,
"z": 0,
},
},
speed: 100,
},
})
check1 = CeleryScript::Checker.new(ok1, corpus, device)
expect(check1.valid?).to be_truthy
ok2 = CeleryScript::AstNode.new(**{
kind: "move_absolute",
args: {
location: {
kind: "tool",
args: { tool_id: FactoryBot.create(:tool).id },
},
offset: {
kind: "coordinate",
args: {
"x": 0,
"y": 0,
"z": 0,
},
},
speed: 100,
},
})
kind: "move_absolute",
args: {
location: {
kind: "tool",
args: { tool_id: FactoryBot.create(:tool).id },
},
offset: {
kind: "coordinate",
args: {
"x": 0,
"y": 0,
"z": 0,
},
},
speed: 100,
},
})
check2 = CeleryScript::Checker.new(ok2, corpus, device)
expect(check2.valid?).to be_truthy
end
it "kicks back invalid move_absolute nodes" do
bad = CeleryScript::AstNode.new(**{
kind: "move_absolute",
args: {
location: 42,
speed: 100,
offset: {
kind: "coordinate",
args: {
"x": 0,
"y": 0,
"z": 0,
},
},
},
})
kind: "move_absolute",
args: {
location: 42,
speed: 100,
offset: {
kind: "coordinate",
args: {
"x": 0,
"y": 0,
"z": 0,
},
},
},
})
check = CeleryScript::Checker.new(bad, corpus, device)
expect(check.valid?).to be_falsey
expect(check.error.message).to include("but got Integer")
@ -76,19 +76,19 @@ describe CeleryScript::Corpus do
it "finds problems with nested nodes" do
bad = CeleryScript::AstNode.new(**{
kind: "move_absolute",
args: {
location: {
kind: "tool",
args: { tool_id: "PROBLEM!" }, # <= Invalid:
},
offset: {
kind: "coordinate",
args: { "x": 0, "y": 0, "z": 0 },
},
speed: 100,
},
})
kind: "move_absolute",
args: {
location: {
kind: "tool",
args: { tool_id: "PROBLEM!" }, # <= Invalid:
},
offset: {
kind: "coordinate",
args: { "x": 0, "y": 0, "z": 0 },
},
speed: 100,
},
})
check = CeleryScript::Checker.new(bad, corpus, device)
expect(check.valid?).to be_falsey
expect(check.error.message).to include("but got String")
@ -110,31 +110,31 @@ describe CeleryScript::Corpus do
# This test is __ONLY__ relevant for version 1.
# Change / delete / update as needed.
tree = CeleryScript::AstNode.new(**{
"kind": "send_message",
"args": {
"message": "Hello, world!",
"message_type": "wrong",
},
"body": [],
})
"kind": "send_message",
"args": {
"message": "Hello, world!",
"message_type": "wrong",
},
"body": [],
})
checker = CeleryScript::Checker.new(tree, corpus, device)
expect(checker.error.message).to include("not a valid message_type")
end
it "Handles channel_name validations" do
tree = CeleryScript::AstNode.new(**{
"kind": "send_message",
"args": {
"message": "Hello, world!",
"message_type": "fun",
},
"body": [
{
"kind": "channel",
"args": { "channel_name": "wrong" },
},
],
})
"kind": "send_message",
"args": {
"message": "Hello, world!",
"message_type": "fun",
},
"body": [
{
"kind": "channel",
"args": { "channel_name": "wrong" },
},
],
})
checker = CeleryScript::Checker.new(tree, corpus, device)
expect(checker.error.message).to include("not a valid channel_name")
end
@ -148,44 +148,49 @@ describe CeleryScript::Corpus do
expect(checker.error.message).to include("Tool #0 does not exist.")
end
it "Validates resource_update nodes" do
ast = { "kind": "resource_update",
"args": { "resource_type" => "Device",
"resource_id" => 23, # Mutated to "0" later..
"label" => "mounted_tool_id",
"value" => 1 } }
it "Validates update_resource nodes" do
ast = {
kind: "update_resource",
args: {
"resource" => {
kind: "resource",
args: {
"resource_type" => "Device",
"resource_id" => 23, # Mutated to "0" later..
},
},
},
body: [
{
kind: "pair",
args: {
"label" => "mounted_tool_id",
"value" => 1,
},
},
],
}
checker = CeleryScript::Checker
.new(CeleryScript::AstNode.new(**ast), corpus, device)
expect(checker.valid?).to be(true)
expect(checker.tree.args[:resource_id].value).to eq(device.id)
device_id = checker.tree.args[:resource].args[:resource_id].value
expect(device_id).to eq(device.id)
end
it "rejects bogus resource_updates" do
it "deprecates resource_updates" do
fake_id = FactoryBot.create(:plant).id + 1
expect(Plant.exists?(fake_id)).to be(false)
ast = { "kind": "resource_update",
"args": { "resource_type" => "Plant",
"resource_id" => fake_id,
"label" => "foo",
"value" => "Should Fail" } }
"args": { "resource_type" => "Plant",
"resource_id" => fake_id,
"label" => "foo",
"value" => "Should Fail" } }
hmm = CeleryScript::AstNode.new(**ast)
expect(hmm.args.fetch(:resource_id).value).to eq(fake_id)
checker = CeleryScript::Checker.new(hmm, corpus, device)
expect(checker.valid?).to be(false)
expect(checker.error.message).to eq("Can't find Plant with id of #{fake_id}")
end
it "rejects bogus resource_types" do
ast = { "kind": "resource_update",
"args": { "resource_type" => "CanOpener",
"resource_id" => 0,
"label" => "foo",
"value" => "Should Fail" } }
checker = CeleryScript::Checker.new(CeleryScript::AstNode.new(**ast),
corpus,
device)
expect(checker.valid?).to be(false)
expect(checker.error.message).to include('"CanOpener" is not a valid resource_type.')
msg = "Deprecated `mark_as` detected. Delete it and re-add"
expect(checker.error.message).to eq(msg)
end
it "has enums" do
@ -224,9 +229,9 @@ describe CeleryScript::Corpus do
it "sets a MAX_WAIT_MS limit for `wait` nodes" do
bad = CeleryScript::AstNode.new(**{
kind: "wait",
args: { milliseconds: CeleryScriptSettingsBag::MAX_WAIT_MS + 10 },
})
kind: "wait",
args: { milliseconds: CeleryScriptSettingsBag::MAX_WAIT_MS + 10 },
})
check = CeleryScript::Checker.new(bad, corpus, device)
expect(check.valid?).to be_falsey
expect(check.error.message).to include("cannot exceed 3 minutes")
@ -238,9 +243,9 @@ describe CeleryScript::Corpus do
name: "cs checks",
point_ids: [])
bad = CeleryScript::AstNode.new(**{
kind: "point_group",
args: { point_group_id: pg.id },
})
kind: "point_group",
args: { point_group_id: pg.id },
})
check = CeleryScript::Checker.new(bad, corpus, device)
expect(check.valid?).to be true
end
@ -249,9 +254,9 @@ describe CeleryScript::Corpus do
it "disallows invalid `point_group` nodes" do
device.auto_sync_transaction do
bad = CeleryScript::AstNode.new(**{
kind: "point_group",
args: { point_group_id: -1 },
})
kind: "point_group",
args: { point_group_id: -1 },
})
check = CeleryScript::Checker.new(bad, corpus, device)
expect(check.valid?).to be false
expect(check.error.message).to eq("Can't find PointGroup with id of -1")

View File

@ -167,13 +167,25 @@ describe Points::Destroy do
def mark_as(resource)
{
kind: "resource_update",
kind: "update_resource",
args: {
resource_type: resource.class.to_s,
resource_id: resource.id,
label: "foo",
value: "bar",
resource: {
kind: "resource",
args: {
resource_type: resource.class.to_s,
resource_id: resource.id,
},
},
},
body: [
{
kind: "pair",
args: {
label: "foo",
value: "bar",
},
},
],
}
end