2025-02-03 17:30:50 +00:00
|
|
|
package test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2025-04-02 18:50:03 +00:00
|
|
|
"fmt"
|
2025-04-22 14:40:16 +00:00
|
|
|
"strings"
|
2025-05-03 14:59:21 +00:00
|
|
|
"sync"
|
2025-03-05 12:05:46 +00:00
|
|
|
"testing"
|
|
|
|
|
|
2025-02-03 17:30:50 +00:00
|
|
|
"queryorchestration/internal/serviceconfig"
|
2025-03-11 16:31:06 +00:00
|
|
|
"queryorchestration/internal/serviceconfig/objectstore"
|
2025-05-27 15:28:46 +00:00
|
|
|
|
2025-03-17 18:14:15 +00:00
|
|
|
queryapi "queryorchestration/pkg/queryAPI"
|
2025-02-03 17:30:50 +00:00
|
|
|
|
2025-03-04 15:51:03 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2025-02-03 17:30:50 +00:00
|
|
|
"github.com/testcontainers/testcontainers-go"
|
|
|
|
|
)
|
|
|
|
|
|
2025-03-19 11:54:14 +00:00
|
|
|
type Network struct {
|
|
|
|
|
Dependencies Dependencies
|
2025-04-02 18:50:03 +00:00
|
|
|
APIs map[APIName]*Container
|
|
|
|
|
Runners map[RunnerName]*Container
|
2025-03-19 11:54:14 +00:00
|
|
|
Client *queryapi.ClientWithResponses
|
2025-02-03 17:30:50 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-19 11:54:14 +00:00
|
|
|
func CreateFullNetwork(t testing.TB, ctx context.Context, cfg FullDependenciesConfig) (Network, func()) {
|
2025-05-06 01:59:52 +00:00
|
|
|
deps := CreateFullDependencies(t, ctx, cfg)
|
2025-02-03 17:30:50 +00:00
|
|
|
|
2025-05-03 14:59:21 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
2025-04-02 18:50:03 +00:00
|
|
|
apiContainers := make(map[APIName]*Container, len(apis))
|
2025-03-19 11:54:14 +00:00
|
|
|
apiClean := make([]func(), len(apis))
|
2025-05-06 01:59:52 +00:00
|
|
|
var apiMu sync.Mutex
|
2025-03-19 11:54:14 +00:00
|
|
|
for i, s := range apis {
|
2025-05-03 14:59:21 +00:00
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
c, ccleanup := CreateAPI(t, ctx, cfg, deps.Network, &APIConfig{
|
|
|
|
|
API: s,
|
|
|
|
|
MockHTTP: string(deps.MockServer.Internal),
|
|
|
|
|
})
|
2025-05-06 01:59:52 +00:00
|
|
|
|
|
|
|
|
apiMu.Lock()
|
2025-05-03 14:59:21 +00:00
|
|
|
apiContainers[s.Name] = c
|
2025-05-06 01:59:52 +00:00
|
|
|
apiMu.Unlock()
|
|
|
|
|
|
2025-05-03 14:59:21 +00:00
|
|
|
apiClean[i] = ccleanup
|
|
|
|
|
wg.Done()
|
|
|
|
|
}()
|
2025-02-12 19:00:25 +00:00
|
|
|
}
|
2025-02-03 17:30:50 +00:00
|
|
|
|
2025-04-02 18:50:03 +00:00
|
|
|
runnerContainers := make(map[RunnerName]*Container, len(runners))
|
2025-03-19 11:54:14 +00:00
|
|
|
runnerClean := make([]func(), len(runners))
|
2025-05-06 01:59:52 +00:00
|
|
|
var runnerMu sync.Mutex
|
2025-03-19 11:54:14 +00:00
|
|
|
for i, r := range runners {
|
2025-05-03 14:59:21 +00:00
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
c, ccleanup := CreateRunner(t, ctx, cfg, deps.Network, &RunnerConfig{
|
|
|
|
|
Runner: r,
|
|
|
|
|
MockHTTP: string(deps.MockServer.Internal),
|
|
|
|
|
})
|
|
|
|
|
|
2025-05-06 01:59:52 +00:00
|
|
|
runnerMu.Lock()
|
2025-05-03 14:59:21 +00:00
|
|
|
runnerContainers[r.Name] = c
|
2025-05-06 01:59:52 +00:00
|
|
|
runnerMu.Unlock()
|
|
|
|
|
|
2025-05-03 14:59:21 +00:00
|
|
|
runnerClean[i] = ccleanup
|
|
|
|
|
wg.Done()
|
|
|
|
|
}()
|
2025-03-19 11:54:14 +00:00
|
|
|
}
|
2025-02-03 17:30:50 +00:00
|
|
|
|
2025-05-03 14:59:21 +00:00
|
|
|
wg.Wait()
|
|
|
|
|
|
2026-01-12 17:46:07 +00:00
|
|
|
// 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()),
|
|
|
|
|
)
|
2025-05-03 14:59:21 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
2025-03-19 11:54:14 +00:00
|
|
|
return Network{
|
|
|
|
|
Dependencies: deps,
|
|
|
|
|
APIs: apiContainers,
|
|
|
|
|
Runners: runnerContainers,
|
|
|
|
|
Client: qService,
|
|
|
|
|
}, func() {
|
2025-05-08 16:04:45 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
2025-03-19 11:54:14 +00:00
|
|
|
for _, c := range apiClean {
|
2025-05-08 16:04:45 +00:00
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
c()
|
|
|
|
|
wg.Done()
|
|
|
|
|
}()
|
2025-03-19 11:54:14 +00:00
|
|
|
}
|
2025-05-03 14:59:21 +00:00
|
|
|
|
2025-03-19 11:54:14 +00:00
|
|
|
for _, c := range runnerClean {
|
2025-05-08 16:04:45 +00:00
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
c()
|
|
|
|
|
wg.Done()
|
|
|
|
|
}()
|
2025-03-19 11:54:14 +00:00
|
|
|
}
|
2025-05-08 16:04:45 +00:00
|
|
|
|
|
|
|
|
wg.Wait()
|
2025-02-12 19:00:25 +00:00
|
|
|
}
|
2025-02-03 17:30:50 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-11 16:31:06 +00:00
|
|
|
type FullDependenciesConfig interface {
|
|
|
|
|
serviceconfig.ConfigProvider
|
|
|
|
|
objectstore.ConfigProvider
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Dependencies struct {
|
2025-04-02 18:50:03 +00:00
|
|
|
QueueURLs map[RunnerName]string
|
2025-03-11 16:31:06 +00:00
|
|
|
AWSConfig *AWSContainerConfig
|
2025-03-19 11:54:14 +00:00
|
|
|
DBConfig testcontainers.Container
|
2025-05-12 15:11:50 +00:00
|
|
|
MockServer *MockServer
|
2025-04-22 14:40:16 +00:00
|
|
|
Network string
|
2025-03-11 16:31:06 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-12 20:54:16 +00:00
|
|
|
type FullDependenciesParams struct {
|
|
|
|
|
NoObjectStore bool
|
|
|
|
|
Runners *[]RunnerName
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func CreateFullDependenciesWithParams(t testing.TB, cfg FullDependenciesConfig, params *FullDependenciesParams) Dependencies {
|
2025-05-05 09:31:21 +00:00
|
|
|
network := GetNetwork(t)
|
2025-03-11 16:31:06 +00:00
|
|
|
|
2025-04-22 14:40:16 +00:00
|
|
|
deps := Dependencies{
|
2025-04-25 17:02:50 +00:00
|
|
|
Network: network,
|
|
|
|
|
QueueURLs: map[RunnerName]string{},
|
2025-04-22 14:40:16 +00:00
|
|
|
}
|
2025-05-03 14:59:21 +00:00
|
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
2025-04-22 14:40:16 +00:00
|
|
|
|
2025-05-03 14:59:21 +00:00
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
2025-05-23 00:20:01 +00:00
|
|
|
deps.AWSConfig = CreateAWSContainer(t, cfg)
|
2025-05-03 14:59:21 +00:00
|
|
|
|
2025-05-12 20:54:16 +00:00
|
|
|
SetQueueClient(t, t.Context(), cfg, deps.AWSConfig.ExternalEndpoint)
|
2025-03-11 16:31:06 +00:00
|
|
|
|
2025-05-12 15:11:50 +00:00
|
|
|
var lock sync.Mutex
|
|
|
|
|
|
2025-05-12 20:54:16 +00:00
|
|
|
runs := params.Runners
|
|
|
|
|
if runs == nil {
|
|
|
|
|
allRuns := []RunnerName{}
|
|
|
|
|
for _, run := range runners {
|
|
|
|
|
allRuns = append(allRuns, run.Name)
|
|
|
|
|
}
|
|
|
|
|
runs = &allRuns
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, runner := range *runs {
|
2025-05-05 09:31:21 +00:00
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
2025-05-23 00:20:01 +00:00
|
|
|
queue := CreateQueue(t, cfg, runner)
|
2025-05-12 15:11:50 +00:00
|
|
|
|
|
|
|
|
lock.Lock()
|
2025-05-12 20:54:16 +00:00
|
|
|
deps.QueueURLs[runner] = queue
|
2025-05-12 15:11:50 +00:00
|
|
|
lock.Unlock()
|
|
|
|
|
|
2025-05-05 09:31:21 +00:00
|
|
|
wg.Done()
|
|
|
|
|
}()
|
|
|
|
|
}
|
2025-04-02 18:50:03 +00:00
|
|
|
|
2025-05-12 20:54:16 +00:00
|
|
|
if !params.NoObjectStore {
|
|
|
|
|
SetStoreClient(t, t.Context(), cfg, deps.AWSConfig.ExternalEndpoint)
|
2025-05-27 15:28:46 +00:00
|
|
|
CreateBucket(t, cfg)
|
2025-05-12 20:54:16 +00:00
|
|
|
SetBucketNotifs(t, t.Context(), cfg)
|
|
|
|
|
}
|
2025-03-11 16:31:06 +00:00
|
|
|
|
2025-05-05 09:31:21 +00:00
|
|
|
wg.Done()
|
|
|
|
|
}()
|
|
|
|
|
|
2025-05-23 00:20:01 +00:00
|
|
|
mockServer := CreateMockServer(t)
|
2025-05-05 09:31:21 +00:00
|
|
|
deps.MockServer = mockServer
|
2025-03-11 16:31:06 +00:00
|
|
|
|
2025-05-23 00:20:01 +00:00
|
|
|
CreateDBWithParams(t, cfg, &CreateDatabaseConfig{
|
2025-05-05 09:31:21 +00:00
|
|
|
NoMigrations: true,
|
|
|
|
|
})
|
2025-03-11 16:31:06 +00:00
|
|
|
|
2025-05-03 14:59:21 +00:00
|
|
|
wg.Wait()
|
|
|
|
|
|
2025-05-06 01:59:52 +00:00
|
|
|
return deps
|
2025-03-11 16:31:06 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-12 20:54:16 +00:00
|
|
|
func CreateFullDependencies(t testing.TB, ctx context.Context, cfg FullDependenciesConfig) Dependencies {
|
|
|
|
|
return CreateFullDependenciesWithParams(t, cfg, &FullDependenciesParams{})
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-22 14:40:16 +00:00
|
|
|
type APINetwork struct {
|
|
|
|
|
Dependencies Dependencies
|
|
|
|
|
API *Container
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 20:54:16 +00:00
|
|
|
func CreateAPINetworkWithParams(t testing.TB, cfg FullDependenciesConfig, api API, params *FullDependenciesParams) (*APINetwork, func()) {
|
|
|
|
|
deps := CreateFullDependenciesWithParams(t, cfg, params)
|
2025-04-02 18:50:03 +00:00
|
|
|
|
2025-05-12 20:54:16 +00:00
|
|
|
c, ccleanup := CreateAPI(t, t.Context(), cfg, deps.Network, &APIConfig{
|
2025-04-22 14:40:16 +00:00
|
|
|
API: api,
|
2025-04-02 18:50:03 +00:00
|
|
|
MockHTTP: string(deps.MockServer.Internal),
|
|
|
|
|
})
|
|
|
|
|
|
2025-04-22 14:40:16 +00:00
|
|
|
return &APINetwork{
|
2025-05-06 01:59:52 +00:00
|
|
|
Dependencies: deps,
|
|
|
|
|
API: c,
|
|
|
|
|
}, ccleanup
|
2025-04-02 18:50:03 +00:00
|
|
|
}
|
|
|
|
|
|
2025-05-12 20:54:16 +00:00
|
|
|
func CreateAPINetwork(t testing.TB, ctx context.Context, cfg FullDependenciesConfig, api API) (*APINetwork, func()) {
|
|
|
|
|
return CreateAPINetworkWithParams(t, cfg, api, &FullDependenciesParams{})
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-05 09:31:21 +00:00
|
|
|
func GetAlias(t testing.TB, baseName string) string {
|
|
|
|
|
name := fmt.Sprintf("%s_%s", baseName, t.Name())
|
|
|
|
|
name = strings.ToLower(name)
|
2025-04-25 17:02:50 +00:00
|
|
|
name = strings.ReplaceAll(name, "/", "")
|
|
|
|
|
name = strings.ReplaceAll(name, " ", "")
|
|
|
|
|
name = strings.ReplaceAll(name, "-", "")
|
2025-05-05 09:31:21 +00:00
|
|
|
name = strings.ReplaceAll(name, "_", "")
|
2025-04-22 14:40:16 +00:00
|
|
|
return name
|
|
|
|
|
}
|