metrics_test.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. package metrics
  2. import (
  3. "bytes"
  4. "io/ioutil"
  5. "runtime"
  6. "sync"
  7. "testing"
  8. "time"
  9. "net/http"
  10. "net/http/httptest"
  11. "github.com/grafana/grafana/pkg/bus"
  12. "github.com/grafana/grafana/pkg/components/simplejson"
  13. "github.com/grafana/grafana/pkg/models"
  14. "github.com/grafana/grafana/pkg/plugins"
  15. "github.com/grafana/grafana/pkg/setting"
  16. . "github.com/smartystreets/goconvey/convey"
  17. )
  18. func TestMetrics(t *testing.T) {
  19. Convey("Test send usage stats", t, func() {
  20. var getSystemStatsQuery *models.GetSystemStatsQuery
  21. bus.AddHandler("test", func(query *models.GetSystemStatsQuery) error {
  22. query.Result = &models.SystemStats{
  23. Dashboards: 1,
  24. Datasources: 2,
  25. Users: 3,
  26. ActiveUsers: 4,
  27. Orgs: 5,
  28. Playlists: 6,
  29. Alerts: 7,
  30. Stars: 8,
  31. Folders: 9,
  32. DashboardPermissions: 10,
  33. FolderPermissions: 11,
  34. ProvisionedDashboards: 12,
  35. Snapshots: 13,
  36. Teams: 14,
  37. }
  38. getSystemStatsQuery = query
  39. return nil
  40. })
  41. var getDataSourceStatsQuery *models.GetDataSourceStatsQuery
  42. bus.AddHandler("test", func(query *models.GetDataSourceStatsQuery) error {
  43. query.Result = []*models.DataSourceStats{
  44. {
  45. Type: models.DS_ES,
  46. Count: 9,
  47. },
  48. {
  49. Type: models.DS_PROMETHEUS,
  50. Count: 10,
  51. },
  52. {
  53. Type: "unknown_ds",
  54. Count: 11,
  55. },
  56. {
  57. Type: "unknown_ds2",
  58. Count: 12,
  59. },
  60. }
  61. getDataSourceStatsQuery = query
  62. return nil
  63. })
  64. var getDataSourceAccessStatsQuery *models.GetDataSourceAccessStatsQuery
  65. bus.AddHandler("test", func(query *models.GetDataSourceAccessStatsQuery) error {
  66. query.Result = []*models.DataSourceAccessStats{
  67. {
  68. Type: models.DS_ES,
  69. Access: "direct",
  70. Count: 1,
  71. },
  72. {
  73. Type: models.DS_ES,
  74. Access: "proxy",
  75. Count: 2,
  76. },
  77. {
  78. Type: models.DS_PROMETHEUS,
  79. Access: "proxy",
  80. Count: 3,
  81. },
  82. {
  83. Type: "unknown_ds",
  84. Access: "proxy",
  85. Count: 4,
  86. },
  87. {
  88. Type: "unknown_ds2",
  89. Access: "",
  90. Count: 5,
  91. },
  92. {
  93. Type: "unknown_ds3",
  94. Access: "direct",
  95. Count: 6,
  96. },
  97. {
  98. Type: "unknown_ds4",
  99. Access: "direct",
  100. Count: 7,
  101. },
  102. {
  103. Type: "unknown_ds5",
  104. Access: "proxy",
  105. Count: 8,
  106. },
  107. }
  108. getDataSourceAccessStatsQuery = query
  109. return nil
  110. })
  111. var getAlertNotifierUsageStatsQuery *models.GetAlertNotifierUsageStatsQuery
  112. bus.AddHandler("test", func(query *models.GetAlertNotifierUsageStatsQuery) error {
  113. query.Result = []*models.NotifierUsageStats{
  114. {
  115. Type: "slack",
  116. Count: 1,
  117. },
  118. {
  119. Type: "webhook",
  120. Count: 2,
  121. },
  122. }
  123. getAlertNotifierUsageStatsQuery = query
  124. return nil
  125. })
  126. var wg sync.WaitGroup
  127. var responseBuffer *bytes.Buffer
  128. var req *http.Request
  129. ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  130. req = r
  131. buf, err := ioutil.ReadAll(r.Body)
  132. if err != nil {
  133. t.Fatalf("Failed to read response body, err=%v", err)
  134. }
  135. responseBuffer = bytes.NewBuffer(buf)
  136. wg.Done()
  137. }))
  138. usageStatsURL = ts.URL
  139. oauthProviders := map[string]bool{
  140. "github": true,
  141. "gitlab": true,
  142. "google": true,
  143. "generic_oauth": true,
  144. "grafana_com": true,
  145. }
  146. sendUsageStats(oauthProviders)
  147. Convey("Given reporting not enabled and sending usage stats", func() {
  148. setting.ReportingEnabled = false
  149. sendUsageStats(oauthProviders)
  150. Convey("Should not gather stats or call http endpoint", func() {
  151. So(getSystemStatsQuery, ShouldBeNil)
  152. So(getDataSourceStatsQuery, ShouldBeNil)
  153. So(getDataSourceAccessStatsQuery, ShouldBeNil)
  154. So(req, ShouldBeNil)
  155. })
  156. })
  157. Convey("Given reporting enabled and sending usage stats", func() {
  158. setting.ReportingEnabled = true
  159. setting.BuildVersion = "5.0.0"
  160. setting.AnonymousEnabled = true
  161. setting.BasicAuthEnabled = true
  162. setting.LdapEnabled = true
  163. setting.AuthProxyEnabled = true
  164. wg.Add(1)
  165. sendUsageStats(oauthProviders)
  166. Convey("Should gather stats and call http endpoint", func() {
  167. if waitTimeout(&wg, 2*time.Second) {
  168. t.Fatalf("Timed out waiting for http request")
  169. }
  170. So(getSystemStatsQuery, ShouldNotBeNil)
  171. So(getDataSourceStatsQuery, ShouldNotBeNil)
  172. So(getDataSourceAccessStatsQuery, ShouldNotBeNil)
  173. So(getAlertNotifierUsageStatsQuery, ShouldNotBeNil)
  174. So(req, ShouldNotBeNil)
  175. So(req.Method, ShouldEqual, http.MethodPost)
  176. So(req.Header.Get("Content-Type"), ShouldEqual, "application/json")
  177. So(responseBuffer, ShouldNotBeNil)
  178. j, err := simplejson.NewFromReader(responseBuffer)
  179. So(err, ShouldBeNil)
  180. So(j.Get("version").MustString(), ShouldEqual, "5_0_0")
  181. So(j.Get("os").MustString(), ShouldEqual, runtime.GOOS)
  182. So(j.Get("arch").MustString(), ShouldEqual, runtime.GOARCH)
  183. metrics := j.Get("metrics")
  184. So(metrics.Get("stats.dashboards.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Dashboards)
  185. So(metrics.Get("stats.users.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Users)
  186. So(metrics.Get("stats.orgs.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Orgs)
  187. So(metrics.Get("stats.playlist.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Playlists)
  188. So(metrics.Get("stats.plugins.apps.count").MustInt(), ShouldEqual, len(plugins.Apps))
  189. So(metrics.Get("stats.plugins.panels.count").MustInt(), ShouldEqual, len(plugins.Panels))
  190. So(metrics.Get("stats.plugins.datasources.count").MustInt(), ShouldEqual, len(plugins.DataSources))
  191. So(metrics.Get("stats.alerts.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Alerts)
  192. So(metrics.Get("stats.active_users.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.ActiveUsers)
  193. So(metrics.Get("stats.datasources.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Datasources)
  194. So(metrics.Get("stats.stars.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Stars)
  195. So(metrics.Get("stats.folders.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Folders)
  196. So(metrics.Get("stats.dashboard_permissions.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.DashboardPermissions)
  197. So(metrics.Get("stats.folder_permissions.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.FolderPermissions)
  198. So(metrics.Get("stats.provisioned_dashboards.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.ProvisionedDashboards)
  199. So(metrics.Get("stats.snapshots.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Snapshots)
  200. So(metrics.Get("stats.teams.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Teams)
  201. So(metrics.Get("stats.ds."+models.DS_ES+".count").MustInt(), ShouldEqual, 9)
  202. So(metrics.Get("stats.ds."+models.DS_PROMETHEUS+".count").MustInt(), ShouldEqual, 10)
  203. So(metrics.Get("stats.ds.other.count").MustInt(), ShouldEqual, 11+12)
  204. So(metrics.Get("stats.ds_access."+models.DS_ES+".direct.count").MustInt(), ShouldEqual, 1)
  205. So(metrics.Get("stats.ds_access."+models.DS_ES+".proxy.count").MustInt(), ShouldEqual, 2)
  206. So(metrics.Get("stats.ds_access."+models.DS_PROMETHEUS+".proxy.count").MustInt(), ShouldEqual, 3)
  207. So(metrics.Get("stats.ds_access.other.direct.count").MustInt(), ShouldEqual, 6+7)
  208. So(metrics.Get("stats.ds_access.other.proxy.count").MustInt(), ShouldEqual, 4+8)
  209. So(metrics.Get("stats.alert_notifiers.slack.count").MustInt(), ShouldEqual, 1)
  210. So(metrics.Get("stats.alert_notifiers.webhook.count").MustInt(), ShouldEqual, 2)
  211. So(metrics.Get("stats.auth_enabled.anonymous.count").MustInt(), ShouldEqual, 1)
  212. So(metrics.Get("stats.auth_enabled.basic_auth.count").MustInt(), ShouldEqual, 1)
  213. So(metrics.Get("stats.auth_enabled.ldap.count").MustInt(), ShouldEqual, 1)
  214. So(metrics.Get("stats.auth_enabled.auth_proxy.count").MustInt(), ShouldEqual, 1)
  215. So(metrics.Get("stats.auth_enabled.oauth_github.count").MustInt(), ShouldEqual, 1)
  216. So(metrics.Get("stats.auth_enabled.oauth_gitlab.count").MustInt(), ShouldEqual, 1)
  217. So(metrics.Get("stats.auth_enabled.oauth_google.count").MustInt(), ShouldEqual, 1)
  218. So(metrics.Get("stats.auth_enabled.oauth_generic_oauth.count").MustInt(), ShouldEqual, 1)
  219. So(metrics.Get("stats.auth_enabled.oauth_grafana_com.count").MustInt(), ShouldEqual, 1)
  220. })
  221. })
  222. Reset(func() {
  223. ts.Close()
  224. })
  225. })
  226. }
  227. func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
  228. c := make(chan struct{})
  229. go func() {
  230. defer close(c)
  231. wg.Wait()
  232. }()
  233. select {
  234. case <-c:
  235. return false // completed normally
  236. case <-time.After(timeout):
  237. return true // timed out
  238. }
  239. }