diff --git a/pkg/services/ngalert/remote/forked_alertmanager_test.go b/pkg/services/ngalert/remote/forked_alertmanager_test.go index be1ba54dbb3..de1af60b623 100644 --- a/pkg/services/ngalert/remote/forked_alertmanager_test.go +++ b/pkg/services/ngalert/remote/forked_alertmanager_test.go @@ -21,6 +21,14 @@ func TestForkedAlertmanager_ModeRemoteSecondary(t *testing.T) { ctx := context.Background() expErr := errors.New("test error") + t.Run("GetStatus", func(tt *testing.T) { + // We care about the status of the internal Alertmanager. + internal, _, forked := genTestAlertmanagers(tt, modeRemoteSecondary) + status := apimodels.GettableStatus{} + internal.EXPECT().GetStatus().Return(status).Once() + require.Equal(tt, status, forked.GetStatus()) + }) + t.Run("CreateSilence", func(tt *testing.T) { // We should create the silence in the internal Alertmanager. internal, _, forked := genTestAlertmanagers(tt, modeRemoteSecondary) @@ -207,12 +215,55 @@ func TestForkedAlertmanager_ModeRemoteSecondary(t *testing.T) { _, err = forked.TestTemplate(ctx, apimodels.TestTemplatesConfigBodyParams{}) require.ErrorIs(tt, expErr, err) }) + + t.Run("CleanUp", func(tt *testing.T) { + // CleanUp() should be called only in the internal Alertmanager, + // there's no cleanup to do in the remote one. + internal, _, forked := genTestAlertmanagers(tt, modeRemotePrimary) + internal.EXPECT().CleanUp().Once() + forked.CleanUp() + }) + + t.Run("StopAndWait", func(tt *testing.T) { + // StopAndWait should be called in both Alertmanagers. + internal, remote, forked := genTestAlertmanagers(tt, modeRemotePrimary) + internal.EXPECT().StopAndWait().Once() + remote.EXPECT().StopAndWait().Once() + forked.StopAndWait() + }) + + t.Run("Ready", func(tt *testing.T) { + // Ready should be called on both Alertmanagers + internal, remote, forked := genTestAlertmanagers(tt, modeRemoteSecondary) + internal.EXPECT().Ready().Return(true).Once() + remote.EXPECT().Ready().Return(true).Once() + require.True(tt, forked.Ready()) + + // If one of the two Alertmanagers is not ready, it returns false. + internal, remote, forked = genTestAlertmanagers(tt, modeRemoteSecondary) + internal.EXPECT().Ready().Return(false).Maybe() + remote.EXPECT().Ready().Return(true).Maybe() + require.False(tt, forked.Ready()) + + internal, remote, forked = genTestAlertmanagers(tt, modeRemoteSecondary) + internal.EXPECT().Ready().Return(true).Maybe() + remote.EXPECT().Ready().Return(false).Maybe() + require.False(tt, forked.Ready()) + }) } func TestForkedAlertmanager_ModeRemotePrimary(t *testing.T) { ctx := context.Background() expErr := errors.New("test error") + t.Run("GetStatus", func(tt *testing.T) { + // We care about the status of the remote Alertmanager. + _, remote, forked := genTestAlertmanagers(tt, modeRemotePrimary) + status := apimodels.GettableStatus{} + remote.EXPECT().GetStatus().Return(status).Once() + require.Equal(tt, status, forked.GetStatus()) + }) + t.Run("CreateSilence", func(tt *testing.T) { // We should create the silence in the remote Alertmanager. _, remote, forked := genTestAlertmanagers(tt, modeRemotePrimary) @@ -396,6 +447,41 @@ func TestForkedAlertmanager_ModeRemotePrimary(t *testing.T) { _, err = forked.TestTemplate(ctx, apimodels.TestTemplatesConfigBodyParams{}) require.ErrorIs(tt, expErr, err) }) + + t.Run("CleanUp", func(tt *testing.T) { + // CleanUp() should be called only in the internal Alertmanager, + // there's no cleanup to do in the remote one. + internal, _, forked := genTestAlertmanagers(tt, modeRemotePrimary) + internal.EXPECT().CleanUp().Once() + forked.CleanUp() + }) + + t.Run("StopAndWait", func(tt *testing.T) { + // StopAndWait should be called in both Alertmanagers. + internal, remote, forked := genTestAlertmanagers(tt, modeRemotePrimary) + internal.EXPECT().StopAndWait().Once() + remote.EXPECT().StopAndWait().Once() + forked.StopAndWait() + }) + + t.Run("Ready", func(tt *testing.T) { + // Ready should be called on both Alertmanagers + internal, remote, forked := genTestAlertmanagers(tt, modeRemotePrimary) + internal.EXPECT().Ready().Return(true).Once() + remote.EXPECT().Ready().Return(true).Once() + require.True(tt, forked.Ready()) + + // If one of the two Alertmanagers is not ready, it returns false. + internal, remote, forked = genTestAlertmanagers(tt, modeRemotePrimary) + internal.EXPECT().Ready().Return(false).Maybe() + remote.EXPECT().Ready().Return(true).Maybe() + require.False(tt, forked.Ready()) + + internal, remote, forked = genTestAlertmanagers(tt, modeRemotePrimary) + internal.EXPECT().Ready().Return(true).Maybe() + remote.EXPECT().Ready().Return(false).Maybe() + require.False(tt, forked.Ready()) + }) } func genTestAlertmanagers(t *testing.T, mode int) (*alertmanager_mock.AlertmanagerMock, *alertmanager_mock.AlertmanagerMock, notifier.Alertmanager) { t.Helper() diff --git a/pkg/services/ngalert/remote/remote_primary_forked_alertmanager.go b/pkg/services/ngalert/remote/remote_primary_forked_alertmanager.go index 9b7b21a33f0..0f010c459a0 100644 --- a/pkg/services/ngalert/remote/remote_primary_forked_alertmanager.go +++ b/pkg/services/ngalert/remote/remote_primary_forked_alertmanager.go @@ -33,7 +33,7 @@ func (fam *RemotePrimaryForkedAlertmanager) SaveAndApplyDefaultConfig(ctx contex } func (fam *RemotePrimaryForkedAlertmanager) GetStatus() apimodels.GettableStatus { - return apimodels.GettableStatus{} + return fam.remote.GetStatus() } func (fam *RemotePrimaryForkedAlertmanager) CreateSilence(ctx context.Context, silence *apimodels.PostableSilence) (string, error) { @@ -76,10 +76,20 @@ func (fam *RemotePrimaryForkedAlertmanager) TestTemplate(ctx context.Context, c return fam.remote.TestTemplate(ctx, c) } -func (fam *RemotePrimaryForkedAlertmanager) CleanUp() {} +func (fam *RemotePrimaryForkedAlertmanager) CleanUp() { + // No cleanup to do in the remote Alertmanager. + fam.internal.CleanUp() +} -func (fam *RemotePrimaryForkedAlertmanager) StopAndWait() {} +func (fam *RemotePrimaryForkedAlertmanager) StopAndWait() { + fam.internal.StopAndWait() + fam.remote.StopAndWait() +} func (fam *RemotePrimaryForkedAlertmanager) Ready() bool { - return false + // Both Alertmanagers must be ready. + if ready := fam.remote.Ready(); !ready { + return false + } + return fam.internal.Ready() } diff --git a/pkg/services/ngalert/remote/remote_secondary_forked_alertmanager.go b/pkg/services/ngalert/remote/remote_secondary_forked_alertmanager.go index ab471f1e828..4d0f64e84f7 100644 --- a/pkg/services/ngalert/remote/remote_secondary_forked_alertmanager.go +++ b/pkg/services/ngalert/remote/remote_secondary_forked_alertmanager.go @@ -33,7 +33,7 @@ func (fam *RemoteSecondaryForkedAlertmanager) SaveAndApplyDefaultConfig(ctx cont } func (fam *RemoteSecondaryForkedAlertmanager) GetStatus() apimodels.GettableStatus { - return apimodels.GettableStatus{} + return fam.internal.GetStatus() } func (fam *RemoteSecondaryForkedAlertmanager) CreateSilence(ctx context.Context, silence *apimodels.PostableSilence) (string, error) { @@ -76,10 +76,20 @@ func (fam *RemoteSecondaryForkedAlertmanager) TestTemplate(ctx context.Context, return fam.internal.TestTemplate(ctx, c) } -func (fam *RemoteSecondaryForkedAlertmanager) CleanUp() {} +func (fam *RemoteSecondaryForkedAlertmanager) CleanUp() { + // No cleanup to do in the remote Alertmanager. + fam.internal.CleanUp() +} -func (fam *RemoteSecondaryForkedAlertmanager) StopAndWait() {} +func (fam *RemoteSecondaryForkedAlertmanager) StopAndWait() { + fam.internal.StopAndWait() + fam.remote.StopAndWait() +} func (fam *RemoteSecondaryForkedAlertmanager) Ready() bool { - return false + // Both Alertmanagers must be ready. + if ready := fam.remote.Ready(); !ready { + return false + } + return fam.internal.Ready() }