account_repo_schedulable_projection_integration_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. //go:build integration
  2. package repository
  3. import (
  4. "context"
  5. "testing"
  6. "time"
  7. "github.com/Wei-Shaw/sub2api/internal/service"
  8. "github.com/stretchr/testify/require"
  9. )
  10. func TestListSchedulableAccountLoadsMatchesListSchedulable(t *testing.T) {
  11. ctx := context.Background()
  12. tx := testEntTx(t)
  13. client := tx.Client()
  14. repo := newAccountRepositoryWithSQL(client, tx, nil)
  15. now := time.Now()
  16. past := now.Add(-time.Hour)
  17. future := now.Add(time.Hour)
  18. create := func(name string) *service.Account {
  19. return mustCreateAccount(t, client, &service.Account{Name: name, Schedulable: true})
  20. }
  21. positiveLoad := create("projection-positive-load")
  22. _, err := client.Account.UpdateOneID(positiveLoad.ID).SetConcurrency(2).SetLoadFactor(9).SetPriority(30).Save(ctx)
  23. require.NoError(t, err)
  24. concurrencyFallback := create("projection-concurrency-fallback")
  25. _, err = client.Account.UpdateOneID(concurrencyFallback.ID).SetConcurrency(4).SetPriority(10).Save(ctx)
  26. require.NoError(t, err)
  27. zeroFallback := create("projection-zero-fallback")
  28. _, err = client.Account.UpdateOneID(zeroFallback.ID).SetConcurrency(0).SetLoadFactor(0).SetPriority(20).Save(ctx)
  29. require.NoError(t, err)
  30. disabled := create("projection-disabled")
  31. _, err = client.Account.UpdateOneID(disabled.ID).SetStatus(service.StatusDisabled).Save(ctx)
  32. require.NoError(t, err)
  33. unschedulable := create("projection-unschedulable")
  34. _, err = client.Account.UpdateOneID(unschedulable.ID).SetSchedulable(false).Save(ctx)
  35. require.NoError(t, err)
  36. expired := create("projection-expired")
  37. _, err = client.Account.UpdateOneID(expired.ID).SetExpiresAt(past).SetAutoPauseOnExpired(true).Save(ctx)
  38. require.NoError(t, err)
  39. expiredAllowed := create("projection-expired-allowed")
  40. _, err = client.Account.UpdateOneID(expiredAllowed.ID).SetExpiresAt(past).SetAutoPauseOnExpired(false).Save(ctx)
  41. require.NoError(t, err)
  42. overloaded := create("projection-overloaded")
  43. _, err = client.Account.UpdateOneID(overloaded.ID).SetOverloadUntil(future).Save(ctx)
  44. require.NoError(t, err)
  45. overloadCleared := create("projection-overload-cleared")
  46. _, err = client.Account.UpdateOneID(overloadCleared.ID).SetOverloadUntil(past).Save(ctx)
  47. require.NoError(t, err)
  48. rateLimited := create("projection-rate-limited")
  49. _, err = client.Account.UpdateOneID(rateLimited.ID).SetRateLimitResetAt(future).Save(ctx)
  50. require.NoError(t, err)
  51. rateLimitCleared := create("projection-rate-limit-cleared")
  52. _, err = client.Account.UpdateOneID(rateLimitCleared.ID).SetRateLimitResetAt(past).Save(ctx)
  53. require.NoError(t, err)
  54. tempBlocked := create("projection-temp-blocked")
  55. _, err = client.Account.UpdateOneID(tempBlocked.ID).SetTempUnschedulableUntil(future).Save(ctx)
  56. require.NoError(t, err)
  57. tempCleared := create("projection-temp-cleared")
  58. _, err = client.Account.UpdateOneID(tempCleared.ID).SetTempUnschedulableUntil(past).Save(ctx)
  59. require.NoError(t, err)
  60. accounts, err := repo.ListSchedulable(ctx)
  61. require.NoError(t, err)
  62. loads, err := repo.ListSchedulableAccountLoads(ctx)
  63. require.NoError(t, err)
  64. accountIDs := make([]int64, 0, len(accounts))
  65. wantByID := make(map[int64]int, len(accounts))
  66. for i := range accounts {
  67. accountIDs = append(accountIDs, accounts[i].ID)
  68. wantByID[accounts[i].ID] = accounts[i].EffectiveLoadFactor()
  69. }
  70. loadIDs := make([]int64, 0, len(loads))
  71. byID := make(map[int64]int, len(loads))
  72. for _, load := range loads {
  73. loadIDs = append(loadIDs, load.ID)
  74. byID[load.ID] = load.MaxConcurrency
  75. }
  76. require.Equal(t, accountIDs, loadIDs)
  77. targetIDs := map[int64]struct{}{
  78. positiveLoad.ID: {}, concurrencyFallback.ID: {}, zeroFallback.ID: {},
  79. }
  80. targetOrder := make([]int64, 0, len(targetIDs))
  81. for _, id := range loadIDs {
  82. if _, ok := targetIDs[id]; ok {
  83. targetOrder = append(targetOrder, id)
  84. }
  85. }
  86. require.Equal(t, []int64{concurrencyFallback.ID, zeroFallback.ID, positiveLoad.ID}, targetOrder)
  87. require.Equal(t, wantByID, byID)
  88. require.Equal(t, 9, byID[positiveLoad.ID])
  89. require.Equal(t, 4, byID[concurrencyFallback.ID])
  90. require.Equal(t, 1, byID[zeroFallback.ID])
  91. for _, included := range []*service.Account{expiredAllowed, overloadCleared, rateLimitCleared, tempCleared} {
  92. require.Contains(t, byID, included.ID)
  93. }
  94. for _, excluded := range []*service.Account{disabled, unschedulable, expired, overloaded, rateLimited, tempBlocked} {
  95. require.NotContains(t, byID, excluded.ID)
  96. }
  97. }