176 lines
4.1 KiB
Go
176 lines
4.1 KiB
Go
package component
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/testcontainers/testcontainers-go"
|
|
"github.com/testcontainers/testcontainers-go/modules/postgres"
|
|
"github.com/testcontainers/testcontainers-go/wait"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
"google.golang.org/grpc/test/bufconn"
|
|
|
|
pb "homelab.lan/music-agregator/gen/music_agregator/v1"
|
|
"homelab.lan/music-agregator/internal"
|
|
"homelab.lan/music-agregator/internal/database"
|
|
"homelab.lan/music-agregator/internal/metadata"
|
|
)
|
|
|
|
const bufSize = 1024 * 1024
|
|
|
|
type testMocks struct {
|
|
metadata *mockMetadataClient
|
|
torrent *mockTorrentClient
|
|
indexer *mockSearcher
|
|
magnet *mockResolver
|
|
}
|
|
|
|
type testSuite struct {
|
|
db *database.DB
|
|
grpcConn *grpc.ClientConn
|
|
client pb.MusicAgregatorServiceClient
|
|
pool *pgxpool.Pool
|
|
mocks *testMocks
|
|
}
|
|
|
|
func setupSuite(t *testing.T) *testSuite {
|
|
ctx := context.Background()
|
|
|
|
schemaPath := getSchemaPath(t)
|
|
schemaSQL, err := os.ReadFile(schemaPath)
|
|
require.NoError(t, err, "failed to read schema file")
|
|
|
|
pgContainer, err := postgres.Run(ctx,
|
|
"postgres:16-alpine",
|
|
postgres.WithDatabase("music_agregator_test"),
|
|
postgres.WithUsername("test"),
|
|
postgres.WithPassword("test"),
|
|
postgres.WithInitScripts(),
|
|
testcontainers.WithWaitStrategy(
|
|
wait.ForLog("database system is ready to accept connections").
|
|
WithOccurrence(2).
|
|
WithStartupTimeout(30*time.Second),
|
|
),
|
|
)
|
|
require.NoError(t, err, "failed to start postgres container")
|
|
|
|
t.Cleanup(func() {
|
|
if err := pgContainer.Terminate(ctx); err != nil {
|
|
t.Logf("failed to terminate postgres container: %v", err)
|
|
}
|
|
})
|
|
|
|
connStr, err := pgContainer.ConnectionString(ctx, "sslmode=disable")
|
|
require.NoError(t, err, "failed to get connection string")
|
|
|
|
pool, err := pgxpool.New(ctx, connStr)
|
|
require.NoError(t, err, "failed to create pgxpool")
|
|
|
|
t.Cleanup(func() {
|
|
pool.Close()
|
|
})
|
|
|
|
_, err = pool.Exec(ctx, string(schemaSQL))
|
|
require.NoError(t, err, "failed to apply schema")
|
|
|
|
db := &database.DB{Pool: pool}
|
|
|
|
mocks := &testMocks{
|
|
metadata: &mockMetadataClient{},
|
|
torrent: &mockTorrentClient{},
|
|
indexer: &mockSearcher{},
|
|
magnet: &mockResolver{},
|
|
}
|
|
|
|
metadataSvc := metadata.NewMetadataService(mocks.metadata, db)
|
|
|
|
service := internal.NewMusicAgregatorServiceWithDeps(
|
|
metadataSvc,
|
|
mocks.indexer,
|
|
mocks.torrent,
|
|
mocks.magnet,
|
|
nil,
|
|
nil,
|
|
db,
|
|
)
|
|
|
|
server := internal.NewMusicAgregatorServerWithService(service)
|
|
|
|
lis := bufconn.Listen(bufSize)
|
|
grpcServer := grpc.NewServer()
|
|
server.Register(grpcServer)
|
|
|
|
go func() {
|
|
if err := grpcServer.Serve(lis); err != nil {
|
|
t.Logf("grpc server error: %v", err)
|
|
}
|
|
}()
|
|
|
|
t.Cleanup(func() {
|
|
grpcServer.GracefulStop()
|
|
})
|
|
|
|
conn, err := grpc.NewClient(
|
|
"passthrough://bufnet",
|
|
grpc.WithContextDialer(func(ctx context.Context, _ string) (net.Conn, error) {
|
|
return lis.DialContext(ctx)
|
|
}),
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
)
|
|
require.NoError(t, err, "failed to create grpc client connection")
|
|
|
|
t.Cleanup(func() {
|
|
conn.Close()
|
|
})
|
|
|
|
client := pb.NewMusicAgregatorServiceClient(conn)
|
|
|
|
return &testSuite{
|
|
db: db,
|
|
grpcConn: conn,
|
|
client: client,
|
|
pool: pool,
|
|
mocks: mocks,
|
|
}
|
|
}
|
|
|
|
func getSchemaPath(t *testing.T) string {
|
|
_, currentFile, _, ok := runtime.Caller(0)
|
|
require.True(t, ok, "failed to get current file path")
|
|
|
|
testDir := filepath.Dir(currentFile)
|
|
schemaPath := filepath.Join(testDir, "..", "..", "..", "containers", "database", "music-agregator", "002_schema.sql")
|
|
|
|
if _, err := os.Stat(schemaPath); os.IsNotExist(err) {
|
|
schemaPath = filepath.Join(testDir, "..", "..", "containers", "database", "music-agregator", "002_schema.sql")
|
|
}
|
|
|
|
return schemaPath
|
|
}
|
|
|
|
func cleanTables(t *testing.T, pool *pgxpool.Pool) {
|
|
ctx := context.Background()
|
|
|
|
tables := []string{
|
|
"download_files",
|
|
"downloads",
|
|
"torrents",
|
|
"tracks",
|
|
"albums",
|
|
"artists",
|
|
}
|
|
|
|
for _, table := range tables {
|
|
_, err := pool.Exec(ctx, "TRUNCATE TABLE "+table+" CASCADE")
|
|
require.NoError(t, err, "failed to truncate table %s", table)
|
|
}
|
|
}
|