Merge pull request #1168 from FarmBot/criteria_groups_cleanup

FarmbotExt Test Suite Cleanup
pull/1169/head
Rick Carlino 2020-03-10 15:47:58 -05:00 committed by GitHub
commit 2f4b0a5754
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 270 additions and 278 deletions

10
COVERAGE.md 100644
View File

@ -0,0 +1,10 @@
# Jan - Mar 2020
| Project | Jan 1 20 | Feb 6 20 | Mar 4 20 |STATUS|
|-----------------------|----------|----------|----------|------|
| farmbot_celery_script | 53.7% | 54.0% | 54.0% |OK |
| farmbot_core | 22.2% | 19.8% | 26.3% |OK |
| farmbot_ext | 53.6% | 52.7% | 38.1% |FIX | !!!
| farmbot_firmware | 13.8% | 56.4% | 62.0% |OK |
| farmbot_os | 22.0% | 27.6% | 45.3% |OK |
| farmbot_telemetry | ??.?% | ??.?% | ??.?% |LATER |

View File

@ -1 +1 @@
9.2.0-rc5
9.2.0

View File

@ -21,10 +21,10 @@ string.
cd $FARMBOT_OS_ROOT_DIRECTORY
git checkout staging
git fetch --all && git reset --hard origin/staging
echo 10.5.6-rc30 > VERSION
# update the CHANGELOG, but DO NOT put the `rc`
# on the semver string.
$EDITOR CHANGELOG.md
echo 10.5.6-rc30 > VERSION
git add CHANGELOG.md VERSION
git commit -m "Release v10.5.6-rc30"
git tag v$(cat VERSION)
@ -84,8 +84,6 @@ done by pushing anything to the master branch:
echo $NEW_VERSION > VERSION
# update CHANGELOG.md
$EDITOR CHANGELOG.md
# update the download link in the readme
$EDITOR README.md
git checkout -b rel-$(cat VERSION)
git commit -am 'Release v$(cat VERSION)'
git push origin rel-$(cat VERSION)

View File

@ -189,7 +189,6 @@ defmodule FarmbotCore.Asset.Command do
# Catch-all use case:
def update(asset_kind, id, params) do
Logger.warn("AssetCommand needs implementation: #{asset_kind}")
mod = as_module!(asset_kind)
case Repo.get_by(mod, id: id) do

View File

@ -94,7 +94,6 @@ defmodule FarmbotCore.AssetMonitor do
Map.put(sub_state, id, updated_at)
is_nil(sub_state[id]) ->
Logger.debug("#{inspect(kind)} #{id} needs to be started")
asset = Repo.preload(asset, AssetWorker.preload(asset))
:ok = AssetSupervisor.start_child(asset) |> assert_result!(asset)
Map.put(sub_state, id, updated_at)

View File

@ -13,7 +13,8 @@ defmodule FarmbotCore.Leds.StubHandler do
def white5(status), do: do_debug(:white, status)
defp do_debug(color, status) do
msg = [IO.ANSI.reset(), "LED STATUS: ",
unless System.get_env("LOG_SILENCE") do
msg = [IO.ANSI.reset(), "LED STATUS: ",
apply(IO.ANSI, color, []),
status_in(status),
to_string(color),
@ -22,7 +23,8 @@ defmodule FarmbotCore.Leds.StubHandler do
status_out(status),
IO.ANSI.reset()
]
IO.puts(msg)
IO.puts(msg)
end
end
defp status_in(:slow_blink), do: IO.ANSI.blink_slow()

View File

@ -23,7 +23,9 @@ defmodule FarmbotCore.LogExecutor do
do: level,
else: :info
Elixir.Logger.bare_log(logger_level, log, logger_meta)
unless System.get_env("LOG_SILENCE") do
Elixir.Logger.bare_log(logger_level, log, logger_meta)
end
log
end
end

View File

@ -23,3 +23,4 @@ erl_crash.dump
farmbot_ext-*.tar
*.sqlite3
*.coverdata

View File

@ -11,3 +11,4 @@ config :farmbot_celery_script, FarmbotCeleryScript.SysCalls,
import_config "ecto.exs"
import_config "farmbot_core.exs"
import_config "lagger.exs"
import_config "test.exs"

View File

@ -0,0 +1,5 @@
use Mix.Config
if Mix.env() == :test do
config :farmbot_ext, FarmbotExt, children: []
end

View File

@ -0,0 +1,6 @@
{
"coverage_options": {
"treat_no_relevant_lines_as_covered": true,
"minimum_coverage": 6.5
}
}

View File

@ -1,19 +1,18 @@
defmodule FarmbotExt do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@moduledoc false
use Application
def start(_type, _args) do
# List all child processes to be supervised
children = [
FarmbotExt.Bootstrap
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: __MODULE__]
Supervisor.start_link(children, opts)
Supervisor.start_link(children(), opts)
end
# This only exists because I was getting too many crashed
# supervisor reports in the test suite (distraction from
# real test failures).
def children do
config = Application.get_env(:farmbot_ext, __MODULE__) || []
Keyword.get(config, :children, [FarmbotExt.Bootstrap])
end
end

View File

@ -0,0 +1,46 @@
defmodule FarmbotExt.AMQP.AutoSyncAssetHandler do
require Logger
alias FarmbotCore.{Asset, BotState, Leds}
alias FarmbotExt.API.{EagerLoader}
# Sync messgages about these assets
# should not be cached. They need to be applied
# in real time.
@no_cache_kinds ~w(
Device
FbosConfig
FirmwareConfig
FarmwareEnv
FarmwareInstallation
)
def handle_asset(asset_kind, id, params) do
if Asset.Query.auto_sync?() do
:ok = BotState.set_sync_status("syncing")
_ = Leds.green(:really_fast_blink)
Asset.Command.update(asset_kind, id, params)
:ok = BotState.set_sync_status("synced")
_ = Leds.green(:solid)
else
cache_sync(asset_kind, id, params)
end
end
def cache_sync(kind, id, params) when kind in @no_cache_kinds do
:ok = Asset.Command.update(kind, id, params)
end
def cache_sync(_, _, nil) do
:ok = BotState.set_sync_status("sync_now")
_ = Leds.green(:slow_blink)
end
def cache_sync(asset_kind, id, params) do
Logger.info("Autocaching sync #{asset_kind} #{id} #{inspect(params)}")
changeset = Asset.Command.new_changeset(asset_kind, id, params)
:ok = EagerLoader.cache(changeset)
:ok = BotState.set_sync_status("sync_now")
_ = Leds.green(:slow_blink)
end
end

View File

@ -8,14 +8,13 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
use GenServer
use AMQP
alias FarmbotCore.{Asset, BotState, JSON, Leds}
alias FarmbotExt.AMQP.ConnectionWorker
alias FarmbotExt.API.{EagerLoader, Preloader}
require Logger
require FarmbotCore.Logger
require FarmbotTelemetry
alias FarmbotCore.{Asset, BotState, JSON, Leds}
alias FarmbotExt.AMQP.{ConnectionWorker, AutoSyncAssetHandler}
alias FarmbotExt.API.{EagerLoader, Preloader}
# The API dispatches messages for other resources, but these
# are the only ones that Farmbot needs to sync.
@known_kinds ~w(
@ -35,18 +34,8 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
Tool
)
# Sync messgaes about these assets
# should not be cached. They need to be applied
# in real time.
@no_cache_kinds ~w(
Device
FbosConfig
FirmwareConfig
FarmwareEnv
FarmwareInstallation
)
defstruct [:conn, :chan, :jwt, :preloaded]
alias __MODULE__, as: State
@doc "Gets status of auto_sync connection for diagnostics / tests."
@ -68,12 +57,15 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
def terminate(reason, state) do
FarmbotCore.Logger.error(1, "Disconnected from AutoSync channel: #{inspect(reason)}")
# If a channel was still open, close it.
if state.chan, do: ConnectionWorker.close_channel(state.chan)
if state.chan do
ConnectionWorker.close_channel(state.chan)
end
try do
EagerLoader.Supervisor.drop_all_cache()
catch
_, _ -> :ok
_, _ ->
:ok
end
end
@ -103,6 +95,7 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
end
def handle_info(:connect, state) do
# THIS IS WHERE state.chan GETS SET
result = ConnectionWorker.maybe_connect_autosync(state.jwt.bot)
compute_reply_from_amqp_state(state, result)
end
@ -134,13 +127,11 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
case String.split(key, ".") do
["bot", ^device, "sync", asset_kind, id_str] when asset_kind in @known_kinds ->
id = data["id"] || String.to_integer(id_str)
_ = handle_asset(asset_kind, id, body)
["bot", ^device, "sync", asset_kind, _id_str] ->
Logger.warn("Unknown syncable asset: #{asset_kind}")
_ = AutoSyncAssetHandler.handle_asset(asset_kind, id, body)
_ ->
Logger.info("ignoring route: #{key}")
""
# Logger.info("ignoring route: #{key}")
end
:ok = ConnectionWorker.rpc_reply(chan, device, label)
@ -158,36 +149,6 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
{:reply, reply, state}
end
def handle_asset(asset_kind, id, params) do
if Asset.Query.auto_sync?() do
:ok = BotState.set_sync_status("syncing")
_ = Leds.green(:really_fast_blink)
# Logger.info "Syncing #{asset_kind} #{id} #{inspect(params)}"
Asset.Command.update(asset_kind, id, params)
:ok = BotState.set_sync_status("synced")
_ = Leds.green(:solid)
else
cache_sync(asset_kind, id, params)
end
end
def cache_sync(kind, id, params) when kind in @no_cache_kinds do
:ok = Asset.Command.update(kind, id, params)
end
def cache_sync(_, _, nil) do
:ok = BotState.set_sync_status("sync_now")
_ = Leds.green(:slow_blink)
end
def cache_sync(asset_kind, id, params) do
Logger.info("Autocaching sync #{asset_kind} #{id} #{inspect(params)}")
changeset = Asset.Command.new_changeset(asset_kind, id, params)
:ok = EagerLoader.cache(changeset)
:ok = BotState.set_sync_status("sync_now")
_ = Leds.green(:slow_blink)
end
defp compute_reply_from_amqp_state(state, %{conn: conn, chan: chan}) do
{:noreply, %{state | conn: conn, chan: chan}}
end

View File

@ -66,7 +66,6 @@ defmodule FarmbotExt.API.EagerLoader do
* a remote `id` field.
"""
def cache(%Changeset{data: %module{}} = changeset) do
Logger.info("Caching #{inspect(changeset)}")
id = Changeset.get_field(changeset, :id)
updated_at = Changeset.get_field(changeset, :updated_at)
id || change_error(changeset, "Can't cache a changeset with no :id attribute")

View File

@ -24,7 +24,7 @@ defmodule FarmbotExt.API.Preloader do
with {:ok, sync_changeset} <- API.get_changeset(Sync),
sync_changeset <- Reconciler.sync_group(sync_changeset, SyncGroup.group_0()) do
FarmbotCore.Logger.success(3, "Successfully preloaded resources.")
maybe_auto_sync(sync_changeset, Query.auto_sync?())
maybe_auto_sync(sync_changeset, Query.auto_sync?() || false)
end
end

View File

@ -51,8 +51,6 @@ defmodule FarmbotExt.Bootstrap do
end
def try_auth(email, server, password, _secret) do
Logger.debug("using password to auth")
with {:ok, tkn} <- Authorization.authorize_with_password(email, password, server),
_ <- update_config_value(:string, "authorization", "token", tkn),
{:ok, pid} <- Supervisor.start_child(FarmbotExt, Bootstrap.Supervisor) do

View File

@ -1,6 +1,6 @@
defmodule FarmbotExt.Bootstrap.Supervisor do
@moduledoc """
Supervisor responsible for starting all
Supervisor responsible for starting all
the tasks and processes that require authentication.
"""
use Supervisor
@ -20,7 +20,6 @@ defmodule FarmbotExt.Bootstrap.Supervisor do
FarmbotExt.Bootstrap.DropPasswordTask
]
opts = [strategy: :one_for_one]
Supervisor.init(children, opts)
Supervisor.init(children, strategy: :one_for_one)
end
end

View File

@ -1,18 +1,15 @@
defmodule AutoSyncChannelTest do
require Helpers
use ExUnit.Case, async: true
use Mimic
alias FarmbotExt.AMQP.AutoSyncChannel
use ExUnit.Case
use Mimic
alias FarmbotCore.JSON
alias FarmbotCore.Asset.{
Query,
Command,
Sync
alias FarmbotExt.{
AMQP.ConnectionWorker,
API.Preloader,
JWT
}
alias FarmbotExt.{JWT, API, AMQP.ConnectionWorker}
setup :verify_on_exit!
setup :set_mimic_global
@ -35,203 +32,127 @@ defmodule AutoSyncChannelTest do
"eXTEVkqw7rved84ogw6EKBSFCVqwRA-NKWLpPMV_q7fRwiEG" <>
"Wj7R-KZqRweALXuvCLF765E6-ENxA"
def pretend_network_returned(fake_value) do
def generate_pid do
apply_default_mocks()
jwt = JWT.decode!(@fake_jwt)
test_pid = self()
expect(Query, :auto_sync?, 2, fn -> false end)
expect(API, :get_changeset, fn _module ->
send(test_pid, :preload_all_called)
changeset = Sync.changeset(%Sync{}, %{})
{:ok, changeset}
end)
expect(ConnectionWorker, :maybe_connect_autosync, fn jwt ->
send(test_pid, {:maybe_connect_called, jwt})
fake_value
end)
stub(ConnectionWorker, :close_channel, fn _ ->
send(test_pid, :close_channel_called)
:ok
end)
stub(ConnectionWorker, :rpc_reply, fn chan, jwt_dot_bot, label ->
send(test_pid, {:rpc_reply_called, chan, jwt_dot_bot, label})
:ok
end)
{:ok, pid} = AutoSyncChannel.start_link([jwt: jwt], [])
Map.merge(%{pid: pid}, AutoSyncChannel.network_status(pid))
pid
end
def under_normal_conditions() do
fake_con = %{fake: :conn}
fake_chan = %{fake: :chan}
pretend_network_returned(%{conn: fake_con, chan: fake_chan})
def apply_default_mocks do
ok1 = fn _ -> :whatever end
stub(FarmbotExt.API.EagerLoader.Supervisor, :drop_all_cache, fn -> :ok end)
stub(ConnectionWorker, :close_channel, ok1)
stub(ConnectionWorker, :maybe_connect_autosync, fn _ ->
%{conn: %{fake_conn: true}, chan: %{fake_chan: true}}
end)
end
test "network returns `nil`" do
results = pretend_network_returned(nil)
%{conn: has_conn, chan: has_chan, preloaded: is_preloaded} = results
assert has_chan == nil
assert has_conn == nil
assert is_preloaded
def ensure_response_to(msg) do
# Not much to check here other than matching clauses.
# AMQP lib handles most all of this.
expect(Preloader, :preload_all, 1, fn -> :ok end)
pid = generate_pid()
send(pid, msg)
Process.sleep(5)
end
test "network returns unexpected object (probably an error)" do
results = pretend_network_returned({:something, :else})
%{conn: has_conn, chan: has_chan, preloaded: is_preloaded} = results
test "basic_cancel", do: ensure_response_to({:basic_cancel, :anything})
test "basic_cancel_ok", do: ensure_response_to({:basic_cancel_ok, :anything})
test "basic_consume_ok", do: ensure_response_to({:basic_consume_ok, :anything})
assert has_chan == nil
assert has_conn == nil
assert is_preloaded
test "init / terminate - auto_sync enabled" do
expect(Preloader, :preload_all, 1, fn -> :ok end)
expect(FarmbotCore.Asset.Query, :auto_sync?, 1, fn -> true end)
expect(FarmbotCore.BotState, :set_sync_status, 1, fn "synced" -> :ok end)
expect(FarmbotCore.Leds, :green, 2, fn
:solid ->
:ok
:really_fast_blink ->
:ok
end)
# Helpers.expect_log("Failed to connect to AutoSync channel: :whatever")
# Helpers.expect_log("Disconnected from AutoSync channel: :normal")
pid = generate_pid()
assert %{chan: nil, conn: nil, preloaded: true} == AutoSyncChannel.network_status(pid)
GenServer.stop(pid, :normal)
end
test "catch-all clause for inbound AMQP messages" do
fake_con = %{fake: :conn}
fake_chan = %{fake: :chan}
fake_response = %{conn: fake_con, chan: fake_chan}
test "init / terminate - auto_sync disabled" do
expect(Preloader, :preload_all, 1, fn -> :ok end)
expect(FarmbotCore.Asset.Query, :auto_sync?, 1, fn -> false end)
expect(FarmbotCore.BotState, :set_sync_status, 1, fn "sync_now" -> :ok end)
%{pid: pid} = pretend_network_returned(fake_response)
expect(FarmbotCore.Leds, :green, 2, fn
:slow_blink ->
:ok
payload =
JSON.encode!(%{
args: %{label: "xyz"}
:really_fast_blink ->
:ok
end)
Helpers.expect_log("Disconnected from AutoSync channel: :normal")
pid = generate_pid()
assert %{chan: nil, conn: nil, preloaded: true} == AutoSyncChannel.network_status(pid)
GenServer.stop(pid, :normal)
end
test "init / terminate - auto_sync error" do
Helpers.expect_log("Error preloading. #{inspect("a test example")}")
Helpers.expect_log("Disconnected from AutoSync channel: :normal")
expect(FarmbotCore.BotState, :set_sync_status, 1, fn "sync_error" -> :ok end)
expect(Preloader, :preload_all, 1, fn -> {:error, "a test example"} end)
expect(FarmbotCore.Leds, :green, 2, fn
:slow_blink ->
:ok
:really_fast_blink ->
:ok
end)
pid = generate_pid()
assert %{chan: nil, conn: nil, preloaded: false} == AutoSyncChannel.network_status(pid)
GenServer.stop(pid, :normal)
end
test "delivery of auto sync messages" do
expect(Preloader, :preload_all, 1, fn -> :ok end)
expect(ConnectionWorker, :rpc_reply, 1, fn chan, device, label ->
assert chan == %{fake_chan: true}
assert device == "device_15"
assert label == "thisismylabelinatestsuite"
:ok
end)
key = "bot.device_15.sync.Device.46"
{:ok, payload} =
FarmbotCore.JSON.encode(%{
"id" => 46,
"args" => %{
"label" => "thisismylabelinatestsuite"
},
"body" => %{name: "This is my bot"}
})
send(pid, {:basic_deliver, payload, %{routing_key: "WRONG!"}})
assert_receive {:rpc_reply_called, %{fake: :chan}, "device_15", "xyz"}
end
test "wont autosync unknown assets" do
fake_con = %{fake: :conn}
fake_chan = %{fake: :chan}
fake_response = %{conn: fake_con, chan: fake_chan}
%{pid: pid} = pretend_network_returned(fake_response)
payload =
JSON.encode!(%{
args: %{label: "xyz"}
})
send(pid, {:basic_deliver, payload, %{routing_key: "bot.device_15.sync.SavedGarden.999"}})
assert_receive {:rpc_reply_called, %{fake: :chan}, "device_15", "xyz"}
end
test "ignores asset deletion when auto_sync is off" do
%{pid: pid} = under_normal_conditions()
test_pid = self()
payload = '{"args":{"label":"foo"}}'
key = "bot.device_15.sync.Device.999"
stub(Query, :auto_sync?, fn ->
send(test_pid, :called_auto_sync?)
false
end)
send(pid, {:basic_deliver, payload, %{routing_key: key}})
assert_receive :called_auto_sync?
end
test "handles Device assets" do
%{pid: pid} = under_normal_conditions()
test_pid = self()
payload = '{"args":{"label":"foo"},"body":{}}'
key = "bot.device_15.sync.Device.999"
stub(Query, :auto_sync?, fn -> true end)
stub(Command, :update, fn x, y, z ->
send(test_pid, {:update_called, x, y, z})
:ok
end)
send(pid, {:basic_deliver, payload, %{routing_key: key}})
assert_receive {:update_called, "Device", 999, %{}}
end
def simple_asset_test_singleton(module_name) do
%{pid: pid} = under_normal_conditions()
test_pid = self()
payload = '{"args":{"label":"foo"},"body":{"foo": "bar"}}'
key = "bot.device_15.sync.#{module_name}.999"
stub(Query, :auto_sync?, fn -> true end)
stub(Command, :update, fn x, y, z ->
send(test_pid, {:update_called, x, y, z})
:ok
end)
stub(Command, :update, fn x, y, z ->
send(test_pid, {:update_called, x, y, z})
:ok
end)
pid = generate_pid()
# We need the process to be preloaded for these tests to work:
%{preloaded: true} = AutoSyncChannel.network_status(pid)
send(pid, {:basic_deliver, payload, %{routing_key: key}})
assert_receive {:update_called, ^module_name, 999, %{"foo" => "bar"}}
end
test "handles auto_sync of 'no_cache' when auto_sync is false" do
test_pid = self()
%{pid: pid} = under_normal_conditions()
key = "bot.device_15.sync.FbosConfig.999"
payload = '{"args":{"label":"foo"},"body":{"foo": "bar"}}'
stub(Query, :auto_sync?, fn ->
send(test_pid, :called_auto_sync?)
false
end)
stub(Command, :update, fn kind, id, params ->
send(test_pid, {:update_called, kind, id, params})
expect(FarmbotExt.AMQP.AutoSyncAssetHandler, :handle_asset, fn kind, id, body ->
assert kind == "Device"
assert id == 46
assert body == %{"name" => "This is my bot"}
:ok
end)
send(pid, {:basic_deliver, payload, %{routing_key: key}})
assert_receive :called_auto_sync?
assert_receive {:update_called, "FbosConfig", 999, %{"foo" => "bar"}}
end
test "auto_sync disabled, resource not in @cache_kinds" do
under_normal_conditions()
stub(Query, :auto_sync?, fn ->
false
end)
stub(Command, :new_changeset, fn _kind, _id, _params ->
:ok
end)
end
test "handles FbosConfig", do: simple_asset_test_singleton("FbosConfig")
test "handles FirmwareConfig", do: simple_asset_test_singleton("FirmwareConfig")
test "handles FarmwareEnv", do: simple_asset_test_plural("FarmwareEnv")
test "handles FarmwareInstallation", do: simple_asset_test_plural("FarmwareInstallation")
defp simple_asset_test_plural(module_name) do
%{pid: pid} = under_normal_conditions()
test_pid = self()
payload = '{"args":{"label":"foo"},"body":{"foo": "bar"}}'
key = "bot.device_15.sync.#{module_name}.999"
stub(Query, :auto_sync?, fn -> true end)
stub(Command, :update, fn x, y, z ->
send(test_pid, {:update_called, x, y, z})
:ok
end)
send(pid, {:basic_deliver, payload, %{routing_key: key}})
assert_receive {:update_called, ^module_name, 999, %{"foo" => "bar"}}
Process.sleep(1000)
end
end

View File

@ -0,0 +1,25 @@
defmodule FarmbotExt.AMQP.BotStateChannelTest do
use ExUnit.Case
use Mimic
# alias FarmbotExt.AMQP.BotStateChannel
# alias FarmbotCore.BotState
setup :verify_on_exit!
setup :set_mimic_global
defmodule FakeState do
defstruct conn: %{fake: :conn}, chan: "fake_chan_", jwt: "fake_jwt_", cache: %{fake: :cache}
end
test "terminate" do
expected = "Disconnected from BotState channel: \"foo\""
expect(AMQP.Channel, :close, 1, fn "fake_chan_" -> :ok end)
expect(FarmbotCore.LogExecutor, :execute, 1, fn log ->
assert log.message == expected
end)
FarmbotExt.AMQP.BotStateChannel.terminate("foo", %FakeState{})
end
end

View File

@ -0,0 +1,12 @@
defmodule FarmbotExt.API.ViewTest do
use ExUnit.Case
def render(%{ok: :ok}) do
:yep
end
test "render/2" do
result = FarmbotExt.API.View.render(__MODULE__, %{ok: :ok})
assert :yep == result
end
end

View File

@ -1,14 +1,33 @@
Application.ensure_all_started(:farmbot)
timeout = System.get_env("EXUNIT_TIMEOUT")
Mimic.copy(AMQP.Channel)
Mimic.copy(FarmbotCeleryScript.SysCalls.Stubs)
Mimic.copy(FarmbotCore.Asset.Command)
Mimic.copy(FarmbotCore.Asset.Query)
Mimic.copy(FarmbotCore.BotState)
Mimic.copy(FarmbotCore.Leds)
Mimic.copy(FarmbotCore.LogExecutor)
Mimic.copy(FarmbotExt.AMQP.ConnectionWorker)
Mimic.copy(FarmbotExt.API.EagerLoader.Supervisor)
Mimic.copy(FarmbotExt.API.Preloader)
Mimic.copy(FarmbotExt.API)
Mimic.copy(FarmbotExt.AMQP.AutoSyncAssetHandler)
timeout = System.get_env("EXUNIT_TIMEOUT")
System.put_env("LOG_SILENCE", "true")
if timeout do
ExUnit.start(assert_receive_timeout: String.to_integer(timeout))
else
ExUnit.start()
end
defmodule Helpers do
defmacro expect_log(message) do
quote do
expect(FarmbotCore.LogExecutor, :execute, fn log ->
assert log.message == unquote(message)
end)
end
end
end

View File

@ -300,20 +300,10 @@ defmodule FarmbotFirmware do
name: state.reset
) do
{:ok, pid} ->
Logger.debug(
"Firmware reset #{state.reset} started. #{
inspect(state.transport_args)
}"
)
{:noreply, %{state | reset_pid: pid}}
# TODO(Rick): I have no idea what's going on here.
{:error, {:already_started, pid}} ->
Logger.debug(
"Firmware reset complete. #{inspect(state.transport_args)}"
)
{:noreply, %{state | reset_pid: pid}}
error ->