Skip to content
This repository has been archived by the owner on Jun 11, 2023. It is now read-only.

Commit

Permalink
Support 'detach' action on MotherboardUpdateRequest
Browse files Browse the repository at this point in the history
  • Loading branch information
renatomassaro committed Dec 14, 2017
1 parent c2067bb commit 7af42f7
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 16 deletions.
2 changes: 1 addition & 1 deletion lib/entity/henforcer/entity.ex
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,6 @@ defmodule Helix.Entity.Henforcer.Entity do
else
reply_error({:network_connection, :not_belongs})
end
|> wrap_relay(%{entity_network_connections: owned})
|> wrap_relay(%{entity_network_connections: owned, entity: entity})
end
end
12 changes: 12 additions & 0 deletions lib/server/action/flow/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule Helix.Server.Action.Flow.Server do
alias Helix.Server.Action.Motherboard, as: MotherboardAction
alias Helix.Server.Action.Server, as: ServerAction
alias Helix.Server.Model.Component
alias Helix.Server.Model.Motherboard
alias Helix.Server.Model.Server

@spec setup(Server.type, Entity.t, Component.mobo, Event.relay) ::
Expand Down Expand Up @@ -67,6 +68,17 @@ defmodule Helix.Server.Action.Flow.Server do
end
end

def detach_mobo(server = %Server{}, motherboard = %Motherboard{}, _relay) do
flowing do
with \
:ok <- MotherboardAction.detach(motherboard),
{:ok, new_server} <- ServerAction.detach(server)
do
{:ok, new_server}
end
end
end

defp update_server_mobo(server = %Server{motherboard_id: mobo_id}, mobo_id),
do: {:ok, server}
defp update_server_mobo(server, nil),
Expand Down
3 changes: 3 additions & 0 deletions lib/server/action/motherboard.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ defmodule Helix.Server.Action.Motherboard do

defdelegate update(cur_mobo_data, new_mobo_data, entity_ncs),
to: __MODULE__.Update

defdelegate detach(motherboard),
to: __MODULE__.Update
end
21 changes: 21 additions & 0 deletions lib/server/action/motherboard/update.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,33 @@ defmodule Helix.Server.Action.Motherboard.Update do
alias Helix.Network.Model.Network
alias Helix.Network.Query.Network, as: NetworkQuery
alias Helix.Server.Action.Component, as: ComponentAction
alias Helix.Server.Model.Component
alias Helix.Server.Model.Motherboard
alias Helix.Server.Internal.Motherboard, as: MotherboardInternal
alias Helix.Server.Query.Component, as: ComponentQuery
alias Helix.Server.Query.Motherboard, as: MotherboardQuery
alias Helix.Server.Repo, as: ServerRepo

@internet_id NetworkQuery.internet().network_id

def detach(motherboard = %Motherboard{}) do
MotherboardInternal.unlink_all(motherboard)

hespawn fn ->
motherboard
|> MotherboardQuery.get_nics()
|> Enum.each(fn nic ->
nc = NetworkQuery.Connection.fetch_by_nic(nic.component_id)

if nc do
perform_network_op({:nilify_nic, nc})
end
end)
end

:ok
end

def update(nil, mobo_data, entity_ncs) do
{:ok, new_mobo} =
MotherboardInternal.setup(mobo_data.mobo, mobo_data.components)
Expand Down
23 changes: 21 additions & 2 deletions lib/server/henforcer/component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ defmodule Helix.Server.Henforcer.Component do

alias Helix.Entity.Henforcer.Entity, as: EntityHenforcer
alias Helix.Network.Query.Network, as: NetworkQuery
alias Helix.Server.Henforcer.Server, as: ServerHenforcer
alias Helix.Server.Model.Component
alias Helix.Server.Model.Motherboard
alias Helix.Server.Model.Server
alias Helix.Server.Query.Component, as: ComponentQuery
alias Helix.Server.Query.Motherboard, as: MotherboardQuery

@internet_id NetworkQuery.internet().network_id

Expand Down Expand Up @@ -90,7 +93,7 @@ defmodule Helix.Server.Henforcer.Component do
|> elem(0)
end

reduce_network_connections = fn entity, components ->
reduce_network_connections = fn entity ->
init = {{true, %{}}, nil}

network_connections
Expand Down Expand Up @@ -146,7 +149,7 @@ defmodule Helix.Server.Henforcer.Component do
{true, _} <- has_initial_components?(components),

# Iterate over NetworkConnections and make the required henforcements
{true, r2} <- reduce_network_connections.(entity, components),
{true, r2} <- reduce_network_connections.(entity),

# The mobo must have at least one public NC assigned to it
{true, _} <- has_public_nip?(r2.network_connections)
Expand All @@ -157,4 +160,20 @@ defmodule Helix.Server.Henforcer.Component do
error
end
end

def can_detach_mobo?(server_id = %Server.ID{}) do
henforce ServerHenforcer.server_exists?(server_id) do
can_detach_mobo?(relay.server)
end
end

# TODO: Mainframe verification, cost analysis (for cooldown) etc.
def can_detach_mobo?(server = %Server{}) do
with \
{true, _} <- component_exists?(server.motherboard_id)
do
motherboard = MotherboardQuery.fetch(server.motherboard_id)
reply_ok(%{motherboard: motherboard})
end
end
end
4 changes: 4 additions & 0 deletions lib/server/public/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ defmodule Helix.Server.Public.Server do
ServerFlow.update_mobo(server, motherboard, mobo_data, entity_ncs, relay)
end

def detach_mobo(server, motherboard, relay) do
ServerFlow.detach_mobo(server, motherboard, relay)
end

defdelegate set_hostname(server, hostname, relay),
to: ServerFlow

Expand Down
35 changes: 33 additions & 2 deletions lib/server/websocket/requests/motherboard_update.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ request Helix.Server.Websocket.Requests.MotherboardUpdate do
alias Helix.Server.Public.Server, as: ServerPublic

def check_params(request, socket) do
if Enum.empty?(request.unsafe) do
if request.unsafe["cmd"] == "detach" do
check_detach(request, socket)
else
check_update(request, socket)
Expand Down Expand Up @@ -64,6 +64,25 @@ request Helix.Server.Websocket.Requests.MotherboardUpdate do
end
end

def check_permissions(request = %{params: %{cmd: :detach}}, socket) do
gateway_id = socket.assigns.gateway.server_id

with \
{true, relay} <- ComponentHenforcer.can_detach_mobo?(gateway_id)
do
meta = %{
server: relay.server,
motherboard: relay.motherboard
}

update_meta(request, meta, reply: true)
else
{false, reason, _} ->
reply_error(request, reason)
end

end

def check_permissions(request = %{params: %{cmd: :update}}, socket) do
gateway_id = socket.assigns.gateway.server_id
entity_id = socket.assigns.gateway.entity_id
Expand Down Expand Up @@ -92,7 +111,19 @@ request Helix.Server.Websocket.Requests.MotherboardUpdate do
end
end

def handle_request(request = %{params: %{cmd: :update}}, socket) do
def handle_request(request = %{params: %{cmd: :detach}}, _socket) do
server = request.meta.server
motherboard = request.meta.motherboard
relay = request.relay

hespawn fn ->
ServerPublic.detach_mobo(server, motherboard, relay)
end

reply_ok(request)
end

def handle_request(request = %{params: %{cmd: :update}}, _socket) do
server = request.meta.server
mobo = request.meta.mobo
components = request.meta.components
Expand Down
40 changes: 32 additions & 8 deletions test/server/websocket/channel/server/topics/motherboard_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,21 @@ defmodule Helix.Server.Websocket.Channel.Server.Topics.MotherboardTest do
import Phoenix.ChannelTest
import Helix.Test.Macros

alias Helix.Websocket.Requestable
alias Helix.Entity.Action.Entity, as: EntityAction
alias Helix.Network.Action.Network, as: NetworkAction
alias Helix.Network.Model.Network
alias Helix.Network.Query.Network, as: NetworkQuery
alias Helix.Server.Model.Component
alias Helix.Server.Query.Motherboard, as: MotherboardQuery
alias Helix.Server.Query.Server, as: ServerQuery

alias HELL.TestHelper.Random
alias Helix.Test.Cache.Helper, as: CacheHelper
alias Helix.Test.Channel.Setup, as: ChannelSetup
alias Helix.Test.Network.Helper, as: NetworkHelper
alias Helix.Test.Software.Setup, as: SoftwareSetup
alias Helix.Test.Universe.NPC.Helper, as: NPCHelper
alias Helix.Test.Server.Helper, as: ServerHelper
alias Helix.Test.Server.Setup, as: ServerSetup

alias Helix.Test.Network.Setup, as: NetworkSetup
alias Helix.Test.Server.Component.Setup, as: ComponentSetup

@internet_id NetworkHelper.internet_id()
@internet_str to_string(@internet_id)

describe "motherboard.update" do
test "updates the components" do
Expand Down Expand Up @@ -122,5 +114,37 @@ defmodule Helix.Server.Websocket.Channel.Server.Topics.MotherboardTest do

assert motherboard.slots.nic_2.custom.network_id == nc_custom.network_id
end

test "detaches the mobo (and unlinks the underlying components)" do
{socket, %{gateway: server}} = ChannelSetup.join_server(own_server: true)

# Get current NC (used for later verification)
%{ip: ip, network_id: network_id} = ServerHelper.get_nip(server)
cur_nc = NetworkQuery.Connection.fetch(network_id, ip)

# It is attached to a NIC
nic_id = cur_nc.nic_id
assert nic_id

params = %{"cmd" => "detach"}

ref = push socket, "motherboard.update", params

# It worked!
assert_reply ref, :ok, response, timeout(:slow)

# Empty response. It's async!
assert Enum.empty?(response.data)

# TODO: Test received the events

new_server = ServerQuery.fetch(server.server_id)

# Motherboard is gone!
refute new_server.motherboard_id

# And so are all the components linked to it
refute MotherboardQuery.fetch(server.motherboard_id)
end
end
end
84 changes: 82 additions & 2 deletions test/server/websocket/requests/motherboard_update_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ defmodule Helix.Server.Websocket.Requests.MotherboardUpdateTest do
alias Helix.Network.Model.Network
alias Helix.Network.Query.Network, as: NetworkQuery
alias Helix.Server.Model.Component
alias Helix.Server.Query.Component, as: ComponentQuery
alias Helix.Server.Query.Motherboard, as: MotherboardQuery
alias Helix.Server.Query.Server, as: ServerQuery
alias Helix.Server.Websocket.Requests.MotherboardUpdate,
Expand Down Expand Up @@ -58,6 +59,15 @@ defmodule Helix.Server.Websocket.Requests.MotherboardUpdateTest do
assert nip == {Network.ID.cast!("::"), "1.2.3.4"}
end

test "infers players want to detach mobo when params are empty" do
params = %{"cmd" => "detach"}

req = MotherboardUpdateRequest.new(params)
assert {:ok, req} = Requestable.check_params(req, @mock_socket)

assert req.params.cmd == :detach
end

test "handles invalid slot data" do
base_params = %{"motherboard_id" => "::"}

Expand Down Expand Up @@ -167,7 +177,7 @@ defmodule Helix.Server.Websocket.Requests.MotherboardUpdateTest do
end

describe "MotherboardUpdateRequest.check_permissions" do
test "accepts when data is valid" do
test "accepts when data is valid (update)" do
{server, %{entity: entity}} = ServerSetup.server()

{cpu, _} = ComponentSetup.component(type: :cpu)
Expand Down Expand Up @@ -218,7 +228,7 @@ defmodule Helix.Server.Websocket.Requests.MotherboardUpdateTest do
assert request.meta.entity_network_connections
end

test "rejects when something is wrong" do
test "rejects when something is wrong (update)" do
{server, %{entity: entity}} = ServerSetup.server()

{cpu, _} = ComponentSetup.component(type: :cpu)
Expand Down Expand Up @@ -267,6 +277,25 @@ defmodule Helix.Server.Websocket.Requests.MotherboardUpdateTest do

assert reason == "network_connection_not_belongs"
end

test "accepts when data is valid (detach)" do
{server, %{entity: entity}} = ServerSetup.server()

params = %{"cmd" => "detach"}

socket =
ChannelSetup.mock_server_socket(
gateway_id: server.server_id,
gateway_entity_id: entity.entity_id,
access_type: :local
)

request = MotherboardUpdateRequest.new(params)
assert {:ok, request} = Requestable.check_params(request, socket)
assert {:ok, request} = Requestable.check_permissions(request, socket)

assert request.meta.server == server
end
end

describe "MotherboardUpdateRequest.handle_request" do
Expand Down Expand Up @@ -372,5 +401,56 @@ defmodule Helix.Server.Websocket.Requests.MotherboardUpdateTest do

assert motherboard.slots.nic_2.custom.network_id == nc_custom.network_id
end

test "detaches the motherboard" do
{server, %{entity: entity}} = ServerSetup.server()

# Get current NC (used for later verification)
%{ip: ip, network_id: network_id} = ServerHelper.get_nip(server)
cur_nc = NetworkQuery.Connection.fetch(network_id, ip)

# It is attached to a NIC
nic_id = cur_nc.nic_id
assert nic_id

params = %{"cmd" => "detach"}

socket =
ChannelSetup.mock_server_socket(
gateway_id: server.server_id,
gateway_entity_id: entity.entity_id,
access_type: :local
)

request = MotherboardUpdateRequest.new(params)
assert {:ok, request} = Requestable.check_params(request, socket)
assert {:ok, request} = Requestable.check_permissions(request, socket)
assert {:ok, _request} = Requestable.handle_request(request, socket)

# Detaching is asynchronous, so we don't care about the returned value of
# `handle_request/2`. Now we must make sure that the mobo was detached.

new_server = ServerQuery.fetch(server.server_id)

# Motherboard is gone!
refute new_server.motherboard_id

# And so are all the components linked to it
refute MotherboardQuery.fetch(server.motherboard_id)

# Underlying components still exist (but they are not linked to any mobo)
assert ComponentQuery.fetch(nic_id)

# Old NIC points to no NC (i.e. no NCs are assigned to the NIC)
refute NetworkQuery.Connection.fetch_by_nic(nic_id)

# Old NIP still exists - but it's unused
new_nc = NetworkQuery.Connection.fetch(network_id, ip)

assert new_nc.network_id == network_id
assert new_nc.ip == ip
assert new_nc.entity_id == entity.entity_id
refute new_nc.nic_id
end
end
end
2 changes: 1 addition & 1 deletion test/support/server/helper.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ defmodule Helix.Test.Server.Helper do
def get_nip(server = %Server{}),
do: get_nip(server.server_id)
def get_nip(server_id = %Server.ID{}),
do: get_all_nips(server_id) |> List.first()
do: get_all_nips(server_id) |> List.first()

def get_all_nips(server = %Server{}),
do: get_all_nips(server.server_id)
Expand Down

0 comments on commit 7af42f7

Please sign in to comment.