diff --git a/assets/js/components/ChecksResults.jsx b/assets/js/components/ChecksResults.jsx
index 4887c6cef1..42b73bfbe8 100644
--- a/assets/js/components/ChecksResults.jsx
+++ b/assets/js/components/ChecksResults.jsx
@@ -2,28 +2,12 @@ import React, { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
-import { EOS_LENS_FILLED, EOS_ERROR } from 'eos-icons-react';
+import { EOS_LENS_FILLED, EOS_ERROR, EOS_SCHEDULE } from 'eos-icons-react';
import Spinner from './Spinner';
import NotificationBox from './NotificationBox';
import LoadingBox from './LoadingBox';
-const getChecksResults = (cluster) => {
- if (cluster) {
- return cluster.checks_results
- .filter((check_result) => check_result.result != 'skipped') // Filter "skipped" results by now
- .reduce((acc, checkResult) => {
- acc[checkResult.host_id] = [
- ...(acc[checkResult.host_id] || []),
- checkResult,
- ];
-
- return acc;
- }, {});
- }
- return {};
-};
-
const getHostname =
(hosts = []) =>
(hostId) => {
@@ -36,16 +20,26 @@ const getHostname =
}, '');
};
-const sortChecksResults = (checksResults = [], group) => {
+const sortChecksResults = (checksResults = []) => {
return checksResults.sort((a, b) => {
- if (a.check_id === b.check_id) {
- return group(a.check_id) > group(b.check_id) ? 1 : -1;
- }
return a.check_id > b.check_id ? 1 : -1;
});
};
-const getResultIcon = (result) => {
+const sortHosts = (hosts = []) => {
+ return hosts.sort((a, b) => {
+ return a.host_id > b.host_id ? 1 : -1;
+ });
+};
+
+const getResultIcon = (checks_execution, result) => {
+ switch (checks_execution) {
+ case 'requested':
+ return ;
+ case 'running':
+ return ;
+ }
+
switch (result) {
case 'passing':
return ;
@@ -54,7 +48,7 @@ const getResultIcon = (result) => {
case 'critical':
return ;
default:
- return ;
+ return ;
}
};
@@ -78,8 +72,6 @@ const ChecksResults = () => {
});
};
- const checksResults = getChecksResults(cluster);
-
const hostname = getHostname(useSelector((state) => state.hostsList.hosts));
useEffect(() => {
@@ -107,60 +99,83 @@ const ChecksResults = () => {
return (
- {Object.keys(checksResults).map((c) => (
-
-
-
-
-
-
- {hostname(c)}
-
-
-
-
-
- (
+
+
+
+
+
+
+ {hostname(host_id)}
+
+ {reachable == false && (
+
- ID
- |
-
- Description
- |
-
- Result
- |
-
-
-
- {sortChecksResults(checksResults[c]).map((checkResult) => (
-
-
- {checkResult.check_id}
- |
-
- {description(checkResult.check_id)}
- |
-
- {getResultIcon(checkResult.result)}
- |
+ {msg}
+
+ )}
+
+
+
+
+
+ ID
+ |
+
+ Description
+ |
+
+ Result
+ |
- ))}
-
-
+
+
+ {sortChecksResults(cluster?.checks_results.slice())
+ .filter(
+ (check_result) => check_result.host_id == host_id
+ )
+ .filter(
+ (check_result) => check_result.result != 'skipped'
+ ) // Filter "skipped" results by now
+ .map((checkResult) => (
+
+
+ {checkResult.check_id}
+ |
+
+ {description(checkResult.check_id)}
+ |
+
+ {getResultIcon(
+ cluster.checks_execution,
+ checkResult.result
+ )}
+ |
+
+ ))}
+
+
+
-
- ))}
+ )
+ )}
);
};
diff --git a/assets/js/state/clusters.js b/assets/js/state/clusters.js
index 57b908c7d1..dbbbb69207 100644
--- a/assets/js/state/clusters.js
+++ b/assets/js/state/clusters.js
@@ -58,6 +58,13 @@ export const clustersListSlice = createSlice({
}),
...action.payload.checks_results,
];
+
+ cluster.hosts_executions = [
+ ...cluster.hosts_executions.filter((host_execution) => {
+ return host_execution.host_id !== action.payload.host_id;
+ }),
+ ...action.payload.hosts_executions,
+ ];
}
return cluster;
});
diff --git a/lib/trento/application/integration/checks/checks.ex b/lib/trento/application/integration/checks/checks.ex
index a05ad6e6f6..0e4ca8e73d 100644
--- a/lib/trento/application/integration/checks/checks.ex
+++ b/lib/trento/application/integration/checks/checks.ex
@@ -99,9 +99,11 @@ defmodule Trento.Integration.Checks do
CompleteChecksExecution.new(%{
cluster_id: cluster_id,
hosts_executions:
- Enum.map(hosts, fn %{host_id: host_id, results: results} ->
+ Enum.map(hosts, fn %{host_id: host_id, reachable: reachable, msg: msg, results: results} ->
%{
host_id: host_id,
+ reachable: reachable,
+ msg: msg,
checks_results: Enum.map(results, &Map.from_struct/1)
}
end)
diff --git a/lib/trento/application/integration/checks/dto/execution_completed_event_dto.ex b/lib/trento/application/integration/checks/dto/execution_completed_event_dto.ex
index 2fa4dc7512..e2e0fc2bcd 100644
--- a/lib/trento/application/integration/checks/dto/execution_completed_event_dto.ex
+++ b/lib/trento/application/integration/checks/dto/execution_completed_event_dto.ex
@@ -12,6 +12,8 @@ defmodule Trento.Integration.Checks.ExecutionCompletedEventDto do
embeds_many :hosts, Host do
field :host_id, Ecto.UUID
+ field :reachable, :boolean
+ field :msg, :string
embeds_many :results, Result do
field :check_id, :string
@@ -29,7 +31,7 @@ defmodule Trento.Integration.Checks.ExecutionCompletedEventDto do
defp host_changeset(host, attrs) do
host
- |> cast(attrs, [:host_id])
+ |> cast(attrs, [:host_id, :reachable, :msg])
|> cast_embed(:results, with: &result_changeset/2)
|> validate_required([:host_id])
end
diff --git a/lib/trento/application/projectors/check_result_projector.ex b/lib/trento/application/projectors/check_result_projector.ex
index 5731c736d2..da997143a0 100644
--- a/lib/trento/application/projectors/check_result_projector.ex
+++ b/lib/trento/application/projectors/check_result_projector.ex
@@ -15,7 +15,10 @@ defmodule Trento.CheckResultProjector do
HostChecksExecutionCompleted
}
- alias Trento.CheckResultReadModel
+ alias Trento.{
+ CheckResultReadModel,
+ HostChecksExecutionsReadModel
+ }
project(
%ChecksExecutionRequested{
@@ -24,14 +27,42 @@ defmodule Trento.CheckResultProjector do
checks: checks
},
fn multi ->
+ # Delete old hosts executions states
+ multi =
+ Ecto.Multi.delete_all(
+ multi,
+ :delete_old_hosts_executions,
+ from(c in CheckResultReadModel, where: c.cluster_id == ^cluster_id)
+ )
+
# Delete old results
multi =
Ecto.Multi.delete_all(
multi,
:delete_old_checks_results,
- from(c in CheckResultReadModel, where: c.cluster_id == ^cluster_id)
+ from(h in HostChecksExecutionsReadModel, where: h.cluster_id == ^cluster_id)
)
+ multi =
+ hosts
+ |> Enum.map(fn host_id ->
+ HostChecksExecutionsReadModel.changeset(
+ %HostChecksExecutionsReadModel{},
+ %{
+ cluster_id: cluster_id,
+ host_id: host_id,
+ reachable: nil,
+ msg: nil
+ }
+ )
+ end)
+ |> List.flatten()
+ |> Enum.reduce(multi, fn %{changes: %{cluster_id: cluster_id, host_id: host_id}} =
+ changeset,
+ acc ->
+ Ecto.Multi.insert(acc, "#{cluster_id}_#{host_id}", changeset)
+ end)
+
hosts
|> Enum.map(fn host_id ->
Enum.map(checks, fn check_id ->
@@ -58,9 +89,17 @@ defmodule Trento.CheckResultProjector do
%HostChecksExecutionCompleted{
cluster_id: cluster_id,
host_id: host_id,
+ reachable: reachable,
+ msg: msg,
checks_results: checks_results
},
fn multi ->
+ hosts_executions_changeset =
+ %HostChecksExecutionsReadModel{cluster_id: cluster_id, host_id: host_id}
+ |> HostChecksExecutionsReadModel.changeset(%{reachable: reachable, msg: msg})
+
+ multi = Ecto.Multi.update(multi, :hosts_executions, hosts_executions_changeset)
+
checks_results
|> Enum.map(fn %{
check_id: check_id,
@@ -95,6 +134,7 @@ defmodule Trento.CheckResultProjector do
TrentoWeb.Endpoint.broadcast("monitoring:clusters", "checks_results_updated", %{
cluster_id: cluster_id,
host_id: host_id,
+ hosts_executions: [%{cluster_id: cluster_id, host_id: host_id, reachable: true, msg: ""}],
checks_results:
Enum.map(checks, fn check_id ->
%{host_id: host_id, check_id: check_id, result: :unknown}
@@ -108,6 +148,8 @@ defmodule Trento.CheckResultProjector do
%HostChecksExecutionCompleted{
cluster_id: cluster_id,
host_id: host_id,
+ reachable: reachable,
+ msg: msg,
checks_results: checks_results
},
_,
@@ -116,6 +158,9 @@ defmodule Trento.CheckResultProjector do
TrentoWeb.Endpoint.broadcast("monitoring:clusters", "checks_results_updated", %{
cluster_id: cluster_id,
host_id: host_id,
+ hosts_executions: [
+ %{cluster_id: cluster_id, host_id: host_id, reachable: reachable, msg: msg}
+ ],
checks_results:
Enum.map(checks_results, fn %{check_id: check_id, result: result} ->
%{host_id: host_id, check_id: check_id, result: result}
diff --git a/lib/trento/application/read_models/cluster_read_model.ex b/lib/trento/application/read_models/cluster_read_model.ex
index f35e2ec85e..fc8bff21f2 100644
--- a/lib/trento/application/read_models/cluster_read_model.ex
+++ b/lib/trento/application/read_models/cluster_read_model.ex
@@ -7,7 +7,10 @@ defmodule Trento.ClusterReadModel do
import Ecto.Changeset
- alias Trento.CheckResultReadModel
+ alias Trento.{
+ CheckResultReadModel,
+ HostChecksExecutionsReadModel
+ }
@type t :: %__MODULE__{}
@@ -24,6 +27,7 @@ defmodule Trento.ClusterReadModel do
field :details, :map
field :checks_execution, Ecto.Enum, values: [:not_running, :requested, :running]
+ has_many :hosts_executions, HostChecksExecutionsReadModel, foreign_key: :cluster_id
has_many :checks_results, CheckResultReadModel, foreign_key: :cluster_id
has_many :tags, Trento.Tag, foreign_key: :resource_id
end
diff --git a/lib/trento/application/read_models/host_checks_executions_read_model.ex b/lib/trento/application/read_models/host_checks_executions_read_model.ex
new file mode 100644
index 0000000000..e0c922bb22
--- /dev/null
+++ b/lib/trento/application/read_models/host_checks_executions_read_model.ex
@@ -0,0 +1,25 @@
+defmodule Trento.HostChecksExecutionsReadModel do
+ @moduledoc """
+ Host checks executions read model
+ """
+
+ use Ecto.Schema
+
+ import Ecto.Changeset
+
+ @type t :: %__MODULE__{}
+
+ @derive {Jason.Encoder, except: [:__meta__, :__struct__]}
+ @primary_key false
+ schema "hosts_checks_executions" do
+ field :cluster_id, Ecto.UUID, primary_key: true
+ field :host_id, Ecto.UUID, primary_key: true
+ field :reachable, :boolean
+ field :msg, :string
+ end
+
+ @spec changeset(t() | Ecto.Changeset.t(), map) :: Ecto.Changeset.t()
+ def changeset(host_checks_executions, attrs) do
+ cast(host_checks_executions, attrs, __MODULE__.__schema__(:fields))
+ end
+end
diff --git a/lib/trento/application/usecases/clusters/clusters.ex b/lib/trento/application/usecases/clusters/clusters.ex
index 3593fd9d03..96ea89d95c 100644
--- a/lib/trento/application/usecases/clusters/clusters.ex
+++ b/lib/trento/application/usecases/clusters/clusters.ex
@@ -48,7 +48,7 @@ defmodule Trento.Clusters do
ClusterReadModel
|> order_by(asc: :name)
|> Repo.all()
- |> Repo.preload([:tags, :checks_results])
+ |> Repo.preload([:tags, :hosts_executions, :checks_results])
end
@spec build_check_results([String.t()]) :: {:ok, [CheckResult.t()]} | {:error, any}
diff --git a/lib/trento/domain/cluster/cluster.ex b/lib/trento/domain/cluster/cluster.ex
index d5549f4bc5..a373190c52 100644
--- a/lib/trento/domain/cluster/cluster.ex
+++ b/lib/trento/domain/cluster/cluster.ex
@@ -7,7 +7,8 @@ defmodule Trento.Domain.Cluster do
CheckResult,
Cluster,
HanaClusterDetails,
- HealthService
+ HealthService,
+ HostExecution
}
alias Trento.Domain.Commands.{
@@ -43,7 +44,7 @@ defmodule Trento.Domain.Cluster do
health: :unknown,
hosts: [],
selected_checks: [],
- hosts_checks_results: %{},
+ hosts_executions: %{},
checks_execution: :not_running
]
@@ -57,7 +58,7 @@ defmodule Trento.Domain.Cluster do
details: HanaClusterDetails.t() | nil,
hosts: [String.t()],
selected_checks: [String.t()],
- hosts_checks_results: %{String.t() => [CheckResult.t()]},
+ hosts_executions: %{String.t() => HostExecution.t()},
checks_execution: :not_running | :requested | :running
}
@@ -183,7 +184,8 @@ defmodule Trento.Domain.Cluster do
# Store checks results
def execute(
%Cluster{
- cluster_id: cluster_id
+ cluster_id: cluster_id,
+ hosts_executions: old_hosts_executions
} = cluster,
%CompleteChecksExecution{
hosts_executions: hosts_executions
@@ -192,15 +194,7 @@ defmodule Trento.Domain.Cluster do
hosts_executions
|> Enum.reduce(
Multi.new(cluster),
- fn %{host_id: host_id, checks_results: results}, multi ->
- Multi.execute(multi, fn _ ->
- %HostChecksExecutionCompleted{
- cluster_id: cluster_id,
- host_id: host_id,
- checks_results: results
- }
- end)
- end
+ &emit_host_execution_completed_event(&1, &2, cluster_id, old_hosts_executions)
)
|> Multi.execute(fn _ -> %ChecksExecutionCompleted{cluster_id: cluster_id} end)
|> Multi.execute(&maybe_emit_cluster_health_changed_event/1)
@@ -292,20 +286,25 @@ defmodule Trento.Domain.Cluster do
%Cluster{selected_checks: selected_checks, hosts: hosts} = cluster,
%ChecksExecutionRequested{}
) do
- hosts_checks_results =
- Enum.reduce(hosts, %{}, fn host, acc ->
+ hosts_executions =
+ Enum.reduce(hosts, %{}, fn host_id, acc ->
Map.put(
acc,
- host,
- Enum.map(selected_checks, fn check_id ->
- %CheckResult{check_id: check_id, result: :unknown}
- end)
+ host_id,
+ %HostExecution{
+ host_id: host_id,
+ reachable: true,
+ checks_results:
+ Enum.map(selected_checks, fn check_id ->
+ %CheckResult{check_id: check_id, result: :unknown}
+ end)
+ }
)
end)
%Cluster{
cluster
- | hosts_checks_results: hosts_checks_results,
+ | hosts_executions: hosts_executions,
checks_execution: :requested
}
end
@@ -331,12 +330,43 @@ defmodule Trento.Domain.Cluster do
end
def apply(
- %Cluster{hosts_checks_results: hosts_checks_results} = cluster,
- %HostChecksExecutionCompleted{host_id: host_id, checks_results: checks_results}
- ) do
+ %Cluster{hosts_executions: hosts_executions} = cluster,
+ %HostChecksExecutionCompleted{
+ host_id: host_id,
+ reachable: reachable,
+ msg: msg,
+ checks_results: checks_results
+ }
+ )
+ when reachable == true do
+ %Cluster{
+ cluster
+ | hosts_executions:
+ Map.put(hosts_executions, host_id, %HostExecution{
+ host_id: host_id,
+ reachable: reachable,
+ msg: msg,
+ checks_results: checks_results
+ })
+ }
+ end
+
+ def apply(
+ %Cluster{hosts_executions: hosts_executions} = cluster,
+ %HostChecksExecutionCompleted{host_id: host_id, reachable: reachable, msg: msg}
+ )
+ when reachable == false do
%Cluster{
cluster
- | hosts_checks_results: Map.put(hosts_checks_results, host_id, checks_results)
+ | hosts_executions:
+ Map.update(hosts_executions, host_id, %HostExecution{}, fn host ->
+ %HostExecution{
+ host_id: host_id,
+ reachable: reachable,
+ msg: msg,
+ checks_results: host.checks_results
+ }
+ end)
}
end
@@ -422,13 +452,14 @@ defmodule Trento.Domain.Cluster do
defp maybe_emit_cluster_health_changed_event(%Cluster{
cluster_id: cluster_id,
- hosts_checks_results: hosts_checks_results,
+ hosts_executions: hosts_executions,
discovered_health: discovered_health,
health: health
}) do
new_health =
- hosts_checks_results
- |> Enum.flat_map(fn {_, results} -> results end)
+ hosts_executions
+ |> Enum.map(fn {_, hosts} -> hosts end)
+ |> Enum.flat_map(fn %{checks_results: checks_results} -> checks_results end)
|> Enum.map(fn %{result: result} -> result end)
|> Enum.reject(fn result -> result == :skipped end)
|> Kernel.++([discovered_health])
@@ -438,4 +469,40 @@ defmodule Trento.Domain.Cluster do
%ClusterHealthChanged{cluster_id: cluster_id, health: new_health}
end
end
+
+ defp emit_host_execution_completed_event(
+ %{host_id: host_id, reachable: false, msg: msg},
+ multi,
+ cluster_id,
+ hosts_executions
+ ) do
+ multi
+ |> Multi.execute(fn _ ->
+ %HostChecksExecutionCompleted{
+ cluster_id: cluster_id,
+ host_id: host_id,
+ reachable: false,
+ msg: msg,
+ checks_results: Map.get(hosts_executions, host_id).checks_results
+ }
+ end)
+ end
+
+ defp emit_host_execution_completed_event(
+ %{host_id: host_id, reachable: true, msg: msg, checks_results: results},
+ multi,
+ cluster_id,
+ _hosts_executions
+ ) do
+ multi
+ |> Multi.execute(fn _ ->
+ %HostChecksExecutionCompleted{
+ cluster_id: cluster_id,
+ host_id: host_id,
+ reachable: true,
+ msg: msg,
+ checks_results: results
+ }
+ end)
+ end
end
diff --git a/lib/trento/domain/cluster/commands/complete_checks_execution.ex b/lib/trento/domain/cluster/commands/complete_checks_execution.ex
index 52439b5fc9..47c7c1b121 100644
--- a/lib/trento/domain/cluster/commands/complete_checks_execution.ex
+++ b/lib/trento/domain/cluster/commands/complete_checks_execution.ex
@@ -3,28 +3,11 @@ defmodule Trento.Domain.Commands.CompleteChecksExecution do
Store the checks results coming from an execution on a specific cluster.
"""
- defmodule HostExecution do
- @moduledoc """
- Host checks results value object
- """
-
- @required_fields :all
-
- use Trento.Type
- alias Trento.Domain.CheckResult
-
- deftype do
- field :host_id, Ecto.UUID
-
- embeds_many :checks_results, CheckResult
- end
- end
-
@required_fields :all
use Trento.Command
- alias Trento.Domain.CheckResult
+ alias Trento.Domain.HostExecution
defcommand do
field :cluster_id, Ecto.UUID
diff --git a/lib/trento/domain/cluster/events/host_checks_execution_completed.ex b/lib/trento/domain/cluster/events/host_checks_execution_completed.ex
index 195084fa97..c6f420ea0c 100644
--- a/lib/trento/domain/cluster/events/host_checks_execution_completed.ex
+++ b/lib/trento/domain/cluster/events/host_checks_execution_completed.ex
@@ -10,6 +10,8 @@ defmodule Trento.Domain.Events.HostChecksExecutionCompleted do
defevent do
field :cluster_id, :string
field :host_id, :string
+ field :reachable, :boolean
+ field :msg, :string
embeds_many :checks_results, CheckResult
end
diff --git a/lib/trento/domain/value_objects/check_result.ex b/lib/trento/domain/value_objects/check_result.ex
index 9fe90e3871..e41a8fece5 100644
--- a/lib/trento/domain/value_objects/check_result.ex
+++ b/lib/trento/domain/value_objects/check_result.ex
@@ -9,6 +9,6 @@ defmodule Trento.Domain.CheckResult do
deftype do
field :check_id, :string
- field :result, Ecto.Enum, values: [:passing, :warning, :critical, :skipped]
+ field :result, Ecto.Enum, values: [:passing, :warning, :critical, :skipped, :unknown]
end
end
diff --git a/lib/trento/domain/value_objects/host_execution.ex b/lib/trento/domain/value_objects/host_execution.ex
new file mode 100644
index 0000000000..2c35bcf846
--- /dev/null
+++ b/lib/trento/domain/value_objects/host_execution.ex
@@ -0,0 +1,18 @@
+defmodule Trento.Domain.HostExecution do
+ @moduledoc """
+ Host checks results value object
+ """
+
+ @required_fields [:host_id, :reachable, :checks_results]
+
+ use Trento.Type
+ alias Trento.Domain.CheckResult
+
+ deftype do
+ field :host_id, Ecto.UUID
+ field :reachable, :boolean
+ field :msg, :string, default: ""
+
+ embeds_many :checks_results, CheckResult
+ end
+end
diff --git a/priv/repo/migrations/20220405142819_create_host_checks_executions.exs b/priv/repo/migrations/20220405142819_create_host_checks_executions.exs
new file mode 100644
index 0000000000..eac9978b0e
--- /dev/null
+++ b/priv/repo/migrations/20220405142819_create_host_checks_executions.exs
@@ -0,0 +1,12 @@
+defmodule Trento.Repo.Migrations.CreateHostChecksExecutions do
+ use Ecto.Migration
+
+ def change do
+ create table(:hosts_checks_executions, primary_key: false) do
+ add :cluster_id, :uuid, primary_key: true
+ add :host_id, :uuid, primary_key: true
+ add :reachable, :boolean
+ add :msg, :string
+ end
+ end
+end
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 0225122afb..de5842dde7 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -37,6 +37,7 @@ defmodule Trento.Factory do
ClusterReadModel,
DatabaseInstanceReadModel,
DatabaseReadModel,
+ HostChecksExecutionsReadModel,
HostConnectionSettings,
HostReadModel,
HostTelemetryReadModel,
@@ -387,6 +388,15 @@ defmodule Trento.Factory do
})
end
+ def host_checks_result_projection(attrs \\ []) do
+ Repo.insert!(%HostChecksExecutionsReadModel{
+ cluster_id: Keyword.get(attrs, :cluster_id, Faker.UUID.v4()),
+ host_id: Keyword.get(attrs, :host_id, Faker.UUID.v4()),
+ reachable: Keyword.get(attrs, :reachable, true),
+ msg: Keyword.get(attrs, :msg, Faker.StarWars.planet())
+ })
+ end
+
def sap_system_with_cluster_and_hosts do
%ClusterReadModel{id: cluster_id} = cluster_projection(type: :hana_scale_up, health: :passing)
diff --git a/test/trento/application/integration/checks/checks_test.exs b/test/trento/application/integration/checks/checks_test.exs
index 40bff99969..de7d948d4d 100644
--- a/test/trento/application/integration/checks/checks_test.exs
+++ b/test/trento/application/integration/checks/checks_test.exs
@@ -3,6 +3,8 @@ defmodule Trento.Integration.ChecksTest do
use Trento.DataCase
import Mox
+ # TODO: Remove Mock usage
+ import Mock
alias Trento.Integration.Checks
@@ -15,6 +17,16 @@ defmodule Trento.Integration.ChecksTest do
ProviderDto
}
+ alias Trento.Domain.Commands.{
+ CompleteChecksExecution,
+ StartChecksExecution
+ }
+
+ alias Trento.Domain.{
+ CheckResult,
+ HostExecution
+ }
+
@runner_fixtures_path File.cwd!() <> "/test/fixtures/runner"
def load_runner_fixture(name) do
@@ -24,6 +36,8 @@ defmodule Trento.Integration.ChecksTest do
|> Jason.decode!()
end
+ @moduletag :integration
+
test "should return an error if the runner is not reachable" do
expect(Trento.Integration.Checks.Mock, :get_catalog, fn ->
{:error, "some error"}
@@ -287,4 +301,114 @@ defmodule Trento.Integration.ChecksTest do
assert {:ok, catalog_by_provider} == Checks.get_catalog_grouped_by_provider()
end
+
+ test "should handle execution started event properly" do
+ with_mock Trento.Commanded, dispatch: fn _, _ -> :ok end do
+ execution_id = Faker.UUID.v4()
+ cluster_id = Faker.UUID.v4()
+
+ Checks.handle_callback(%{
+ "event" => "execution_started",
+ "execution_id" => execution_id,
+ "payload" => %{
+ "cluster_id" => cluster_id
+ }
+ })
+
+ assert_called Trento.Commanded.dispatch(
+ %StartChecksExecution{
+ cluster_id: cluster_id
+ },
+ correlation_id: execution_id
+ )
+ end
+ end
+
+ test "should handle execution completed event properly" do
+ with_mock Trento.Commanded, dispatch: fn _, _ -> :ok end do
+ execution_id = Faker.UUID.v4()
+ cluster_id = Faker.UUID.v4()
+ host_id_1 = Faker.UUID.v4()
+ host_id_2 = Faker.UUID.v4()
+
+ Checks.handle_callback(%{
+ "event" => "execution_completed",
+ "execution_id" => execution_id,
+ "payload" => %{
+ "cluster_id" => cluster_id,
+ "hosts" => [
+ %{
+ "host_id" => host_id_1,
+ "reachable" => true,
+ "msg" => "",
+ "results" => [
+ %{
+ "check_id" => "check1",
+ "result" => "passing"
+ },
+ %{
+ "check_id" => "check2",
+ "result" => "warning"
+ }
+ ]
+ },
+ %{
+ "host_id" => host_id_2,
+ "reachable" => true,
+ "msg" => "",
+ "results" => [
+ %{
+ "check_id" => "check1",
+ "result" => "critical"
+ },
+ %{
+ "check_id" => "check2",
+ "result" => "warning"
+ }
+ ]
+ }
+ ]
+ }
+ })
+
+ assert_called Trento.Commanded.dispatch(
+ %CompleteChecksExecution{
+ cluster_id: cluster_id,
+ hosts_executions: [
+ %HostExecution{
+ checks_results: [
+ %CheckResult{
+ check_id: "check1",
+ result: :passing
+ },
+ %CheckResult{
+ check_id: "check2",
+ result: :warning
+ }
+ ],
+ host_id: host_id_1,
+ msg: nil,
+ reachable: true
+ },
+ %HostExecution{
+ checks_results: [
+ %CheckResult{
+ check_id: "check1",
+ result: :critical
+ },
+ %CheckResult{
+ check_id: "check2",
+ result: :warning
+ }
+ ],
+ host_id: host_id_2,
+ msg: nil,
+ reachable: true
+ }
+ ]
+ },
+ correlation_id: execution_id
+ )
+ end
+ end
end
diff --git a/test/trento/application/projectors/check_result_projector_test.exs b/test/trento/application/projectors/check_result_projector_test.exs
index 1483084587..c100bc5346 100644
--- a/test/trento/application/projectors/check_result_projector_test.exs
+++ b/test/trento/application/projectors/check_result_projector_test.exs
@@ -8,10 +8,14 @@ defmodule Trento.CheckResultProjectorTest do
alias Trento.{
CheckResultProjector,
- CheckResultReadModel
+ CheckResultReadModel,
+ HostChecksExecutionsReadModel
}
- alias Trento.Domain.Events.HostChecksExecutionCompleted
+ alias Trento.Domain.Events.{
+ ChecksExecutionRequested,
+ HostChecksExecutionCompleted
+ }
test "should project checks results with result unknown when a ChecksExecutionRequested event is received" do
event = checks_execution_requested_event()
@@ -32,6 +36,36 @@ defmodule Trento.CheckResultProjectorTest do
end)
end
+ test "should project hosts executions with emtpy data when a ChecksExecutionRequested event is received" do
+ host_checks_result_projection(
+ cluster_id: cluster_id = Faker.UUID.v4(),
+ host_id: host_id = Faker.UUID.v4(),
+ reachable: true,
+ msg: ""
+ )
+
+ event =
+ ChecksExecutionRequested.new!(%{
+ cluster_id: cluster_id,
+ hosts: [host_id],
+ checks: ["check1"]
+ })
+
+ ProjectorTestHelper.project(
+ CheckResultProjector,
+ event,
+ "check_result_projector"
+ )
+
+ hosts_executions = Repo.all(HostChecksExecutionsReadModel)
+
+ assert Enum.all?(hosts_executions, fn %HostChecksExecutionsReadModel{
+ reachable: reachable
+ } ->
+ reachable == nil
+ end)
+ end
+
test "should update a check result when HostChecksExecutionCompleted event is received" do
check_result_projection(
cluster_id: cluster_id = Faker.UUID.v4(),
@@ -61,4 +95,36 @@ defmodule Trento.CheckResultProjectorTest do
assert :critical == check_result_projections.result
end
+
+ test "should update a host execution when HostChecksExecutionCompleted event is received" do
+ host_checks_result_projection(
+ cluster_id: cluster_id = Faker.UUID.v4(),
+ host_id: host_id = Faker.UUID.v4(),
+ reachable: true,
+ msg: ""
+ )
+
+ event =
+ HostChecksExecutionCompleted.new!(%{
+ cluster_id: cluster_id,
+ host_id: host_id,
+ reachable: true,
+ msg: "",
+ checks_results: []
+ })
+
+ ProjectorTestHelper.project(
+ CheckResultProjector,
+ event,
+ "check_result_projector"
+ )
+
+ hosts_executions = Repo.all(HostChecksExecutionsReadModel)
+
+ assert Enum.all?(hosts_executions, fn %HostChecksExecutionsReadModel{
+ reachable: reachable
+ } ->
+ reachable == true
+ end)
+ end
end
diff --git a/test/trento/domain/cluster/cluster_test.exs b/test/trento/domain/cluster/cluster_test.exs
index 5608339d53..3d18595af8 100644
--- a/test/trento/domain/cluster/cluster_test.exs
+++ b/test/trento/domain/cluster/cluster_test.exs
@@ -5,8 +5,6 @@ defmodule Trento.ClusterTest do
alias Trento.Support.StructHelper
- alias Trento.Domain.Cluster
-
alias Trento.Domain.Commands.{
CompleteChecksExecution,
RegisterClusterHost,
@@ -27,7 +25,11 @@ defmodule Trento.ClusterTest do
HostChecksExecutionCompleted
}
- alias Trento.Domain.Cluster
+ alias Trento.Domain.{
+ CheckResult,
+ Cluster,
+ HostExecution
+ }
describe "cluster registration" do
test "should register a cluster and add the node host to the cluster if the node is a DC" do
@@ -221,6 +223,7 @@ defmodule Trento.ClusterTest do
cluster_id = Faker.UUID.v4()
host_id = Faker.UUID.v4()
selected_checks = Enum.map(0..4, fn _ -> Faker.Cat.name() end)
+ checks_results = Enum.map(selected_checks, &%CheckResult{check_id: &1, result: :unknown})
assert_events_and_state(
[
@@ -248,7 +251,14 @@ defmodule Trento.ClusterTest do
fn cluster ->
assert %Cluster{
health: :unknown,
- checks_execution: :requested
+ checks_execution: :requested,
+ hosts_executions: %{
+ ^host_id => %HostExecution{
+ host_id: ^host_id,
+ reachable: true,
+ checks_results: ^checks_results
+ }
+ }
} = cluster
end
)
@@ -289,6 +299,8 @@ defmodule Trento.ClusterTest do
host_id = Faker.UUID.v4()
selected_checks = Enum.map(0..4, fn _ -> Faker.Cat.name() end)
checks_results = Enum.map(selected_checks, &%{check_id: &1, result: :critical})
+ expected_results = Enum.map(checks_results, &CheckResult.new!(&1))
+ msg = Faker.StarWars.planet()
assert_events_and_state(
[
@@ -304,6 +316,8 @@ defmodule Trento.ClusterTest do
hosts_executions: [
%{
host_id: host_id,
+ reachable: true,
+ msg: msg,
checks_results: checks_results
}
]
@@ -312,6 +326,8 @@ defmodule Trento.ClusterTest do
HostChecksExecutionCompleted.new!(%{
cluster_id: cluster_id,
host_id: host_id,
+ reachable: true,
+ msg: msg,
checks_results: checks_results
}),
%ChecksExecutionCompleted{
@@ -324,7 +340,72 @@ defmodule Trento.ClusterTest do
],
fn cluster ->
assert %Cluster{
- checks_execution: :not_running
+ checks_execution: :not_running,
+ hosts_executions: %{
+ ^host_id => %HostExecution{
+ host_id: ^host_id,
+ reachable: true,
+ checks_results: ^expected_results
+ }
+ }
+ } = cluster
+ end
+ )
+ end
+
+ test "should complete a checks execution when reachable is false" do
+ cluster_id = Faker.UUID.v4()
+ host_id = Faker.UUID.v4()
+ selected_checks = Enum.map(0..4, fn _ -> Faker.Cat.name() end)
+ checks_results = Enum.map(selected_checks, &%{check_id: &1, result: :unknown})
+ expected_results = Enum.map(checks_results, &CheckResult.new!(&1))
+ msg = Faker.StarWars.planet()
+
+ assert_events_and_state(
+ [
+ cluster_registered_event(cluster_id: cluster_id),
+ host_added_to_cluster_event(cluster_id: cluster_id, host_id: host_id),
+ %ChecksSelected{
+ cluster_id: cluster_id,
+ checks: selected_checks
+ },
+ checks_execution_requested_event(
+ cluster_id: cluster_id,
+ hosts: [host_id],
+ checks: selected_checks
+ )
+ ],
+ CompleteChecksExecution.new!(%{
+ cluster_id: cluster_id,
+ hosts_executions: [
+ %{
+ host_id: host_id,
+ reachable: false,
+ msg: msg
+ }
+ ]
+ }),
+ [
+ HostChecksExecutionCompleted.new!(%{
+ cluster_id: cluster_id,
+ host_id: host_id,
+ reachable: false,
+ msg: msg,
+ checks_results: checks_results
+ }),
+ %ChecksExecutionCompleted{
+ cluster_id: cluster_id
+ },
+ %ClusterHealthChanged{cluster_id: cluster_id, health: :unknown}
+ ],
+ fn cluster ->
+ assert %Cluster{
+ checks_execution: :not_running,
+ hosts_executions: %{
+ ^host_id => %HostExecution{
+ checks_results: ^expected_results
+ }
+ }
} = cluster
end
)