This repository has been archived by the owner on Jun 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MotherboardUpdateRequest (check_params)
- Loading branch information
1 parent
bf75c87
commit 43e5c58
Showing
3 changed files
with
318 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import Helix.Websocket.Request | ||
|
||
request Helix.Server.Websocket.Requests.MotherboardUpdate do | ||
|
||
alias HELL.IPv4 | ||
alias HELL.Utils | ||
alias Helix.Network.Model.Network | ||
alias Helix.Server.Model.Component | ||
alias Helix.Server.Public.Server, as: ServerPublic | ||
|
||
def check_params(request, socket) do | ||
if Enum.empty?(request.unsafe) do | ||
check_detach(request, socket) | ||
else | ||
check_update(request, socket) | ||
end | ||
end | ||
|
||
def check_detach(request, socket) do | ||
with \ | ||
true <- socket.assigns.meta.access_type == :local || :bad_src | ||
do | ||
update_params(request, %{cmd: :detach}, reply: true) | ||
else | ||
:bad_src -> | ||
reply_error(request, "bad_src") | ||
|
||
_ -> | ||
bad_request(request) | ||
end | ||
end | ||
|
||
def check_update(request, socket) do | ||
with \ | ||
true <- socket.assigns.meta.access_type == :local || :bad_src, | ||
{:ok, mobo_id} <- Component.ID.cast(request.unsafe["motherboard_id"]), | ||
{:ok, slots} <- cast_slots(request.unsafe["slots"]), | ||
{:ok, ncs} <- cast_ncs(request.unsafe["network_connections"]) | ||
do | ||
params = %{ | ||
slots: slots, | ||
network_connections: ncs, | ||
mobo_id: mobo_id, | ||
cmd: :update | ||
} | ||
|
||
update_params(request, params, reply: true) | ||
else | ||
:bad_src -> | ||
reply_error(request, "bad_src") | ||
|
||
:bad_slots -> | ||
reply_error(request, "bad_slot_data") | ||
|
||
:bad_ncs -> | ||
reply_error(request, "bad_network_connections") | ||
|
||
_ -> | ||
bad_request(request) | ||
end | ||
end | ||
|
||
def check_permissions(request, socket) do | ||
end | ||
|
||
def handle_request(request, socket) do | ||
end | ||
|
||
render_empty() | ||
|
||
defp cast_ncs(nil), | ||
do: :bad_ncs | ||
defp cast_ncs(network_connections) do | ||
try do | ||
ncs = | ||
Enum.map(network_connections, fn {nic_id, nc} -> | ||
{:ok, nic_id} = Component.ID.cast(nic_id) | ||
{:ok, ip} = IPv4.cast(nc["ip"]) | ||
{:ok, network_id} = Network.ID.cast(nc["network_id"]) | ||
|
||
{nic_id, {ip, network_id}} | ||
end) | ||
|
||
{:ok, ncs} | ||
rescue | ||
_ -> | ||
:bad_ncs | ||
end | ||
end | ||
|
||
# TODO: Move to a SpecableHelper or something like that | ||
defp cast_slots(nil), | ||
do: :bad_slots | ||
defp cast_slots(slots) do | ||
try do | ||
slots = | ||
slots | ||
|> Enum.map(fn {slot_id, component_id} -> | ||
component_id = | ||
if component_id do | ||
Component.ID.cast!(component_id) | ||
else | ||
nil | ||
end | ||
|
||
{:ok, slot_id} = cast_slot_id(slot_id) | ||
|
||
{slot_id, component_id} | ||
end) | ||
|> Enum.into(%{}) | ||
|
||
{:ok, slots} | ||
rescue | ||
_ -> | ||
:bad_slots | ||
end | ||
end | ||
|
||
defp cast_slot_id("cpu_" <> id), | ||
do: concat_slot(:cpu, id) | ||
defp cast_slot_id("ram_" <> id), | ||
do: concat_slot(:ram, id) | ||
defp cast_slot_id("hdd_" <> id), | ||
do: concat_slot(:hdd, id) | ||
defp cast_slot_id("nic_" <> id), | ||
do: concat_slot(:nic, id) | ||
defp cast_slot_id("usb_" <> id), | ||
do: concat_slot(:usb, id) | ||
defp cast_slot_id(_), | ||
do: :error | ||
|
||
defp concat_slot(component, id) do | ||
case Integer.parse(id) do | ||
{_, ""} -> | ||
slot_id = | ||
component | ||
|> Utils.concat_atom("_") | ||
|> Utils.concat_atom(id) | ||
|
||
{:ok, slot_id} | ||
|
||
_ -> | ||
:error | ||
end | ||
end | ||
|
||
end |
153 changes: 153 additions & 0 deletions
153
test/server/websocket/requests/motherboard_update_test.exs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
defmodule Helix.Server.Websocket.Requests.MotherboardUpdateTest do | ||
|
||
use Helix.Test.Case.Integration | ||
|
||
alias Helix.Websocket.Requestable | ||
alias Helix.Network.Model.Network | ||
alias Helix.Server.Model.Component | ||
alias Helix.Server.Websocket.Requests.MotherboardUpdate, | ||
as: MotherboardUpdateRequest | ||
|
||
alias Helix.Test.Channel.Setup, as: ChannelSetup | ||
|
||
@mock_socket ChannelSetup.mock_server_socket(access_type: :local) | ||
|
||
describe "MotherboardUpdateRequest.check_params" do | ||
test "casts the params to internal Helix format" do | ||
params = | ||
%{ | ||
"motherboard_id" => "::1", | ||
"slots" => %{ | ||
"cpu_1" => "::f", | ||
"ram_1" => nil, | ||
}, | ||
"network_connections" => %{ | ||
"::5" => %{ | ||
"network_id" => "::", | ||
"ip" => "1.2.3.4" | ||
} | ||
} | ||
} | ||
|
||
req = MotherboardUpdateRequest.new(params) | ||
assert {:ok, req} = Requestable.check_params(req, @mock_socket) | ||
|
||
assert req.params.cmd == :update | ||
assert req.params.mobo_id == Component.ID.cast!(params["motherboard_id"]) | ||
assert req.params.slots.cpu_1 == Component.ID.cast!("::f") | ||
refute req.params.slots.ram_1 | ||
|
||
[{nic_id, nip}] = req.params.network_connections | ||
|
||
assert nic_id == Component.ID.cast!("::5") | ||
assert nip == {"1.2.3.4", Network.ID.cast!("::")} | ||
end | ||
|
||
test "handles invalid slot data" do | ||
base_params = %{"motherboard_id" => "::"} | ||
|
||
# Invalid component type `notexists` | ||
p1 = | ||
%{ | ||
"slots" => %{"notexists_50" => "::"} | ||
} |> Map.merge(base_params) | ||
|
||
# Invalid slot `abc` | ||
p2 = | ||
%{ | ||
"slots" => %{"cpu_abc" => nil} | ||
} |> Map.merge(base_params) | ||
|
||
# Invalid component ID `wtf` | ||
p3 = | ||
%{ | ||
"slots" => %{"cpu_1" => "wtf"} | ||
} |> Map.merge(base_params) | ||
|
||
# Empty slots | ||
p4 = base_params | ||
|
||
req1 = MotherboardUpdateRequest.new(p1) | ||
req2 = MotherboardUpdateRequest.new(p2) | ||
req3 = MotherboardUpdateRequest.new(p3) | ||
req4 = MotherboardUpdateRequest.new(p4) | ||
|
||
assert {:error, %{message: reason1}, _} = | ||
Requestable.check_params(req1, @mock_socket) | ||
assert {:error, %{message: reason2}, _} = | ||
Requestable.check_params(req2, @mock_socket) | ||
assert {:error, %{message: reason3}, _} = | ||
Requestable.check_params(req3, @mock_socket) | ||
assert {:error, %{message: reason4}, _} = | ||
Requestable.check_params(req4, @mock_socket) | ||
|
||
assert reason1 == "bad_slot_data" | ||
assert reason2 == reason1 | ||
assert reason3 == reason2 | ||
assert reason4 == reason3 | ||
end | ||
|
||
test "handles invalid network connections" do | ||
base_params = | ||
%{ | ||
"motherboard_id" => "::f", | ||
"slots" => %{"cpu_1" => "::1"}, | ||
} | ||
|
||
# Empty NCs | ||
p1 = base_params | ||
|
||
# Invalid NIC ID | ||
p2 = | ||
%{ | ||
"network_connections" => %{ | ||
"invalid_component" => %{ | ||
"ip" => "1.2.3.4", | ||
"network_id" => "::" | ||
} | ||
} | ||
} |> Map.merge(base_params) | ||
|
||
# Invalid IP | ||
p3 = | ||
%{ | ||
"network_connections" => %{ | ||
"::f" => %{ | ||
"ip" => "abc", | ||
"network_id" => "::" | ||
} | ||
} | ||
} |> Map.merge(base_params) | ||
|
||
# Invalid network ID | ||
p4 = | ||
%{ | ||
"network_connections" => %{ | ||
"::f" => %{ | ||
"ip" => "127.0.0.1", | ||
"network_id" => "invalid" | ||
} | ||
} | ||
} |> Map.merge(base_params) | ||
|
||
req1 = MotherboardUpdateRequest.new(p1) | ||
req2 = MotherboardUpdateRequest.new(p2) | ||
req3 = MotherboardUpdateRequest.new(p3) | ||
req4 = MotherboardUpdateRequest.new(p4) | ||
|
||
assert {:error, %{message: reason1}, _} = | ||
Requestable.check_params(req1, @mock_socket) | ||
assert {:error, %{message: reason2}, _} = | ||
Requestable.check_params(req2, @mock_socket) | ||
assert {:error, %{message: reason3}, _} = | ||
Requestable.check_params(req3, @mock_socket) | ||
assert {:error, %{message: reason4}, _} = | ||
Requestable.check_params(req4, @mock_socket) | ||
|
||
assert reason1 == "bad_network_connections" | ||
assert reason2 == reason1 | ||
assert reason3 == reason2 | ||
assert reason4 == reason3 | ||
end | ||
end | ||
end |