Skip to content

Commit

Permalink
Don't raise if Nerves.Runtime.KV is empty
Browse files Browse the repository at this point in the history
While this isn't a common case, if you're bringing up a board, it's nice
when NervesMOTD doesn't crash.
  • Loading branch information
fhunleth committed Feb 4, 2023
1 parent 1ce12f0 commit 1db9e52
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 13 deletions.
15 changes: 9 additions & 6 deletions lib/nerves_motd.ex
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,16 @@ defmodule NervesMOTD do

@spec firmware_cell() :: cell()
defp firmware_cell() do
fw_active = Nerves.Runtime.KV.get("nerves_fw_active") |> String.upcase()
fw_active = runtime_mod().active_partition()

if runtime_mod().firmware_valid?() do
{"Firmware", [:green, "Valid (#{fw_active})"]}
else
{"Firmware", [:red, "Not validated (#{fw_active})"]}
end
status =
case runtime_mod().firmware_validity() do
:valid -> [:green, "Valid (#{fw_active})"]
:invalid -> [:red, "Not validated (#{fw_active})"]
_ -> fw_active
end

{"Firmware", status}
end

@spec applications_cell(%{loaded: list(), started: list()}) :: cell()
Expand Down
15 changes: 12 additions & 3 deletions lib/nerves_motd/runtime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ defmodule NervesMOTD.Runtime do
@moduledoc false
@callback applications() :: %{started: [atom()], loaded: [atom()]}
@callback cpu_temperature() :: {:ok, float()} | :error
@callback firmware_valid?() :: boolean()
@callback active_partition() :: String.t()
@callback firmware_validity() :: :valid | :invalid | :unknown
@callback load_average() :: [String.t()]
@callback memory_stats() ::
{:ok,
Expand Down Expand Up @@ -50,8 +51,16 @@ defmodule NervesMOTD.Runtime.Target do
end

@impl NervesMOTD.Runtime
def firmware_valid?() do
Nerves.Runtime.firmware_valid?()
def active_partition() do
case Nerves.Runtime.KV.get("nerves_fw_active") do
nil -> "unknown"
partition -> String.upcase(partition)
end
end

@impl NervesMOTD.Runtime
def firmware_validity() do
if Nerves.Runtime.firmware_valid?(), do: :valid, else: :invalid
end

@impl NervesMOTD.Runtime
Expand Down
66 changes: 62 additions & 4 deletions test/nerves_motd_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,17 @@ defmodule NervesMOTDTest do
test "Default logo" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ @nerves_logo_regex
end

test "Custom logo" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd(logo: "custom logo") =~ ~r/custom logo/
refute capture_motd(logo: "custom logo") =~ @nerves_logo_regex
Expand All @@ -55,20 +59,26 @@ defmodule NervesMOTDTest do
test "No logo" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

refute capture_motd(logo: "") =~ @nerves_logo_regex
end

test "Custom rows" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd(extra_rows: [[{"custom row", "hello"}]]) =~ ~r/hello/
end

test "Uname" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~
~r/nerves_livebook 0.2.17 \(0540f0cd-f95a-5596-d152-221a70c078a9\) arm rpi4/
Expand All @@ -77,6 +87,8 @@ defmodule NervesMOTDTest do
test "Serial number" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

# Nerves.Runtime.serial_number() is expected to fail when running
# the regression tests since not using Nerves.
Expand All @@ -86,20 +98,26 @@ defmodule NervesMOTDTest do
test "Uptime" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ ~r/Uptime : .*\d{0,2} seconds/
end

test "Clock" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ ~r/Clock : \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \w{3}/
end

test "Temperature when available" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)
|> Mox.expect(:cpu_temperature, 1, fn -> {:ok, 41.234} end)

assert capture_motd() =~ ~r/Temperature : 41.2°C/
Expand All @@ -108,6 +126,8 @@ defmodule NervesMOTDTest do
test "Temperature when unavailable" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)
|> Mox.expect(:cpu_temperature, 1, fn -> :error end)

refute capture_motd() =~ ~r/Temperature/
Expand All @@ -116,22 +136,38 @@ defmodule NervesMOTDTest do
test "Firmware when valid" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:firmware_valid?, 1, fn -> true end)
|> Mox.expect(:active_partition, 1, fn -> "B" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ ~r/Firmware : Valid \(A\)/
assert capture_motd() =~ ~r/Firmware : Valid \(B\)/
end

test "Firmware when invalid" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:firmware_valid?, 1, fn -> false end)
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :invalid end)

assert capture_motd() =~ ~r/Firmware : Not validated \(A\)/
end

test "Firmware validity is unknown" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :unknown end)

assert capture_motd() =~ ~r/Firmware : A/
end

test "Applications when all apps started" do
apps = %{started: [:a, :b, :nerves_runtime], loaded: [:a, :b, :nerves_runtime]}
Mox.expect(NervesMOTD.MockRuntime, :applications, 1, fn -> apps end)

NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, fn -> apps end)
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :unknown end)

assert capture_motd() =~ ~r/Applications : \d* started/
end

Expand All @@ -140,27 +176,35 @@ defmodule NervesMOTDTest do

NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, fn -> apps end)
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ ~r/Applications : \d* started \(a, b not started\)/
end

test "Hostname" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ ~r/Hostname : [0-9a-zA-Z\-]*/
end

test "Memory usage when ok" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ ~r/Memory usage : 78 MB \(25%\)/
end

test "Memory usage when high" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)
|> Mox.expect(:memory_stats, 1, fn ->
{:ok, %{size_mb: 316, used_mb: 316, used_percent: 100}}
end)
Expand All @@ -171,13 +215,17 @@ defmodule NervesMOTDTest do
test "Load average" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ ~r/Load average : 0.35 0.16 0.11/
end

test "Load average error" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)
|> Mox.expect(:load_average, 1, fn -> [] end)

assert capture_motd() =~ ~r/Load average : error/
Expand All @@ -186,13 +234,17 @@ defmodule NervesMOTDTest do
test "Application partition usage" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ ~r/Part usage : 37 MB \(0%\)/
end

test "Application partition usage high" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)
|> Mox.expect(:filesystem_stats, 1, fn _path ->
{:ok, %{size_mb: 14_300, used_mb: 12_900, used_percent: 90}}
end)
Expand All @@ -203,6 +255,8 @@ defmodule NervesMOTDTest do
test "Application partition usage not available" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)
|> Mox.expect(:filesystem_stats, 1, fn _path ->
:error
end)
Expand All @@ -213,6 +267,8 @@ defmodule NervesMOTDTest do
test "No application partition" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

old_devpath = Nerves.Runtime.KV.get_active("nerves_fw_application_part0_devpath")
Nerves.Runtime.KV.put_active("nerves_fw_application_part0_devpath", "")
Expand All @@ -224,6 +280,8 @@ defmodule NervesMOTDTest do
test "IP addresses" do
NervesMOTD.MockRuntime
|> Mox.expect(:applications, 1, default_applications_code())
|> Mox.expect(:active_partition, 1, fn -> "A" end)
|> Mox.expect(:firmware_validity, 1, fn -> :valid end)

assert capture_motd() =~ ~r/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,3}/
end
Expand Down

0 comments on commit 1db9e52

Please sign in to comment.