From afcf07f1f34f5519d6d000d492979d4ab14b5557 Mon Sep 17 00:00:00 2001 From: Jamie Rodriguez Date: Thu, 5 Oct 2023 14:50:05 +0200 Subject: [PATCH 1/3] Notify user when `ClusterHealthChanged` event occurs --- assets/js/state/sagas/clusters.js | 15 +++++++++++++++ assets/js/state/sagas/clusters.test.js | 20 ++++++++++++++++++-- assets/js/state/sagas/index.js | 10 +--------- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/assets/js/state/sagas/clusters.js b/assets/js/state/sagas/clusters.js index 2be810b87a..2341008542 100644 --- a/assets/js/state/sagas/clusters.js +++ b/assets/js/state/sagas/clusters.js @@ -6,6 +6,7 @@ import { CLUSTER_RESTORED, appendCluster, removeCluster, + updateClusterHealth, } from '@state/clusters'; export function* clusterDeregistered({ payload: { name, id } }) { @@ -28,6 +29,20 @@ export function* clusterRestored({ payload }) { ); } +export function* clusterHealthChanged({ payload: { cluster_id, health } }) { + yield put(updateClusterHealth({ cluster_id, health })); + yield put( + notify({ + text: `Cluster ${cluster_id} 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..e4457f5628 100644 --- a/assets/js/state/sagas/clusters.test.js +++ b/assets/js/state/sagas/clusters.test.js @@ -2,8 +2,8 @@ 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 +30,20 @@ describe('Clusters sagas', () => { }), ]); }); + + it('should update health status of a cluster', async () => { + const { id: cluster_id, health } = clusterFactory.build(); + + const dispatched = await recordSaga(clusterHealthChanged, { + payload: { cluster_id, health }, + }); + + expect(dispatched).toEqual([ + updateClusterHealth({ cluster_id, health }), + notify({ + text: `Cluster ${cluster_id} health changed to ${health}.`, + icon: 'ℹ️', + }), + ]); + }); }); diff --git a/assets/js/state/sagas/index.js b/assets/js/state/sagas/index.js index 07c7eb5716..06f2b6c6bc 100644 --- a/assets/js/state/sagas/index.js +++ b/assets/js/state/sagas/index.js @@ -35,7 +35,6 @@ import { updateCluster, updateCibLastWritten, updateChecksResults, - updateClusterHealth, startClustersLoading, stopClustersLoading, } from '@state/clusters'; @@ -84,6 +83,7 @@ import { import { watchClusterDeregistered, watchClusterRestored, + watchClusterHealthChanged, } from '@state/sagas/clusters'; import { watchUpdateLastExecution, @@ -287,14 +287,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; From 0a0a27a133183555952de4451e0f54edb878b4d4 Mon Sep 17 00:00:00 2001 From: Jamie Rodriguez Date: Thu, 5 Oct 2023 16:51:10 +0200 Subject: [PATCH 2/3] Send cluster name in `cluster_health_changed` websocket event --- assets/js/state/sagas/clusters.js | 8 +++++--- assets/js/state/sagas/clusters.test.js | 20 +++++++++++++------ .../projectors/cluster_projector.ex | 9 ++++----- lib/trento_web/views/v2/cluster_view.ex | 4 ++++ .../projectors/cluster_projector_test.exs | 9 +++------ .../trento_web/views/v2/cluster_view_test.exs | 17 ++++++++++++++++ 6 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 test/trento_web/views/v2/cluster_view_test.exs diff --git a/assets/js/state/sagas/clusters.js b/assets/js/state/sagas/clusters.js index 2341008542..f1b15f7167 100644 --- a/assets/js/state/sagas/clusters.js +++ b/assets/js/state/sagas/clusters.js @@ -29,11 +29,13 @@ export function* clusterRestored({ payload }) { ); } -export function* clusterHealthChanged({ payload: { cluster_id, health } }) { - yield put(updateClusterHealth({ cluster_id, health })); +export function* clusterHealthChanged({ + payload: { cluster_id, name, health }, +}) { + yield put(updateClusterHealth({ cluster_id, name, health })); yield put( notify({ - text: `Cluster ${cluster_id} health changed to ${health}.`, + text: `Cluster ${name} health changed to ${health}.`, icon: 'ℹ️', }) ); diff --git a/assets/js/state/sagas/clusters.test.js b/assets/js/state/sagas/clusters.test.js index e4457f5628..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, clusterHealthChanged } from '@state/sagas/clusters'; -import { removeCluster, appendCluster, updateClusterHealth } 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', () => { @@ -32,16 +40,16 @@ describe('Clusters sagas', () => { }); it('should update health status of a cluster', async () => { - const { id: cluster_id, health } = clusterFactory.build(); + const { id: cluster_id, name, health } = clusterFactory.build(); const dispatched = await recordSaga(clusterHealthChanged, { - payload: { cluster_id, health }, + payload: { cluster_id, name, health }, }); expect(dispatched).toEqual([ - updateClusterHealth({ cluster_id, health }), + updateClusterHealth({ cluster_id, name, health }), notify({ - text: `Cluster ${cluster_id} health changed to ${health}.`, + text: `Cluster ${name} health changed to ${health}.`, icon: 'ℹ️', }), ]); 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 From 814ebbbfe715b5ec87968fd75486a6ec994a92b7 Mon Sep 17 00:00:00 2001 From: Jamie Rodriguez Date: Thu, 5 Oct 2023 19:25:15 +0200 Subject: [PATCH 3/3] Use string constant to reference `CLUSTER_HEALTH_CHANGED` event --- assets/js/state/clusters.js | 1 + assets/js/state/sagas/clusters.js | 3 ++- assets/js/state/sagas/index.js | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) 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 f1b15f7167..d4439f4843 100644 --- a/assets/js/state/sagas/clusters.js +++ b/assets/js/state/sagas/clusters.js @@ -4,6 +4,7 @@ import { notify } from '@state/actions/notifications'; import { CLUSTER_DEREGISTERED, CLUSTER_RESTORED, + CLUSTER_HEALTH_CHANGED, appendCluster, removeCluster, updateClusterHealth, @@ -42,7 +43,7 @@ export function* clusterHealthChanged({ } export function* watchClusterHealthChanged() { - yield takeEvery('CLUSTER_HEALTH_CHANGED', clusterHealthChanged); + yield takeEvery(CLUSTER_HEALTH_CHANGED, clusterHealthChanged); } export function* watchClusterDeregistered() { diff --git a/assets/js/state/sagas/index.js b/assets/js/state/sagas/index.js index 06f2b6c6bc..99c5a2fe6c 100644 --- a/assets/js/state/sagas/index.js +++ b/assets/js/state/sagas/index.js @@ -30,6 +30,7 @@ import { import { CLUSTER_DEREGISTERED, CLUSTER_RESTORED, + CLUSTER_HEALTH_CHANGED, setClusters, appendCluster, updateCluster, @@ -332,7 +333,7 @@ function* refreshHealthSummaryOnComponentsHealthChange() { ); yield debounce( debounceDuration, - 'CLUSTER_HEALTH_CHANGED', + CLUSTER_HEALTH_CHANGED, loadSapSystemsHealthSummary ); yield debounce(