diff --git a/assets/js/state/clusters.js b/assets/js/state/clusters.js index e3a568f946..de44d3ff1a 100644 --- a/assets/js/state/clusters.js +++ b/assets/js/state/clusters.js @@ -104,6 +104,7 @@ export const clustersListSlice = createSlice({ export const CLUSTER_DEREGISTERED = 'CLUSTER_DEREGISTERED'; export const CLUSTER_RESTORED = 'CLUSTER_RESTORED'; export const CLUSTER_CHECKS_SELECTED = 'CLUSTER_CHECKS_SELECTED'; +export const CLUSTER_HEALTH_CHANGED = 'CLUSTER_HEALTH_CHANGED'; export const checksSelected = createAction(CLUSTER_CHECKS_SELECTED); export const { diff --git a/assets/js/state/sagas/clusters.js b/assets/js/state/sagas/clusters.js index 2be810b87a..d4439f4843 100644 --- a/assets/js/state/sagas/clusters.js +++ b/assets/js/state/sagas/clusters.js @@ -4,8 +4,10 @@ import { notify } from '@state/actions/notifications'; import { CLUSTER_DEREGISTERED, CLUSTER_RESTORED, + CLUSTER_HEALTH_CHANGED, appendCluster, removeCluster, + updateClusterHealth, } from '@state/clusters'; export function* clusterDeregistered({ payload: { name, id } }) { @@ -28,6 +30,22 @@ export function* clusterRestored({ payload }) { ); } +export function* clusterHealthChanged({ + payload: { cluster_id, name, health }, +}) { + yield put(updateClusterHealth({ cluster_id, name, health })); + yield put( + notify({ + text: `Cluster ${name} health changed to ${health}.`, + icon: 'ℹ️', + }) + ); +} + +export function* watchClusterHealthChanged() { + yield takeEvery(CLUSTER_HEALTH_CHANGED, clusterHealthChanged); +} + export function* watchClusterDeregistered() { yield takeEvery(CLUSTER_DEREGISTERED, clusterDeregistered); } diff --git a/assets/js/state/sagas/clusters.test.js b/assets/js/state/sagas/clusters.test.js index 2b035a1903..7cf5b2aea1 100644 --- a/assets/js/state/sagas/clusters.test.js +++ b/assets/js/state/sagas/clusters.test.js @@ -2,8 +2,16 @@ import { recordSaga } from '@lib/test-utils'; import { clusterFactory } from '@lib/test-utils/factories'; -import { clusterDeregistered, clusterRestored } from '@state/sagas/clusters'; -import { removeCluster, appendCluster } from '@state/clusters'; +import { + clusterDeregistered, + clusterRestored, + clusterHealthChanged, +} from '@state/sagas/clusters'; +import { + removeCluster, + appendCluster, + updateClusterHealth, +} from '@state/clusters'; import { notify } from '@state/actions/notifications'; describe('Clusters sagas', () => { @@ -30,4 +38,20 @@ describe('Clusters sagas', () => { }), ]); }); + + it('should update health status of a cluster', async () => { + const { id: cluster_id, name, health } = clusterFactory.build(); + + const dispatched = await recordSaga(clusterHealthChanged, { + payload: { cluster_id, name, health }, + }); + + expect(dispatched).toEqual([ + updateClusterHealth({ cluster_id, name, health }), + notify({ + text: `Cluster ${name} health changed to ${health}.`, + icon: 'ℹ️', + }), + ]); + }); }); diff --git a/assets/js/state/sagas/index.js b/assets/js/state/sagas/index.js index 07c7eb5716..99c5a2fe6c 100644 --- a/assets/js/state/sagas/index.js +++ b/assets/js/state/sagas/index.js @@ -30,12 +30,12 @@ import { import { CLUSTER_DEREGISTERED, CLUSTER_RESTORED, + CLUSTER_HEALTH_CHANGED, setClusters, appendCluster, updateCluster, updateCibLastWritten, updateChecksResults, - updateClusterHealth, startClustersLoading, stopClustersLoading, } from '@state/clusters'; @@ -84,6 +84,7 @@ import { import { watchClusterDeregistered, watchClusterRestored, + watchClusterHealthChanged, } from '@state/sagas/clusters'; import { watchUpdateLastExecution, @@ -287,14 +288,6 @@ function* watchChecksResultsUpdated() { yield takeEvery('CHECKS_RESULTS_UPDATED', checksResultsUpdated); } -function* clusterHealthChanged({ payload }) { - yield put(updateClusterHealth(payload)); -} - -function* watchClusterHealthChanged() { - yield takeEvery('CLUSTER_HEALTH_CHANGED', clusterHealthChanged); -} - function* refreshHealthSummaryOnComponentsHealthChange() { const debounceDuration = 5000; @@ -340,7 +333,7 @@ function* refreshHealthSummaryOnComponentsHealthChange() { ); yield debounce( debounceDuration, - 'CLUSTER_HEALTH_CHANGED', + CLUSTER_HEALTH_CHANGED, loadSapSystemsHealthSummary ); yield debounce( diff --git a/lib/trento/application/projectors/cluster_projector.ex b/lib/trento/application/projectors/cluster_projector.ex index 53fd07afbe..63e35faf60 100644 --- a/lib/trento/application/projectors/cluster_projector.ex +++ b/lib/trento/application/projectors/cluster_projector.ex @@ -184,11 +184,10 @@ defmodule Trento.ClusterProjector do }) end - def after_update(%ClusterHealthChanged{cluster_id: cluster_id, health: health}, _, _) do - TrentoWeb.Endpoint.broadcast("monitoring:clusters", "cluster_health_changed", %{ - cluster_id: cluster_id, - health: health - }) + def after_update(%ClusterHealthChanged{}, _, %{cluster: %ClusterReadModel{} = cluster}) do + message = ClusterView.render("cluster_health_changed.json", %{cluster: cluster}) + + TrentoWeb.Endpoint.broadcast("monitoring:clusters", "cluster_health_changed", message) end @impl true diff --git a/lib/trento_web/views/v2/cluster_view.ex b/lib/trento_web/views/v2/cluster_view.ex index 5d9185965b..1a9904bbf7 100644 --- a/lib/trento_web/views/v2/cluster_view.ex +++ b/lib/trento_web/views/v2/cluster_view.ex @@ -25,4 +25,8 @@ defmodule TrentoWeb.V2.ClusterView do |> Map.delete(:cluster_id) |> Map.put(:id, data.cluster_id) end + + def render("cluster_health_changed.json", %{cluster: %{id: id, name: name, health: health}}) do + %{cluster_id: id, name: name, health: health} + end end diff --git a/test/trento/application/projectors/cluster_projector_test.exs b/test/trento/application/projectors/cluster_projector_test.exs index 9e2a08ff07..6c7c7829f8 100644 --- a/test/trento/application/projectors/cluster_projector_test.exs +++ b/test/trento/application/projectors/cluster_projector_test.exs @@ -241,12 +241,9 @@ defmodule Trento.ClusterProjectorTest do end test "should broadcast cluster_health_changed after the ClusterHealthChanged event" do - insert(:cluster, id: cluster_id = Faker.UUID.v4()) + %{id: cluster_id, name: name, health: health} = insert(:cluster) - event = %ClusterHealthChanged{ - cluster_id: cluster_id, - health: :passing - } + event = %ClusterHealthChanged{cluster_id: cluster_id, health: health} ProjectorTestHelper.project( ClusterProjector, @@ -255,7 +252,7 @@ defmodule Trento.ClusterProjectorTest do ) assert_broadcast "cluster_health_changed", - %{cluster_id: ^cluster_id, health: :passing}, + %{cluster_id: ^cluster_id, name: ^name, health: ^health}, 1000 end end diff --git a/test/trento_web/views/v2/cluster_view_test.exs b/test/trento_web/views/v2/cluster_view_test.exs new file mode 100644 index 0000000000..529ba00610 --- /dev/null +++ b/test/trento_web/views/v2/cluster_view_test.exs @@ -0,0 +1,17 @@ +defmodule TrentoWeb.V2.ClusterViewTest do + use TrentoWeb.ConnCase, async: true + + import Phoenix.View + import Trento.Factory + + alias TrentoWeb.V2.ClusterView + + alias Trento.ClusterReadModel + + test "should render health changed relevant information" do + %ClusterReadModel{id: id, name: name, health: health} = cluster = build(:cluster) + + assert %{cluster_id: id, name: name, health: health} == + render(ClusterView, "cluster_health_changed.json", %{cluster: cluster}) + end +end