| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- package repository
- import (
- "context"
- "database/sql"
- "encoding/json"
- "testing"
- "time"
- dbent "github.com/Wei-Shaw/sub2api/ent"
- "github.com/Wei-Shaw/sub2api/ent/enttest"
- dbusagecleanuptask "github.com/Wei-Shaw/sub2api/ent/usagecleanuptask"
- "github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/stretchr/testify/require"
- "entgo.io/ent/dialect"
- entsql "entgo.io/ent/dialect/sql"
- _ "modernc.org/sqlite"
- )
- func newUsageCleanupEntRepo(t *testing.T) (*usageCleanupRepository, *dbent.Client) {
- t.Helper()
- db, err := sql.Open("sqlite", "file:usage_cleanup?mode=memory&cache=shared")
- require.NoError(t, err)
- t.Cleanup(func() { _ = db.Close() })
- _, err = db.Exec("PRAGMA foreign_keys = ON")
- require.NoError(t, err)
- drv := entsql.OpenDB(dialect.SQLite, db)
- client := enttest.NewClient(t, enttest.WithOptions(dbent.Driver(drv)))
- t.Cleanup(func() { _ = client.Close() })
- repo := &usageCleanupRepository{client: client, sql: db}
- return repo, client
- }
- func TestUsageCleanupRepositoryEntCreateAndList(t *testing.T) {
- repo, _ := newUsageCleanupEntRepo(t)
- start := time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)
- end := start.Add(24 * time.Hour)
- task := &service.UsageCleanupTask{
- Status: service.UsageCleanupStatusPending,
- Filters: service.UsageCleanupFilters{StartTime: start, EndTime: end},
- CreatedBy: 9,
- }
- require.NoError(t, repo.CreateTask(context.Background(), task))
- require.NotZero(t, task.ID)
- task2 := &service.UsageCleanupTask{
- Status: service.UsageCleanupStatusRunning,
- Filters: service.UsageCleanupFilters{StartTime: start.Add(-24 * time.Hour), EndTime: end.Add(-24 * time.Hour)},
- CreatedBy: 10,
- }
- require.NoError(t, repo.CreateTask(context.Background(), task2))
- tasks, result, err := repo.ListTasks(context.Background(), pagination.PaginationParams{Page: 1, PageSize: 10})
- require.NoError(t, err)
- require.Len(t, tasks, 2)
- require.Equal(t, int64(2), result.Total)
- require.Greater(t, tasks[0].ID, tasks[1].ID)
- require.Equal(t, start, tasks[1].Filters.StartTime)
- require.Equal(t, end, tasks[1].Filters.EndTime)
- }
- func TestUsageCleanupRepositoryEntListEmpty(t *testing.T) {
- repo, _ := newUsageCleanupEntRepo(t)
- tasks, result, err := repo.ListTasks(context.Background(), pagination.PaginationParams{Page: 1, PageSize: 10})
- require.NoError(t, err)
- require.Empty(t, tasks)
- require.Equal(t, int64(0), result.Total)
- }
- func TestUsageCleanupRepositoryEntGetStatusAndProgress(t *testing.T) {
- repo, client := newUsageCleanupEntRepo(t)
- task := &service.UsageCleanupTask{
- Status: service.UsageCleanupStatusPending,
- Filters: service.UsageCleanupFilters{StartTime: time.Now().UTC(), EndTime: time.Now().UTC().Add(time.Hour)},
- CreatedBy: 3,
- }
- require.NoError(t, repo.CreateTask(context.Background(), task))
- status, err := repo.GetTaskStatus(context.Background(), task.ID)
- require.NoError(t, err)
- require.Equal(t, service.UsageCleanupStatusPending, status)
- _, err = repo.GetTaskStatus(context.Background(), task.ID+99)
- require.ErrorIs(t, err, sql.ErrNoRows)
- require.NoError(t, repo.UpdateTaskProgress(context.Background(), task.ID, 42))
- loaded, err := client.UsageCleanupTask.Get(context.Background(), task.ID)
- require.NoError(t, err)
- require.Equal(t, int64(42), loaded.DeletedRows)
- }
- func TestUsageCleanupRepositoryEntCancelAndFinish(t *testing.T) {
- repo, client := newUsageCleanupEntRepo(t)
- task := &service.UsageCleanupTask{
- Status: service.UsageCleanupStatusPending,
- Filters: service.UsageCleanupFilters{StartTime: time.Now().UTC(), EndTime: time.Now().UTC().Add(time.Hour)},
- CreatedBy: 5,
- }
- require.NoError(t, repo.CreateTask(context.Background(), task))
- ok, err := repo.CancelTask(context.Background(), task.ID, 7)
- require.NoError(t, err)
- require.True(t, ok)
- loaded, err := client.UsageCleanupTask.Get(context.Background(), task.ID)
- require.NoError(t, err)
- require.Equal(t, service.UsageCleanupStatusCanceled, loaded.Status)
- require.NotNil(t, loaded.CanceledBy)
- require.NotNil(t, loaded.CanceledAt)
- require.NotNil(t, loaded.FinishedAt)
- loaded.Status = service.UsageCleanupStatusSucceeded
- _, err = client.UsageCleanupTask.Update().Where(dbusagecleanuptask.IDEQ(task.ID)).SetStatus(loaded.Status).Save(context.Background())
- require.NoError(t, err)
- ok, err = repo.CancelTask(context.Background(), task.ID, 7)
- require.NoError(t, err)
- require.False(t, ok)
- }
- func TestUsageCleanupRepositoryEntCancelError(t *testing.T) {
- repo, client := newUsageCleanupEntRepo(t)
- task := &service.UsageCleanupTask{
- Status: service.UsageCleanupStatusPending,
- Filters: service.UsageCleanupFilters{StartTime: time.Now().UTC(), EndTime: time.Now().UTC().Add(time.Hour)},
- CreatedBy: 5,
- }
- require.NoError(t, repo.CreateTask(context.Background(), task))
- require.NoError(t, client.Close())
- _, err := repo.CancelTask(context.Background(), task.ID, 7)
- require.Error(t, err)
- }
- func TestUsageCleanupRepositoryEntMarkResults(t *testing.T) {
- repo, client := newUsageCleanupEntRepo(t)
- task := &service.UsageCleanupTask{
- Status: service.UsageCleanupStatusRunning,
- Filters: service.UsageCleanupFilters{StartTime: time.Now().UTC(), EndTime: time.Now().UTC().Add(time.Hour)},
- CreatedBy: 12,
- }
- require.NoError(t, repo.CreateTask(context.Background(), task))
- require.NoError(t, repo.MarkTaskSucceeded(context.Background(), task.ID, 6))
- loaded, err := client.UsageCleanupTask.Get(context.Background(), task.ID)
- require.NoError(t, err)
- require.Equal(t, service.UsageCleanupStatusSucceeded, loaded.Status)
- require.Equal(t, int64(6), loaded.DeletedRows)
- require.NotNil(t, loaded.FinishedAt)
- task2 := &service.UsageCleanupTask{
- Status: service.UsageCleanupStatusRunning,
- Filters: service.UsageCleanupFilters{StartTime: time.Now().UTC(), EndTime: time.Now().UTC().Add(time.Hour)},
- CreatedBy: 12,
- }
- require.NoError(t, repo.CreateTask(context.Background(), task2))
- require.NoError(t, repo.MarkTaskFailed(context.Background(), task2.ID, 4, "boom"))
- loaded2, err := client.UsageCleanupTask.Get(context.Background(), task2.ID)
- require.NoError(t, err)
- require.Equal(t, service.UsageCleanupStatusFailed, loaded2.Status)
- require.Equal(t, "boom", *loaded2.ErrorMessage)
- }
- func TestUsageCleanupRepositoryEntInvalidStatus(t *testing.T) {
- repo, _ := newUsageCleanupEntRepo(t)
- task := &service.UsageCleanupTask{
- Status: "invalid",
- Filters: service.UsageCleanupFilters{StartTime: time.Now().UTC(), EndTime: time.Now().UTC().Add(time.Hour)},
- CreatedBy: 1,
- }
- require.Error(t, repo.CreateTask(context.Background(), task))
- }
- func TestUsageCleanupRepositoryEntListInvalidFilters(t *testing.T) {
- repo, client := newUsageCleanupEntRepo(t)
- now := time.Now().UTC()
- driver, ok := client.Driver().(*entsql.Driver)
- require.True(t, ok)
- _, err := driver.DB().ExecContext(
- context.Background(),
- `INSERT INTO usage_cleanup_tasks (status, filters, created_by, deleted_rows, created_at, updated_at)
- VALUES (?, ?, ?, ?, ?, ?)`,
- service.UsageCleanupStatusPending,
- []byte("invalid-json"),
- int64(1),
- int64(0),
- now,
- now,
- )
- require.NoError(t, err)
- _, _, err = repo.ListTasks(context.Background(), pagination.PaginationParams{Page: 1, PageSize: 10})
- require.Error(t, err)
- }
- func TestUsageCleanupTaskFromEntFull(t *testing.T) {
- start := time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)
- end := start.Add(24 * time.Hour)
- errMsg := "failed"
- canceledBy := int64(2)
- canceledAt := start.Add(time.Minute)
- startedAt := start.Add(2 * time.Minute)
- finishedAt := start.Add(3 * time.Minute)
- filters := service.UsageCleanupFilters{StartTime: start, EndTime: end}
- filtersJSON, err := json.Marshal(filters)
- require.NoError(t, err)
- task, err := usageCleanupTaskFromEnt(&dbent.UsageCleanupTask{
- ID: 10,
- Status: service.UsageCleanupStatusFailed,
- Filters: filtersJSON,
- CreatedBy: 11,
- DeletedRows: 7,
- ErrorMessage: &errMsg,
- CanceledBy: &canceledBy,
- CanceledAt: &canceledAt,
- StartedAt: &startedAt,
- FinishedAt: &finishedAt,
- CreatedAt: start,
- UpdatedAt: end,
- })
- require.NoError(t, err)
- require.Equal(t, int64(10), task.ID)
- require.Equal(t, service.UsageCleanupStatusFailed, task.Status)
- require.NotNil(t, task.ErrorMsg)
- require.NotNil(t, task.CanceledBy)
- require.NotNil(t, task.CanceledAt)
- require.NotNil(t, task.StartedAt)
- require.NotNil(t, task.FinishedAt)
- }
- func TestUsageCleanupTaskFromEntInvalidFilters(t *testing.T) {
- task, err := usageCleanupTaskFromEnt(&dbent.UsageCleanupTask{
- Filters: json.RawMessage("invalid-json"),
- })
- require.Error(t, err)
- require.Empty(t, task)
- }
|