ops_metrics_collector_projection_test.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package service
  2. import (
  3. "context"
  4. "testing"
  5. "github.com/stretchr/testify/require"
  6. )
  7. type opsMetricsProjectionRepo struct {
  8. AccountRepository
  9. accounts []Account
  10. accountLoads []AccountWithConcurrency
  11. listCalls int
  12. projectionCalls int
  13. }
  14. func (r *opsMetricsProjectionRepo) ListSchedulable(context.Context) ([]Account, error) {
  15. r.listCalls++
  16. return r.accounts, nil
  17. }
  18. func (r *opsMetricsProjectionRepo) ListSchedulableAccountLoads(context.Context) ([]AccountWithConcurrency, error) {
  19. r.projectionCalls++
  20. return r.accountLoads, nil
  21. }
  22. type opsMetricsFallbackRepo struct {
  23. AccountRepository
  24. accounts []Account
  25. listCalls int
  26. }
  27. func (r *opsMetricsFallbackRepo) ListSchedulable(context.Context) ([]Account, error) {
  28. r.listCalls++
  29. return r.accounts, nil
  30. }
  31. type opsMetricsLoadCache struct {
  32. ConcurrencyCache
  33. loads map[int64]*AccountLoadInfo
  34. got []AccountWithConcurrency
  35. }
  36. func (c *opsMetricsLoadCache) GetAccountsLoadBatch(_ context.Context, accounts []AccountWithConcurrency) (map[int64]*AccountLoadInfo, error) {
  37. c.got = accounts
  38. return c.loads, nil
  39. }
  40. func TestCollectConcurrencyQueueDepthUsesProjectionAndPreservesFallbackResult(t *testing.T) {
  41. loadFactor := 7
  42. accounts := []Account{
  43. {ID: 11, Concurrency: 2, LoadFactor: &loadFactor},
  44. {ID: 12, Concurrency: 3},
  45. {ID: 13},
  46. }
  47. accountLoads := []AccountWithConcurrency{
  48. {ID: 11, MaxConcurrency: 7},
  49. {ID: 12, MaxConcurrency: 3},
  50. {ID: 13, MaxConcurrency: 1},
  51. }
  52. loads := map[int64]*AccountLoadInfo{
  53. 11: {AccountID: 11, WaitingCount: 2},
  54. 12: {AccountID: 12, WaitingCount: 3},
  55. 13: {AccountID: 13, WaitingCount: 0},
  56. }
  57. projectionRepo := &opsMetricsProjectionRepo{accounts: accounts, accountLoads: accountLoads}
  58. projectionCache := &opsMetricsLoadCache{loads: loads}
  59. projectionConcurrency := NewConcurrencyService(projectionCache)
  60. projectionConcurrency.SetAccountLoadBatchCacheTTL(0)
  61. projectionCollector := &OpsMetricsCollector{
  62. accountRepo: projectionRepo,
  63. concurrencyService: projectionConcurrency,
  64. }
  65. fallbackRepo := &opsMetricsFallbackRepo{accounts: accounts}
  66. fallbackCache := &opsMetricsLoadCache{loads: loads}
  67. fallbackConcurrency := NewConcurrencyService(fallbackCache)
  68. fallbackConcurrency.SetAccountLoadBatchCacheTTL(0)
  69. fallbackCollector := &OpsMetricsCollector{
  70. accountRepo: fallbackRepo,
  71. concurrencyService: fallbackConcurrency,
  72. }
  73. projectionDepth := projectionCollector.collectConcurrencyQueueDepth(context.Background())
  74. fallbackDepth := fallbackCollector.collectConcurrencyQueueDepth(context.Background())
  75. require.NotNil(t, projectionDepth)
  76. require.NotNil(t, fallbackDepth)
  77. require.Equal(t, 5, *projectionDepth)
  78. require.Equal(t, *fallbackDepth, *projectionDepth)
  79. require.Equal(t, 1, projectionRepo.projectionCalls)
  80. require.Zero(t, projectionRepo.listCalls)
  81. require.Equal(t, 1, fallbackRepo.listCalls)
  82. require.Equal(t, accountLoads, projectionCache.got)
  83. require.Equal(t, fallbackCache.got, projectionCache.got)
  84. }
  85. func BenchmarkOpsMetricsCollectorCollectConcurrencyQueueDepth(b *testing.B) {
  86. const accountCount = 1000
  87. loadFactor := 8
  88. accounts := make([]Account, accountCount)
  89. accountLoads := make([]AccountWithConcurrency, accountCount)
  90. for i := range accountCount {
  91. id := int64(i + 1)
  92. accounts[i] = Account{
  93. ID: id,
  94. Concurrency: 4,
  95. LoadFactor: &loadFactor,
  96. }
  97. accountLoads[i] = AccountWithConcurrency{ID: id, MaxConcurrency: loadFactor}
  98. }
  99. repo := &opsMetricsProjectionRepo{accounts: accounts, accountLoads: accountLoads}
  100. cache := &opsMetricsLoadCache{loads: map[int64]*AccountLoadInfo{}}
  101. concurrency := NewConcurrencyService(cache)
  102. concurrency.SetAccountLoadBatchCacheTTL(0)
  103. collector := &OpsMetricsCollector{accountRepo: repo, concurrencyService: concurrency}
  104. b.ReportAllocs()
  105. b.ResetTimer()
  106. for range b.N {
  107. if depth := collector.collectConcurrencyQueueDepth(context.Background()); depth == nil || *depth != 0 {
  108. b.Fatalf("unexpected queue depth: %v", depth)
  109. }
  110. }
  111. }