usage_stats_test.go 9.0 KB

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