Files
llink/go/internal/depot/service_test.go
T
2026-02-21 08:48:34 -08:00

251 lines
7.4 KiB
Go

package depot_test
import (
"context"
"os"
"testing"
"time"
"github.com/flowy-live/llink/internal/depot"
"github.com/flowy-live/llink/internal/testhelper"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/stretchr/testify/assert"
)
var dbPool *pgxpool.Pool
func TestMain(m *testing.M) {
dbPool = testhelper.SetupTestDB()
defer testhelper.TeardownTestDB()
ret := m.Run()
os.Exit(ret)
}
// TestDepotRepository tests the repository layer directly
// These tests can run without GCS since they only test database operations
func TestDepotRepository_CreateAndGet(t *testing.T) {
ctx := context.Background()
// Create a depot object directly in the database for testing
var id string
err := dbPool.QueryRow(ctx,
`INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id`,
"dpo_test123", "test-file.txt", "text/plain", int64(1024), "test-bucket", "test-key-123", false,
).Scan(&id)
assert.NoError(t, err)
assert.Equal(t, "dpo_test123", id)
// Query the object back
var obj struct {
ID string
Name string
ContentType string
ContentLength int64
BucketName string
ObjectKey string
ContainsContent bool
CreatedAt time.Time
}
err = dbPool.QueryRow(ctx,
`SELECT id, name, content_type, content_length, bucket_name, object_key, contains_content, created_at
FROM depot_objects WHERE id = $1`,
id,
).Scan(&obj.ID, &obj.Name, &obj.ContentType, &obj.ContentLength,
&obj.BucketName, &obj.ObjectKey, &obj.ContainsContent, &obj.CreatedAt)
assert.NoError(t, err)
assert.Equal(t, "test-file.txt", obj.Name)
assert.Equal(t, "text/plain", obj.ContentType)
assert.Equal(t, int64(1024), obj.ContentLength)
assert.Equal(t, "test-bucket", obj.BucketName)
assert.Equal(t, "test-key-123", obj.ObjectKey)
assert.False(t, obj.ContainsContent)
assert.False(t, obj.CreatedAt.IsZero())
// Clean up
_, err = dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id = $1`, id)
assert.NoError(t, err)
}
func TestDepotRepository_ConfirmUpload(t *testing.T) {
ctx := context.Background()
// Create a depot object
var id string
err := dbPool.QueryRow(ctx,
`INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id`,
"dpo_confirm123", "confirm-file.txt", "text/plain", int64(2048), "test-bucket", "confirm-key", false,
).Scan(&id)
assert.NoError(t, err)
// Verify it starts with contains_content = false
var containsContent bool
err = dbPool.QueryRow(ctx,
`SELECT contains_content FROM depot_objects WHERE id = $1`,
id,
).Scan(&containsContent)
assert.NoError(t, err)
assert.False(t, containsContent)
// Confirm upload
_, err = dbPool.Exec(ctx,
`UPDATE depot_objects SET contains_content = TRUE WHERE id = $1`,
id,
)
assert.NoError(t, err)
// Verify it's now true
err = dbPool.QueryRow(ctx,
`SELECT contains_content FROM depot_objects WHERE id = $1`,
id,
).Scan(&containsContent)
assert.NoError(t, err)
assert.True(t, containsContent)
// Clean up
_, err = dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id = $1`, id)
assert.NoError(t, err)
}
func TestDepotRepository_Delete(t *testing.T) {
ctx := context.Background()
// Create a depot object
var id string
err := dbPool.QueryRow(ctx,
`INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id`,
"dpo_delete123", "delete-file.txt", "text/plain", int64(512), "test-bucket", "delete-key", false,
).Scan(&id)
assert.NoError(t, err)
// Delete it
result, err := dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id = $1`, id)
assert.NoError(t, err)
assert.Equal(t, int64(1), result.RowsAffected())
// Verify it's gone
var count int
err = dbPool.QueryRow(ctx,
`SELECT COUNT(*) FROM depot_objects WHERE id = $1`,
id,
).Scan(&count)
assert.NoError(t, err)
assert.Equal(t, 0, count)
}
func TestDepotRepository_Exists(t *testing.T) {
ctx := context.Background()
// Create a depot object
var id string
err := dbPool.QueryRow(ctx,
`INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id`,
"dpo_exists123", "exists-file.txt", "text/plain", int64(256), "test-bucket", "exists-key", true,
).Scan(&id)
assert.NoError(t, err)
// Check exists
var exists bool
err = dbPool.QueryRow(ctx,
`SELECT EXISTS(SELECT 1 FROM depot_objects WHERE id = $1)`,
id,
).Scan(&exists)
assert.NoError(t, err)
assert.True(t, exists)
// Check non-existent
err = dbPool.QueryRow(ctx,
`SELECT EXISTS(SELECT 1 FROM depot_objects WHERE id = $1)`,
"dpo_nonexistent",
).Scan(&exists)
assert.NoError(t, err)
assert.False(t, exists)
// Clean up
_, err = dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id = $1`, id)
assert.NoError(t, err)
}
func TestDepotRepository_OrphanedIndex(t *testing.T) {
ctx := context.Background()
// Create an orphaned object (contains_content = false)
var orphanID string
err := dbPool.QueryRow(ctx,
`INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id`,
"dpo_orphan123", "orphan-file.txt", "text/plain", int64(128), "test-bucket", "orphan-key", false,
).Scan(&orphanID)
assert.NoError(t, err)
// Create a confirmed object (contains_content = true)
var confirmedID string
err = dbPool.QueryRow(ctx,
`INSERT INTO depot_objects (id, name, content_type, content_length, bucket_name, object_key, contains_content)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id`,
"dpo_confirmed123", "confirmed-file.txt", "text/plain", int64(128), "test-bucket", "confirmed-key", true,
).Scan(&confirmedID)
assert.NoError(t, err)
// Query orphaned objects using the index
rows, err := dbPool.Query(ctx,
`SELECT id FROM depot_objects WHERE contains_content = FALSE`)
assert.NoError(t, err)
defer rows.Close()
var orphanedIDs []string
for rows.Next() {
var id string
err := rows.Scan(&id)
assert.NoError(t, err)
orphanedIDs = append(orphanedIDs, id)
}
// Our orphan should be in the list
assert.Contains(t, orphanedIDs, orphanID)
assert.NotContains(t, orphanedIDs, confirmedID)
// Clean up
_, err = dbPool.Exec(ctx, `DELETE FROM depot_objects WHERE id IN ($1, $2)`, orphanID, confirmedID)
assert.NoError(t, err)
}
// TestDepotModels tests the model structures
func TestDepotModels(t *testing.T) {
// Test Config defaults
config := depot.Config{
BucketName: "test-bucket",
}
assert.Equal(t, "test-bucket", config.BucketName)
assert.Equal(t, time.Duration(0), config.UploadURLExpiry)
assert.Equal(t, time.Duration(0), config.DownloadURLExpiry)
// Test with explicit values
config = depot.Config{
BucketName: "custom-bucket",
UploadURLExpiry: 10 * time.Minute,
DownloadURLExpiry: 12 * time.Hour,
}
assert.Equal(t, "custom-bucket", config.BucketName)
assert.Equal(t, 10*time.Minute, config.UploadURLExpiry)
assert.Equal(t, 12*time.Hour, config.DownloadURLExpiry)
}
// TestDepotErrors tests the error definitions
func TestDepotErrors(t *testing.T) {
assert.Error(t, depot.ErrNotFound)
assert.Error(t, depot.ErrInvalidInput)
assert.Equal(t, "object not found", depot.ErrNotFound.Error())
assert.Equal(t, "invalid input", depot.ErrInvalidInput.Error())
}