Farmbot-Web-App/spec/lib/celery_script/corpus_spec.rb

266 lines
11 KiB
Ruby

require "spec_helper"
describe CeleryScript::Corpus do
let(:device) { FactoryBot.create(:device) }
let(:corpus) { Sequence::Corpus }
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,
},
})
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,
},
})
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,
},
},
},
})
check = CeleryScript::Checker.new(bad, corpus, device)
expect(check.valid?).to be_falsey
expect(check.error.message).to include("but got Integer")
expect(check.error.message).to include("'location' within 'move_absolute'")
end
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,
},
})
check = CeleryScript::Checker.new(bad, corpus, device)
expect(check.valid?).to be_falsey
expect(check.error.message).to include("but got String")
end
it "serializes into JSON" do
result = JSON.parse(corpus.to_json)
expect(result["version"]).to eq(Sequence::LATEST_VERSION)
expect(result["args"]).to be_kind_of(Array)
expect(result["nodes"]).to be_kind_of(Array)
keys = result["nodes"].sample.keys.sort.map(&:to_sym)
expect(keys).to eq([:allowed_args, :allowed_body_types, :docs, :name, :tags])
expect(result["args"].sample.keys.sort).to eq(["allowed_values",
"name"])
end
it "Handles message_type validations for version 1" 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": [],
})
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" },
},
],
})
checker = CeleryScript::Checker.new(tree, corpus, device)
expect(checker.error.message).to include("not a valid channel_name")
end
it "validates tool_ids" do
ast = { "kind": "tool", "args": { "tool_id": 0 } }
checker = CeleryScript::Checker.new(CeleryScript::AstNode.new(**ast),
corpus,
device)
expect(checker.valid?).to be(false)
expect(checker.error.message).to include("Tool #0 does not exist.")
end
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)
device_id = checker.tree.args[:resource].args[:resource_id].value
expect(device_id).to eq(device.id)
end
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" } }
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)
msg = "Deprecated `mark_as` detected. Delete it and re-add"
expect(checker.error.message).to eq(msg)
end
it "has enums" do
args = [name = :foo, list = ["bar", "baz"], tpl = ["foo: %s bar: %s"]]
c = CeleryScript::Corpus.new.enum(*args)
json = c.as_json
enums = json.fetch(:enums)
expect(enums.length).to eq(1)
expect(enums.first.fetch("name")).to eq(name)
expect(enums.first.fetch("allowed_values")).to eq(list)
end
it "has values" do
args = [name = :whatever, list = [Symbol, Hash]]
c = CeleryScript::Corpus.new.value(*args)
json = c.as_json
values = json.fetch(:values)
expect(values.length).to eq(1)
expect(values.first.fetch("name")).to eq(name)
expect(values.first.keys.length).to eq(1)
end
it "assigns tags and documentation to nodes" do
c = CeleryScript::Corpus.new.node("wonderful",
args: [],
body: [],
tags: ["great"],
docs: "spectacular")
json = c.as_json
values = json.fetch(:nodes)
expect(values.length).to eq(1)
value = values.first
expect(value.fetch("tags").first).to eq("great")
expect(value.fetch("docs")).to eq("spectacular")
end
it "sets a MAX_WAIT_MS limit for `wait` nodes" do
bad = CeleryScript::AstNode.new(**{
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")
end
it "allows valid `point_group` nodes" do
device.auto_sync_transaction do
pg = PointGroups::Create.run!(device: device,
name: "cs checks",
point_ids: [])
bad = CeleryScript::AstNode.new(**{
kind: "point_group",
args: { point_group_id: pg.id },
})
check = CeleryScript::Checker.new(bad, corpus, device)
expect(check.valid?).to be true
end
end
it "disallows invalid `point_group` nodes" do
device.auto_sync_transaction do
bad = CeleryScript::AstNode.new(**{
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")
end
end
end