Chore: Refactor GoConvey in provisioning package (#40892)

* refactor goconvey in some provisioning subpackages

* fix goconvey in provisioning/datasources

* remove goconvey from notifiers subpackage

* finally resolve goconvey in dashboards subpackage
This commit is contained in:
Serge Zaitsev 2021-11-01 11:31:55 +01:00 committed by GitHub
parent b80fbe03f0
commit 7b15cd0ed2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 821 additions and 782 deletions

View File

@ -17,7 +17,8 @@ import (
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/infra/log"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
const (
@ -32,403 +33,432 @@ const (
var fakeService *fakeDashboardProvisioningService
func TestCreatingNewDashboardFileReader(t *testing.T) {
Convey("creating new dashboard file reader", t, func() {
cfg := &config{
setup := func() *config {
return &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "",
Options: map[string]interface{}{},
}
}
Convey("using path parameter", func() {
cfg.Options["path"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
So(reader.Path, ShouldNotEqual, "")
})
t.Run("using path parameter", func(t *testing.T) {
cfg := setup()
cfg.Options["path"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
require.NoError(t, err)
require.NotEqual(t, reader.Path, "")
})
Convey("using folder as options", func() {
cfg.Options["folder"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
So(reader.Path, ShouldNotEqual, "")
})
t.Run("using folder as options", func(t *testing.T) {
cfg := setup()
cfg.Options["folder"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
require.NoError(t, err)
require.NotEqual(t, reader.Path, "")
})
Convey("using foldersFromFilesStructure as options", func() {
cfg.Options["path"] = foldersFromFilesStructure
cfg.Options["foldersFromFilesStructure"] = true
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
So(reader.Path, ShouldNotEqual, "")
})
t.Run("using foldersFromFilesStructure as options", func(t *testing.T) {
cfg := setup()
cfg.Options["path"] = foldersFromFilesStructure
cfg.Options["foldersFromFilesStructure"] = true
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
require.NoError(t, err)
require.NotEqual(t, reader.Path, "")
})
Convey("using full path", func() {
fullPath := "/var/lib/grafana/dashboards"
if runtime.GOOS == "windows" {
fullPath = `c:\var\lib\grafana`
}
t.Run("using full path", func(t *testing.T) {
cfg := setup()
fullPath := "/var/lib/grafana/dashboards"
if runtime.GOOS == "windows" {
fullPath = `c:\var\lib\grafana`
}
cfg.Options["folder"] = fullPath
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
cfg.Options["folder"] = fullPath
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
require.NoError(t, err)
So(reader.Path, ShouldEqual, fullPath)
So(filepath.IsAbs(reader.Path), ShouldBeTrue)
})
require.Equal(t, reader.Path, fullPath)
require.True(t, filepath.IsAbs(reader.Path))
})
Convey("using relative path", func() {
cfg.Options["folder"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
t.Run("using relative path", func(t *testing.T) {
cfg := setup()
cfg.Options["folder"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
require.NoError(t, err)
resolvedPath := reader.resolvedPath()
So(filepath.IsAbs(resolvedPath), ShouldBeTrue)
})
resolvedPath := reader.resolvedPath()
require.True(t, filepath.IsAbs(resolvedPath))
})
}
func TestDashboardFileReader(t *testing.T) {
Convey("Dashboard file reader", t, func() {
logger := log.New("test.logger")
cfg := &config{}
origNewDashboardProvisioningService := dashboards.NewProvisioningService
defer func() {
dashboards.NewProvisioningService = origNewDashboardProvisioningService
}()
setup := func() {
bus.ClearBusHandlers()
origNewDashboardProvisioningService := dashboards.NewProvisioningService
Reset(func() {
dashboards.NewProvisioningService = origNewDashboardProvisioningService
})
fakeService = mockDashboardProvisioningService()
bus.AddHandler("test", mockGetDashboardQuery)
logger := log.New("test.logger")
cfg = &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "",
Options: map[string]interface{}{},
}
}
Convey("Reading dashboards from disk", func() {
cfg := &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "",
Options: map[string]interface{}{},
t.Run("Reading dashboards from disk", func(t *testing.T) {
t.Run("Can read default dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = defaultDashboards
cfg.Folder = "Team A"
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
folders := 0
dashboards := 0
for _, i := range fakeService.inserted {
if i.Dashboard.IsFolder {
folders++
} else {
dashboards++
}
}
Convey("Can read default dashboard", func() {
cfg.Options["path"] = defaultDashboards
cfg.Folder = "Team A"
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
folders := 0
dashboards := 0
for _, i := range fakeService.inserted {
if i.Dashboard.IsFolder {
folders++
} else {
dashboards++
}
}
So(folders, ShouldEqual, 1)
So(dashboards, ShouldEqual, 2)
})
Convey("Can read default dashboard and replace old version in database", func() {
cfg.Options["path"] = oneDashboard
stat, _ := os.Stat(oneDashboard + "/dashboard1.json")
fakeService.getDashboard = append(fakeService.getDashboard, &models.Dashboard{
Updated: stat.ModTime().AddDate(0, 0, -1),
Slug: "grafana",
})
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 1)
})
Convey("Dashboard with older timestamp and the same checksum will not replace imported dashboard", func() {
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
file, err := os.Open(filepath.Clean(absPath))
So(err, ShouldBeNil)
t.Cleanup(func() {
_ = file.Close()
})
checksum, err := util.Md5Sum(file)
So(err, ShouldBeNil)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{
Name: "Default",
ExternalId: absPath,
Updated: stat.ModTime().AddDate(0, 0, +1).Unix(),
CheckSum: checksum,
},
},
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 0)
})
Convey("Dashboard with older timestamp and different checksum will replace imported dashboard", func() {
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{
Name: "Default",
ExternalId: absPath,
Updated: stat.ModTime().AddDate(0, 0, +1).Unix(),
CheckSum: "fakechecksum",
},
},
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 1)
})
Convey("Dashboard with newer timestamp and the same checksum will not replace imported dashboard", func() {
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
file, err := os.Open(filepath.Clean(absPath))
So(err, ShouldBeNil)
t.Cleanup(func() {
_ = file.Close()
})
checksum, err := util.Md5Sum(file)
So(err, ShouldBeNil)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{
Name: "Default",
ExternalId: absPath,
Updated: stat.ModTime().AddDate(0, 0, -1).Unix(),
CheckSum: checksum,
},
},
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 0)
})
Convey("Dashboard with newer timestamp and different checksum should replace imported dashboard", func() {
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{
Name: "Default",
ExternalId: absPath,
Updated: stat.ModTime().AddDate(0, 0, -1).Unix(),
CheckSum: "fakechecksum",
},
},
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 1)
})
Convey("Overrides id from dashboard.json files", func() {
cfg.Options["path"] = containingID
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 1)
})
Convey("Get folder from files structure", func() {
cfg.Options["path"] = foldersFromFilesStructure
cfg.Options["foldersFromFilesStructure"] = true
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 5)
foldersCount := 0
for _, d := range fakeService.inserted {
if d.Dashboard.IsFolder {
foldersCount++
}
}
So(foldersCount, ShouldEqual, 2)
foldersAndDashboards := make(map[string]struct{}, 5)
for _, d := range fakeService.inserted {
title := d.Dashboard.Title
if _, ok := foldersAndDashboards[title]; ok {
So(fmt.Errorf("dashboard title %q already exists", title), ShouldBeNil)
}
switch title {
case "folderOne", "folderTwo":
So(d.Dashboard.IsFolder, ShouldBeTrue)
case "Grafana1", "Grafana2", "RootDashboard":
So(d.Dashboard.IsFolder, ShouldBeFalse)
default:
So(fmt.Errorf("unknown dashboard title %q", title), ShouldBeNil)
}
foldersAndDashboards[title] = struct{}{}
}
})
Convey("Invalid configuration should return error", func() {
cfg := &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "",
}
_, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldNotBeNil)
})
Convey("Broken dashboards should not cause error", func() {
cfg.Options["path"] = brokenDashboards
_, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
})
Convey("Two dashboard providers should be able to provisioned the same dashboard without uid", func() {
cfg1 := &config{Name: "1", Type: "file", OrgID: 1, Folder: "f1", Options: map[string]interface{}{"path": containingID}}
cfg2 := &config{Name: "2", Type: "file", OrgID: 1, Folder: "f2", Options: map[string]interface{}{"path": containingID}}
reader1, err := NewDashboardFileReader(cfg1, logger, nil)
So(err, ShouldBeNil)
err = reader1.walkDisk(context.Background())
So(err, ShouldBeNil)
reader2, err := NewDashboardFileReader(cfg2, logger, nil)
So(err, ShouldBeNil)
err = reader2.walkDisk(context.Background())
So(err, ShouldBeNil)
var folderCount int
var dashCount int
for _, o := range fakeService.inserted {
if o.Dashboard.IsFolder {
folderCount++
} else {
dashCount++
}
}
So(folderCount, ShouldEqual, 2)
So(dashCount, ShouldEqual, 2)
})
require.Equal(t, folders, 1)
require.Equal(t, dashboards, 2)
})
Convey("Should not create new folder if folder name is missing", func() {
t.Run("Can read default dashboard and replace old version in database", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
stat, _ := os.Stat(oneDashboard + "/dashboard1.json")
fakeService.getDashboard = append(fakeService.getDashboard, &models.Dashboard{
Updated: stat.ModTime().AddDate(0, 0, -1),
Slug: "grafana",
})
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 1)
})
t.Run("Dashboard with older timestamp and the same checksum will not replace imported dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
require.NoError(t, err)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
require.NoError(t, err)
file, err := os.Open(filepath.Clean(absPath))
require.NoError(t, err)
t.Cleanup(func() {
_ = file.Close()
})
checksum, err := util.Md5Sum(file)
require.NoError(t, err)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{
Name: "Default",
ExternalId: absPath,
Updated: stat.ModTime().AddDate(0, 0, +1).Unix(),
CheckSum: checksum,
},
},
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 0)
})
t.Run("Dashboard with older timestamp and different checksum will replace imported dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
require.NoError(t, err)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
require.NoError(t, err)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{
Name: "Default",
ExternalId: absPath,
Updated: stat.ModTime().AddDate(0, 0, +1).Unix(),
CheckSum: "fakechecksum",
},
},
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 1)
})
t.Run("Dashboard with newer timestamp and the same checksum will not replace imported dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
require.NoError(t, err)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
require.NoError(t, err)
file, err := os.Open(filepath.Clean(absPath))
require.NoError(t, err)
t.Cleanup(func() {
_ = file.Close()
})
checksum, err := util.Md5Sum(file)
require.NoError(t, err)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{
Name: "Default",
ExternalId: absPath,
Updated: stat.ModTime().AddDate(0, 0, -1).Unix(),
CheckSum: checksum,
},
},
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 0)
})
t.Run("Dashboard with newer timestamp and different checksum should replace imported dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
require.NoError(t, err)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
require.NoError(t, err)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{
Name: "Default",
ExternalId: absPath,
Updated: stat.ModTime().AddDate(0, 0, -1).Unix(),
CheckSum: "fakechecksum",
},
},
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 1)
})
t.Run("Overrides id from dashboard.json files", func(t *testing.T) {
setup()
cfg.Options["path"] = containingID
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 1)
})
t.Run("Get folder from files structure", func(t *testing.T) {
setup()
cfg.Options["path"] = foldersFromFilesStructure
cfg.Options["foldersFromFilesStructure"] = true
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 5)
foldersCount := 0
for _, d := range fakeService.inserted {
if d.Dashboard.IsFolder {
foldersCount++
}
}
require.Equal(t, foldersCount, 2)
foldersAndDashboards := make(map[string]struct{}, 5)
for _, d := range fakeService.inserted {
title := d.Dashboard.Title
if _, ok := foldersAndDashboards[title]; ok {
require.Nil(t, fmt.Errorf("dashboard title %q already exists", title))
}
switch title {
case "folderOne", "folderTwo":
require.True(t, d.Dashboard.IsFolder)
case "Grafana1", "Grafana2", "RootDashboard":
require.False(t, d.Dashboard.IsFolder)
default:
require.Nil(t, fmt.Errorf("unknown dashboard title %q", title))
}
foldersAndDashboards[title] = struct{}{}
}
})
t.Run("Invalid configuration should return error", func(t *testing.T) {
setup()
cfg := &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "",
Options: map[string]interface{}{
"folder": defaultDashboards,
},
}
_, err := getOrCreateFolderID(context.Background(), cfg, fakeService, cfg.Folder)
So(err, ShouldEqual, ErrFolderNameMissing)
_, err := NewDashboardFileReader(cfg, logger, nil)
require.NotNil(t, err)
})
Convey("can get or Create dashboard folder", func() {
cfg := &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "TEAM A",
Options: map[string]interface{}{
"folder": defaultDashboards,
},
}
t.Run("Broken dashboards should not cause error", func(t *testing.T) {
setup()
cfg.Options["path"] = brokenDashboards
folderID, err := getOrCreateFolderID(context.Background(), cfg, fakeService, cfg.Folder)
So(err, ShouldBeNil)
inserted := false
for _, d := range fakeService.inserted {
if d.Dashboard.IsFolder && d.Dashboard.Id == folderID {
inserted = true
_, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
})
t.Run("Two dashboard providers should be able to provisioned the same dashboard without uid", func(t *testing.T) {
setup()
cfg1 := &config{Name: "1", Type: "file", OrgID: 1, Folder: "f1", Options: map[string]interface{}{"path": containingID}}
cfg2 := &config{Name: "2", Type: "file", OrgID: 1, Folder: "f2", Options: map[string]interface{}{"path": containingID}}
reader1, err := NewDashboardFileReader(cfg1, logger, nil)
require.NoError(t, err)
err = reader1.walkDisk(context.Background())
require.NoError(t, err)
reader2, err := NewDashboardFileReader(cfg2, logger, nil)
require.NoError(t, err)
err = reader2.walkDisk(context.Background())
require.NoError(t, err)
var folderCount int
var dashCount int
for _, o := range fakeService.inserted {
if o.Dashboard.IsFolder {
folderCount++
} else {
dashCount++
}
}
So(len(fakeService.inserted), ShouldEqual, 1)
So(inserted, ShouldBeTrue)
require.Equal(t, folderCount, 2)
require.Equal(t, dashCount, 2)
})
})
t.Run("Should not create new folder if folder name is missing", func(t *testing.T) {
setup()
cfg := &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "",
Options: map[string]interface{}{
"folder": defaultDashboards,
},
}
_, err := getOrCreateFolderID(context.Background(), cfg, fakeService, cfg.Folder)
require.Equal(t, err, ErrFolderNameMissing)
})
t.Run("can get or Create dashboard folder", func(t *testing.T) {
setup()
cfg := &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "TEAM A",
Options: map[string]interface{}{
"folder": defaultDashboards,
},
}
folderID, err := getOrCreateFolderID(context.Background(), cfg, fakeService, cfg.Folder)
require.NoError(t, err)
inserted := false
for _, d := range fakeService.inserted {
if d.Dashboard.IsFolder && d.Dashboard.Id == folderID {
inserted = true
}
}
require.Equal(t, len(fakeService.inserted), 1)
require.True(t, inserted)
})
t.Run("Walking the folder with dashboards", func(t *testing.T) {
setup()
noFiles := map[string]os.FileInfo{}
t.Run("should skip dirs that starts with .", func(t *testing.T) {
shouldSkip := createWalkFn(noFiles)("path", &FakeFileInfo{isDirectory: true, name: ".folder"}, nil)
require.Equal(t, shouldSkip, filepath.SkipDir)
})
Convey("Walking the folder with dashboards", func() {
noFiles := map[string]os.FileInfo{}
Convey("should skip dirs that starts with .", func() {
shouldSkip := createWalkFn(noFiles)("path", &FakeFileInfo{isDirectory: true, name: ".folder"}, nil)
So(shouldSkip, ShouldEqual, filepath.SkipDir)
})
Convey("should keep walking if file is not .json", func() {
shouldSkip := createWalkFn(noFiles)("path", &FakeFileInfo{isDirectory: true, name: "folder"}, nil)
So(shouldSkip, ShouldBeNil)
})
t.Run("should keep walking if file is not .json", func(t *testing.T) {
shouldSkip := createWalkFn(noFiles)("path", &FakeFileInfo{isDirectory: true, name: "folder"}, nil)
require.Nil(t, shouldSkip)
})
})
Convey("Given missing dashboard file", func() {
cfg := &config{
t.Run("Given missing dashboard file", func(t *testing.T) {
absPath1, err := filepath.Abs(unprovision + "/dashboard1.json")
require.NoError(t, err)
// This one does not exist on disk, simulating a deleted file
absPath2, err := filepath.Abs(unprovision + "/dashboard2.json")
require.NoError(t, err)
setupFakeService := func() {
setup()
cfg = &config{
Name: "Default",
Type: "file",
OrgID: 1,
@ -442,44 +472,40 @@ func TestDashboardFileReader(t *testing.T) {
{Dashboard: &models.Dashboard{Id: 2}},
}
absPath1, err := filepath.Abs(unprovision + "/dashboard1.json")
So(err, ShouldBeNil)
// This one does not exist on disk, simulating a deleted file
absPath2, err := filepath.Abs(unprovision + "/dashboard2.json")
So(err, ShouldBeNil)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{DashboardId: 1, Name: "Default", ExternalId: absPath1},
{DashboardId: 2, Name: "Default", ExternalId: absPath2},
},
}
}
Convey("Missing dashboard should be unprovisioned if DisableDeletion = true", func() {
cfg.DisableDeletion = true
t.Run("Missing dashboard should be unprovisioned if DisableDeletion = true", func(t *testing.T) {
setupFakeService()
cfg.DisableDeletion = true
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
So(len(fakeService.provisioned["Default"]), ShouldEqual, 1)
So(fakeService.provisioned["Default"][0].ExternalId, ShouldEqual, absPath1)
})
require.Equal(t, len(fakeService.provisioned["Default"]), 1)
require.Equal(t, fakeService.provisioned["Default"][0].ExternalId, absPath1)
})
Convey("Missing dashboard should be deleted if DisableDeletion = false", func() {
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
t.Run("Missing dashboard should be deleted if DisableDeletion = false", func(t *testing.T) {
setupFakeService()
reader, err := NewDashboardFileReader(cfg, logger, nil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
err = reader.walkDisk(context.Background())
require.NoError(t, err)
So(len(fakeService.provisioned["Default"]), ShouldEqual, 1)
So(fakeService.provisioned["Default"][0].ExternalId, ShouldEqual, absPath1)
So(len(fakeService.inserted), ShouldEqual, 1)
So(fakeService.inserted[0].Dashboard.Id, ShouldEqual, 1)
})
require.Equal(t, len(fakeService.provisioned["Default"]), 1)
require.Equal(t, fakeService.provisioned["Default"][0].ExternalId, absPath1)
require.Equal(t, len(fakeService.inserted), 1)
require.Equal(t, fakeService.inserted[0].Dashboard.Id, int64(1))
})
})
}

View File

@ -9,7 +9,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
var (
@ -29,7 +29,7 @@ var (
)
func TestDatasourceAsConfig(t *testing.T) {
Convey("Testing datasource as configuration", t, func() {
setup := func() {
fakeRepo = &fakeRepository{}
bus.ClearBusHandlers()
bus.AddHandler("test", mockDelete)
@ -37,226 +37,229 @@ func TestDatasourceAsConfig(t *testing.T) {
bus.AddHandler("test", mockUpdate)
bus.AddHandler("test", mockGet)
bus.AddHandler("test", mockGetOrg)
}
Convey("apply default values when missing", func() {
t.Run("apply default values when missing", func(t *testing.T) {
setup()
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), withoutDefaults)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
require.Equal(t, len(fakeRepo.inserted), 1)
require.Equal(t, fakeRepo.inserted[0].OrgId, int64(1))
require.Equal(t, fakeRepo.inserted[0].Access, models.DsAccess("proxy"))
})
t.Run("no datasource in database", func(t *testing.T) {
setup()
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
require.Equal(t, len(fakeRepo.deleted), 0)
require.Equal(t, len(fakeRepo.inserted), 2)
require.Equal(t, len(fakeRepo.updated), 0)
})
t.Run("One datasource in database with same name", func(t *testing.T) {
setup()
fakeRepo.loadAll = []*models.DataSource{
{Name: "Graphite", OrgId: 1, Id: 1},
}
t.Run("should update one datasource", func(t *testing.T) {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), withoutDefaults)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
So(len(fakeRepo.inserted), ShouldEqual, 1)
So(fakeRepo.inserted[0].OrgId, ShouldEqual, 1)
So(fakeRepo.inserted[0].Access, ShouldEqual, "proxy")
require.Equal(t, len(fakeRepo.deleted), 0)
require.Equal(t, len(fakeRepo.inserted), 1)
require.Equal(t, len(fakeRepo.updated), 1)
})
})
Convey("One configured datasource", func() {
Convey("no datasource in database", func() {
t.Run("Two datasources with is_default", func(t *testing.T) {
setup()
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), doubleDatasourcesConfig)
t.Run("should raise error", func(t *testing.T) { require.Equal(t, err, ErrInvalidConfigToManyDefault) })
})
t.Run("Multiple datasources in different organizations with isDefault in each organization", func(t *testing.T) {
setup()
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), multipleOrgsWithDefault)
t.Run("should not raise error", func(t *testing.T) {
require.NoError(t, err)
require.Equal(t, len(fakeRepo.inserted), 4)
require.True(t, fakeRepo.inserted[0].IsDefault)
require.Equal(t, fakeRepo.inserted[0].OrgId, int64(1))
require.True(t, fakeRepo.inserted[2].IsDefault)
require.Equal(t, fakeRepo.inserted[2].OrgId, int64(2))
})
})
t.Run("Two configured datasource and purge others ", func(t *testing.T) {
setup()
t.Run("two other datasources in database", func(t *testing.T) {
fakeRepo.loadAll = []*models.DataSource{
{Name: "old-graphite", OrgId: 1, Id: 1},
{Name: "old-graphite2", OrgId: 1, Id: 2},
}
t.Run("should have two new datasources", func(t *testing.T) {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfigPurgeOthers)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
require.Equal(t, len(fakeRepo.deleted), 2)
require.Equal(t, len(fakeRepo.inserted), 2)
require.Equal(t, len(fakeRepo.updated), 0)
})
})
})
t.Run("Two configured datasource and purge others = false", func(t *testing.T) {
setup()
t.Run("two other datasources in database", func(t *testing.T) {
fakeRepo.loadAll = []*models.DataSource{
{Name: "Graphite", OrgId: 1, Id: 1},
{Name: "old-graphite2", OrgId: 1, Id: 2},
}
t.Run("should have two new datasources", func(t *testing.T) {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
So(len(fakeRepo.deleted), ShouldEqual, 0)
So(len(fakeRepo.inserted), ShouldEqual, 2)
So(len(fakeRepo.updated), ShouldEqual, 0)
})
Convey("One datasource in database with same name", func() {
fakeRepo.loadAll = []*models.DataSource{
{Name: "Graphite", OrgId: 1, Id: 1},
}
Convey("should update one datasource", func() {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
So(len(fakeRepo.deleted), ShouldEqual, 0)
So(len(fakeRepo.inserted), ShouldEqual, 1)
So(len(fakeRepo.updated), ShouldEqual, 1)
})
})
Convey("Two datasources with is_default", func() {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), doubleDatasourcesConfig)
Convey("should raise error", func() {
So(err, ShouldEqual, ErrInvalidConfigToManyDefault)
})
require.Equal(t, len(fakeRepo.deleted), 0)
require.Equal(t, len(fakeRepo.inserted), 1)
require.Equal(t, len(fakeRepo.updated), 1)
})
})
})
Convey("Multiple datasources in different organizations with isDefault in each organization", func() {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), multipleOrgsWithDefault)
Convey("should not raise error", func() {
So(err, ShouldBeNil)
So(len(fakeRepo.inserted), ShouldEqual, 4)
So(fakeRepo.inserted[0].IsDefault, ShouldBeTrue)
So(fakeRepo.inserted[0].OrgId, ShouldEqual, 1)
So(fakeRepo.inserted[2].IsDefault, ShouldBeTrue)
So(fakeRepo.inserted[2].OrgId, ShouldEqual, 2)
})
})
t.Run("broken yaml should return error", func(t *testing.T) {
reader := &configReader{}
_, err := reader.readConfig(brokenYaml)
require.NotNil(t, err)
})
Convey("Two configured datasource and purge others ", func() {
Convey("two other datasources in database", func() {
fakeRepo.loadAll = []*models.DataSource{
{Name: "old-graphite", OrgId: 1, Id: 1},
{Name: "old-graphite2", OrgId: 1, Id: 2},
}
t.Run("invalid access should warn about invalid value and return 'proxy'", func(t *testing.T) {
reader := &configReader{log: logger}
configs, err := reader.readConfig(invalidAccess)
require.NoError(t, err)
require.Equal(t, configs[0].Datasources[0].Access, models.DS_ACCESS_PROXY)
})
Convey("should have two new datasources", func() {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfigPurgeOthers)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
t.Run("skip invalid directory", func(t *testing.T) {
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig("./invalid-directory")
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(fakeRepo.deleted), ShouldEqual, 2)
So(len(fakeRepo.inserted), ShouldEqual, 2)
So(len(fakeRepo.updated), ShouldEqual, 0)
})
})
})
require.Equal(t, len(cfg), 0)
})
Convey("Two configured datasource and purge others = false", func() {
Convey("two other datasources in database", func() {
fakeRepo.loadAll = []*models.DataSource{
{Name: "Graphite", OrgId: 1, Id: 1},
{Name: "old-graphite2", OrgId: 1, Id: 2},
}
t.Run("can read all properties from version 1", func(t *testing.T) {
_ = os.Setenv("TEST_VAR", "name")
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig(allProperties)
_ = os.Unsetenv("TEST_VAR")
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
Convey("should have two new datasources", func() {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
require.Equal(t, len(cfg), 3)
So(len(fakeRepo.deleted), ShouldEqual, 0)
So(len(fakeRepo.inserted), ShouldEqual, 1)
So(len(fakeRepo.updated), ShouldEqual, 1)
})
})
})
dsCfg := cfg[0]
Convey("broken yaml should return error", func() {
reader := &configReader{}
_, err := reader.readConfig(brokenYaml)
So(err, ShouldNotBeNil)
})
require.Equal(t, dsCfg.APIVersion, int64(1))
Convey("invalid access should warn about invalid value and return 'proxy'", func() {
reader := &configReader{log: logger}
configs, err := reader.readConfig(invalidAccess)
So(err, ShouldBeNil)
So(configs[0].Datasources[0].Access, ShouldEqual, models.DS_ACCESS_PROXY)
})
validateDatasourceV1(t, dsCfg)
validateDeleteDatasources(t, dsCfg)
Convey("skip invalid directory", func() {
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig("./invalid-directory")
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
dsCount := 0
delDsCount := 0
So(len(cfg), ShouldEqual, 0)
})
for _, c := range cfg {
dsCount += len(c.Datasources)
delDsCount += len(c.DeleteDatasources)
}
Convey("can read all properties from version 1", func() {
_ = os.Setenv("TEST_VAR", "name")
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig(allProperties)
_ = os.Unsetenv("TEST_VAR")
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
require.Equal(t, dsCount, 2)
require.Equal(t, delDsCount, 1)
})
So(len(cfg), ShouldEqual, 3)
t.Run("can read all properties from version 0", func(t *testing.T) {
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig(versionZero)
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
dsCfg := cfg[0]
require.Equal(t, len(cfg), 1)
So(dsCfg.APIVersion, ShouldEqual, 1)
dsCfg := cfg[0]
validateDatasourceV1(dsCfg)
validateDeleteDatasources(dsCfg)
require.Equal(t, dsCfg.APIVersion, int64(0))
dsCount := 0
delDsCount := 0
for _, c := range cfg {
dsCount += len(c.Datasources)
delDsCount += len(c.DeleteDatasources)
}
So(dsCount, ShouldEqual, 2)
So(delDsCount, ShouldEqual, 1)
})
Convey("can read all properties from version 0", func() {
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig(versionZero)
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 1)
dsCfg := cfg[0]
So(dsCfg.APIVersion, ShouldEqual, 0)
validateDatasource(dsCfg)
validateDeleteDatasources(dsCfg)
})
validateDatasource(t, dsCfg)
validateDeleteDatasources(t, dsCfg)
})
}
func validateDeleteDatasources(dsCfg *configs) {
So(len(dsCfg.DeleteDatasources), ShouldEqual, 1)
func validateDeleteDatasources(t *testing.T, dsCfg *configs) {
require.Equal(t, len(dsCfg.DeleteDatasources), 1)
deleteDs := dsCfg.DeleteDatasources[0]
So(deleteDs.Name, ShouldEqual, "old-graphite3")
So(deleteDs.OrgID, ShouldEqual, 2)
require.Equal(t, deleteDs.Name, "old-graphite3")
require.Equal(t, deleteDs.OrgID, int64(2))
}
func validateDatasource(dsCfg *configs) {
func validateDatasource(t *testing.T, dsCfg *configs) {
ds := dsCfg.Datasources[0]
So(ds.Name, ShouldEqual, "name")
So(ds.Type, ShouldEqual, "type")
So(ds.Access, ShouldEqual, models.DS_ACCESS_PROXY)
So(ds.OrgID, ShouldEqual, 2)
So(ds.URL, ShouldEqual, "url")
So(ds.User, ShouldEqual, "user")
So(ds.Password, ShouldEqual, "password")
So(ds.Database, ShouldEqual, "database")
So(ds.BasicAuth, ShouldBeTrue)
So(ds.BasicAuthUser, ShouldEqual, "basic_auth_user")
So(ds.BasicAuthPassword, ShouldEqual, "basic_auth_password")
So(ds.WithCredentials, ShouldBeTrue)
So(ds.IsDefault, ShouldBeTrue)
So(ds.Editable, ShouldBeTrue)
So(ds.Version, ShouldEqual, 10)
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.Password, "password")
require.Equal(t, ds.Database, "database")
require.True(t, ds.BasicAuth)
require.Equal(t, ds.BasicAuthUser, "basic_auth_user")
require.Equal(t, ds.BasicAuthPassword, "basic_auth_password")
require.True(t, ds.WithCredentials)
require.True(t, ds.IsDefault)
require.True(t, ds.Editable)
require.Equal(t, ds.Version, 10)
So(len(ds.JSONData), ShouldBeGreaterThan, 2)
So(ds.JSONData["graphiteVersion"], ShouldEqual, "1.1")
So(ds.JSONData["tlsAuth"], ShouldEqual, true)
So(ds.JSONData["tlsAuthWithCACert"], ShouldEqual, true)
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)
So(len(ds.SecureJSONData), ShouldBeGreaterThan, 2)
So(ds.SecureJSONData["tlsCACert"], ShouldEqual, "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==")
So(ds.SecureJSONData["tlsClientCert"], ShouldEqual, "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==")
So(ds.SecureJSONData["tlsClientKey"], ShouldEqual, "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==")
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==")
}
func validateDatasourceV1(dsCfg *configs) {
validateDatasource(dsCfg)
func validateDatasourceV1(t *testing.T, dsCfg *configs) {
validateDatasource(t, dsCfg)
ds := dsCfg.Datasources[0]
So(ds.UID, ShouldEqual, "test_uid")
require.Equal(t, ds.UID, "test_uid")
}
type fakeRepository struct {

View File

@ -12,7 +12,8 @@ import (
"github.com/grafana/grafana/pkg/services/alerting/notifiers"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/sqlstore"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
var (
@ -29,31 +30,35 @@ var (
)
func TestNotificationAsConfig(t *testing.T) {
var sqlStore *sqlstore.SQLStore
logger := log.New("fake.log")
Convey("Testing notification as configuration", t, func() {
sqlStore := sqlstore.InitTestDB(t)
setupBusHandlers(sqlStore)
t.Run("Testing notification as configuration", func(t *testing.T) {
setup := func() {
sqlStore = sqlstore.InitTestDB(t)
setupBusHandlers(sqlStore)
for i := 1; i < 5; i++ {
orgCommand := models.CreateOrgCommand{Name: fmt.Sprintf("Main Org. %v", i)}
err := sqlstore.CreateOrg(&orgCommand)
So(err, ShouldBeNil)
for i := 1; i < 5; i++ {
orgCommand := models.CreateOrgCommand{Name: fmt.Sprintf("Main Org. %v", i)}
err := sqlstore.CreateOrg(&orgCommand)
require.NoError(t, err)
}
alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: "slack",
Name: "slack",
Factory: notifiers.NewSlackNotifier,
})
alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: "email",
Name: "email",
Factory: notifiers.NewEmailNotifier,
})
}
alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: "slack",
Name: "slack",
Factory: notifiers.NewSlackNotifier,
})
alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: "email",
Name: "email",
Factory: notifiers.NewEmailNotifier,
})
Convey("Can read correct properties", func() {
t.Run("Can read correct properties", func(t *testing.T) {
setup()
_ = os.Setenv("TEST_VAR", "default")
cfgProvider := &configReader{
encryptionService: ossencryption.ProvideService(),
@ -65,73 +70,74 @@ func TestNotificationAsConfig(t *testing.T) {
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 1)
require.Equal(t, len(cfg), 1)
ntCfg := cfg[0]
nts := ntCfg.Notifications
So(len(nts), ShouldEqual, 4)
require.Equal(t, len(nts), 4)
nt := nts[0]
So(nt.Name, ShouldEqual, "default-slack-notification")
So(nt.Type, ShouldEqual, "slack")
So(nt.OrgID, ShouldEqual, 2)
So(nt.UID, ShouldEqual, "notifier1")
So(nt.IsDefault, ShouldBeTrue)
So(nt.Settings, ShouldResemble, map[string]interface{}{
require.Equal(t, nt.Name, "default-slack-notification")
require.Equal(t, nt.Type, "slack")
require.Equal(t, nt.OrgID, int64(2))
require.Equal(t, nt.UID, "notifier1")
require.True(t, nt.IsDefault)
require.Equal(t, nt.Settings, map[string]interface{}{
"recipient": "XXX", "token": "xoxb", "uploadImage": true, "url": "https://slack.com",
})
So(nt.SecureSettings, ShouldResemble, map[string]string{
require.Equal(t, nt.SecureSettings, map[string]string{
"token": "xoxbsecure", "url": "https://slack.com/secure",
})
So(nt.SendReminder, ShouldBeTrue)
So(nt.Frequency, ShouldEqual, "1h")
require.True(t, nt.SendReminder)
require.Equal(t, nt.Frequency, "1h")
nt = nts[1]
So(nt.Name, ShouldEqual, "another-not-default-notification")
So(nt.Type, ShouldEqual, "email")
So(nt.OrgID, ShouldEqual, 3)
So(nt.UID, ShouldEqual, "notifier2")
So(nt.IsDefault, ShouldBeFalse)
require.Equal(t, nt.Name, "another-not-default-notification")
require.Equal(t, nt.Type, "email")
require.Equal(t, nt.OrgID, int64(3))
require.Equal(t, nt.UID, "notifier2")
require.False(t, nt.IsDefault)
nt = nts[2]
So(nt.Name, ShouldEqual, "check-unset-is_default-is-false")
So(nt.Type, ShouldEqual, "slack")
So(nt.OrgID, ShouldEqual, 3)
So(nt.UID, ShouldEqual, "notifier3")
So(nt.IsDefault, ShouldBeFalse)
require.Equal(t, nt.Name, "check-unset-is_default-is-false")
require.Equal(t, nt.Type, "slack")
require.Equal(t, nt.OrgID, int64(3))
require.Equal(t, nt.UID, "notifier3")
require.False(t, nt.IsDefault)
nt = nts[3]
So(nt.Name, ShouldEqual, "Added notification with whitespaces in name")
So(nt.Type, ShouldEqual, "email")
So(nt.UID, ShouldEqual, "notifier4")
So(nt.OrgID, ShouldEqual, 3)
require.Equal(t, nt.Name, "Added notification with whitespaces in name")
require.Equal(t, nt.Type, "email")
require.Equal(t, nt.UID, "notifier4")
require.Equal(t, nt.OrgID, int64(3))
deleteNts := ntCfg.DeleteNotifications
So(len(deleteNts), ShouldEqual, 4)
require.Equal(t, len(deleteNts), 4)
deleteNt := deleteNts[0]
So(deleteNt.Name, ShouldEqual, "default-slack-notification")
So(deleteNt.UID, ShouldEqual, "notifier1")
So(deleteNt.OrgID, ShouldEqual, 2)
require.Equal(t, deleteNt.Name, "default-slack-notification")
require.Equal(t, deleteNt.UID, "notifier1")
require.Equal(t, deleteNt.OrgID, int64(2))
deleteNt = deleteNts[1]
So(deleteNt.Name, ShouldEqual, "deleted-notification-without-orgId")
So(deleteNt.OrgID, ShouldEqual, 1)
So(deleteNt.UID, ShouldEqual, "notifier2")
require.Equal(t, deleteNt.Name, "deleted-notification-without-orgId")
require.Equal(t, deleteNt.OrgID, int64(1))
require.Equal(t, deleteNt.UID, "notifier2")
deleteNt = deleteNts[2]
So(deleteNt.Name, ShouldEqual, "deleted-notification-with-0-orgId")
So(deleteNt.OrgID, ShouldEqual, 1)
So(deleteNt.UID, ShouldEqual, "notifier3")
require.Equal(t, deleteNt.Name, "deleted-notification-with-0-orgId")
require.Equal(t, deleteNt.OrgID, int64(1))
require.Equal(t, deleteNt.UID, "notifier3")
deleteNt = deleteNts[3]
So(deleteNt.Name, ShouldEqual, "Deleted notification with whitespaces in name")
So(deleteNt.OrgID, ShouldEqual, 1)
So(deleteNt.UID, ShouldEqual, "notifier4")
require.Equal(t, deleteNt.Name, "Deleted notification with whitespaces in name")
require.Equal(t, deleteNt.OrgID, int64(1))
require.Equal(t, deleteNt.UID, "notifier4")
})
Convey("One configured notification", func() {
Convey("no notification in database", func() {
t.Run("One configured notification", func(t *testing.T) {
t.Run("no notification in database", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(twoNotificationsConfig)
@ -140,12 +146,13 @@ func TestNotificationAsConfig(t *testing.T) {
}
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 2)
})
Convey("One notification in database with same name and uid", func() {
t.Run("One notification in database with same name and uid", func(t *testing.T) {
setup()
existingNotificationCmd := models.CreateAlertNotificationCommand{
Name: "channel1",
OrgId: 1,
@ -153,56 +160,58 @@ func TestNotificationAsConfig(t *testing.T) {
Type: "slack",
}
err := sqlStore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
So(existingNotificationCmd.Result, ShouldNotBeNil)
require.NoError(t, err)
require.NotNil(t, existingNotificationCmd.Result)
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 1)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 1)
Convey("should update one notification", func() {
t.Run("should update one notification", func(t *testing.T) {
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err = dc.applyChanges(twoNotificationsConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 2)
nts := notificationsQuery.Result
nt1 := nts[0]
So(nt1.Type, ShouldEqual, "email")
So(nt1.Name, ShouldEqual, "channel1")
So(nt1.Uid, ShouldEqual, "notifier1")
require.Equal(t, nt1.Type, "email")
require.Equal(t, nt1.Name, "channel1")
require.Equal(t, nt1.Uid, "notifier1")
nt2 := nts[1]
So(nt2.Type, ShouldEqual, "slack")
So(nt2.Name, ShouldEqual, "channel2")
So(nt2.Uid, ShouldEqual, "notifier2")
require.Equal(t, nt2.Type, "slack")
require.Equal(t, nt2.Name, "channel2")
require.Equal(t, nt2.Uid, "notifier2")
})
})
Convey("Two notifications with is_default", func() {
t.Run("Two notifications with is_default", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(doubleNotificationsConfig)
Convey("should both be inserted", func() {
So(err, ShouldBeNil)
t.Run("should both be inserted", func(t *testing.T) {
require.NoError(t, err)
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 2)
So(notificationsQuery.Result[0].IsDefault, ShouldBeTrue)
So(notificationsQuery.Result[1].IsDefault, ShouldBeTrue)
require.True(t, notificationsQuery.Result[0].IsDefault)
require.True(t, notificationsQuery.Result[1].IsDefault)
})
})
})
Convey("Two configured notification", func() {
Convey("two other notifications in database", func() {
t.Run("Two configured notification", func(t *testing.T) {
t.Run("two other notifications in database", func(t *testing.T) {
setup()
existingNotificationCmd := models.CreateAlertNotificationCommand{
Name: "channel0",
OrgId: 1,
@ -210,7 +219,7 @@ func TestNotificationAsConfig(t *testing.T) {
Type: "slack",
}
err := sqlStore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
require.NoError(t, err)
existingNotificationCmd = models.CreateAlertNotificationCommand{
Name: "channel3",
OrgId: 1,
@ -218,15 +227,15 @@ func TestNotificationAsConfig(t *testing.T) {
Type: "slack",
}
err = sqlStore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
require.NoError(t, err)
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 2)
Convey("should have two new notifications", func() {
t.Run("should have two new notifications", func(t *testing.T) {
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(twoNotificationsConfig)
if err != nil {
@ -234,22 +243,23 @@ func TestNotificationAsConfig(t *testing.T) {
}
notificationsQuery = models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 4)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 4)
})
})
})
Convey("Can read correct properties with orgName instead of orgId", func() {
t.Run("Can read correct properties with orgName instead of orgId", func(t *testing.T) {
setup()
existingOrg1 := models.GetOrgByNameQuery{Name: "Main Org. 1"}
err := sqlstore.GetOrgByName(&existingOrg1)
So(err, ShouldBeNil)
So(existingOrg1.Result, ShouldNotBeNil)
require.NoError(t, err)
require.NotNil(t, existingOrg1.Result)
existingOrg2 := models.GetOrgByNameQuery{Name: "Main Org. 2"}
err = sqlstore.GetOrgByName(&existingOrg2)
So(err, ShouldBeNil)
So(existingOrg2.Result, ShouldNotBeNil)
require.NoError(t, err)
require.NotNil(t, existingOrg2.Result)
existingNotificationCmd := models.CreateAlertNotificationCommand{
Name: "default-notification-delete",
@ -258,7 +268,7 @@ func TestNotificationAsConfig(t *testing.T) {
Type: "slack",
}
err = sqlStore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
require.NoError(t, err)
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err = dc.applyChanges(correctPropertiesWithOrgName)
@ -268,29 +278,31 @@ func TestNotificationAsConfig(t *testing.T) {
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: existingOrg2.Result.Id}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 1)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 1)
nt := notificationsQuery.Result[0]
So(nt.Name, ShouldEqual, "default-notification-create")
So(nt.OrgId, ShouldEqual, existingOrg2.Result.Id)
require.Equal(t, nt.Name, "default-notification-create")
require.Equal(t, nt.OrgId, existingOrg2.Result.Id)
})
Convey("Config doesn't contain required field", func() {
t.Run("Config doesn't contain required field", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(noRequiredFields)
So(err, ShouldNotBeNil)
require.NotNil(t, err)
errString := err.Error()
So(errString, ShouldContainSubstring, "Deleted alert notification item 1 in configuration doesn't contain required field uid")
So(errString, ShouldContainSubstring, "Deleted alert notification item 2 in configuration doesn't contain required field name")
So(errString, ShouldContainSubstring, "Added alert notification item 1 in configuration doesn't contain required field name")
So(errString, ShouldContainSubstring, "Added alert notification item 2 in configuration doesn't contain required field uid")
require.Contains(t, errString, "Deleted alert notification item 1 in configuration doesn't contain required field uid")
require.Contains(t, errString, "Deleted alert notification item 2 in configuration doesn't contain required field name")
require.Contains(t, errString, "Added alert notification item 1 in configuration doesn't contain required field name")
require.Contains(t, errString, "Added alert notification item 2 in configuration doesn't contain required field uid")
})
Convey("Empty yaml file", func() {
Convey("should have not changed repo", func() {
t.Run("Empty yaml file", func(t *testing.T) {
t.Run("should have not changed repo", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(emptyFile)
if err != nil {
@ -298,22 +310,22 @@ func TestNotificationAsConfig(t *testing.T) {
}
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldBeEmpty)
require.NoError(t, err)
require.Empty(t, notificationsQuery.Result)
})
})
Convey("Broken yaml should return error", func() {
t.Run("Broken yaml should return error", func(t *testing.T) {
reader := &configReader{
encryptionService: ossencryption.ProvideService(),
log: log.New("test logger"),
}
_, err := reader.readConfig(brokenYaml)
So(err, ShouldNotBeNil)
require.NotNil(t, err)
})
Convey("Skip invalid directory", func() {
t.Run("Skip invalid directory", func(t *testing.T) {
cfgProvider := &configReader{
encryptionService: ossencryption.ProvideService(),
log: log.New("test logger"),
@ -323,27 +335,27 @@ func TestNotificationAsConfig(t *testing.T) {
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 0)
require.Equal(t, len(cfg), 0)
})
Convey("Unknown notifier should return error", func() {
t.Run("Unknown notifier should return error", func(t *testing.T) {
cfgProvider := &configReader{
encryptionService: ossencryption.ProvideService(),
log: log.New("test logger"),
}
_, err := cfgProvider.readConfig(unknownNotifier)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, `unsupported notification type "nonexisting"`)
require.NotNil(t, err)
require.Equal(t, err.Error(), `unsupported notification type "nonexisting"`)
})
Convey("Read incorrect properties", func() {
t.Run("Read incorrect properties", func(t *testing.T) {
cfgProvider := &configReader{
encryptionService: ossencryption.ProvideService(),
log: log.New("test logger"),
}
_, err := cfgProvider.readConfig(incorrectSettings)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, "alert validation error: token must be specified when using the Slack chat API")
require.NotNil(t, err)
require.Equal(t, err.Error(), "alert validation error: token must be specified when using the Slack chat API")
})
})
}

View File

@ -5,25 +5,26 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
func TestCheckOrgExists(t *testing.T) {
Convey("with default org in database", t, func() {
t.Run("with default org in database", func(t *testing.T) {
sqlstore.InitTestDB(t)
defaultOrg := models.CreateOrgCommand{Name: "Main Org."}
err := sqlstore.CreateOrg(&defaultOrg)
So(err, ShouldBeNil)
require.NoError(t, err)
Convey("default org exists", func() {
t.Run("default org exists", func(t *testing.T) {
err := CheckOrgExists(defaultOrg.Result.Id)
So(err, ShouldBeNil)
require.NoError(t, err)
})
Convey("other org doesn't exist", func() {
t.Run("other org doesn't exist", func(t *testing.T) {
err := CheckOrgExists(defaultOrg.Result.Id + 1)
So(err, ShouldEqual, models.ErrOrgNotFound)
require.Equal(t, err, models.ErrOrgNotFound)
})
})
}

View File

@ -8,132 +8,140 @@ import (
"testing"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/ini.v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/ini.v1"
"gopkg.in/yaml.v2"
)
func TestValues(t *testing.T) {
Convey("Values", t, func() {
t.Run("Values", func(t *testing.T) {
err := os.Setenv("INT", "1")
So(err, ShouldBeNil)
require.NoError(t, err)
err = os.Setenv("STRING", "test")
So(err, ShouldBeNil)
require.NoError(t, err)
err = os.Setenv("EMPTYSTRING", "")
So(err, ShouldBeNil)
require.NoError(t, err)
err = os.Setenv("BOOL", "true")
So(err, ShouldBeNil)
require.NoError(t, err)
Convey("IntValue", func() {
defer func() {
err := os.Unsetenv("INT")
require.NoError(t, err)
err = os.Unsetenv("STRING")
require.NoError(t, err)
err = os.Unsetenv("EMPTYSTRING")
require.NoError(t, err)
err = os.Unsetenv("BOOL")
require.NoError(t, err)
}()
t.Run("IntValue", func(t *testing.T) {
type Data struct {
Val IntValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal simple number", func() {
unmarshalingTest(`val: 1`, d)
So(d.Val.Value(), ShouldEqual, 1)
So(d.Val.Raw, ShouldEqual, "1")
t.Run("Should unmarshal simple number", func(t *testing.T) {
unmarshalingTest(t, `val: 1`, d)
require.Equal(t, d.Val.Value(), 1)
require.Equal(t, d.Val.Raw, "1")
})
Convey("Should unmarshal env var", func() {
unmarshalingTest(`val: $INT`, d)
So(d.Val.Value(), ShouldEqual, 1)
So(d.Val.Raw, ShouldEqual, "$INT")
t.Run("Should unmarshal env var", func(t *testing.T) {
unmarshalingTest(t, `val: $INT`, d)
require.Equal(t, d.Val.Value(), 1)
require.Equal(t, d.Val.Raw, "$INT")
})
Convey("Should ignore empty value", func() {
unmarshalingTest(`val: `, d)
So(d.Val.Value(), ShouldEqual, 0)
So(d.Val.Raw, ShouldEqual, "")
t.Run("Should ignore empty value", func(t *testing.T) {
unmarshalingTest(t, `val: `, d)
require.Equal(t, d.Val.Value(), 0)
require.Equal(t, d.Val.Raw, "")
})
})
Convey("StringValue", func() {
t.Run("StringValue", func(t *testing.T) {
type Data struct {
Val StringValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal simple string", func() {
unmarshalingTest(`val: test`, d)
So(d.Val.Value(), ShouldEqual, "test")
So(d.Val.Raw, ShouldEqual, "test")
t.Run("Should unmarshal simple string", func(t *testing.T) {
unmarshalingTest(t, `val: test`, d)
require.Equal(t, d.Val.Value(), "test")
require.Equal(t, d.Val.Raw, "test")
})
Convey("Should unmarshal env var", func() {
unmarshalingTest(`val: $STRING`, d)
So(d.Val.Value(), ShouldEqual, "test")
So(d.Val.Raw, ShouldEqual, "$STRING")
t.Run("Should unmarshal env var", func(t *testing.T) {
unmarshalingTest(t, `val: $STRING`, d)
require.Equal(t, d.Val.Value(), "test")
require.Equal(t, d.Val.Raw, "$STRING")
})
Convey("Should ignore empty value", func() {
unmarshalingTest(`val: `, d)
So(d.Val.Value(), ShouldEqual, "")
So(d.Val.Raw, ShouldEqual, "")
t.Run("Should ignore empty value", func(t *testing.T) {
unmarshalingTest(t, `val: `, d)
require.Equal(t, d.Val.Value(), "")
require.Equal(t, d.Val.Raw, "")
})
Convey("empty var should have empty value", func() {
unmarshalingTest(`val: $EMPTYSTRING`, d)
So(d.Val.Value(), ShouldEqual, "")
So(d.Val.Raw, ShouldEqual, "$EMPTYSTRING")
t.Run("empty var should have empty value", func(t *testing.T) {
unmarshalingTest(t, `val: $EMPTYSTRING`, d)
require.Equal(t, d.Val.Value(), "")
require.Equal(t, d.Val.Raw, "$EMPTYSTRING")
})
Convey("$$ should be a literal $", func() {
unmarshalingTest(`val: $$`, d)
So(d.Val.Value(), ShouldEqual, "$")
So(d.Val.Raw, ShouldEqual, "$$")
t.Run("$$ should be a literal $", func(t *testing.T) {
unmarshalingTest(t, `val: $$`, d)
require.Equal(t, d.Val.Value(), "$")
require.Equal(t, d.Val.Raw, "$$")
})
Convey("$$ should be a literal $ and not expanded within a string", func() {
unmarshalingTest(`val: mY,Passwo$$rd`, d)
So(d.Val.Value(), ShouldEqual, "mY,Passwo$rd")
So(d.Val.Raw, ShouldEqual, "mY,Passwo$$rd")
t.Run("$$ should be a literal $ and not expanded within a string", func(t *testing.T) {
unmarshalingTest(t, `val: mY,Passwo$$rd`, d)
require.Equal(t, d.Val.Value(), "mY,Passwo$rd")
require.Equal(t, d.Val.Raw, "mY,Passwo$$rd")
})
})
Convey("BoolValue", func() {
t.Run("BoolValue", func(t *testing.T) {
type Data struct {
Val BoolValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal bool value", func() {
unmarshalingTest(`val: true`, d)
So(d.Val.Value(), ShouldBeTrue)
So(d.Val.Raw, ShouldEqual, "true")
t.Run("Should unmarshal bool value", func(t *testing.T) {
unmarshalingTest(t, `val: true`, d)
require.True(t, d.Val.Value())
require.Equal(t, d.Val.Raw, "true")
})
Convey("Should unmarshal explicit string", func() {
unmarshalingTest(`val: "true"`, d)
So(d.Val.Value(), ShouldBeTrue)
So(d.Val.Raw, ShouldEqual, "true")
t.Run("Should unmarshal explicit string", func(t *testing.T) {
unmarshalingTest(t, `val: "true"`, d)
require.True(t, d.Val.Value())
require.Equal(t, d.Val.Raw, "true")
})
Convey("Should unmarshal env var", func() {
unmarshalingTest(`val: $BOOL`, d)
So(d.Val.Value(), ShouldBeTrue)
So(d.Val.Raw, ShouldEqual, "$BOOL")
t.Run("Should unmarshal env var", func(t *testing.T) {
unmarshalingTest(t, `val: $BOOL`, d)
require.True(t, d.Val.Value())
require.Equal(t, d.Val.Raw, "$BOOL")
})
Convey("Should ignore empty value", func() {
unmarshalingTest(`val: `, d)
So(d.Val.Value(), ShouldBeFalse)
So(d.Val.Raw, ShouldEqual, "")
t.Run("Should ignore empty value", func(t *testing.T) {
unmarshalingTest(t, `val: `, d)
require.False(t, d.Val.Value())
require.Equal(t, d.Val.Raw, "")
})
})
Convey("JSONValue", func() {
t.Run("JSONValue", func(t *testing.T) {
type Data struct {
Val JSONValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal variable nesting", func() {
t.Run("Should unmarshal variable nesting", func(t *testing.T) {
doc := `
val:
one: 1
@ -153,10 +161,10 @@ func TestValues(t *testing.T) {
anchor: &label $INT
anchored: *label
`
unmarshalingTest(doc, d)
unmarshalingTest(t, doc, d)
type stringMap = map[string]interface{}
So(d.Val.Value(), ShouldResemble, stringMap{
require.Equal(t, d.Val.Value(), stringMap{
"one": 1,
"two": "test",
"three": []interface{}{
@ -183,7 +191,7 @@ func TestValues(t *testing.T) {
"anchored": "1",
})
So(d.Val.Raw, ShouldResemble, stringMap{
require.Equal(t, d.Val.Raw, stringMap{
"one": 1,
"two": "$STRING",
"three": []interface{}{
@ -212,13 +220,13 @@ func TestValues(t *testing.T) {
})
})
Convey("StringMapValue", func() {
t.Run("StringMapValue", func(t *testing.T) {
type Data struct {
Val StringMapValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal mapping", func() {
t.Run("Should unmarshal mapping", func(t *testing.T) {
doc := `
val:
one: 1
@ -226,15 +234,15 @@ func TestValues(t *testing.T) {
three: $STRING
four: true
`
unmarshalingTest(doc, d)
So(d.Val.Value(), ShouldResemble, map[string]string{
unmarshalingTest(t, doc, d)
require.Equal(t, d.Val.Value(), map[string]string{
"one": "1",
"two": "test string",
"three": "test",
"four": "true",
})
So(d.Val.Raw, ShouldResemble, map[string]string{
require.Equal(t, d.Val.Raw, map[string]string{
"one": "1",
"two": "test string",
"three": "$STRING",
@ -242,23 +250,12 @@ func TestValues(t *testing.T) {
})
})
})
Reset(func() {
err := os.Unsetenv("INT")
So(err, ShouldBeNil)
err = os.Unsetenv("STRING")
So(err, ShouldBeNil)
err = os.Unsetenv("EMPTYSTRING")
So(err, ShouldBeNil)
err = os.Unsetenv("BOOL")
So(err, ShouldBeNil)
})
})
}
func unmarshalingTest(document string, out interface{}) {
func unmarshalingTest(t *testing.T, document string, out interface{}) {
err := yaml.Unmarshal([]byte(document), out)
So(err, ShouldBeNil)
require.NoError(t, err)
}
func TestValues_readFile(t *testing.T) {