mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Allow configuration of non-ready alertmanagers (#43063)
* Create API test for overwriting invalid alertmanager config * Avoid requiring alertmanager readiness for config changes * AlertmanagerSrv depends on functionality rather than concrete types * Add test for non-ready alertmanagers * Additional cleanup and polish * Back out previous integration test changes * Refactor of tests incorrectly caused a test to become redundant * Use pre-existing fake secret service * Drop unused interface * Test against concrete MultiOrgAlertmanager re-using fake infra from other tests * Fix linter error * Empty commit to rerun checks
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/schedule"
|
"github.com/grafana/grafana/pkg/services/ngalert/schedule"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/state"
|
"github.com/grafana/grafana/pkg/services/ngalert/state"
|
||||||
@@ -49,6 +50,10 @@ type Alertmanager interface {
|
|||||||
TestReceivers(ctx context.Context, c apimodels.TestReceiversConfigBodyParams) (*notifier.TestReceiversResult, error)
|
TestReceivers(ctx context.Context, c apimodels.TestReceiversConfigBodyParams) (*notifier.TestReceiversResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AlertingStore interface {
|
||||||
|
GetLatestAlertmanagerConfiguration(query *models.GetLatestAlertmanagerConfigurationQuery) error
|
||||||
|
}
|
||||||
|
|
||||||
// API handlers.
|
// API handlers.
|
||||||
type API struct {
|
type API struct {
|
||||||
Cfg *setting.Cfg
|
Cfg *setting.Cfg
|
||||||
@@ -59,7 +64,7 @@ type API struct {
|
|||||||
Schedule schedule.ScheduleService
|
Schedule schedule.ScheduleService
|
||||||
RuleStore store.RuleStore
|
RuleStore store.RuleStore
|
||||||
InstanceStore store.InstanceStore
|
InstanceStore store.InstanceStore
|
||||||
AlertingStore store.AlertingStore
|
AlertingStore AlertingStore
|
||||||
AdminConfigStore store.AdminConfigurationStore
|
AdminConfigStore store.AdminConfigurationStore
|
||||||
DataProxy *datasourceproxy.DataSourceProxyService
|
DataProxy *datasourceproxy.DataSourceProxyService
|
||||||
MultiOrgAlertmanager *notifier.MultiOrgAlertmanager
|
MultiOrgAlertmanager *notifier.MultiOrgAlertmanager
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const (
|
|||||||
type AlertmanagerSrv struct {
|
type AlertmanagerSrv struct {
|
||||||
mam *notifier.MultiOrgAlertmanager
|
mam *notifier.MultiOrgAlertmanager
|
||||||
secrets secrets.Service
|
secrets secrets.Service
|
||||||
store store.AlertingStore
|
store AlertingStore
|
||||||
log log.Logger
|
log log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +361,10 @@ func (srv AlertmanagerSrv) RoutePostAlertingConfig(c *models.ReqContext, body ap
|
|||||||
|
|
||||||
am, errResp := srv.AlertmanagerFor(c.OrgId)
|
am, errResp := srv.AlertmanagerFor(c.OrgId)
|
||||||
if errResp != nil {
|
if errResp != nil {
|
||||||
return errResp
|
// It's okay if the alertmanager isn't ready yet, we're changing its config anyway.
|
||||||
|
if !errors.Is(errResp.Err(), notifier.ErrAlertmanagerNotReady) {
|
||||||
|
return errResp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := am.SaveAndApplyConfig(&body); err != nil {
|
if err := am.SaveAndApplyConfig(&body); err != nil {
|
||||||
@@ -517,11 +520,11 @@ func (srv AlertmanagerSrv) AlertmanagerFor(orgID int64) (Alertmanager, *response
|
|||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, notifier.ErrNoAlertmanagerForOrg) {
|
if errors.Is(err, notifier.ErrNoAlertmanagerForOrg) {
|
||||||
return nil, response.Error(http.StatusNotFound, err.Error(), nil)
|
return nil, response.Error(http.StatusNotFound, err.Error(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, notifier.ErrAlertmanagerNotReady) {
|
if errors.Is(err, notifier.ErrAlertmanagerNotReady) {
|
||||||
return nil, response.Error(http.StatusConflict, err.Error(), nil)
|
return am, response.Error(http.StatusConflict, err.Error(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
srv.log.Error("unable to obtain the org's Alertmanager", "err", err)
|
srv.log.Error("unable to obtain the org's Alertmanager", "err", err)
|
||||||
|
|||||||
@@ -2,11 +2,22 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
||||||
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
||||||
|
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||||
|
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -138,3 +149,148 @@ func TestStatusForTestReceivers(t *testing.T) {
|
|||||||
}}))
|
}}))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAlertmanagerConfig(t *testing.T) {
|
||||||
|
sut := createSut(t)
|
||||||
|
|
||||||
|
t.Run("assert 404 Not Found when applying config to nonexistent org", func(t *testing.T) {
|
||||||
|
rc := models.ReqContext{
|
||||||
|
SignedInUser: &models.SignedInUser{
|
||||||
|
OrgRole: models.ROLE_EDITOR,
|
||||||
|
OrgId: 12,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
request := createAmConfigRequest(t)
|
||||||
|
|
||||||
|
response := sut.RoutePostAlertingConfig(&rc, request)
|
||||||
|
|
||||||
|
require.Equal(t, 404, response.Status())
|
||||||
|
require.Contains(t, string(response.Body()), "Alertmanager does not exist for this organization")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("assert 403 Forbidden when applying config while not Editor", func(t *testing.T) {
|
||||||
|
rc := models.ReqContext{
|
||||||
|
SignedInUser: &models.SignedInUser{
|
||||||
|
OrgRole: models.ROLE_VIEWER,
|
||||||
|
OrgId: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
request := createAmConfigRequest(t)
|
||||||
|
|
||||||
|
response := sut.RoutePostAlertingConfig(&rc, request)
|
||||||
|
|
||||||
|
require.Equal(t, 403, response.Status())
|
||||||
|
require.Contains(t, string(response.Body()), "permission denied")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("assert 202 when config successfully applied", func(t *testing.T) {
|
||||||
|
rc := models.ReqContext{
|
||||||
|
SignedInUser: &models.SignedInUser{
|
||||||
|
OrgRole: models.ROLE_EDITOR,
|
||||||
|
OrgId: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
request := createAmConfigRequest(t)
|
||||||
|
|
||||||
|
response := sut.RoutePostAlertingConfig(&rc, request)
|
||||||
|
|
||||||
|
require.Equal(t, 202, response.Status())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("assert 202 when alertmanager to configure is not ready", func(t *testing.T) {
|
||||||
|
sut := createSut(t)
|
||||||
|
rc := models.ReqContext{
|
||||||
|
SignedInUser: &models.SignedInUser{
|
||||||
|
OrgRole: models.ROLE_EDITOR,
|
||||||
|
OrgId: 3, // Org 3 was initialized with broken config.
|
||||||
|
},
|
||||||
|
}
|
||||||
|
request := createAmConfigRequest(t)
|
||||||
|
|
||||||
|
response := sut.RoutePostAlertingConfig(&rc, request)
|
||||||
|
|
||||||
|
require.Equal(t, 202, response.Status())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSut(t *testing.T) AlertmanagerSrv {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
mam := createMultiOrgAlertmanager(t)
|
||||||
|
store := newFakeAlertingStore(t)
|
||||||
|
store.Setup(1)
|
||||||
|
store.Setup(2)
|
||||||
|
store.Setup(3)
|
||||||
|
secrets := fakes.NewFakeSecretsService()
|
||||||
|
return AlertmanagerSrv{mam: mam, store: store, secrets: secrets}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAmConfigRequest(t *testing.T) apimodels.PostableUserConfig {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
request := apimodels.PostableUserConfig{}
|
||||||
|
err := request.UnmarshalJSON([]byte(validConfig))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMultiOrgAlertmanager(t *testing.T) *notifier.MultiOrgAlertmanager {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
configs := map[int64]*ngmodels.AlertConfiguration{
|
||||||
|
1: {AlertmanagerConfiguration: validConfig, OrgID: 1},
|
||||||
|
2: {AlertmanagerConfiguration: validConfig, OrgID: 2},
|
||||||
|
3: {AlertmanagerConfiguration: brokenConfig, OrgID: 3},
|
||||||
|
}
|
||||||
|
configStore := notifier.NewFakeConfigStore(t, configs)
|
||||||
|
orgStore := notifier.NewFakeOrgStore(t, []int64{1, 2, 3})
|
||||||
|
tmpDir, err := ioutil.TempDir("", "test")
|
||||||
|
require.NoError(t, err)
|
||||||
|
kvStore := notifier.NewFakeKVStore(t)
|
||||||
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
|
reg := prometheus.NewPedanticRegistry()
|
||||||
|
m := metrics.NewNGAlert(reg)
|
||||||
|
decryptFn := secretsService.GetDecryptedValue
|
||||||
|
cfg := &setting.Cfg{
|
||||||
|
DataPath: tmpDir,
|
||||||
|
UnifiedAlerting: setting.UnifiedAlertingSettings{
|
||||||
|
AlertmanagerConfigPollInterval: 3 * time.Minute,
|
||||||
|
DefaultConfiguration: setting.GetAlertmanagerDefaultConfiguration(),
|
||||||
|
DisabledOrgs: map[int64]struct{}{5: {}},
|
||||||
|
}, // do not poll in tests.
|
||||||
|
}
|
||||||
|
|
||||||
|
mam, err := notifier.NewMultiOrgAlertmanager(cfg, &configStore, &orgStore, kvStore, decryptFn, m.GetMultiOrgAlertmanagerMetrics(), log.New("testlogger"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(cleanOrgDirectories(tmpDir, t))
|
||||||
|
err = mam.LoadAndSyncAlertmanagersForOrgs(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
return mam
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanOrgDirectories(path string, t *testing.T) func() {
|
||||||
|
return func() {
|
||||||
|
require.NoError(t, os.RemoveAll(path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var validConfig = setting.GetAlertmanagerDefaultConfiguration()
|
||||||
|
|
||||||
|
var brokenConfig = `
|
||||||
|
"alertmanager_config": {
|
||||||
|
"route": {
|
||||||
|
"receiver": "grafana-default-email"
|
||||||
|
},
|
||||||
|
"receivers": [{
|
||||||
|
"name": "grafana-default-email",
|
||||||
|
"grafana_managed_receiver_configs": [{
|
||||||
|
"uid": "abc",
|
||||||
|
"name": "default-email",
|
||||||
|
"type": "email",
|
||||||
|
"isDefault": true,
|
||||||
|
"settings": {}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|||||||
31
pkg/services/ngalert/api/testing.go
Normal file
31
pkg/services/ngalert/api/testing.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FakeAlertingStore struct {
|
||||||
|
orgsWithConfig map[int64]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFakeAlertingStore(t *testing.T) FakeAlertingStore {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
return FakeAlertingStore{
|
||||||
|
orgsWithConfig: map[int64]bool{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FakeAlertingStore) Setup(orgID int64) {
|
||||||
|
f.orgsWithConfig[orgID] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FakeAlertingStore) GetLatestAlertmanagerConfiguration(query *models.GetLatestAlertmanagerConfigurationQuery) error {
|
||||||
|
if _, ok := f.orgsWithConfig[query.OrgID]; ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return store.ErrNoAlertmanagerConfiguration
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ func setupAMTest(t *testing.T) *Alertmanager {
|
|||||||
Logger: log.New("alertmanager-test"),
|
Logger: log.New("alertmanager-test"),
|
||||||
}
|
}
|
||||||
|
|
||||||
kvStore := newFakeKVStore(t)
|
kvStore := NewFakeKVStore(t)
|
||||||
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
|
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
|
||||||
decryptFn := secretsService.GetDecryptedValue
|
decryptFn := secretsService.GetDecryptedValue
|
||||||
am, err := newAlertmanager(1, cfg, s, kvStore, &NilPeer{}, decryptFn, m)
|
am, err := newAlertmanager(1, cfg, s, kvStore, &NilPeer{}, decryptFn, m)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFileStore_FilepathFor_DirectoryNotExist(t *testing.T) {
|
func TestFileStore_FilepathFor_DirectoryNotExist(t *testing.T) {
|
||||||
store := newFakeKVStore(t)
|
store := NewFakeKVStore(t)
|
||||||
workingDir := filepath.Join(t.TempDir(), "notexistdir")
|
workingDir := filepath.Join(t.TempDir(), "notexistdir")
|
||||||
fs := NewFileStore(1, store, workingDir)
|
fs := NewFileStore(1, store, workingDir)
|
||||||
filekey := "silences"
|
filekey := "silences"
|
||||||
@@ -32,7 +32,7 @@ func TestFileStore_FilepathFor_DirectoryNotExist(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestFileStore_FilepathFor(t *testing.T) {
|
func TestFileStore_FilepathFor(t *testing.T) {
|
||||||
store := newFakeKVStore(t)
|
store := NewFakeKVStore(t)
|
||||||
workingDir := t.TempDir()
|
workingDir := t.TempDir()
|
||||||
fs := NewFileStore(1, store, workingDir)
|
fs := NewFileStore(1, store, workingDir)
|
||||||
filekey := "silences"
|
filekey := "silences"
|
||||||
@@ -74,7 +74,7 @@ func TestFileStore_FilepathFor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStore_Persist(t *testing.T) {
|
func TestFileStore_Persist(t *testing.T) {
|
||||||
store := newFakeKVStore(t)
|
store := NewFakeKVStore(t)
|
||||||
state := &fakeState{data: "something to marshal"}
|
state := &fakeState{data: "something to marshal"}
|
||||||
workingDir := t.TempDir()
|
workingDir := t.TempDir()
|
||||||
fs := NewFileStore(1, store, workingDir)
|
fs := NewFileStore(1, store, workingDir)
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ func (moa *MultiOrgAlertmanager) AlertmanagerFor(orgID int64) (*Alertmanager, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !orgAM.Ready() {
|
if !orgAM.Ready() {
|
||||||
return nil, ErrAlertmanagerNotReady
|
return orgAM, ErrAlertmanagerNotReady
|
||||||
}
|
}
|
||||||
|
|
||||||
return orgAM, nil
|
return orgAM, nil
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func TestMultiOrgAlertmanager_SyncAlertmanagersForOrgs(t *testing.T) {
|
|||||||
|
|
||||||
tmpDir, err := ioutil.TempDir("", "test")
|
tmpDir, err := ioutil.TempDir("", "test")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
kvStore := newFakeKVStore(t)
|
kvStore := NewFakeKVStore(t)
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
decryptFn := secretsService.GetDecryptedValue
|
decryptFn := secretsService.GetDecryptedValue
|
||||||
reg := prometheus.NewPedanticRegistry()
|
reg := prometheus.NewPedanticRegistry()
|
||||||
@@ -161,7 +161,7 @@ func TestMultiOrgAlertmanager_SyncAlertmanagersForOrgsWithFailures(t *testing.T)
|
|||||||
|
|
||||||
tmpDir, err := ioutil.TempDir("", "test")
|
tmpDir, err := ioutil.TempDir("", "test")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
kvStore := newFakeKVStore(t)
|
kvStore := NewFakeKVStore(t)
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
decryptFn := secretsService.GetDecryptedValue
|
decryptFn := secretsService.GetDecryptedValue
|
||||||
reg := prometheus.NewPedanticRegistry()
|
reg := prometheus.NewPedanticRegistry()
|
||||||
@@ -219,7 +219,7 @@ func TestMultiOrgAlertmanager_AlertmanagerFor(t *testing.T) {
|
|||||||
DataPath: tmpDir,
|
DataPath: tmpDir,
|
||||||
UnifiedAlerting: setting.UnifiedAlertingSettings{AlertmanagerConfigPollInterval: 3 * time.Minute, DefaultConfiguration: setting.GetAlertmanagerDefaultConfiguration()}, // do not poll in tests.
|
UnifiedAlerting: setting.UnifiedAlertingSettings{AlertmanagerConfigPollInterval: 3 * time.Minute, DefaultConfiguration: setting.GetAlertmanagerDefaultConfiguration()}, // do not poll in tests.
|
||||||
}
|
}
|
||||||
kvStore := newFakeKVStore(t)
|
kvStore := NewFakeKVStore(t)
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
decryptFn := secretsService.GetDecryptedValue
|
decryptFn := secretsService.GetDecryptedValue
|
||||||
reg := prometheus.NewPedanticRegistry()
|
reg := prometheus.NewPedanticRegistry()
|
||||||
@@ -246,7 +246,9 @@ func TestMultiOrgAlertmanager_AlertmanagerFor(t *testing.T) {
|
|||||||
{
|
{
|
||||||
// let's delete its "running config" to make it non-ready
|
// let's delete its "running config" to make it non-ready
|
||||||
mam.alertmanagers[1].config = nil
|
mam.alertmanagers[1].config = nil
|
||||||
_, err := mam.AlertmanagerFor(1)
|
am, err := mam.AlertmanagerFor(1)
|
||||||
|
require.NotNil(t, am)
|
||||||
|
require.False(t, am.Ready())
|
||||||
require.EqualError(t, err, ErrAlertmanagerNotReady.Error())
|
require.EqualError(t, err, ErrAlertmanagerNotReady.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,14 @@ type FakeConfigStore struct {
|
|||||||
configs map[int64]*models.AlertConfiguration
|
configs map[int64]*models.AlertConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewFakeConfigStore(t *testing.T, configs map[int64]*models.AlertConfiguration) FakeConfigStore {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
return FakeConfigStore{
|
||||||
|
configs: configs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FakeConfigStore) GetAllLatestAlertmanagerConfiguration(context.Context) ([]*models.AlertConfiguration, error) {
|
func (f *FakeConfigStore) GetAllLatestAlertmanagerConfiguration(context.Context) ([]*models.AlertConfiguration, error) {
|
||||||
result := make([]*models.AlertConfiguration, 0, len(f.configs))
|
result := make([]*models.AlertConfiguration, 0, len(f.configs))
|
||||||
for _, configuration := range f.configs {
|
for _, configuration := range f.configs {
|
||||||
@@ -63,6 +71,14 @@ type FakeOrgStore struct {
|
|||||||
orgs []int64
|
orgs []int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewFakeOrgStore(t *testing.T, orgs []int64) FakeOrgStore {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
return FakeOrgStore{
|
||||||
|
orgs: orgs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FakeOrgStore) GetOrgs(_ context.Context) ([]int64, error) {
|
func (f *FakeOrgStore) GetOrgs(_ context.Context) ([]int64, error) {
|
||||||
return f.orgs, nil
|
return f.orgs, nil
|
||||||
}
|
}
|
||||||
@@ -72,7 +88,7 @@ type FakeKVStore struct {
|
|||||||
store map[int64]map[string]map[string]string
|
store map[int64]map[string]map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFakeKVStore(t *testing.T) *FakeKVStore {
|
func NewFakeKVStore(t *testing.T) *FakeKVStore {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
return &FakeKVStore{
|
return &FakeKVStore{
|
||||||
|
|||||||
Reference in New Issue
Block a user