diff --git a/README.md b/README.md index 9827ec1..549613d 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,17 @@ Application.ensure_all_started(:hound) ExUnit.start() ``` -When you run `mix test`, Hound is automatically started. __You'll need a webdriver server__ running, like Selenium Server or Chrome Driver. If you aren't sure what it is, then [read this](https://github.com/HashNuke/hound/wiki/Starting-a-webdriver-server). +* Hound does *NOT* start local server automatically. You need to handle it on your own. +If you use Phoenix, you can edit `config/test.exs` and set `server: true` to launch server +automatically: + +```elixir +config :myapp, MyAppWeb.Endpoint, + http: [port: 4001], + server: true +``` + +* When you run `mix test`, Hound is automatically started, but __you'll need a webdriver server__ running, like Selenium Server or Chrome Driver. If you aren't sure what it is, then [read this](https://github.com/HashNuke/hound/wiki/Starting-a-webdriver-server). #### If you're using Phoenix Ensure the server is started when your tests are run. In `config/test.exs` change the `server` option of your endpoint config to `true`: diff --git a/lib/hound/request_utils.ex b/lib/hound/request_utils.ex index 9615575..df5874c 100644 --- a/lib/hound/request_utils.ex +++ b/lib/hound/request_utils.ex @@ -55,7 +55,7 @@ defmodule Hound.RequestUtils do end defp handle_response({:error, reason}, _, _) do - {:error, reason} + raise Hound.Error, "Webdriver request error: #{inspect(reason)}" end defp response_parser do diff --git a/lib/hound/session_server.ex b/lib/hound/session_server.ex index c8de347..652a862 100644 --- a/lib/hound/session_server.ex +++ b/lib/hound/session_server.ex @@ -17,14 +17,14 @@ defmodule Hound.SessionServer do def current_session_id(pid) do case :ets.lookup(@name, pid) do - [{^pid, _ref, session_id, _all_sessions}] -> session_id + [{^pid, session_id, _all_sessions}] -> session_id [] -> nil end end def current_session_name(pid) do case :ets.lookup(@name, pid) do - [{^pid, _ref, session_id, all_sessions}] -> + [{^pid, session_id, all_sessions}] -> Enum.find_value all_sessions, fn {name, id} when id == session_id -> name _ -> nil @@ -35,18 +35,42 @@ defmodule Hound.SessionServer do def change_current_session_for_pid(pid, session_name, opts) do - GenServer.call(@name, {:change_session, pid, session_name, opts}, genserver_timeout()) + {:ok, driver_info} = Hound.driver_info + + sessions = + case :ets.lookup(@name, pid) do + [{^pid, _session_id, sessions}] -> + sessions + [] -> %{} + end + + {session_id, sessions} = + case Map.fetch(sessions, session_name) do + {:ok, session_id} -> + {session_id, sessions} + :error -> + session_id = create_session(driver_info, opts) + {session_id, Map.put(sessions, session_name, session_id)} + end + + :ok = GenServer.call(@name, {:register, pid, session_id, sessions}, genserver_timeout()) + session_id end def all_sessions_for_pid(pid) do case :ets.lookup(@name, pid) do - [{^pid, _ref, _session_id, all_sessions}] -> all_sessions + [{^pid, _session_id, all_sessions}] -> all_sessions [] -> %{} end end + def all_sessions do + :ets.foldl(fn {_pid, _session_id, sessions}, acc -> acc ++ Map.values(sessions) end, [], @name) + end + + def destroy_sessions_for_pid(pid) do GenServer.call(@name, {:destroy_sessions, pid}, 60000) end @@ -59,28 +83,9 @@ defmodule Hound.SessionServer do end - def handle_call({:change_session, pid, session_name, opts}, _from, state) do - {:ok, driver_info} = Hound.driver_info - - {ref, sessions} = - case :ets.lookup(@name, pid) do - [{^pid, ref, _session_id, sessions}] -> - {ref, sessions} - [] -> - {Process.monitor(pid), %{}} - end - - {session_id, sessions} = - case Map.fetch(sessions, session_name) do - {:ok, session_id} -> - {session_id, sessions} - :error -> - session_id = create_session(driver_info, opts) - {session_id, Map.put(sessions, session_name, session_id)} - end - - :ets.insert(@name, {pid, ref, session_id, sessions}) - {:reply, session_id, Map.put(state, ref, pid)} + def handle_call({:register, pid, session_id, sessions}, _from, state) do + :ets.insert(@name, {pid, session_id, sessions}) + {:reply, :ok, monitor_session(pid, state)} end def handle_call({:destroy_sessions, pid}, _from, state) do @@ -95,6 +100,15 @@ defmodule Hound.SessionServer do {:noreply, state} end + defp monitor_session(pid, state) do + if state |> Map.values |> Enum.member?(pid) do + state + else + ref = Process.monitor(pid) + Map.put(state, ref, pid) + end + end + defp create_session(driver_info, opts) do case Hound.Session.create_session(driver_info[:browser], opts) do {:ok, session_id} -> session_id @@ -106,10 +120,15 @@ defmodule Hound.SessionServer do sessions = all_sessions_for_pid(pid) :ets.delete(@name, pid) Enum.each sessions, fn({_session_name, session_id})-> - Hound.Session.destroy_session(session_id) + spawn fn -> destroy_session(session_id) end end end + defp destroy_session(session_id) do + Hound.Session.destroy_session(session_id) + rescue Hound.Error -> false + end + defp genserver_timeout() do Application.get_env(:hound, :genserver_timeout, 60000) end diff --git a/test/hound_test.exs b/test/hound_test.exs index ca65e81..81ba3d2 100644 --- a/test/hound_test.exs +++ b/test/hound_test.exs @@ -19,8 +19,11 @@ defmodule HoundTest do assert is_binary(Hound.current_session_id) end + test "should return all sessions" do + assert Hound.SessionServer.all_sessions |> Enum.member?(Hound.current_session_id) + end - test "Should destroy all sessions for current process" do + test "should destroy all sessions for current process" do Hound.end_session assert Hound.SessionServer.all_sessions_for_pid(self()) == %{} end