setting_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package setting
  2. import (
  3. "bufio"
  4. "os"
  5. "path"
  6. "path/filepath"
  7. "runtime"
  8. "strings"
  9. "testing"
  10. "gopkg.in/ini.v1"
  11. . "github.com/smartystreets/goconvey/convey"
  12. )
  13. const (
  14. windows = "windows"
  15. )
  16. func TestLoadingSettings(t *testing.T) {
  17. Convey("Testing loading settings from ini file", t, func() {
  18. skipStaticRootValidation = true
  19. Convey("Given the default ini files", func() {
  20. cfg := NewCfg()
  21. err := cfg.Load(&CommandLineArgs{HomePath: "../../"})
  22. So(err, ShouldBeNil)
  23. So(AdminUser, ShouldEqual, "admin")
  24. So(cfg.RendererCallbackUrl, ShouldEqual, "http://localhost:3000/")
  25. })
  26. Convey("default.ini should have no semi-colon commented entries", func() {
  27. file, err := os.Open("../../conf/defaults.ini")
  28. if err != nil {
  29. t.Errorf("failed to load defaults.ini file: %v", err)
  30. }
  31. defer file.Close()
  32. scanner := bufio.NewScanner(file)
  33. for scanner.Scan() {
  34. // This only catches values commented out with ";" and will not catch those that are commented out with "#".
  35. if strings.HasPrefix(scanner.Text(), ";") {
  36. t.Errorf("entries in defaults.ini must not be commented or environment variables will not work: %v", scanner.Text())
  37. }
  38. }
  39. })
  40. Convey("Should be able to override via environment variables", func() {
  41. os.Setenv("GF_SECURITY_ADMIN_USER", "superduper")
  42. cfg := NewCfg()
  43. cfg.Load(&CommandLineArgs{HomePath: "../../"})
  44. So(AdminUser, ShouldEqual, "superduper")
  45. So(cfg.DataPath, ShouldEqual, filepath.Join(HomePath, "data"))
  46. So(cfg.LogsPath, ShouldEqual, filepath.Join(cfg.DataPath, "log"))
  47. })
  48. Convey("Should replace password when defined in environment", func() {
  49. os.Setenv("GF_SECURITY_ADMIN_PASSWORD", "supersecret")
  50. cfg := NewCfg()
  51. cfg.Load(&CommandLineArgs{HomePath: "../../"})
  52. So(appliedEnvOverrides, ShouldContain, "GF_SECURITY_ADMIN_PASSWORD=*********")
  53. })
  54. Convey("Should return an error when url is invalid", func() {
  55. os.Setenv("GF_DATABASE_URL", "postgres.%31://grafana:secret@postgres:5432/grafana")
  56. cfg := NewCfg()
  57. err := cfg.Load(&CommandLineArgs{HomePath: "../../"})
  58. So(err, ShouldNotBeNil)
  59. })
  60. Convey("Should replace password in URL when url environment is defined", func() {
  61. os.Setenv("GF_DATABASE_URL", "mysql://user:secret@localhost:3306/database")
  62. cfg := NewCfg()
  63. cfg.Load(&CommandLineArgs{HomePath: "../../"})
  64. So(appliedEnvOverrides, ShouldContain, "GF_DATABASE_URL=mysql://user:-redacted-@localhost:3306/database")
  65. })
  66. Convey("Should get property map from command line args array", func() {
  67. props := getCommandLineProperties([]string{"cfg:test=value", "cfg:map.test=1"})
  68. So(len(props), ShouldEqual, 2)
  69. So(props["test"], ShouldEqual, "value")
  70. So(props["map.test"], ShouldEqual, "1")
  71. })
  72. Convey("Should be able to override via command line", func() {
  73. if runtime.GOOS == windows {
  74. cfg := NewCfg()
  75. cfg.Load(&CommandLineArgs{
  76. HomePath: "../../",
  77. Args: []string{`cfg:paths.data=c:\tmp\data`, `cfg:paths.logs=c:\tmp\logs`},
  78. })
  79. So(cfg.DataPath, ShouldEqual, `c:\tmp\data`)
  80. So(cfg.LogsPath, ShouldEqual, `c:\tmp\logs`)
  81. } else {
  82. cfg := NewCfg()
  83. cfg.Load(&CommandLineArgs{
  84. HomePath: "../../",
  85. Args: []string{"cfg:paths.data=/tmp/data", "cfg:paths.logs=/tmp/logs"},
  86. })
  87. So(cfg.DataPath, ShouldEqual, "/tmp/data")
  88. So(cfg.LogsPath, ShouldEqual, "/tmp/logs")
  89. }
  90. })
  91. Convey("Should be able to override defaults via command line", func() {
  92. cfg := NewCfg()
  93. cfg.Load(&CommandLineArgs{
  94. HomePath: "../../",
  95. Args: []string{
  96. "cfg:default.server.domain=test2",
  97. },
  98. Config: filepath.Join(HomePath, "pkg/setting/testdata/override.ini"),
  99. })
  100. So(Domain, ShouldEqual, "test2")
  101. })
  102. Convey("Defaults can be overridden in specified config file", func() {
  103. if runtime.GOOS == windows {
  104. cfg := NewCfg()
  105. cfg.Load(&CommandLineArgs{
  106. HomePath: "../../",
  107. Config: filepath.Join(HomePath, "pkg/setting/testdata/override_windows.ini"),
  108. Args: []string{`cfg:default.paths.data=c:\tmp\data`},
  109. })
  110. So(cfg.DataPath, ShouldEqual, `c:\tmp\override`)
  111. } else {
  112. cfg := NewCfg()
  113. cfg.Load(&CommandLineArgs{
  114. HomePath: "../../",
  115. Config: filepath.Join(HomePath, "pkg/setting/testdata/override.ini"),
  116. Args: []string{"cfg:default.paths.data=/tmp/data"},
  117. })
  118. So(cfg.DataPath, ShouldEqual, "/tmp/override")
  119. }
  120. })
  121. Convey("Command line overrides specified config file", func() {
  122. if runtime.GOOS == windows {
  123. cfg := NewCfg()
  124. cfg.Load(&CommandLineArgs{
  125. HomePath: "../../",
  126. Config: filepath.Join(HomePath, "pkg/setting/testdata/override_windows.ini"),
  127. Args: []string{`cfg:paths.data=c:\tmp\data`},
  128. })
  129. So(cfg.DataPath, ShouldEqual, `c:\tmp\data`)
  130. } else {
  131. cfg := NewCfg()
  132. cfg.Load(&CommandLineArgs{
  133. HomePath: "../../",
  134. Config: filepath.Join(HomePath, "pkg/setting/testdata/override.ini"),
  135. Args: []string{"cfg:paths.data=/tmp/data"},
  136. })
  137. So(cfg.DataPath, ShouldEqual, "/tmp/data")
  138. }
  139. })
  140. Convey("Can use environment variables in config values", func() {
  141. if runtime.GOOS == windows {
  142. os.Setenv("GF_DATA_PATH", `c:\tmp\env_override`)
  143. cfg := NewCfg()
  144. cfg.Load(&CommandLineArgs{
  145. HomePath: "../../",
  146. Args: []string{"cfg:paths.data=${GF_DATA_PATH}"},
  147. })
  148. So(cfg.DataPath, ShouldEqual, `c:\tmp\env_override`)
  149. } else {
  150. os.Setenv("GF_DATA_PATH", "/tmp/env_override")
  151. cfg := NewCfg()
  152. cfg.Load(&CommandLineArgs{
  153. HomePath: "../../",
  154. Args: []string{"cfg:paths.data=${GF_DATA_PATH}"},
  155. })
  156. So(cfg.DataPath, ShouldEqual, "/tmp/env_override")
  157. }
  158. })
  159. Convey("instance_name default to hostname even if hostname env is empty", func() {
  160. cfg := NewCfg()
  161. cfg.Load(&CommandLineArgs{
  162. HomePath: "../../",
  163. })
  164. hostname, _ := os.Hostname()
  165. So(InstanceName, ShouldEqual, hostname)
  166. })
  167. Convey("Reading callback_url should add trailing slash", func() {
  168. cfg := NewCfg()
  169. cfg.Load(&CommandLineArgs{
  170. HomePath: "../../",
  171. Args: []string{"cfg:rendering.callback_url=http://myserver/renderer"},
  172. })
  173. So(cfg.RendererCallbackUrl, ShouldEqual, "http://myserver/renderer/")
  174. })
  175. })
  176. Convey("Test reading string values from .ini file", t, func() {
  177. iniFile, err := ini.Load(path.Join(HomePath, "pkg/setting/testdata/invalid.ini"))
  178. So(err, ShouldBeNil)
  179. Convey("If key is found - should return value from ini file", func() {
  180. value, err := valueAsString(iniFile.Section("server"), "alt_url", "")
  181. So(err, ShouldBeNil)
  182. So(value, ShouldEqual, "https://grafana.com/")
  183. })
  184. Convey("If key is not found - should return default value", func() {
  185. value, err := valueAsString(iniFile.Section("server"), "extra_url", "default_url_val")
  186. So(err, ShouldBeNil)
  187. So(value, ShouldEqual, "default_url_val")
  188. })
  189. Convey("In case of panic - should return user-friendly error", func() {
  190. value, err := valueAsString(iniFile.Section("server"), "root_url", "")
  191. So(err.Error(), ShouldEqual, "Invalid value for key 'root_url' in configuration file")
  192. So(value, ShouldEqual, "")
  193. })
  194. })
  195. }