Skip to content

Commit

Permalink
Add Host aggregate and Host registration command/event (#21)
Browse files Browse the repository at this point in the history
* Add Domo and TypedStruct to the mix; import Commanded.AggregateCase support module

* Import typed struct formatter config

* Add host aggregate and host registration command/event

* Add router and wire-up commands

* Start commanded when application starts

* Add host aggregate tests

* Add domo generated code to dialyzer ignore list
  • Loading branch information
fabriziosestito authored Dec 27, 2021
1 parent a87b803 commit 86a931d
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .dialyzer_ignore.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
~r/.*domo_generated_code.*/
]
2 changes: 1 addition & 1 deletion .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[
import_deps: [:ecto, :phoenix],
import_deps: [:ecto, :phoenix, :typed_struct],
locals_without_parens: [
# mock
assert_called: :*
Expand Down
1 change: 1 addition & 0 deletions lib/tronto/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ defmodule Tronto.Application do
{Phoenix.PubSub, name: Tronto.PubSub},
# Start the Endpoint (http/https)
TrontoWeb.Endpoint,
Tronto.Commanded,
Tronto.Scheduler
# Start a worker by calling: Tronto.Worker.start_link(arg)
# {Tronto.Worker, arg}
Expand Down
2 changes: 2 additions & 0 deletions lib/tronto/commanded.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ defmodule Tronto.Commanded do
"""

use Commanded.Application, otp_app: :tronto

router(Tronto.Router)
end
17 changes: 17 additions & 0 deletions lib/tronto/monitoring/domain/hosts/commands/register_host.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule Tronto.Monitoring.Domain.Commands.RegisterHost do
@moduledoc """
Register a host to the monitoring system.
"""

use TypedStruct
use Domo

typedstruct do
@typedoc "RegisterHost command"

field :id_host, String.t(), enforce: true
field :hostname, String.t(), enforce: true
field :ip_addresses, [String.t()], enforce: true
field :agent_version, String.t(), enforce: true
end
end
17 changes: 17 additions & 0 deletions lib/tronto/monitoring/domain/hosts/events/host_registered.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule Tronto.Monitoring.Domain.Events.HostRegistered do
@moduledoc """
This event is emitted when a host is registered.
"""

use TypedStruct

@derive Jason.Encoder
typedstruct do
@typedoc "HostRegistered event"

field :id_host, String.t(), enforce: true
field :hostname, String.t(), enforce: true
field :ip_addresses, [String.t()], enforce: true
field :agent_version, String.t(), enforce: true
end
end
70 changes: 70 additions & 0 deletions lib/tronto/monitoring/domain/hosts/host.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
defmodule Tronto.Monitoring.Domain.Host do
@moduledoc false

alias Tronto.Monitoring.Domain.Host

alias Tronto.Monitoring.Domain.Commands.{
RegisterHost
}

alias Tronto.Monitoring.Domain.Events.{
HostRegistered
}

defstruct [
:id_host,
:hostname,
:ip_addresses,
:agent_version
]

@type t :: %__MODULE__{
id_host: String.t(),
hostname: String.t(),
ip_addresses: [String.t()],
agent_version: String.t()
}

# New host registered
def execute(
%Host{id_host: nil},
%RegisterHost{
id_host: id_host,
hostname: hostname,
ip_addresses: ip_addresses,
agent_version: agent_version
}
) do
%HostRegistered{
id_host: id_host,
hostname: hostname,
ip_addresses: ip_addresses,
agent_version: agent_version
}
end

def execute(
%Host{id_host: _},
%RegisterHost{}
) do
[]
end

def apply(
%Host{} = host,
%HostRegistered{
id_host: id_host,
hostname: hostname,
ip_addresses: ip_addresses,
agent_version: agent_version
}
) do
%Host{
host
| id_host: id_host,
hostname: hostname,
ip_addresses: ip_addresses,
agent_version: agent_version
}
end
end
12 changes: 12 additions & 0 deletions lib/tronto/router.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule Tronto.Router do
use Commanded.Commands.Router

alias Tronto.Monitoring.Domain.Host

alias Tronto.Monitoring.Domain.Commands.{
RegisterHost
}

identify(Host, by: :id_host)
dispatch(RegisterHost, to: Host)
end
10 changes: 7 additions & 3 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ defmodule Tronto.MixProject do
version: "0.1.0",
elixir: "~> 1.12",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:gettext] ++ Mix.compilers(),
compilers: [:gettext, :domo_compiler] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps(),
Expand All @@ -30,7 +30,9 @@ defmodule Tronto.MixProject do
end

# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(:test),
do: ["lib", "test/support", "deps/commanded/test/support/aggregate_case.ex"]

defp elixirc_paths(_), do: ["lib"]

# Specifies your project dependencies.
Expand All @@ -42,6 +44,7 @@ defmodule Tronto.MixProject do
{:commanded_eventstore_adapter, "~> 1.2"},
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false},
{:domo, "~> 1.5"},
{:ecto_sql, "~> 3.6"},
{:esbuild, "~> 0.2", runtime: Mix.env() == :dev},
{:faker, "~> 0.17", only: :test},
Expand All @@ -61,7 +64,8 @@ defmodule Tronto.MixProject do
{:quantum, ">= 1.8.0"},
{:swoosh, "~> 1.3"},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"}
{:telemetry_poller, "~> 1.0"},
{:typed_struct, "~> 0.2.1"}
]
end

Expand Down
2 changes: 2 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"db_connection": {:hex, :db_connection, "2.4.1", "6411f6e23f1a8b68a82fa3a36366d4881f21f47fc79a9efb8c615e62050219da", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ea36d226ec5999781a9a8ad64e5d8c4454ecedc7a4d643e4832bf08efca01f00"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
"domo": {:hex, :domo, "1.5.1", "188f1ab6fa4d57c531d4fc191406505e9be5d03b38e890fb51ad55b946e6adb9", [:mix], [{:decimal, ">= 0.0.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "bc5b9cd87bd3557bc7cd997df3dcd375a808565fe9c5858ddd6ad476389b483e"},
"ecto": {:hex, :ecto, "3.7.1", "a20598862351b29f80f285b21ec5297da1181c0442687f9b8329f0445d228892", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d36e5b39fc479e654cffd4dbe1865d9716e4a9b6311faff799b6f90ab81b8638"},
"ecto_sql": {:hex, :ecto_sql, "3.7.1", "8de624ef50b2a8540252d8c60506379fbbc2707be1606853df371cf53df5d053", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2b42a32e2ce92f64aba5c88617891ab3b0ba34f3f3a503fa20009eae1a401c81"},
"elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"},
Expand Down Expand Up @@ -50,4 +51,5 @@
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"telemetry_registry": {:hex, :telemetry_registry, "0.3.0", "6768f151ea53fc0fbca70dbff5b20a8d663ee4e0c0b2ae589590e08658e76f1e", [:mix, :rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "492e2adbc609f3e79ece7f29fec363a97a2c484ac78a83098535d6564781e917"},
"typed_struct": {:hex, :typed_struct, "0.2.1", "e1993414c371f09ff25231393b6430bd89d780e2a499ae3b2d2b00852f593d97", [:mix], [], "hexpm", "8f5218c35ec38262f627b2c522542f1eae41f625f92649c0af701a6fab2e11b3"},
}
69 changes: 69 additions & 0 deletions test/tronto/domain/host/host_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
defmodule Tronto.Monitoring.HostTest do
use Commanded.AggregateCase, aggregate: Tronto.Monitoring.Domain.Host, async: true

alias Tronto.Monitoring.Domain.Host
alias Tronto.Monitoring.Domain.Commands.RegisterHost
alias Tronto.Monitoring.Domain.Events.HostRegistered

describe "host registration" do
test "should register a host" do
id_host = Faker.UUID.v4()
hostname = Faker.StarWars.character()
ip_addresses = [Faker.Internet.ip_v4_address()]
agent_version = Faker.Internet.slug()

commands = [
RegisterHost.new!(
id_host: id_host,
hostname: hostname,
ip_addresses: ip_addresses,
agent_version: agent_version
)
]

assert_events(
commands,
%HostRegistered{
id_host: id_host,
hostname: hostname,
ip_addresses: ip_addresses,
agent_version: agent_version
}
)

assert_state(
commands,
%Host{
id_host: id_host,
hostname: hostname,
ip_addresses: ip_addresses,
agent_version: agent_version
}
)
end

test "should not register a host if it is already registered" do
id_host = Faker.UUID.v4()

assert_events(
[
%HostRegistered{
id_host: id_host,
hostname: Faker.StarWars.character(),
ip_addresses: [Faker.Internet.ip_v4_address()],
agent_version: Faker.Internet.slug()
}
],
[
RegisterHost.new!(
id_host: id_host,
hostname: Faker.StarWars.character(),
ip_addresses: [Faker.Internet.ip_v4_address()],
agent_version: Faker.Internet.slug()
)
],
[]
)
end
end
end

0 comments on commit 86a931d

Please sign in to comment.