Write some tests for configurator

pull/974/head
Connor Rigby 2019-06-20 07:44:24 -07:00
parent 92fef18b62
commit d6925b1541
No known key found for this signature in database
GPG Key ID: 29A88B24B70456E0
10 changed files with 384 additions and 24 deletions

View File

@ -27,4 +27,9 @@ config :farmbot,
{Farmbot.Platform.Host.Configurator, []}
]
config :farmbot, FarmbotOS.Configurator,
data_layer: FarmbotTest.Configurator.MockDataLayer,
network_layer: FarmbotTest.Configurator.MockNetworkLayer
config :farmbot, FarmbotOS.FirmwareTTYDetector, expected_names: []
config :plug, :validate_header_keys_during_test, true

View File

@ -26,7 +26,7 @@ defmodule FarmbotOS.Configurator.Router do
get "/" do
case load_last_reset_reason() do
{:ok, reason} when is_binary(reason) ->
reason when is_binary(reason) ->
if String.contains?(reason, "CeleryScript request.") do
render_page(conn, "index", version: version(), last_reset_reason: nil)
else
@ -53,13 +53,13 @@ defmodule FarmbotOS.Configurator.Router do
conn
|> put_resp_content_type("application/octet-stream")
|> put_resp_header(
"Content-Disposition",
"content-disposition",
"inline; filename=\"#{version()}-#{md5}-logs.sqlite3\""
)
|> send_resp(200, data)
{:error, posix} ->
send_resp(conn, 404, "Error downloading file: #{posix}")
send_resp(conn, 500, "Error downloading file: #{posix}")
end
end
@ -105,7 +105,7 @@ defmodule FarmbotOS.Configurator.Router do
end
get "/config_wireless" do
ifname = get_session("ifname")
ifname = get_session(conn, "ifname")
render_page(conn, "/config_wireless_step_1",
ifname: ifname,
@ -115,7 +115,7 @@ defmodule FarmbotOS.Configurator.Router do
end
post "config_wireless_step_1" do
ifname = get_session("ifname")
ifname = get_session(conn, "ifname")
ssid = conn.params["ssid"] |> remove_empty_string()
security = conn.params["security"] |> remove_empty_string()
manualssid = conn.params["manualssid"] |> remove_empty_string()
@ -221,18 +221,18 @@ defmodule FarmbotOS.Configurator.Router do
%{"email" => email, "password" => pass, "server" => server} ->
if server = test_uri(server) do
FarmbotCore.Logger.info(1, "server valid: #{server}")
conn
|> put_session("auth_email", email)
|> put_session("auth_password", pass)
|> put_session("auth_server", server)
|> redir("/finish")
else
conn
|> put_session("__error", "Server is not a valid URI")
|> redir("/credentials")
end
conn
|> put_session("email", email)
|> put_session("password", pass)
|> put_session("server", server)
|> redir("/finish")
_ ->
conn
|> put_session("__error", "Email, Server, or Password are missing or invalid")

View File

@ -42,6 +42,7 @@
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"},
"muontrap": {:hex, :muontrap, "0.4.3", "f6c6d2c4e6eeb3b03780da77741945cab1a5ee7fb6d3e9ce9080717b6b4042a7", [:make, :mix], [{:elixir_make, "~> 0.5", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nerves": {:hex, :nerves, "1.4.4", "7d2d6c0129d541e12ed12117ae059e7db8849faaefc4b4d30f4af55ba6f8d089", [:mix], [{:distillery, "2.0.12", [hex: :distillery, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"nerves_firmware_ssh": {:hex, :nerves_firmware_ssh, "0.4.2", "315b515b872b7a4f18ae1bc37f7943064dfda984ec5ec4a6111b9d69adecee2e", [:mix], [{:nerves_runtime, "~> 0.4", [hex: :nerves_runtime, repo: "hexpm", optional: false]}], "hexpm"},

View File

@ -53,7 +53,7 @@
<%= for ssid_result <- ssids do %>
<%= if ssid_result.ssid && String.printable?(ssid_result.ssid) do %>
<tr id="<%= ssid_result.bssid %>" name="ssidSelector" class="ssid_result"
onclick='selectSsid("<%= escape_javascript(ssid_result.ssid) %>", "<%= escape_javascript(ssid_result.bssid) %>", "<%= escape_javascript(to_string(ssid_result.security)) %>")' >
onclick='selectSsid("<%= javascript_escape(ssid_result.ssid) %>", "<%= javascript_escape(ssid_result.bssid) %>", "<%= javascript_escape(to_string(ssid_result.security)) %>")' >
<td class="ssid_name"> <%= ssid_result.ssid || "hidden network" %> </td>
<td class="ssid_quality">
<script>

View File

@ -57,7 +57,7 @@
</select>
<div id="pskdiv">
<label for=psk> Password </label>
<label for=psk> PSK </label>
<div class="psk-input-group">
<input type="password" name="psk" id="psk">
<img class="eye-icon" src="icon_eye.svg"

View File

@ -19,7 +19,7 @@
function copyLSR() {
var tmp = document.createElement("div");
<%= if last_reset_reason do %>
tmp.innerHTML = "<%= escape_javascript(last_reset_reason) %>";
tmp.innerHTML = "<%= javascript_escape(last_reset_reason) %>";
<% end %>
var textArea = document.createElement("textarea");
textArea.value += "```\n";
@ -65,7 +65,7 @@
<div id="last-shutdown-reason-content">
<i> Last shutdown reason: </i>
<script>
var all = "<%= escape_javascript(last_reset_reason) %>";
var all = "<%= javascript_escape(last_reset_reason) %>";
var reason = all.split("<hr>")[0];
document.write(reason)
</script>
@ -76,7 +76,7 @@
</label>
<div id="envDetails" class="env-details" hidden>
<script>
var all = "<%= escape_javascript(last_reset_reason) %>";
var all = "<%= javascript_escape(last_reset_reason) %>";
var envDetails = all.split("<hr>")[1];
document.write(envDetails)
</script>

View File

@ -56,7 +56,7 @@
<div class="colapsablecontent">
<%= log.message %>
</div>
<%= end %>
<% end %>
</div>
<script>

View File

@ -1,7 +0,0 @@
defmodule DummyTest do
use ExUnit.Case
test "delete me" do
assert true
end
end

View File

@ -0,0 +1,359 @@
defmodule FarmbotOS.Configurator.RouterTest do
alias FarmbotOS.Configurator.Router
use ExUnit.Case, async: true
use Plug.Test
alias FarmbotTest.Configurator.{MockDataLayer, MockNetworkLayer}
import Mox
setup :verify_on_exit!
@opts Router.init([])
test "index" do
MockDataLayer
|> expect(:load_last_reset_reason, fn -> "whoops!" end)
conn = conn(:get, "/")
conn = Router.call(conn, @opts)
assert conn.resp_body =~ "Configure your Farmbot"
assert conn.resp_body =~ "<div class=\"last-shutdown-reason\">"
assert conn.resp_body =~ "whoops!"
end
test "redirect to index" do
MockDataLayer
|> expect(:load_last_reset_reason, fn -> nil end)
conn = conn(:get, "/setup")
conn = Router.call(conn, @opts)
redir = redirected_to(conn)
assert redir == "/"
conn = conn(:get, redir)
conn = Router.call(conn, @opts)
assert conn.resp_body =~ "Configure your Farmbot"
end
test "celeryscript requests don't get listed as last reset reason" do
MockDataLayer
|> expect(:load_last_reset_reason, fn -> "CeleryScript request." end)
conn = conn(:get, "/")
conn = Router.call(conn, @opts)
refute conn.resp_body =~ "CeleryScript request."
end
test "no reset reason" do
MockDataLayer
|> expect(:load_last_reset_reason, fn -> nil end)
conn = conn(:get, "/")
conn = Router.call(conn, @opts)
refute conn.resp_body =~ "<div class=\"last-shutdown-reason\">"
end
test "captive portal" do
conn = conn(:get, "/generate_204")
conn = Router.call(conn, @opts)
assert conn.status == 204
conn = conn(:get, "/gen_204")
conn = Router.call(conn, @opts)
assert conn.status == 204
end
test "secret log view page" do
MockDataLayer
|> expect(:dump_logs, fn -> [%{message: "hello, world!"}] end)
conn = conn(:get, "/view_logs")
conn = Router.call(conn, @opts)
assert conn.resp_body =~ "hello, world!"
end
test "secret log download page" do
MockDataLayer
|> expect(:dump_log_db, fn -> {:error, :enoent} end)
conn = conn(:get, "/logs")
conn = Router.call(conn, @opts)
assert conn.status == 500
assert conn.resp_body == "Error downloading file: enoent"
MockDataLayer
|> expect(:dump_log_db, fn -> {:ok, "this is supposed to be a sqlite db"} end)
conn = conn(:get, "/logs")
conn = Router.call(conn, @opts)
assert conn.status == 200
assert conn.resp_body == "this is supposed to be a sqlite db"
[disposition] = get_resp_header(conn, "content-disposition")
assert disposition =~ "-logs.sqlite3"
end
test "network index" do
MockNetworkLayer
|> expect(:list_interfaces, fn -> [{"eth0", %{mac_address: "aa:bb:cc:dd:ee"}}] end)
conn = conn(:get, "/network")
conn = Router.call(conn, @opts)
assert conn.resp_body =~ "eth0"
end
test "select network sets session data" do
conn = conn(:post, "select_interface")
conn = Router.call(conn, @opts)
assert redirected_to(conn) == "/network"
conn = conn(:post, "select_interface", %{"interface" => "eth0"})
conn = Router.call(conn, @opts)
assert redirected_to(conn) == "/config_wired"
assert get_session(conn, "ifname") == "eth0"
conn = conn(:post, "select_interface", %{"interface" => "wlan0"})
conn = Router.call(conn, @opts)
assert redirected_to(conn) == "/config_wireless"
assert get_session(conn, "ifname") == "wlan0"
end
test "config wired" do
conn =
conn(:get, "/config_wired")
|> init_test_session(%{"ifname" => "eth0"})
|> Router.call(@opts)
assert conn.resp_body =~ "Advanced settings"
end
test "config wireless SSID list" do
MockNetworkLayer
|> expect(:scan, fn _ ->
[
%{
ssid: "Test Network",
bssid: "aa:bb:cc:dd:ee:ff",
security: "WPA-PSK",
level: 100
}
]
end)
conn =
conn(:get, "/config_wireless")
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
assert conn.resp_body =~ "Test Network"
end
test "config wireless" do
# No SSID or SECURITY
conn =
conn(:post, "/config_wireless_step_1", %{})
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
assert redirected_to(conn) == "/config_wireless"
# No SECURITY
conn =
conn(:post, "/config_wireless_step_1", %{"ssid" => "Test Network"})
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
assert redirected_to(conn) == "/config_wireless"
conn =
conn(:post, "/config_wireless_step_1", %{"ssid" => "Test Network", "security" => "NONE"})
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
refute conn.resp_body =~ "PSK"
assert conn.resp_body =~ "Advanced settings"
conn =
conn(:post, "/config_wireless_step_1", %{"ssid" => "Test Network", "security" => "WPA-PSK"})
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
assert conn.resp_body =~ "PSK"
assert conn.resp_body =~ "Advanced settings"
conn =
conn(:post, "/config_wireless_step_1", %{"ssid" => "Test Network", "security" => "WPA2-PSK"})
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
assert conn.resp_body =~ "PSK"
assert conn.resp_body =~ "Advanced settings"
conn =
conn(:post, "/config_wireless_step_1", %{"ssid" => "Test Network", "security" => "WPA-EAP"})
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
refute conn.resp_body =~ "PSK"
assert conn.resp_body =~ "IDENTITY"
assert conn.resp_body =~ "PASSWORD"
assert conn.resp_body =~ "Advanced settings"
conn =
conn(:post, "/config_wireless_step_1", %{"manualssid" => "Test Network"})
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
assert conn.resp_body =~ "PSK"
assert conn.resp_body =~ "EAP Identity"
assert conn.resp_body =~ "EAP Password"
assert conn.resp_body =~ "Advanced settings"
conn =
conn(:post, "/config_wireless_step_1", %{
"ssid" => "Test Network",
"security" => "WPA-UNSUPPORTED"
})
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
assert conn.resp_body =~ "unknown or unsupported"
end
test "config_network" do
params = %{
"dns_name" => "super custom",
"ntp_server_1" => "pool0.ntpd.org",
"ntp_server_2" => "pool1.ntpd.org",
"ssh_key" => "very long ssh key",
"ssid" => "Test Network",
"security" => "WPA-PSK",
"psk" => "ABCDEF",
"identity" => "NOT TECHNICALLY POSSIBLE",
"password" => "NOT TECHNICALLY POSSIBLE",
"domain" => "farmbot.org",
"name_servers" => "192.168.1.1, 192.168.1.2",
"ipv4_method" => "static",
"ipv4_address" => "192.168.1.100",
"ipv4_gateway" => "192.168.1.1",
"ipv4_subnet_mask" => "255.255.0.0",
"regulatory_domain" => "US"
}
conn =
conn(:post, "/config_network", params)
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
assert get_session(conn, "net_config_dns_name") == "super custom"
assert get_session(conn, "net_config_ntp1") == "pool0.ntpd.org"
assert get_session(conn, "net_config_ntp2") == "pool1.ntpd.org"
assert get_session(conn, "net_config_ssh_key") == "very long ssh key"
assert get_session(conn, "net_config_ssid") == "Test Network"
assert get_session(conn, "net_config_security") == "WPA-PSK"
assert get_session(conn, "net_config_psk") == "ABCDEF"
assert get_session(conn, "net_config_identity") == "NOT TECHNICALLY POSSIBLE"
assert get_session(conn, "net_config_password") == "NOT TECHNICALLY POSSIBLE"
assert get_session(conn, "net_config_domain") == "farmbot.org"
assert get_session(conn, "net_config_name_servers") == "192.168.1.1, 192.168.1.2"
assert get_session(conn, "net_config_ipv4_method") == "static"
assert get_session(conn, "net_config_ipv4_address") == "192.168.1.100"
assert get_session(conn, "net_config_ipv4_gateway") == "192.168.1.1"
assert get_session(conn, "net_config_ipv4_subnet_mask") == "255.255.0.0"
assert get_session(conn, "net_config_reg_domain") == "US"
assert redirected_to(conn) == "/credentials"
end
test "credentials index" do
MockDataLayer
|> expect(:load_email, fn -> "test@test.org" end)
|> expect(:load_password, fn -> "password123" end)
|> expect(:load_server, fn -> "https://my.farm.bot" end)
conn = conn(:get, "/credentials") |> Router.call(@opts)
assert conn.resp_body =~ "test@test.org"
assert conn.resp_body =~ "password123"
assert conn.resp_body =~ "https://my.farm.bot"
end
test "configure credentials" do
params = %{
"email" => "test@test.org",
"password" => "password123",
"server" => "https://my.farm.bot"
}
conn =
conn(:post, "/configure_credentials", params)
|> Router.call(@opts)
assert redirected_to(conn) == "/finish"
assert get_session(conn, "auth_email") == "test@test.org"
assert get_session(conn, "auth_password") == "password123"
assert get_session(conn, "auth_server") == "https://my.farm.bot"
conn =
conn(:post, "/configure_credentials", %{params | "server" => "whoops/i/made/a/type"})
|> Router.call(@opts)
assert redirected_to(conn) == "/credentials"
conn =
conn(:post, "/configure_credentials", %{})
|> Router.call(@opts)
assert redirected_to(conn) == "/credentials"
end
test "finish" do
conn =
conn(:get, "/finish")
|> Router.call(@opts)
assert conn.resp_body =~ "Configuration Complete"
end
test "404" do
conn =
conn(:get, "/whoops")
|> Router.call(@opts)
assert conn.resp_body == "Page not found"
end
test "500" do
MockNetworkLayer
|> expect(:scan, fn _ ->
[
%{
incorrect: :data
}
]
end)
conn =
conn(:get, "/config_wireless")
|> init_test_session(%{"ifname" => "wlan0"})
|> Router.call(@opts)
assert conn.status == 500
end
# Stolen from https://github.com/phoenixframework/phoenix/blob/3f157c30ceae8d1eb524fdd05b5e3de10e434c42/lib/phoenix/test/conn_test.ex#L438
defp redirected_to(conn, status \\ 302)
defp redirected_to(%Plug.Conn{state: :unset}, _status) do
raise "expected connection to have redirected but no response was set/sent"
end
defp redirected_to(conn, status) when is_atom(status) do
redirected_to(conn, Plug.Conn.Status.code(status))
end
defp redirected_to(%Plug.Conn{status: status} = conn, status) do
location = Plug.Conn.get_resp_header(conn, "location") |> List.first()
location || raise "no location header was set on redirected_to"
end
defp redirected_to(conn, status) do
raise "expected redirection with status #{status}, got: #{conn.status}"
end
end

View File

@ -0,0 +1,2 @@
Mox.defmock(FarmbotTest.Configurator.MockDataLayer, for: FarmbotOS.Configurator.DataLayer)
Mox.defmock(FarmbotTest.Configurator.MockNetworkLayer, for: FarmbotOS.Configurator.NetworkLayer)