From 096cbccfd89c870ae615b69b8a7504aed21053f5 Mon Sep 17 00:00:00 2001 From: Adam Zaninovich Date: Tue, 12 Sep 2017 01:24:57 -0700 Subject: [PATCH 1/2] it runs with multiple adapters but tests need fixing --- lib/alice/adapter.ex | 20 +++-------- lib/alice/adapter/supervisor.ex | 15 ++++++++ lib/alice/adapters/console.ex | 6 ++-- lib/alice/adapters/noop.ex | 9 +++-- lib/alice/bot.ex | 63 ++++++++++++++++++++++----------- lib/alice/bot/config.ex | 22 ++++++------ lib/alice/bot/supervisor.ex | 15 ++++---- lib/alice/handler/supervisor.ex | 15 +++++--- lib/alice/message.ex | 19 +++++----- lib/alice/supervisor.ex | 19 +++++----- lib/alice/test/test_bot.ex | 2 +- 11 files changed, 124 insertions(+), 81 deletions(-) create mode 100644 lib/alice/adapter/supervisor.ex diff --git a/lib/alice/adapter.ex b/lib/alice/adapter.ex index 64395f2..b5796f3 100644 --- a/lib/alice/adapter.ex +++ b/lib/alice/adapter.ex @@ -15,8 +15,8 @@ defmodule Alice.Adapter do @callback reply(bot, msg) :: term @doc false - def start_link(module, opts) do - GenServer.start_link(module, {self(), opts}) + def start_link(adapter_module, bot_pid, opts) do + GenServer.start_link(adapter_module, {bot_pid, opts}) end @doc false @@ -25,13 +25,8 @@ defmodule Alice.Adapter do use GenServer @behaviour Alice.Adapter - def reply(bot, %Alice.Message{} = msg) do - GenServer.cast(bot, {:reply, msg}) - end - - @doc false - def start_link(bot, opts) do - Alice.Adapter.start_link(__MODULE__, opts) + def reply(pid, %Alice.Message{} = msg) do + GenServer.cast(pid, {:reply, msg}) end @doc false @@ -46,12 +41,7 @@ defmodule Alice.Adapter do :ok end - @doc false - defmacro __before_compile__(_env) do - :ok - end - - defoverridable [__before_compile__: 1, reply: 2] + defoverridable [reply: 2] end end end diff --git a/lib/alice/adapter/supervisor.ex b/lib/alice/adapter/supervisor.ex new file mode 100644 index 0000000..f433a2a --- /dev/null +++ b/lib/alice/adapter/supervisor.ex @@ -0,0 +1,15 @@ +defmodule Alice.Adapter.Supervisor do + @moduledoc """ + Supervises any Alice.Adapter process that are started. + """ + + use Supervisor + + def start_link(_) do + Supervisor.start_link([ + worker(Alice.Adapter, [], restart: :transient) + ], strategy: :simple_one_for_one, name: __MODULE__) + end + + def init(_), do: :ok +end diff --git a/lib/alice/adapters/console.ex b/lib/alice/adapters/console.ex index 2bd0f60..8d427f2 100644 --- a/lib/alice/adapters/console.ex +++ b/lib/alice/adapters/console.ex @@ -44,10 +44,10 @@ defmodule Alice.Adapters.Console do ref: make_ref(), bot: bot, text: text, - type: "chat", room: "console", - user: user + adapter: {__MODULE__, self()}, + type: "chat", + user: %Alice.User{id: "console", name: user} } end end - diff --git a/lib/alice/adapters/noop.ex b/lib/alice/adapters/noop.ex index 25788fe..a21fbc3 100644 --- a/lib/alice/adapters/noop.ex +++ b/lib/alice/adapters/noop.ex @@ -20,16 +20,19 @@ defmodule Alice.Adapters.NoOp do end @doc false - def handle_cast({:reply, _msg}, bot) do + def handle_cast({:reply, msg}, bot) do + IO.puts "got reply message #{inspect msg} from bot #{inspect bot}" {:noreply, bot} end @doc false def handle_info(:connected, bot) do :ok = Alice.Bot.handle_connect(bot) + IO.puts "NoOp connected" {:noreply, bot} end def handle_info({:message, msg}, bot) do + IO.puts "received message #{inspect msg} for bot #{inspect bot}" Alice.Bot.handle_in(bot, make_msg(bot, msg)) {:noreply, bot} end @@ -39,8 +42,10 @@ defmodule Alice.Adapters.NoOp do ref: make_ref(), bot: bot, text: msg, + room: "noop", + adapter: {__MODULE__, self()}, type: "chat", - user: "user" + user: %Alice.User{id: "user", name: "user"} } end end diff --git a/lib/alice/bot.ex b/lib/alice/bot.ex index 87442c2..479d3cf 100644 --- a/lib/alice/bot.ex +++ b/lib/alice/bot.ex @@ -26,18 +26,16 @@ defmodule Alice.Bot do *`handers` - list of handlers to register """ - defstruct adapter: nil, - name: nil, + defstruct name: nil, + adapters: [], handlers: [], - handler_sup: [], opts: [] - def new(adapter, name, handlers, handler_sup, opts) do + def new(name, adapters, handlers, opts) do %__MODULE__{ - adapter: adapter, name: name, + adapters: adapters, handlers: handlers, - handler_sup: handler_sup, opts: opts } end @@ -106,8 +104,7 @@ defmodule Alice.Bot do config = Alice.Bot.Config.init_config(__MODULE__, opts) - @adapter config.adapter - @before_compile config.adapter + @adapters config.adapters @config config.bot_config @log_level config.bot_config[:log_level] @otp_app config.otp_app @@ -134,14 +131,13 @@ defmodule Alice.Bot do Logger.unquote(@log_level)(fn()-> msg end, []) end - def __adapter__, do: @adapter + def __adapters__, do: @adapters def init({bot_module, opts}) do with {handlers, opts} <- register_handlers(bot_module.bot_config(opts)), - {:ok, adapter} <- @adapter.start_link(bot_module, opts), - {:ok, handler_sup} <- Alice.Handler.Supervisor.start_link(), + {adapters, opts} <- register_adapters(opts), name <- opts[:name], - bot <- Alice.Bot.new(adapter, name, handlers, handler_sup, opts) do + bot <- Alice.Bot.new(name, adapters, handlers, opts) do {:ok, bot} else _ -> {:stop, :shutdown} @@ -154,6 +150,12 @@ defmodule Alice.Bot do {handlers, opts} end + defp register_adapters(opts) do + {adapters, opts} = Keyword.pop(opts, :adapters, []) + GenServer.cast(self(), {:register_adapters, adapters, opts}) + {adapters, opts} + end + def handle_connect(state) do {:ok, state} end @@ -172,9 +174,9 @@ defmodule Alice.Bot do def handle_call(:name, _from, %{name: name} = state) do {:reply, name, state} end - def handle_call(:handler_processes, _from, %{handler_sup: sup} = state) do + def handle_call(:handler_processes, _from, state) do handler_processes = - sup + Alice.Handler.Supervisor |> Supervisor.which_children() |> Enum.map(fn({_,pid,_,_}) -> {_,[{_,{mod,_,_}}|_]} = Process.info(pid, :dictionary) @@ -199,14 +201,15 @@ defmodule Alice.Bot do end end - def handle_cast({:reply, msg}, %{adapter: adapter} = state) do - @adapter.reply(adapter, msg) + def handle_cast({:reply, msg}, state) do + {adapter_mod, adapter_pid} = msg.adapter + adapter_mod.reply(adapter_pid, msg) {:noreply, state} end def handle_cast({:handle_in, msg}, state) do case handle_in(msg, state) do {:dispatch, %Alice.Message{} = msg, state} -> - handlers = Supervisor.which_children(state.handler_sup) + handlers = Supervisor.which_children(Alice.Handler.Supervisor) Alice.Handler.dispatch(msg, handlers) {:noreply, state} @@ -225,13 +228,31 @@ defmodule Alice.Bot do {:noreply, state} -> {:noreply, state} end end - def handle_cast({:register_handlers, handlers}, %{name: name, handler_sup: sup} = state) do + def handle_cast({:register_handlers, handlers}, %{name: name} = state) do handlers = ensure_builtin_handlers(handlers) - Enum.each(handlers, fn(handler) -> - Supervisor.start_child(sup, [handler, {name, self()}]) - end) + for handler <- handlers do + {:ok, pid} = Supervisor.start_child(Alice.Handler.Supervisor, [handler, {name, self()}]) + Process.register(pid, handler) + end {:noreply, %{state | handlers: handlers}} end + def handle_cast({:register_adapters, adapters, opts}, state) do + adapters = for adapter <- ensure_adapter(adapters) do + case adapter do + {name, mod} -> + {:ok, pid} = Supervisor.start_child(Alice.Adapter.Supervisor, [mod, self(), opts]) + Process.register(pid, name) + mod + mod when is_atom(mod) -> + {:ok, _pid} = Supervisor.start_child(Alice.Adapter.Supervisor, [mod, self(), opts]) + mod + end + end + {:noreply, %{state | adapters: adapters}} + end + + defp ensure_adapter([]), do: [{:default_noop, Alice.Adapters.NoOp}] + defp ensure_adapter(adapters), do: adapters defp ensure_builtin_handlers(handlers) when is_list(handlers) do Enum.reduce(Alice.Handler.builtins(), handlers, fn(builtin, acc) -> diff --git a/lib/alice/bot/config.ex b/lib/alice/bot/config.ex index c7e2ef7..514e56b 100644 --- a/lib/alice/bot/config.ex +++ b/lib/alice/bot/config.ex @@ -1,15 +1,15 @@ defmodule Alice.Bot.Config do - defstruct [:otp_app, :adapter, :bot_config] + defstruct [:otp_app, :adapters, :bot_config] - def new(otp_app, adapter, bot_config) do - %__MODULE__{otp_app: otp_app, adapter: adapter, bot_config: bot_config} + def new(otp_app, adapters, bot_config) do + %__MODULE__{otp_app: otp_app, adapters: adapters, bot_config: bot_config} end def init_config(bot_module, opts_from_use) do otp_app = opts_from_use[:otp_app] bot_config = get_bot_config(bot_module, otp_app, opts_from_use) - adapter = ensure_adapter!(opts_from_use, bot_config) - new(otp_app, adapter, bot_config) + adapters = get_adapters(opts_from_use, bot_config) + new(otp_app, adapters, bot_config) end def get_bot_config(bot_module, otp_app, opts_from_use) do @@ -34,10 +34,12 @@ defmodule Alice.Bot.Config do |> Keyword.merge(opts_from_use) end - defp ensure_adapter!(opts, config) do - adapter = opts[:adapter] || config[:adapter] || :no_adapter - ensure_adapter!(adapter) + defp get_adapters(opts, config) do + with [] <- opts[:adapters], + [] <- config[:adapters] do + [] + else + adapters -> adapters + end end - defp ensure_adapter!(:no_adapter), do: raise ArgumentError, "please configure an adapter" - defp ensure_adapter!(adapter), do: adapter end diff --git a/lib/alice/bot/supervisor.ex b/lib/alice/bot/supervisor.ex index 7af5f72..0d366bf 100644 --- a/lib/alice/bot/supervisor.ex +++ b/lib/alice/bot/supervisor.ex @@ -1,14 +1,15 @@ defmodule Alice.Bot.Supervisor do - @moduledoc false + @moduledoc """ + Supervises any Alice.Bot process that are started. + """ use Supervisor - def start_link(opts \\ []) do - Supervisor.start_link(__MODULE__, :ok, opts) + def start_link(_) do + Supervisor.start_link([ + worker(Alice.Bot, [], restart: :transient) + ], strategy: :simple_one_for_one, name: __MODULE__) end - def init(:ok) do - [worker(Alice.Bot, [], restart: :transient)] - |> supervise(strategy: :simple_one_for_one) - end + def init(_), do: :ok end diff --git a/lib/alice/handler/supervisor.ex b/lib/alice/handler/supervisor.ex index c087b2c..252b29f 100644 --- a/lib/alice/handler/supervisor.ex +++ b/lib/alice/handler/supervisor.ex @@ -1,10 +1,15 @@ defmodule Alice.Handler.Supervisor do - def start_link do - import Supervisor.Spec, warn: false + @moduledoc """ + Supervises any Alice.Handler process that are started. + """ - children = [ + use Supervisor + + def start_link(_) do + Supervisor.start_link([ worker(Alice.Handler, [], restart: :transient) - ] - Supervisor.start_link(children, strategy: :simple_one_for_one) + ], strategy: :simple_one_for_one, name: __MODULE__) end + + def init(_), do: :ok end diff --git a/lib/alice/message.ex b/lib/alice/message.ex index ea32f1f..88ee263 100644 --- a/lib/alice/message.ex +++ b/lib/alice/message.ex @@ -1,20 +1,22 @@ defmodule Alice.Message do @moduledoc "Alice message" - @type captures :: list | map - @type private :: map - @type ref :: reference - @type bot :: pid - @type room :: binary - @type text :: binary - @type type :: binary - @type user :: Alice.User.t + @type captures :: map() + @type private :: map() + @type ref :: reference() + @type bot :: pid() + @type adapter :: {module(), pid()} + @type room :: binary() + @type text :: binary() + @type type :: binary() + @type user :: Alice.User.t() @type t :: %__MODULE__{ captures: captures, private: private, ref: ref, bot: bot, + adapter: adapter, room: room, text: text, type: type, @@ -25,6 +27,7 @@ defmodule Alice.Message do private: %{}, ref: nil, bot: nil, + adapter: nil, room: nil, text: nil, type: nil, diff --git a/lib/alice/supervisor.ex b/lib/alice/supervisor.ex index 0c6d79d..7e90a31 100644 --- a/lib/alice/supervisor.ex +++ b/lib/alice/supervisor.ex @@ -1,17 +1,18 @@ defmodule Alice.Supervisor do - @moduledoc false + @moduledoc """ + The main Supervisor in an Alice bot's hierarchy. Starts + and supervises the Bot, Handler, and Adapter supervisors. + """ use Supervisor def start_link do - Supervisor.start_link(__MODULE__, :ok, name: __MODULE__) + Supervisor.start_link([ + Alice.Adapter.Supervisor, + Alice.Handler.Supervisor, + Alice.Bot.Supervisor, + ], strategy: :one_for_one, name: __MODULE__) end - def init(:ok) do - children = [ - supervisor(Alice.Bot.Supervisor, [[name: Alice.Bot.Supervisor]]), - ] - - supervise(children, strategy: :one_for_one) - end + def init(_), do: :ok end diff --git a/lib/alice/test/test_bot.ex b/lib/alice/test/test_bot.ex index e55a006..f0aa72a 100644 --- a/lib/alice/test/test_bot.ex +++ b/lib/alice/test/test_bot.ex @@ -1,7 +1,7 @@ Code.ensure_compiled(Alice.Adapters.Test) defmodule Alice.TestBot do - use Alice.Bot, otp_app: :alice, adapter: Alice.Adapters.Test + use Alice.Bot, otp_app: :alice, adapters: [Alice.Adapters.Test] def handle_connect(%{name: name} = state) do if :undefined = :global.whereis_name(name) do From 6ec4aaaeb1879acecd0ec0097b9544a5bbfdf52a Mon Sep 17 00:00:00 2001 From: Adam Zaninovich Date: Tue, 12 Sep 2017 23:44:36 -0700 Subject: [PATCH 2/2] fixes tests --- lib/alice.ex | 13 +++++++++-- lib/alice/adapters/test.ex | 2 +- lib/alice/bot.ex | 4 ++-- lib/alice/test/bot_case.ex | 21 ++++++++++------- lib/alice/test/test_bot.ex | 11 ++++----- lib/alice/utils/process_utils.ex | 25 ++++++++++++++++++++ test/alice/adapters/console_test.exs | 18 +++++++++----- test/alice/bot/config_test.exs | 19 ++++----------- test/alice/bot_test.exs | 11 ++++----- test/alice/utils/process_utils_test.exs | 31 +++++++++++++++++++++++++ test/alice_test.exs | 5 ++-- 11 files changed, 110 insertions(+), 50 deletions(-) create mode 100644 lib/alice/utils/process_utils.ex create mode 100644 test/alice/utils/process_utils_test.exs diff --git a/lib/alice.ex b/lib/alice.ex index 356d2a4..2fcb7e5 100644 --- a/lib/alice.ex +++ b/lib/alice.ex @@ -26,10 +26,19 @@ defmodule Alice do end @doc """ - Stops an Alice bot instance + Stops an Alice bot instance along with its handlers and adapters """ def stop_bot(pid) do - Supervisor.terminate_child(Alice.Bot.Supervisor, pid) + if Process.alive?(pid) do + %{adapters: adapters, handlers: handlers} = :sys.get_state(pid) + for adapter <- adapters do + Supervisor.terminate_child(Alice.Adapter.Supervisor, Process.whereis(adapter)) + end + for handler <- handlers do + Supervisor.terminate_child(Alice.Handler.Supervisor, Process.whereis(handler)) + end + Supervisor.terminate_child(Alice.Bot.Supervisor, pid) + end end @doc """ diff --git a/lib/alice/adapters/test.ex b/lib/alice/adapters/test.ex index 24d9b97..be7275e 100644 --- a/lib/alice/adapters/test.ex +++ b/lib/alice/adapters/test.ex @@ -19,7 +19,7 @@ defmodule Alice.Adapters.Test do end def handle_info({:message, msg}, %{bot: bot} = state) do - msg = %Alice.Message{bot: bot, text: msg.text, user: msg.user} + msg = %Alice.Message{bot: bot, adapter: {__MODULE__, self()}, text: msg.text, user: msg.user} Alice.Bot.handle_in(bot, msg) {:noreply, state} end diff --git a/lib/alice/bot.ex b/lib/alice/bot.ex index 479d3cf..b55bd90 100644 --- a/lib/alice/bot.ex +++ b/lib/alice/bot.ex @@ -232,7 +232,7 @@ defmodule Alice.Bot do handlers = ensure_builtin_handlers(handlers) for handler <- handlers do {:ok, pid} = Supervisor.start_child(Alice.Handler.Supervisor, [handler, {name, self()}]) - Process.register(pid, handler) + ProcessUtils.register_eventually(pid, handler) end {:noreply, %{state | handlers: handlers}} end @@ -241,7 +241,7 @@ defmodule Alice.Bot do case adapter do {name, mod} -> {:ok, pid} = Supervisor.start_child(Alice.Adapter.Supervisor, [mod, self(), opts]) - Process.register(pid, name) + ProcessUtils.register_eventually(pid, name) mod mod when is_atom(mod) -> {:ok, _pid} = Supervisor.start_child(Alice.Adapter.Supervisor, [mod, self(), opts]) diff --git a/lib/alice/test/bot_case.ex b/lib/alice/test/bot_case.ex index 591e1f2..bdd3e77 100644 --- a/lib/alice/test/bot_case.ex +++ b/lib/alice/test/bot_case.ex @@ -1,5 +1,6 @@ defmodule Alice.BotCase do use ExUnit.CaseTemplate + alias Alice.Adapters.Test, as: TestAdapter @bot Alice.TestBot @@ -15,17 +16,19 @@ defmodule Alice.BotCase do bot = Map.get(tags, :bot, @bot) name = Map.get(tags, :name, "alice") handlers = Map.get(tags, :handlers, [TestHandler]) - config = [name: name, handlers: handlers] + adapters = Map.get(tags, :adapters, [{TestAdapter, TestAdapter}]) + config = [name: name, handlers: handlers, adapters: adapters] Application.put_env(:alice, bot, config) - {:ok, pid} = Alice.start_bot(bot, config) - adapter = update_bot_adapter(pid) + {:ok, bot_pid} = Alice.start_bot(bot, config) + Process.register(bot_pid, Alice.TestBot) + test_adapter = update_bot_adapter(bot_pid) - on_exit fn -> Alice.stop_bot(pid) end + on_exit fn -> Alice.stop_bot(bot_pid) end user = %Alice.User{id: "user_id", name: "user_name"} - msg = %Alice.Message{bot: pid, text: "", user: user} + msg = %Alice.Message{bot: bot_pid, adapter: {TestAdapter, Process.whereis(TestAdapter)}, text: "", user: user} - {:ok, %{bot: pid, adapter: adapter, msg: msg}} + {:ok, %{bot: bot_pid, adapter: test_adapter, msg: msg}} else :ok end @@ -33,9 +36,9 @@ defmodule Alice.BotCase do def update_bot_adapter(bot_pid) do test_process = self() - adapter = :sys.get_state(bot_pid).adapter - :sys.replace_state(adapter, fn state -> %{state | conn: test_process} end) + [adapter_mod] = :sys.get_state(bot_pid).adapters + :sys.replace_state(adapter_mod, fn state -> %{state | conn: test_process} end) - adapter + adapter_mod end end diff --git a/lib/alice/test/test_bot.ex b/lib/alice/test/test_bot.ex index f0aa72a..5191d78 100644 --- a/lib/alice/test/test_bot.ex +++ b/lib/alice/test/test_bot.ex @@ -1,14 +1,11 @@ Code.ensure_compiled(Alice.Adapters.Test) defmodule Alice.TestBot do - use Alice.Bot, otp_app: :alice, adapters: [Alice.Adapters.Test] + use Alice.Bot, otp_app: :alice - def handle_connect(%{name: name} = state) do - if :undefined = :global.whereis_name(name) do - :yes = :global.register_name(name, self()) - end - - {:ok, state} + def handle_connect(bot) do + true = ProcessUtils.register_eventually(self(), Alice.TestBot) + {:ok, bot} end def handle_disconnect(:error, state) do diff --git a/lib/alice/utils/process_utils.ex b/lib/alice/utils/process_utils.ex new file mode 100644 index 0000000..1b58d2e --- /dev/null +++ b/lib/alice/utils/process_utils.ex @@ -0,0 +1,25 @@ +defmodule ProcessUtils do + def register_eventually(pid, name) do + case Process.whereis(name) do + ^pid -> true + nil -> Process.register(pid, name) + _ -> register_eventually(pid, make_name(name)) + end + end + + def make_name(name) when is_atom(name) do + "#{name}" + |> String.split(".") + |> Enum.reverse() + |> make_name() + |> String.to_atom() + end + def make_name(["Alt" <> num | rest]) do + {num, _} = Integer.parse(num) + ending = "Alt#{num+1}" + Enum.join(Enum.reverse([ending | rest]), ".") + end + def make_name(name) when is_list(name) do + Enum.join(Enum.reverse(["Alt1" | name]), ".") + end +end diff --git a/test/alice/adapters/console_test.exs b/test/alice/adapters/console_test.exs index f9d1d27..fc5cd27 100644 --- a/test/alice/adapters/console_test.exs +++ b/test/alice/adapters/console_test.exs @@ -6,22 +6,19 @@ defmodule Alice.Adapters.ConsoleTest do test "console handles messages from the connection" do capture_io fn -> - {:ok, adapter} = Alice.Adapter.start_link(Console, name: "alice", user: "testuser") + {:ok, adapter} = start_adapter(self(), name: "alice", user: "testuser") - handle_connect() msg = {:message, %{"text" => "ping", "user" => "testuser"}} send(adapter, msg) - assert_receive {:"$gen_cast", {:handle_in, %Alice.Message{text: "ping", user: "testuser"}}} + assert_receive {:"$gen_cast", {:handle_in, %Alice.Message{text: "ping", user: %Alice.User{name: "testuser"}}}} end end test "sending messages to the connection process" do capture_io fn -> - {:ok, adapter_pid} = Alice.Adapter.start_link(Console, name: "alice", user: "testuser") - on_exit fn -> Console.stop(adapter_pid, 1) end + {:ok, adapter_pid} = start_adapter(self(), name: "alice", user: "testuser") - handle_connect() test_process = self() adapter = :sys.replace_state(adapter_pid, fn state -> %{state | conn: test_process} end) msg = %Alice.Message{text: "pong", user: "testuser"} @@ -31,6 +28,15 @@ defmodule Alice.Adapters.ConsoleTest do end end + defp start_adapter(pid, opts) do + {:ok, adapter_pid} = Supervisor.start_child(Alice.Adapter.Supervisor, [Console, pid, opts]) + on_exit fn -> + Supervisor.terminate_child(Alice.Adapter.Supervisor, adapter_pid) + end + handle_connect() + {:ok, adapter_pid} + end + defp handle_connect() do receive do {:"$gen_call", from, :handle_connect} -> GenServer.reply(from, :ok) diff --git a/test/alice/bot/config_test.exs b/test/alice/bot/config_test.exs index 3bd2097..65b1b95 100644 --- a/test/alice/bot/config_test.exs +++ b/test/alice/bot/config_test.exs @@ -14,19 +14,10 @@ defmodule Alice.Bot.ConfigTest do end end - describe "init_config" do - test "when config is good" do - opts = [otp_app: :alice, adapter: Alice.Adapters.Console] - result = Config.init_config(Alice.Bot, opts) - bot_config = [log_level: :debug, bot_module: Alice.Bot, otp_app: :alice, adapter: Alice.Adapters.Console] - assert result == Config.new(:alice, Alice.Adapters.Console, bot_config) - end - - test "when missing adapter keyword" do - opts = [otp_app: :alice] - assert_raise ArgumentError, fn -> - Config.init_config(Alice.Bot, opts) - end - end + test "init_config" do + opts = [otp_app: :alice, adapters: [Alice.Adapters.Console]] + result = Config.init_config(Alice.Bot, opts) + bot_config = [log_level: :debug, bot_module: Alice.Bot, otp_app: :alice, adapters: [Alice.Adapters.Console]] + assert result == Config.new(:alice, [Alice.Adapters.Console], bot_config) end end diff --git a/test/alice/bot_test.exs b/test/alice/bot_test.exs index b2360a4..af738a4 100644 --- a/test/alice/bot_test.exs +++ b/test/alice/bot_test.exs @@ -1,13 +1,12 @@ defmodule Alice.BotTest do - use Alice.BotCase + use Alice.BotCase, async: false test "new/5" do - bot = Alice.Bot.new(:adapter, :name, :handlers, :handler_sup, :opts) + bot = Alice.Bot.new(:name, :adapters, :handlers, :opts) assert bot == %Alice.Bot{ - adapter: :adapter, name: :name, + adapters: :adapters, handlers: :handlers, - handler_sup: :handler_sup, opts: :opts } end @@ -31,7 +30,7 @@ defmodule Alice.BotTest do @tag start_bot: true test "handler_processes/1 returns list of handlers", %{bot: bot} do processes = - :sys.get_state(bot).handler_sup + Alice.Handler.Supervisor |> Supervisor.which_children() |> Enum.map(fn({_,pid,_,_}) -> {_,[{_,{mod,_,_}}|_]} = Process.info(pid, :dictionary) @@ -48,7 +47,7 @@ defmodule Alice.BotTest do @tag start_bot: true test "handle_connect/1", %{bot: bot} do - assert bot == :global.whereis_name("alice") + assert bot == Process.whereis(Alice.TestBot) end @tag start_bot: true diff --git a/test/alice/utils/process_utils_test.exs b/test/alice/utils/process_utils_test.exs new file mode 100644 index 0000000..b897f54 --- /dev/null +++ b/test/alice/utils/process_utils_test.exs @@ -0,0 +1,31 @@ +defmodule ProcessUtilsTest do + use ExUnit.Case + + test "register_eventually registers eventually" do + p1 = make_proc() + p2 = make_proc() + p3 = make_proc() + true = ProcessUtils.register_eventually(p1, My.Proc) + true = ProcessUtils.register_eventually(p2, My.Proc) + true = ProcessUtils.register_eventually(p3, My.Proc) + assert p1 == Process.whereis(My.Proc) + assert p2 == Process.whereis(My.Proc.Alt1) + assert p3 == Process.whereis(My.Proc.Alt2) + end + + test "register_eventually returns true if the process is already registered with the name" do + p1 = make_proc() + true = Process.register(p1, My.Proc) + assert ProcessUtils.register_eventually(p1, My.Proc) + end + + def make_proc do + pid = spawn fn -> + receive do + :exit -> :ok + end + end + on_exit fn -> send(pid, :exit) end + pid + end +end diff --git a/test/alice_test.exs b/test/alice_test.exs index 85726c2..dcd23e0 100644 --- a/test/alice_test.exs +++ b/test/alice_test.exs @@ -7,10 +7,9 @@ defmodule AliceTest do assert [{_id, ^bot, _type, [Alice.Bot]}] = bots end - @tag start_bot: true, name: "fred" + @tag start_bot: true test "find a bot by name", %{bot: bot} do - assert :undefined == :global.whereis_name("alice") - assert bot == :global.whereis_name("fred") + assert bot == Process.whereis(Alice.TestBot) end @tag start_bot: true