account_repo_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package repository
  2. import (
  3. "context"
  4. "database/sql"
  5. "database/sql/driver"
  6. "fmt"
  7. "io"
  8. "sync"
  9. "testing"
  10. dbent "github.com/Wei-Shaw/sub2api/ent"
  11. _ "github.com/Wei-Shaw/sub2api/ent/runtime"
  12. "github.com/Wei-Shaw/sub2api/internal/service"
  13. "github.com/stretchr/testify/require"
  14. "entgo.io/ent/dialect"
  15. entsql "entgo.io/ent/dialect/sql"
  16. )
  17. const parameterLimitTestDriverName = "sub2api_param_limit_test"
  18. var registerParameterLimitTestDriverOnce sync.Once
  19. func TestAccountsToService_LargeActiveAccountSetDoesNotExceedPostgresParameterLimit(t *testing.T) {
  20. repo := newParameterLimitAccountRepo(t)
  21. accounts := make([]*dbent.Account, 0, 65536)
  22. for i := range 65536 {
  23. accounts = append(accounts, &dbent.Account{
  24. ID: int64(i + 1),
  25. Name: "large-active",
  26. Platform: service.PlatformOpenAI,
  27. Type: service.AccountTypeOAuth,
  28. Credentials: map[string]any{},
  29. Extra: map[string]any{},
  30. Status: service.StatusActive,
  31. Schedulable: true,
  32. })
  33. }
  34. got, err := repo.accountsToService(context.Background(), accounts)
  35. require.NoError(t, err)
  36. require.Len(t, got, len(accounts))
  37. }
  38. func newParameterLimitAccountRepo(t *testing.T) *accountRepository {
  39. t.Helper()
  40. registerParameterLimitTestDriverOnce.Do(func() {
  41. sql.Register(parameterLimitTestDriverName, parameterLimitDriver{})
  42. })
  43. db, err := sql.Open(parameterLimitTestDriverName, "")
  44. require.NoError(t, err)
  45. t.Cleanup(func() { _ = db.Close() })
  46. drv := entsql.OpenDB(dialect.Postgres, db)
  47. client := dbent.NewClient(dbent.Driver(drv))
  48. t.Cleanup(func() { _ = client.Close() })
  49. return newAccountRepositoryWithSQL(client, nil, nil)
  50. }
  51. type parameterLimitDriver struct{}
  52. func (parameterLimitDriver) Open(string) (driver.Conn, error) {
  53. return parameterLimitConn{}, nil
  54. }
  55. type parameterLimitConn struct{}
  56. func (parameterLimitConn) Prepare(query string) (driver.Stmt, error) {
  57. return parameterLimitStmt{query: query}, nil
  58. }
  59. func (parameterLimitConn) Close() error {
  60. return nil
  61. }
  62. func (parameterLimitConn) Begin() (driver.Tx, error) {
  63. return parameterLimitTx{}, nil
  64. }
  65. func (parameterLimitConn) QueryContext(_ context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
  66. return queryWithParameterLimit(query, args)
  67. }
  68. type parameterLimitStmt struct {
  69. query string
  70. }
  71. func (s parameterLimitStmt) Close() error {
  72. return nil
  73. }
  74. func (s parameterLimitStmt) NumInput() int {
  75. return -1
  76. }
  77. func (s parameterLimitStmt) Exec(args []driver.Value) (driver.Result, error) {
  78. return driver.RowsAffected(0), parameterLimitError(len(args))
  79. }
  80. func (s parameterLimitStmt) Query(args []driver.Value) (driver.Rows, error) {
  81. namedArgs := make([]driver.NamedValue, len(args))
  82. for i, arg := range args {
  83. namedArgs[i] = driver.NamedValue{Ordinal: i + 1, Value: arg}
  84. }
  85. return queryWithParameterLimit(s.query, namedArgs)
  86. }
  87. type parameterLimitTx struct{}
  88. func (parameterLimitTx) Commit() error {
  89. return nil
  90. }
  91. func (parameterLimitTx) Rollback() error {
  92. return nil
  93. }
  94. func queryWithParameterLimit(query string, args []driver.NamedValue) (driver.Rows, error) {
  95. if err := parameterLimitError(len(args)); err != nil {
  96. return nil, err
  97. }
  98. return parameterLimitRows{columns: columnsForParameterLimitQuery(query)}, nil
  99. }
  100. func parameterLimitError(paramCount int) error {
  101. if paramCount <= 65535 {
  102. return nil
  103. }
  104. return fmt.Errorf("pq: got %d parameters but PostgreSQL only supports 65535 parameters", paramCount)
  105. }
  106. func columnsForParameterLimitQuery(query string) []string {
  107. if query == "" {
  108. return nil
  109. }
  110. return []string{"account_id", "group_id", "priority", "created_at"}
  111. }
  112. type parameterLimitRows struct {
  113. columns []string
  114. }
  115. func (r parameterLimitRows) Columns() []string {
  116. return r.columns
  117. }
  118. func (parameterLimitRows) Close() error {
  119. return nil
  120. }
  121. func (parameterLimitRows) Next([]driver.Value) error {
  122. return io.EOF
  123. }