2017-10-09 20:36:31 +02:00
|
|
|
package datasources
|
|
|
|
|
|
|
|
|
|
import (
|
2021-10-18 16:06:19 +01:00
|
|
|
"context"
|
2019-04-24 15:39:47 +02:00
|
|
|
"os"
|
2017-10-09 20:36:31 +02:00
|
|
|
"testing"
|
|
|
|
|
|
2019-05-13 14:45:54 +08:00
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
2017-10-09 20:36:31 +02:00
|
|
|
"github.com/grafana/grafana/pkg/models"
|
2021-12-13 14:14:39 -05:00
|
|
|
"github.com/grafana/grafana/pkg/util"
|
2017-10-09 20:36:31 +02:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
"github.com/stretchr/testify/require"
|
2017-10-09 20:36:31 +02:00
|
|
|
)
|
|
|
|
|
|
2017-10-21 22:50:12 +02:00
|
|
|
var (
|
2018-04-27 22:14:36 +02:00
|
|
|
logger log.Logger = log.New("fake.log")
|
|
|
|
|
|
2018-05-29 14:07:37 +02:00
|
|
|
twoDatasourcesConfig = "testdata/two-datasources"
|
|
|
|
|
twoDatasourcesConfigPurgeOthers = "testdata/insert-two-delete-two"
|
2022-02-09 08:38:13 -03:00
|
|
|
deleteOneDatasource = "testdata/delete-one"
|
2018-05-29 14:07:37 +02:00
|
|
|
doubleDatasourcesConfig = "testdata/double-default"
|
|
|
|
|
allProperties = "testdata/all-properties"
|
|
|
|
|
versionZero = "testdata/version-0"
|
|
|
|
|
brokenYaml = "testdata/broken-yaml"
|
2018-08-14 14:48:14 +02:00
|
|
|
multipleOrgsWithDefault = "testdata/multiple-org-default"
|
2020-05-14 12:40:00 +02:00
|
|
|
withoutDefaults = "testdata/appliedDefaults"
|
2020-07-20 12:01:25 +04:00
|
|
|
invalidAccess = "testdata/invalid-access"
|
2017-10-21 22:50:12 +02:00
|
|
|
)
|
2017-10-09 20:36:31 +02:00
|
|
|
|
|
|
|
|
func TestDatasourceAsConfig(t *testing.T) {
|
2022-02-23 11:12:37 +01:00
|
|
|
t.Run("when some values missing should apply default on insert", func(t *testing.T) {
|
|
|
|
|
store := &spyStore{}
|
|
|
|
|
orgStore := &mockOrgStore{ExpectedOrg: &models.Org{Id: 1}}
|
|
|
|
|
dc := newDatasourceProvisioner(logger, store, orgStore)
|
|
|
|
|
err := dc.applyChanges(context.Background(), withoutDefaults)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("applyChanges return an error %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require.Equal(t, len(store.inserted), 1)
|
|
|
|
|
require.Equal(t, store.inserted[0].OrgId, int64(1))
|
|
|
|
|
require.Equal(t, store.inserted[0].Access, models.DsAccess("proxy"))
|
|
|
|
|
require.Equal(t, store.inserted[0].Name, "My datasource name")
|
|
|
|
|
require.Equal(t, store.inserted[0].Uid, "P2AD1F727255C56BA")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("when some values missing should not change UID when updates", func(t *testing.T) {
|
|
|
|
|
store := &spyStore{
|
|
|
|
|
items: []*models.DataSource{{Name: "My datasource name", OrgId: 1, Id: 1, Uid: util.GenerateShortUID()}},
|
|
|
|
|
}
|
|
|
|
|
orgStore := &mockOrgStore{}
|
|
|
|
|
dc := newDatasourceProvisioner(logger, store, orgStore)
|
|
|
|
|
err := dc.applyChanges(context.Background(), withoutDefaults)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("applyChanges return an error %v", err)
|
|
|
|
|
}
|
2021-11-01 11:31:55 +01:00
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
require.Equal(t, len(store.deleted), 0)
|
|
|
|
|
require.Equal(t, len(store.inserted), 0)
|
|
|
|
|
require.Equal(t, len(store.updated), 1)
|
|
|
|
|
require.Equal(t, "", store.updated[0].Uid) // XORM will not update the field if its value is default
|
2021-11-01 11:31:55 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("no datasource in database", func(t *testing.T) {
|
2022-02-23 11:12:37 +01:00
|
|
|
store := &spyStore{}
|
|
|
|
|
orgStore := &mockOrgStore{}
|
|
|
|
|
dc := newDatasourceProvisioner(logger, store, orgStore)
|
2021-11-01 11:31:55 +01:00
|
|
|
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("applyChanges return an error %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
require.Equal(t, len(store.deleted), 0)
|
|
|
|
|
require.Equal(t, len(store.inserted), 2)
|
|
|
|
|
require.Equal(t, len(store.updated), 0)
|
2021-11-01 11:31:55 +01:00
|
|
|
})
|
|
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
t.Run("One datasource in database with same name should update one datasource", func(t *testing.T) {
|
|
|
|
|
store := &spyStore{items: []*models.DataSource{{Name: "Graphite", OrgId: 1, Id: 1}}}
|
|
|
|
|
orgStore := &mockOrgStore{}
|
|
|
|
|
dc := newDatasourceProvisioner(logger, store, orgStore)
|
|
|
|
|
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("applyChanges return an error %v", err)
|
2021-11-01 11:31:55 +01:00
|
|
|
}
|
2017-10-09 20:36:31 +02:00
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
require.Equal(t, len(store.deleted), 0)
|
|
|
|
|
require.Equal(t, len(store.inserted), 1)
|
|
|
|
|
require.Equal(t, len(store.updated), 1)
|
2021-11-01 11:31:55 +01:00
|
|
|
})
|
2020-05-14 12:40:00 +02:00
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
t.Run("Two datasources with is_default should raise error", func(t *testing.T) {
|
|
|
|
|
store := &spyStore{}
|
|
|
|
|
orgStore := &mockOrgStore{}
|
|
|
|
|
dc := newDatasourceProvisioner(logger, store, orgStore)
|
2021-11-01 11:31:55 +01:00
|
|
|
err := dc.applyChanges(context.Background(), doubleDatasourcesConfig)
|
2022-02-23 11:12:37 +01:00
|
|
|
require.Equal(t, err, ErrInvalidConfigToManyDefault)
|
2021-11-01 11:31:55 +01:00
|
|
|
})
|
2017-10-09 20:36:31 +02:00
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
t.Run("Multiple datasources in different organizations with isDefault in each organization should not raise error", func(t *testing.T) {
|
|
|
|
|
store := &spyStore{}
|
|
|
|
|
orgStore := &mockOrgStore{}
|
|
|
|
|
dc := newDatasourceProvisioner(logger, store, orgStore)
|
2021-11-01 11:31:55 +01:00
|
|
|
err := dc.applyChanges(context.Background(), multipleOrgsWithDefault)
|
2022-02-23 11:12:37 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, len(store.inserted), 4)
|
|
|
|
|
require.True(t, store.inserted[0].IsDefault)
|
|
|
|
|
require.Equal(t, store.inserted[0].OrgId, int64(1))
|
|
|
|
|
require.True(t, store.inserted[2].IsDefault)
|
|
|
|
|
require.Equal(t, store.inserted[2].OrgId, int64(2))
|
2021-11-01 11:31:55 +01:00
|
|
|
})
|
2017-10-09 20:36:31 +02:00
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
t.Run("Remove one datasource should have removed old datasource", func(t *testing.T) {
|
|
|
|
|
store := &spyStore{}
|
|
|
|
|
orgStore := &mockOrgStore{}
|
|
|
|
|
dc := newDatasourceProvisioner(logger, store, orgStore)
|
|
|
|
|
err := dc.applyChanges(context.Background(), deleteOneDatasource)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("applyChanges return an error %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require.Equal(t, 1, len(store.deleted))
|
|
|
|
|
// should have set OrgID to 1
|
|
|
|
|
require.Equal(t, store.deleted[0].OrgID, int64(1))
|
|
|
|
|
require.Equal(t, 0, len(store.inserted))
|
|
|
|
|
require.Equal(t, len(store.updated), 0)
|
2022-02-09 08:38:13 -03:00
|
|
|
})
|
|
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
t.Run("Two configured datasource and purge others", func(t *testing.T) {
|
|
|
|
|
store := &spyStore{items: []*models.DataSource{{Name: "old-graphite", OrgId: 1, Id: 1}, {Name: "old-graphite2", OrgId: 1, Id: 2}}}
|
|
|
|
|
orgStore := &mockOrgStore{}
|
|
|
|
|
dc := newDatasourceProvisioner(logger, store, orgStore)
|
|
|
|
|
err := dc.applyChanges(context.Background(), twoDatasourcesConfigPurgeOthers)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("applyChanges return an error %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require.Equal(t, len(store.deleted), 2)
|
|
|
|
|
require.Equal(t, len(store.inserted), 2)
|
|
|
|
|
require.Equal(t, len(store.updated), 0)
|
2021-11-01 11:31:55 +01:00
|
|
|
})
|
2017-10-11 20:59:15 +02:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
t.Run("Two configured datasource and purge others = false", func(t *testing.T) {
|
2022-02-23 11:12:37 +01:00
|
|
|
store := &spyStore{items: []*models.DataSource{{Name: "Graphite", OrgId: 1, Id: 1}, {Name: "old-graphite2", OrgId: 1, Id: 2}}}
|
|
|
|
|
orgStore := &mockOrgStore{}
|
|
|
|
|
dc := newDatasourceProvisioner(logger, store, orgStore)
|
|
|
|
|
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("applyChanges return an error %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require.Equal(t, len(store.deleted), 0)
|
|
|
|
|
require.Equal(t, len(store.inserted), 1)
|
|
|
|
|
require.Equal(t, len(store.updated), 1)
|
2021-11-01 11:31:55 +01:00
|
|
|
})
|
2017-10-24 10:15:06 +02:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
t.Run("broken yaml should return error", func(t *testing.T) {
|
|
|
|
|
reader := &configReader{}
|
2021-11-03 11:31:56 +01:00
|
|
|
_, err := reader.readConfig(context.Background(), brokenYaml)
|
2021-11-01 11:31:55 +01:00
|
|
|
require.NotNil(t, err)
|
|
|
|
|
})
|
2017-10-24 10:15:06 +02:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
t.Run("invalid access should warn about invalid value and return 'proxy'", func(t *testing.T) {
|
2022-02-23 11:12:37 +01:00
|
|
|
reader := &configReader{log: logger, orgStore: &mockOrgStore{}}
|
2021-11-03 11:31:56 +01:00
|
|
|
configs, err := reader.readConfig(context.Background(), invalidAccess)
|
2021-11-01 11:31:55 +01:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, configs[0].Datasources[0].Access, models.DS_ACCESS_PROXY)
|
|
|
|
|
})
|
2020-07-20 12:01:25 +04:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
t.Run("skip invalid directory", func(t *testing.T) {
|
2022-02-23 11:12:37 +01:00
|
|
|
cfgProvider := &configReader{log: log.New("test logger"), orgStore: &mockOrgStore{}}
|
2021-11-03 11:31:56 +01:00
|
|
|
cfg, err := cfgProvider.readConfig(context.Background(), "./invalid-directory")
|
2021-11-01 11:31:55 +01:00
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("readConfig return an error %v", err)
|
|
|
|
|
}
|
2018-01-24 14:20:16 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
require.Equal(t, len(cfg), 0)
|
|
|
|
|
})
|
2018-01-24 14:20:16 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
t.Run("can read all properties from version 1", func(t *testing.T) {
|
|
|
|
|
_ = os.Setenv("TEST_VAR", "name")
|
2022-02-23 11:12:37 +01:00
|
|
|
cfgProvider := &configReader{log: log.New("test logger"), orgStore: &mockOrgStore{}}
|
2021-11-03 11:31:56 +01:00
|
|
|
cfg, err := cfgProvider.readConfig(context.Background(), allProperties)
|
2021-11-01 11:31:55 +01:00
|
|
|
_ = os.Unsetenv("TEST_VAR")
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("readConfig return an error %v", err)
|
|
|
|
|
}
|
2017-10-24 10:15:06 +02:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
require.Equal(t, len(cfg), 3)
|
2017-10-26 17:13:07 +02:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
dsCfg := cfg[0]
|
2018-02-12 15:17:32 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
require.Equal(t, dsCfg.APIVersion, int64(1))
|
2018-02-12 15:17:32 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
validateDatasourceV1(t, dsCfg)
|
|
|
|
|
validateDeleteDatasources(t, dsCfg)
|
2018-02-20 07:33:24 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
dsCount := 0
|
|
|
|
|
delDsCount := 0
|
2018-02-20 07:33:24 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
for _, c := range cfg {
|
|
|
|
|
dsCount += len(c.Datasources)
|
|
|
|
|
delDsCount += len(c.DeleteDatasources)
|
|
|
|
|
}
|
2018-02-20 07:33:24 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
require.Equal(t, dsCount, 2)
|
|
|
|
|
require.Equal(t, delDsCount, 1)
|
|
|
|
|
})
|
2018-02-12 15:17:32 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
t.Run("can read all properties from version 0", func(t *testing.T) {
|
2022-02-23 11:12:37 +01:00
|
|
|
cfgProvider := &configReader{log: log.New("test logger"), orgStore: &mockOrgStore{}}
|
2021-11-03 11:31:56 +01:00
|
|
|
cfg, err := cfgProvider.readConfig(context.Background(), versionZero)
|
2021-11-01 11:31:55 +01:00
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("readConfig return an error %v", err)
|
|
|
|
|
}
|
2018-02-12 15:17:32 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
require.Equal(t, len(cfg), 1)
|
2018-02-12 15:17:32 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
dsCfg := cfg[0]
|
2018-02-12 15:17:32 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
require.Equal(t, dsCfg.APIVersion, int64(0))
|
2018-02-12 15:17:32 +01:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
validateDatasource(t, dsCfg)
|
|
|
|
|
validateDeleteDatasources(t, dsCfg)
|
2017-10-09 20:36:31 +02:00
|
|
|
})
|
|
|
|
|
}
|
2020-04-11 21:07:07 +02:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
func validateDeleteDatasources(t *testing.T, dsCfg *configs) {
|
|
|
|
|
require.Equal(t, len(dsCfg.DeleteDatasources), 1)
|
2018-02-12 15:17:32 +01:00
|
|
|
deleteDs := dsCfg.DeleteDatasources[0]
|
2021-11-01 11:31:55 +01:00
|
|
|
require.Equal(t, deleteDs.Name, "old-graphite3")
|
|
|
|
|
require.Equal(t, deleteDs.OrgID, int64(2))
|
2018-02-12 15:17:32 +01:00
|
|
|
}
|
2020-04-11 21:07:07 +02:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
func validateDatasource(t *testing.T, dsCfg *configs) {
|
2018-02-12 15:17:32 +01:00
|
|
|
ds := dsCfg.Datasources[0]
|
2021-11-01 11:31:55 +01:00
|
|
|
require.Equal(t, ds.Name, "name")
|
|
|
|
|
require.Equal(t, ds.Type, "type")
|
|
|
|
|
require.Equal(t, ds.Access, models.DS_ACCESS_PROXY)
|
|
|
|
|
require.Equal(t, ds.OrgID, int64(2))
|
|
|
|
|
require.Equal(t, ds.URL, "url")
|
|
|
|
|
require.Equal(t, ds.User, "user")
|
|
|
|
|
require.Equal(t, ds.Database, "database")
|
|
|
|
|
require.True(t, ds.BasicAuth)
|
|
|
|
|
require.Equal(t, ds.BasicAuthUser, "basic_auth_user")
|
|
|
|
|
require.True(t, ds.WithCredentials)
|
|
|
|
|
require.True(t, ds.IsDefault)
|
|
|
|
|
require.True(t, ds.Editable)
|
|
|
|
|
require.Equal(t, ds.Version, 10)
|
|
|
|
|
|
|
|
|
|
require.Greater(t, len(ds.JSONData), 2)
|
|
|
|
|
require.Equal(t, ds.JSONData["graphiteVersion"], "1.1")
|
|
|
|
|
require.Equal(t, ds.JSONData["tlsAuth"], true)
|
|
|
|
|
require.Equal(t, ds.JSONData["tlsAuthWithCACert"], true)
|
|
|
|
|
|
|
|
|
|
require.Greater(t, len(ds.SecureJSONData), 2)
|
|
|
|
|
require.Equal(t, ds.SecureJSONData["tlsCACert"], "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==")
|
|
|
|
|
require.Equal(t, ds.SecureJSONData["tlsClientCert"], "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==")
|
|
|
|
|
require.Equal(t, ds.SecureJSONData["tlsClientKey"], "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==")
|
2018-02-12 15:17:32 +01:00
|
|
|
}
|
2017-10-09 20:36:31 +02:00
|
|
|
|
2021-11-01 11:31:55 +01:00
|
|
|
func validateDatasourceV1(t *testing.T, dsCfg *configs) {
|
|
|
|
|
validateDatasource(t, dsCfg)
|
2020-04-20 15:48:38 +02:00
|
|
|
ds := dsCfg.Datasources[0]
|
2021-11-01 11:31:55 +01:00
|
|
|
require.Equal(t, ds.UID, "test_uid")
|
2020-04-20 15:48:38 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
type mockOrgStore struct{ ExpectedOrg *models.Org }
|
|
|
|
|
|
|
|
|
|
func (m *mockOrgStore) GetOrgById(c context.Context, cmd *models.GetOrgByIdQuery) error {
|
|
|
|
|
cmd.Result = m.ExpectedOrg
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type spyStore struct {
|
2017-10-09 20:36:31 +02:00
|
|
|
inserted []*models.AddDataSourceCommand
|
2021-01-13 13:16:27 -05:00
|
|
|
deleted []*models.DeleteDataSourceCommand
|
2017-10-09 20:36:31 +02:00
|
|
|
updated []*models.UpdateDataSourceCommand
|
2022-02-23 11:12:37 +01:00
|
|
|
items []*models.DataSource
|
2017-10-09 20:36:31 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
func (s *spyStore) GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error {
|
|
|
|
|
for _, v := range s.items {
|
|
|
|
|
if query.Name == v.Name && query.OrgId == v.OrgId {
|
|
|
|
|
query.Result = v
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return models.ErrDataSourceNotFound
|
2017-10-09 20:36:31 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
func (s *spyStore) DeleteDataSource(ctx context.Context, cmd *models.DeleteDataSourceCommand) error {
|
|
|
|
|
s.deleted = append(s.deleted, cmd)
|
2017-10-09 20:36:31 +02:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
func (s *spyStore) AddDataSource(ctx context.Context, cmd *models.AddDataSourceCommand) error {
|
|
|
|
|
s.inserted = append(s.inserted, cmd)
|
2017-10-09 20:36:31 +02:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-23 11:12:37 +01:00
|
|
|
func (s *spyStore) UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSourceCommand) error {
|
|
|
|
|
s.updated = append(s.updated, cmd)
|
2020-07-30 13:59:12 +04:00
|
|
|
return nil
|
|
|
|
|
}
|