account_repo_schedulable_projection_test.go 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. package repository
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. "testing"
  7. "github.com/DATA-DOG/go-sqlmock"
  8. dbent "github.com/Wei-Shaw/sub2api/ent"
  9. _ "github.com/Wei-Shaw/sub2api/ent/runtime"
  10. "github.com/stretchr/testify/require"
  11. "entgo.io/ent/dialect"
  12. entsql "entgo.io/ent/dialect/sql"
  13. )
  14. type captureEntQueryMatcher struct {
  15. actual *string
  16. }
  17. func (m captureEntQueryMatcher) Match(_, actual string) error {
  18. if m.actual == nil {
  19. return fmt.Errorf("query capture target is nil")
  20. }
  21. *m.actual = actual
  22. return nil
  23. }
  24. func TestListSchedulableAccountLoadsUsesSingleProjectionQuery(t *testing.T) {
  25. var capturedSQL string
  26. db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(captureEntQueryMatcher{actual: &capturedSQL}))
  27. require.NoError(t, err)
  28. t.Cleanup(func() { _ = db.Close() })
  29. driver := entsql.OpenDB(dialect.Postgres, db)
  30. client := dbent.NewClient(dbent.Driver(driver))
  31. t.Cleanup(func() { _ = client.Close() })
  32. repo := newAccountRepositoryWithSQL(client, db, nil)
  33. mock.ExpectQuery("schedulable account load projection").
  34. WillReturnRows(sqlmock.NewRows([]string{"id", "concurrency", "load_factor"}).
  35. AddRow(int64(11), 3, nil).
  36. AddRow(int64(12), 2, 7))
  37. loads, err := repo.ListSchedulableAccountLoads(context.Background())
  38. require.NoError(t, err)
  39. require.Len(t, loads, 2)
  40. require.Equal(t, int64(11), loads[0].ID)
  41. require.Equal(t, 3, loads[0].MaxConcurrency)
  42. require.Equal(t, int64(12), loads[1].ID)
  43. require.Equal(t, 7, loads[1].MaxConcurrency)
  44. require.NoError(t, mock.ExpectationsWereMet(), "projection path must execute exactly one query")
  45. normalized := normalizeSQLWhitespace(capturedSQL)
  46. selectClause, _, found := strings.Cut(normalized, " FROM ")
  47. require.True(t, found, "unexpected projection SQL: %s", normalized)
  48. require.Equal(t, 2, strings.Count(selectClause, ","), "projection must select exactly three columns: %s", selectClause)
  49. require.Contains(t, selectClause, `"id"`)
  50. require.Contains(t, selectClause, `"concurrency"`)
  51. require.Contains(t, selectClause, `"load_factor"`)
  52. require.NotContains(t, selectClause, "credentials")
  53. require.NotContains(t, selectClause, "extra")
  54. require.NotContains(t, selectClause, "proxy_id")
  55. require.NotContains(t, normalized, "account_groups")
  56. require.NotContains(t, normalized, "proxies")
  57. for _, predicateColumn := range []string{
  58. "status",
  59. "schedulable",
  60. "temp_unschedulable_until",
  61. "expires_at",
  62. "auto_pause_on_expired",
  63. "overload_until",
  64. "rate_limit_reset_at",
  65. "deleted_at",
  66. } {
  67. require.Contains(t, normalized, predicateColumn)
  68. }
  69. _, orderClause, hasOrder := strings.Cut(normalized, " ORDER BY ")
  70. require.True(t, hasOrder, "projection query must preserve schedulable account order: %s", normalized)
  71. require.Contains(t, orderClause, `"priority" ASC`)
  72. }