config_reader_test.go 7.8 KB

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