config_reader_test.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. package datasources
  2. import (
  3. "os"
  4. "testing"
  5. "github.com/grafana/grafana/pkg/bus"
  6. "github.com/grafana/grafana/pkg/infra/log"
  7. "github.com/grafana/grafana/pkg/models"
  8. . "github.com/smartystreets/goconvey/convey"
  9. )
  10. var (
  11. logger log.Logger = log.New("fake.log")
  12. twoDatasourcesConfig = "testdata/two-datasources"
  13. twoDatasourcesConfigPurgeOthers = "testdata/insert-two-delete-two"
  14. doubleDatasourcesConfig = "testdata/double-default"
  15. allProperties = "testdata/all-properties"
  16. versionZero = "testdata/version-0"
  17. brokenYaml = "testdata/broken-yaml"
  18. multipleOrgsWithDefault = "testdata/multiple-org-default"
  19. fakeRepo *fakeRepository
  20. )
  21. func TestDatasourceAsConfig(t *testing.T) {
  22. Convey("Testing datasource as configuration", t, func() {
  23. fakeRepo = &fakeRepository{}
  24. bus.ClearBusHandlers()
  25. bus.AddHandler("test", mockDelete)
  26. bus.AddHandler("test", mockInsert)
  27. bus.AddHandler("test", mockUpdate)
  28. bus.AddHandler("test", mockGet)
  29. bus.AddHandler("test", mockGetAll)
  30. Convey("One configured datasource", func() {
  31. Convey("no datasource in database", func() {
  32. dc := newDatasourceProvisioner(logger)
  33. err := dc.applyChanges(twoDatasourcesConfig)
  34. if err != nil {
  35. t.Fatalf("applyChanges return an error %v", err)
  36. }
  37. So(len(fakeRepo.deleted), ShouldEqual, 0)
  38. So(len(fakeRepo.inserted), ShouldEqual, 2)
  39. So(len(fakeRepo.updated), ShouldEqual, 0)
  40. })
  41. Convey("One datasource in database with same name", func() {
  42. fakeRepo.loadAll = []*models.DataSource{
  43. {Name: "Graphite", OrgId: 1, Id: 1},
  44. }
  45. Convey("should update one datasource", func() {
  46. dc := newDatasourceProvisioner(logger)
  47. err := dc.applyChanges(twoDatasourcesConfig)
  48. if err != nil {
  49. t.Fatalf("applyChanges return an error %v", err)
  50. }
  51. So(len(fakeRepo.deleted), ShouldEqual, 0)
  52. So(len(fakeRepo.inserted), ShouldEqual, 1)
  53. So(len(fakeRepo.updated), ShouldEqual, 1)
  54. })
  55. })
  56. Convey("Two datasources with is_default", func() {
  57. dc := newDatasourceProvisioner(logger)
  58. err := dc.applyChanges(doubleDatasourcesConfig)
  59. Convey("should raise error", func() {
  60. So(err, ShouldEqual, ErrInvalidConfigToManyDefault)
  61. })
  62. })
  63. })
  64. Convey("Multiple datasources in different organizations with isDefault in each organization", func() {
  65. dc := newDatasourceProvisioner(logger)
  66. err := dc.applyChanges(multipleOrgsWithDefault)
  67. Convey("should not raise error", func() {
  68. So(err, ShouldBeNil)
  69. So(len(fakeRepo.inserted), ShouldEqual, 4)
  70. So(fakeRepo.inserted[0].IsDefault, ShouldBeTrue)
  71. So(fakeRepo.inserted[0].OrgId, ShouldEqual, 1)
  72. So(fakeRepo.inserted[2].IsDefault, ShouldBeTrue)
  73. So(fakeRepo.inserted[2].OrgId, ShouldEqual, 2)
  74. })
  75. })
  76. Convey("Two configured datasource and purge others ", func() {
  77. Convey("two other datasources in database", func() {
  78. fakeRepo.loadAll = []*models.DataSource{
  79. {Name: "old-graphite", OrgId: 1, Id: 1},
  80. {Name: "old-graphite2", OrgId: 1, Id: 2},
  81. }
  82. Convey("should have two new datasources", func() {
  83. dc := newDatasourceProvisioner(logger)
  84. err := dc.applyChanges(twoDatasourcesConfigPurgeOthers)
  85. if err != nil {
  86. t.Fatalf("applyChanges return an error %v", err)
  87. }
  88. So(len(fakeRepo.deleted), ShouldEqual, 2)
  89. So(len(fakeRepo.inserted), ShouldEqual, 2)
  90. So(len(fakeRepo.updated), ShouldEqual, 0)
  91. })
  92. })
  93. })
  94. Convey("Two configured datasource and purge others = false", func() {
  95. Convey("two other datasources in database", func() {
  96. fakeRepo.loadAll = []*models.DataSource{
  97. {Name: "Graphite", OrgId: 1, Id: 1},
  98. {Name: "old-graphite2", OrgId: 1, Id: 2},
  99. }
  100. Convey("should have two new datasources", func() {
  101. dc := newDatasourceProvisioner(logger)
  102. err := dc.applyChanges(twoDatasourcesConfig)
  103. if err != nil {
  104. t.Fatalf("applyChanges return an error %v", err)
  105. }
  106. So(len(fakeRepo.deleted), ShouldEqual, 0)
  107. So(len(fakeRepo.inserted), ShouldEqual, 1)
  108. So(len(fakeRepo.updated), ShouldEqual, 1)
  109. })
  110. })
  111. })
  112. Convey("broken yaml should return error", func() {
  113. reader := &configReader{}
  114. _, err := reader.readConfig(brokenYaml)
  115. So(err, ShouldNotBeNil)
  116. })
  117. Convey("skip invalid directory", func() {
  118. cfgProvifer := &configReader{log: log.New("test logger")}
  119. cfg, err := cfgProvifer.readConfig("./invalid-directory")
  120. if err != nil {
  121. t.Fatalf("readConfig return an error %v", err)
  122. }
  123. So(len(cfg), ShouldEqual, 0)
  124. })
  125. Convey("can read all properties from version 1", func() {
  126. _ = os.Setenv("TEST_VAR", "name")
  127. cfgProvifer := &configReader{log: log.New("test logger")}
  128. cfg, err := cfgProvifer.readConfig(allProperties)
  129. _ = os.Unsetenv("TEST_VAR")
  130. if err != nil {
  131. t.Fatalf("readConfig return an error %v", err)
  132. }
  133. So(len(cfg), ShouldEqual, 3)
  134. dsCfg := cfg[0]
  135. So(dsCfg.ApiVersion, ShouldEqual, 1)
  136. validateDatasource(dsCfg)
  137. validateDeleteDatasources(dsCfg)
  138. dsCount := 0
  139. delDsCount := 0
  140. for _, c := range cfg {
  141. dsCount += len(c.Datasources)
  142. delDsCount += len(c.DeleteDatasources)
  143. }
  144. So(dsCount, ShouldEqual, 2)
  145. So(delDsCount, ShouldEqual, 1)
  146. })
  147. Convey("can read all properties from version 0", func() {
  148. cfgProvifer := &configReader{log: log.New("test logger")}
  149. cfg, err := cfgProvifer.readConfig(versionZero)
  150. if err != nil {
  151. t.Fatalf("readConfig return an error %v", err)
  152. }
  153. So(len(cfg), ShouldEqual, 1)
  154. dsCfg := cfg[0]
  155. So(dsCfg.ApiVersion, ShouldEqual, 0)
  156. validateDatasource(dsCfg)
  157. validateDeleteDatasources(dsCfg)
  158. })
  159. })
  160. }
  161. func validateDeleteDatasources(dsCfg *DatasourcesAsConfig) {
  162. So(len(dsCfg.DeleteDatasources), ShouldEqual, 1)
  163. deleteDs := dsCfg.DeleteDatasources[0]
  164. So(deleteDs.Name, ShouldEqual, "old-graphite3")
  165. So(deleteDs.OrgId, ShouldEqual, 2)
  166. }
  167. func validateDatasource(dsCfg *DatasourcesAsConfig) {
  168. ds := dsCfg.Datasources[0]
  169. So(ds.Name, ShouldEqual, "name")
  170. So(ds.Type, ShouldEqual, "type")
  171. So(ds.Access, ShouldEqual, models.DS_ACCESS_PROXY)
  172. So(ds.OrgId, ShouldEqual, 2)
  173. So(ds.Url, ShouldEqual, "url")
  174. So(ds.User, ShouldEqual, "user")
  175. So(ds.Password, ShouldEqual, "password")
  176. So(ds.Database, ShouldEqual, "database")
  177. So(ds.BasicAuth, ShouldBeTrue)
  178. So(ds.BasicAuthUser, ShouldEqual, "basic_auth_user")
  179. So(ds.BasicAuthPassword, ShouldEqual, "basic_auth_password")
  180. So(ds.WithCredentials, ShouldBeTrue)
  181. So(ds.IsDefault, ShouldBeTrue)
  182. So(ds.Editable, ShouldBeTrue)
  183. So(ds.Version, ShouldEqual, 10)
  184. So(len(ds.JsonData), ShouldBeGreaterThan, 2)
  185. So(ds.JsonData["graphiteVersion"], ShouldEqual, "1.1")
  186. So(ds.JsonData["tlsAuth"], ShouldEqual, true)
  187. So(ds.JsonData["tlsAuthWithCACert"], ShouldEqual, true)
  188. So(len(ds.SecureJsonData), ShouldBeGreaterThan, 2)
  189. So(ds.SecureJsonData["tlsCACert"], ShouldEqual, "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==")
  190. So(ds.SecureJsonData["tlsClientCert"], ShouldEqual, "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==")
  191. So(ds.SecureJsonData["tlsClientKey"], ShouldEqual, "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==")
  192. }
  193. type fakeRepository struct {
  194. inserted []*models.AddDataSourceCommand
  195. deleted []*models.DeleteDataSourceByNameCommand
  196. updated []*models.UpdateDataSourceCommand
  197. loadAll []*models.DataSource
  198. }
  199. func mockDelete(cmd *models.DeleteDataSourceByNameCommand) error {
  200. fakeRepo.deleted = append(fakeRepo.deleted, cmd)
  201. return nil
  202. }
  203. func mockUpdate(cmd *models.UpdateDataSourceCommand) error {
  204. fakeRepo.updated = append(fakeRepo.updated, cmd)
  205. return nil
  206. }
  207. func mockInsert(cmd *models.AddDataSourceCommand) error {
  208. fakeRepo.inserted = append(fakeRepo.inserted, cmd)
  209. return nil
  210. }
  211. func mockGetAll(cmd *models.GetAllDataSourcesQuery) error {
  212. cmd.Result = fakeRepo.loadAll
  213. return nil
  214. }
  215. func mockGet(cmd *models.GetDataSourceByNameQuery) error {
  216. for _, v := range fakeRepo.loadAll {
  217. if cmd.Name == v.Name && cmd.OrgId == v.OrgId {
  218. cmd.Result = v
  219. return nil
  220. }
  221. }
  222. return models.ErrDataSourceNotFound
  223. }