Skip to content

Commit 8baf7e5

Browse files
authored
Add fetch_server_status/1 (#9)
1 parent 6f7be8f commit 8baf7e5

File tree

17 files changed

+439
-0
lines changed

17 files changed

+439
-0
lines changed

lib/web_driver_client.ex

+42
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ defmodule WebDriverClient do
1616
alias WebDriverClient.KeyCodes
1717
alias WebDriverClient.LogEntry
1818
alias WebDriverClient.ProtocolMismatchError
19+
alias WebDriverClient.ServerStatus
1920
alias WebDriverClient.Session
2021
alias WebDriverClient.Size
2122
alias WebDriverClient.UnexpectedResponseError
@@ -782,6 +783,31 @@ defmodule WebDriverClient do
782783
end
783784
end
784785

786+
@doc """
787+
Fetches server status
788+
"""
789+
@spec fetch_server_status(Config.t()) :: {:ok, ServerStatus.t()} | {:error, reason}
790+
def fetch_server_status(%Config{protocol: protocol} = config) do
791+
with {:ok, http_response} <-
792+
send_request_for_protocol(protocol,
793+
jwp: fn -> JWPCommands.FetchServerStatus.send_request(config) end,
794+
w3c: fn -> W3CCommands.FetchServerStatus.send_request(config) end
795+
) do
796+
parse_with_fallbacks(
797+
http_response,
798+
protocol,
799+
[
800+
jwp: &JWPCommands.FetchServerStatus.parse_response/1,
801+
w3c: &W3CCommands.FetchServerStatus.parse_response/1
802+
],
803+
fn
804+
{:ok, server_status} -> {:ok, to_server_status(server_status)}
805+
{:error, error} -> {:error, to_error(error)}
806+
end
807+
)
808+
end
809+
end
810+
785811
@spec to_log_entry(JSONWireProtocolClient.LogEntry.t()) :: LogEntry.t()
786812
defp to_log_entry(%JSONWireProtocolClient.LogEntry{} = log_entry) do
787813
log_entry
@@ -810,6 +836,22 @@ defmodule WebDriverClient do
810836
|> (&struct!(Cookie, &1)).()
811837
end
812838

839+
@spec to_server_status(
840+
W3CWireProtocolClient.ServerStatus.t()
841+
| JSONWireProtocolClient.ServerStatus.t()
842+
) :: ServerStatus.t()
843+
defp to_server_status(%JSONWireProtocolClient.ServerStatus{} = server_status) do
844+
server_status
845+
|> Map.from_struct()
846+
|> (&struct!(ServerStatus, &1)).()
847+
end
848+
849+
defp to_server_status(%W3CWireProtocolClient.ServerStatus{} = server_status) do
850+
server_status
851+
|> Map.from_struct()
852+
|> (&struct!(ServerStatus, &1)).()
853+
end
854+
813855
defp to_error(%JSONWireProtocolClient.WebDriverError{reason: reason}) do
814856
reason =
815857
case reason do

lib/web_driver_client/json_wire_protocol_client.ex

+14
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ defmodule WebDriverClient.JSONWireProtocolClient do
2020
alias WebDriverClient.JSONWireProtocolClient.Commands
2121
alias WebDriverClient.JSONWireProtocolClient.Cookie
2222
alias WebDriverClient.JSONWireProtocolClient.LogEntry
23+
alias WebDriverClient.JSONWireProtocolClient.ServerStatus
2324
alias WebDriverClient.JSONWireProtocolClient.UnexpectedResponseError
2425
alias WebDriverClient.JSONWireProtocolClient.WebDriverError
2526
alias WebDriverClient.KeyCodes
@@ -529,4 +530,17 @@ defmodule WebDriverClient.JSONWireProtocolClient do
529530
:ok
530531
end
531532
end
533+
534+
@doc """
535+
Fetches the current server status
536+
537+
Specification: https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#get-status
538+
"""
539+
@spec fetch_server_status(Config.t()) :: {:ok, ServerStatus.t()} | {:error, basic_reason()}
540+
def fetch_server_status(%Config{} = config) do
541+
with {:ok, http_response} <- Commands.FetchServerStatus.send_request(config),
542+
{:ok, server_status} <- Commands.FetchServerStatus.parse_response(http_response) do
543+
{:ok, server_status}
544+
end
545+
end
532546
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
defmodule WebDriverClient.JSONWireProtocolClient.Commands.FetchServerStatus do
2+
@moduledoc false
3+
4+
alias WebDriverClient.Config
5+
alias WebDriverClient.ConnectionError
6+
alias WebDriverClient.HTTPResponse
7+
alias WebDriverClient.JSONWireProtocolClient.ResponseParser
8+
alias WebDriverClient.JSONWireProtocolClient.ServerStatus
9+
alias WebDriverClient.JSONWireProtocolClient.TeslaClientBuilder
10+
alias WebDriverClient.JSONWireProtocolClient.UnexpectedResponseError
11+
alias WebDriverClient.JSONWireProtocolClient.WebDriverError
12+
13+
@spec send_request(Config.t()) :: {:ok, HTTPResponse.t()} | {:error, ConnectionError.t()}
14+
def send_request(%Config{} = config) do
15+
client = TeslaClientBuilder.build_simple(config)
16+
17+
case Tesla.get(client, "/status") do
18+
{:ok, env} ->
19+
{:ok, HTTPResponse.build(env)}
20+
21+
{:error, reason} ->
22+
{:error, reason}
23+
end
24+
end
25+
26+
@spec parse_response(HTTPResponse.t()) ::
27+
{:ok, ServerStatus.t()} | {:error, UnexpectedResponseError.t() | WebDriverError.t()}
28+
def parse_response(%HTTPResponse{} = http_response) do
29+
# The spec says a 200 response indicates the server is ready (the "ready" key
30+
# returned by some implementations doesn't matter). This implementation also ensures
31+
# a valid jwp response and status code.
32+
33+
with {:ok, jwp_response} <- ResponseParser.parse_response(http_response),
34+
:ok <- ResponseParser.ensure_successful_jwp_status(jwp_response) do
35+
{:ok, %ServerStatus{ready?: true}}
36+
end
37+
end
38+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# credo:disable-for-this-file Credo.Check.Readability.ModuleDoc
2+
import WebDriverClient.CompatibilityMacros
3+
4+
defmodule WebDriverClient.JSONWireProtocolClient.ServerStatus do
5+
prerelease_moduledoc """
6+
A server status response
7+
"""
8+
9+
@type t :: %__MODULE__{
10+
ready?: boolean
11+
}
12+
13+
defstruct [:ready?]
14+
end
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
defmodule WebDriverClient.ServerStatus do
2+
@moduledoc """
3+
A server status response
4+
"""
5+
6+
@type t :: %__MODULE__{
7+
ready?: boolean
8+
}
9+
10+
defstruct [:ready?]
11+
end

lib/web_driver_client/w3c_wire_protocol_client.ex

+14
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ defmodule WebDriverClient.W3CWireProtocolClient do
2323
alias WebDriverClient.W3CWireProtocolClient.Cookie
2424
alias WebDriverClient.W3CWireProtocolClient.LogEntry
2525
alias WebDriverClient.W3CWireProtocolClient.Rect
26+
alias WebDriverClient.W3CWireProtocolClient.ServerStatus
2627
alias WebDriverClient.W3CWireProtocolClient.UnexpectedResponseError
2728
alias WebDriverClient.W3CWireProtocolClient.WebDriverError
2829

@@ -517,4 +518,17 @@ defmodule WebDriverClient.W3CWireProtocolClient do
517518
:ok
518519
end
519520
end
521+
522+
@doc """
523+
Fetches the server status
524+
525+
Specification: https://w3c.github.io/webdriver/#status
526+
"""
527+
@spec fetch_server_status(Config.t()) :: {:ok, ServerStatus.t()} | {:error, basic_reason()}
528+
def fetch_server_status(%Config{} = config) do
529+
with {:ok, http_response} <- Commands.FetchServerStatus.send_request(config),
530+
{:ok, server_status} <- Commands.FetchServerStatus.parse_response(http_response) do
531+
{:ok, server_status}
532+
end
533+
end
520534
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
defmodule WebDriverClient.W3CWireProtocolClient.Commands.FetchServerStatus do
2+
@moduledoc false
3+
4+
alias WebDriverClient.Config
5+
alias WebDriverClient.ConnectionError
6+
alias WebDriverClient.HTTPResponse
7+
alias WebDriverClient.W3CWireProtocolClient.ResponseParser
8+
alias WebDriverClient.W3CWireProtocolClient.ServerStatus
9+
alias WebDriverClient.W3CWireProtocolClient.TeslaClientBuilder
10+
alias WebDriverClient.W3CWireProtocolClient.UnexpectedResponseError
11+
alias WebDriverClient.W3CWireProtocolClient.WebDriverError
12+
13+
@spec send_request(Config.t()) :: {:ok, HTTPResponse.t()} | {:error, ConnectionError.t()}
14+
def send_request(%Config{} = config) do
15+
client = TeslaClientBuilder.build_simple(config)
16+
url = "/status"
17+
18+
case Tesla.get(client, url) do
19+
{:ok, env} ->
20+
{:ok, HTTPResponse.build(env)}
21+
22+
{:error, reason} ->
23+
{:error, reason}
24+
end
25+
end
26+
27+
@spec parse_response(HTTPResponse.t()) ::
28+
{:ok, ServerStatus.t()} | {:error, UnexpectedResponseError.t() | WebDriverError.t()}
29+
def parse_response(%HTTPResponse{} = http_response) do
30+
with {:ok, w3c_response} <- ResponseParser.parse_response(http_response),
31+
:ok <- ResponseParser.ensure_successful_response(w3c_response),
32+
{:ok, server_status} <- ResponseParser.parse_server_status(w3c_response) do
33+
{:ok, server_status}
34+
end
35+
end
36+
end

lib/web_driver_client/w3c_wire_protocol_client/response_parser.ex

+12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ defmodule WebDriverClient.W3CWireProtocolClient.ResponseParser do
1212
alias WebDriverClient.W3CWireProtocolClient.LogEntry
1313
alias WebDriverClient.W3CWireProtocolClient.Rect
1414
alias WebDriverClient.W3CWireProtocolClient.Response
15+
alias WebDriverClient.W3CWireProtocolClient.ServerStatus
1516
alias WebDriverClient.W3CWireProtocolClient.UnexpectedResponseError
1617
alias WebDriverClient.W3CWireProtocolClient.WebDriverError
1718

@@ -182,6 +183,17 @@ defmodule WebDriverClient.W3CWireProtocolClient.ResponseParser do
182183
end
183184
end
184185

186+
@spec parse_server_status(Response.t()) ::
187+
{:ok, ServerStatus.t()} | {:error, UnexpectedResponseError.t()}
188+
def parse_server_status(%Response{body: %{"value" => %{"ready" => ready?}}})
189+
when is_boolean(ready?) do
190+
{:ok, %ServerStatus{ready?: ready?}}
191+
end
192+
193+
def parse_server_status(%Response{body: body}) do
194+
{:error, UnexpectedResponseError.exception(response_body: body)}
195+
end
196+
185197
defp do_parse_elements(elements) do
186198
elements
187199
|> Enum.reduce_while([], fn
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# credo:disable-for-this-file Credo.Check.Readability.ModuleDoc
2+
import WebDriverClient.CompatibilityMacros
3+
4+
defmodule WebDriverClient.W3CWireProtocolClient.ServerStatus do
5+
prerelease_moduledoc """
6+
A server status response
7+
"""
8+
9+
@type t :: %__MODULE__{
10+
ready?: boolean
11+
}
12+
13+
defstruct [:ready?]
14+
end

mix.exs

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ defmodule WebDriverClient.MixProject do
6767
WebDriverClient.Element,
6868
WebDriverClient.LogEntry,
6969
WebDriverClient.ProtocolMismatchError,
70+
WebDriverClient.ServerStatus,
7071
WebDriverClient.Session,
7172
WebDriverClient.Size,
7273
WebDriverClient.UnexpectedResponseError,

test/integration/status_test.exs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
defmodule WebDriverClient.Integration.StatusTest do
2+
use ExUnit.Case, async: false
3+
4+
alias WebDriverClient.ConnectionError
5+
alias WebDriverClient.IntegrationTesting.Scenarios
6+
alias WebDriverClient.IntegrationTesting.TestGenerator
7+
alias WebDriverClient.ProtocolMismatchError
8+
alias WebDriverClient.ServerStatus
9+
10+
require TestGenerator
11+
12+
@moduletag :integration
13+
@moduletag :capture_log
14+
15+
TestGenerator.generate_describe_per_scenario do
16+
test "checking server status", %{scenario: scenario} do
17+
config = Scenarios.get_config(scenario)
18+
19+
assert {:ok, %ServerStatus{ready?: true}} =
20+
config
21+
|> WebDriverClient.fetch_server_status()
22+
|> unwrap_protocol_mismatch_error()
23+
24+
assert {:error, %ConnectionError{}} =
25+
config
26+
|> struct!(base_url: "http://does-not-exist-123")
27+
|> WebDriverClient.fetch_server_status()
28+
end
29+
end
30+
31+
defp unwrap_protocol_mismatch_error({:error, %ProtocolMismatchError{response: response}}),
32+
do: response
33+
34+
defp unwrap_protocol_mismatch_error(response), do: response
35+
end

test/support/json_wire_protocol_client/test_responses.ex

+9
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ defmodule WebDriverClient.JSONWireProtocolClient.TestResponses do
5959
|> map(&Jason.encode!/1)
6060
end
6161

62+
def fetch_server_status_response do
63+
one_of([
64+
fixed_map(%{"ready" => boolean()}),
65+
constant(%{})
66+
])
67+
|> jwp_response()
68+
|> map(&Jason.encode!/1)
69+
end
70+
6271
def end_session_response do
6372
nil
6473
|> jwp_response()

test/support/w3c_wire_protocol_client/test_responses.ex

+6
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ defmodule WebDriverClient.W3CWireProtocolClient.TestResponses do
7272
|> map(&Jason.encode!/1)
7373
end
7474

75+
def fetch_server_status_response do
76+
%{"value" => fixed_map(%{"ready" => boolean()})}
77+
|> fixed_map()
78+
|> map(&Jason.encode!/1)
79+
end
80+
7581
def end_session_response do
7682
constant(%{"value" => nil}) |> map(&Jason.encode!/1)
7783
end

0 commit comments

Comments
 (0)