35d72fccbe
Feature/remove mocks * remove mocks * cleanup db migrations
234 lines
5.6 KiB
Go
234 lines
5.6 KiB
Go
// Package test provides test ecosystem infrastructure.
|
|
// Note: MockServer has been removed since text extraction (Textract) is deprecated.
|
|
// See remove_texttract_and_mocks_plan.md for details.
|
|
package test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
|
|
"queryorchestration/internal/serviceconfig"
|
|
"queryorchestration/internal/serviceconfig/objectstore"
|
|
|
|
queryapi "queryorchestration/pkg/queryAPI"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/testcontainers/testcontainers-go"
|
|
)
|
|
|
|
type Network struct {
|
|
Dependencies Dependencies
|
|
APIs map[APIName]*Container
|
|
Runners map[RunnerName]*Container
|
|
Client *queryapi.ClientWithResponses
|
|
}
|
|
|
|
func CreateFullNetwork(t testing.TB, ctx context.Context, cfg FullDependenciesConfig) (Network, func()) {
|
|
deps := CreateFullDependencies(t, ctx, cfg)
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
apiContainers := make(map[APIName]*Container, len(apis))
|
|
apiClean := make([]func(), len(apis))
|
|
var apiMu sync.Mutex
|
|
for i, s := range apis {
|
|
wg.Add(1)
|
|
go func() {
|
|
c, ccleanup := CreateAPI(t, ctx, cfg, deps.Network, &APIConfig{
|
|
API: s,
|
|
})
|
|
|
|
apiMu.Lock()
|
|
apiContainers[s.Name] = c
|
|
apiMu.Unlock()
|
|
|
|
apiClean[i] = ccleanup
|
|
wg.Done()
|
|
}()
|
|
}
|
|
|
|
runnerContainers := make(map[RunnerName]*Container, len(runners))
|
|
runnerClean := make([]func(), len(runners))
|
|
var runnerMu sync.Mutex
|
|
for i, r := range runners {
|
|
wg.Add(1)
|
|
go func() {
|
|
c, ccleanup := CreateRunner(t, ctx, cfg, deps.Network, &RunnerConfig{
|
|
Runner: r,
|
|
})
|
|
|
|
runnerMu.Lock()
|
|
runnerContainers[r.Name] = c
|
|
runnerMu.Unlock()
|
|
|
|
runnerClean[i] = ccleanup
|
|
wg.Done()
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
// Wait for external readiness before creating the client.
|
|
// This addresses the race condition where containers report healthy internally
|
|
// but the external port mapping isn't fully ready, causing 404 errors in CI.
|
|
err := WaitForExternalReadiness(apiContainers[QueryAPIName].URI, "/health", GetPollingTimeout())
|
|
require.NoError(t, err, "QueryAPI not externally reachable")
|
|
|
|
// Wait for API routes to be registered.
|
|
// The health endpoint may return 200 before all routes are registered,
|
|
// causing "404 page not found" errors on actual API calls.
|
|
err = WaitForAPIRoutes(apiContainers[QueryAPIName].URI, GetPollingTimeout())
|
|
require.NoError(t, err, "QueryAPI routes not registered")
|
|
|
|
// Create API client with bounded HTTP timeout to prevent indefinite hangs
|
|
// that were causing CI failures (goroutines blocking until 15-minute global timeout)
|
|
qService, err := queryapi.NewClientWithResponses(
|
|
apiContainers[QueryAPIName].URI,
|
|
queryapi.WithHTTPClient(GetHTTPClient()),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
return Network{
|
|
Dependencies: deps,
|
|
APIs: apiContainers,
|
|
Runners: runnerContainers,
|
|
Client: qService,
|
|
}, func() {
|
|
var wg sync.WaitGroup
|
|
|
|
for _, c := range apiClean {
|
|
wg.Add(1)
|
|
go func() {
|
|
c()
|
|
wg.Done()
|
|
}()
|
|
}
|
|
|
|
for _, c := range runnerClean {
|
|
wg.Add(1)
|
|
go func() {
|
|
c()
|
|
wg.Done()
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
}
|
|
}
|
|
|
|
type FullDependenciesConfig interface {
|
|
serviceconfig.ConfigProvider
|
|
objectstore.ConfigProvider
|
|
}
|
|
|
|
// Dependencies holds test infrastructure components.
|
|
// Note: MockServer has been removed since text extraction is deprecated.
|
|
type Dependencies struct {
|
|
QueueURLs map[RunnerName]string
|
|
AWSConfig *AWSContainerConfig
|
|
DBConfig testcontainers.Container
|
|
Network string
|
|
}
|
|
|
|
type FullDependenciesParams struct {
|
|
NoObjectStore bool
|
|
Runners *[]RunnerName
|
|
}
|
|
|
|
func CreateFullDependenciesWithParams(t testing.TB, cfg FullDependenciesConfig, params *FullDependenciesParams) Dependencies {
|
|
network := GetNetwork(t)
|
|
|
|
deps := Dependencies{
|
|
Network: network,
|
|
QueueURLs: map[RunnerName]string{},
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(1)
|
|
go func() {
|
|
deps.AWSConfig = CreateAWSContainer(t, cfg)
|
|
|
|
SetQueueClient(t, t.Context(), cfg, deps.AWSConfig.ExternalEndpoint)
|
|
|
|
var lock sync.Mutex
|
|
|
|
runs := params.Runners
|
|
if runs == nil {
|
|
allRuns := []RunnerName{}
|
|
for _, run := range runners {
|
|
allRuns = append(allRuns, run.Name)
|
|
}
|
|
runs = &allRuns
|
|
}
|
|
|
|
for _, runner := range *runs {
|
|
wg.Add(1)
|
|
go func() {
|
|
queue := CreateQueue(t, cfg, runner)
|
|
|
|
lock.Lock()
|
|
deps.QueueURLs[runner] = queue
|
|
lock.Unlock()
|
|
|
|
wg.Done()
|
|
}()
|
|
}
|
|
|
|
if !params.NoObjectStore {
|
|
SetStoreClient(t, t.Context(), cfg, deps.AWSConfig.ExternalEndpoint)
|
|
CreateBucket(t, cfg)
|
|
SetBucketNotifs(t, t.Context(), cfg)
|
|
}
|
|
|
|
wg.Done()
|
|
}()
|
|
|
|
CreateDBWithParams(t, cfg, &CreateDatabaseConfig{
|
|
NoMigrations: true,
|
|
})
|
|
|
|
wg.Wait()
|
|
|
|
return deps
|
|
}
|
|
|
|
func CreateFullDependencies(t testing.TB, ctx context.Context, cfg FullDependenciesConfig) Dependencies {
|
|
return CreateFullDependenciesWithParams(t, cfg, &FullDependenciesParams{})
|
|
}
|
|
|
|
type APINetwork struct {
|
|
Dependencies Dependencies
|
|
API *Container
|
|
}
|
|
|
|
func CreateAPINetworkWithParams(t testing.TB, cfg FullDependenciesConfig, api API, params *FullDependenciesParams) (*APINetwork, func()) {
|
|
deps := CreateFullDependenciesWithParams(t, cfg, params)
|
|
|
|
c, ccleanup := CreateAPI(t, t.Context(), cfg, deps.Network, &APIConfig{
|
|
API: api,
|
|
})
|
|
|
|
return &APINetwork{
|
|
Dependencies: deps,
|
|
API: c,
|
|
}, ccleanup
|
|
}
|
|
|
|
func CreateAPINetwork(t testing.TB, ctx context.Context, cfg FullDependenciesConfig, api API) (*APINetwork, func()) {
|
|
return CreateAPINetworkWithParams(t, cfg, api, &FullDependenciesParams{})
|
|
}
|
|
|
|
func GetAlias(t testing.TB, baseName string) string {
|
|
name := fmt.Sprintf("%s_%s", baseName, t.Name())
|
|
name = strings.ToLower(name)
|
|
name = strings.ReplaceAll(name, "/", "")
|
|
name = strings.ReplaceAll(name, " ", "")
|
|
name = strings.ReplaceAll(name, "-", "")
|
|
name = strings.ReplaceAll(name, "_", "")
|
|
return name
|
|
}
|