mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-09-14 20:19:34 +00:00
112 lines
2.8 KiB
Go
112 lines
2.8 KiB
Go
// Package mongotest provides a shared MongoDB Testcontainers lifecycle for
|
|
// integration-test packages.
|
|
package mongotest
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/testcontainers/testcontainers-go"
|
|
"github.com/testcontainers/testcontainers-go/modules/mongodb"
|
|
)
|
|
|
|
const mongoImage = "mongo:8"
|
|
|
|
// Manager lazily starts one MongoDB container for a test package and stops it
|
|
// after that package's tests finish. MONGODB_TEST_URL bypasses Testcontainers.
|
|
type Manager struct {
|
|
healthOnce sync.Once
|
|
healthErr error
|
|
warningOnce sync.Once
|
|
startOnce sync.Once
|
|
container *mongodb.MongoDBContainer
|
|
uri string
|
|
startErr error
|
|
healthCheck func() error
|
|
warningOut io.Writer
|
|
}
|
|
|
|
// URI returns the configured external MongoDB URL or lazily provisions a
|
|
// MongoDB 8 container. Tests are skipped with a warning when Docker is absent.
|
|
func (m *Manager) URI(t *testing.T) string {
|
|
t.Helper()
|
|
if uri := strings.TrimSpace(os.Getenv("MONGODB_TEST_URL")); uri != "" {
|
|
return uri
|
|
}
|
|
|
|
m.healthOnce.Do(func() {
|
|
healthCheck := m.healthCheck
|
|
if healthCheck == nil {
|
|
healthCheck = dockerHealthError
|
|
}
|
|
m.healthErr = healthCheck()
|
|
})
|
|
if m.healthErr != nil {
|
|
warning := fmt.Sprintf("WARNING: Docker is not available; MongoDB integration tests skipped: %v", m.healthErr)
|
|
m.warningOnce.Do(func() {
|
|
warningOut := m.warningOut
|
|
if warningOut == nil {
|
|
warningOut = os.Stderr
|
|
}
|
|
_, _ = fmt.Fprintln(warningOut, warning)
|
|
})
|
|
t.Skip(warning)
|
|
}
|
|
|
|
m.startOnce.Do(func() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
|
defer cancel()
|
|
|
|
m.container, m.startErr = mongodb.Run(ctx, mongoImage)
|
|
if m.startErr != nil {
|
|
return
|
|
}
|
|
m.uri, m.startErr = m.container.ConnectionString(ctx)
|
|
})
|
|
if m.startErr != nil {
|
|
t.Fatalf("start MongoDB Testcontainer: %v", m.startErr)
|
|
}
|
|
return m.uri
|
|
}
|
|
|
|
// Run executes a package test suite and terminates any container started by
|
|
// URI. A cleanup failure turns an otherwise successful suite into a failure.
|
|
func (m *Manager) Run(tests *testing.M) int {
|
|
code := tests.Run()
|
|
if m.container == nil {
|
|
return code
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
if err := testcontainers.TerminateContainer(m.container, testcontainers.StopContext(ctx)); err != nil {
|
|
_, _ = fmt.Fprintf(os.Stderr, "ERROR: terminate MongoDB Testcontainer: %v\n", err)
|
|
if code == 0 {
|
|
return 1
|
|
}
|
|
}
|
|
return code
|
|
}
|
|
|
|
func dockerHealthError() (err error) {
|
|
defer func() {
|
|
if recovered := recover(); recovered != nil {
|
|
err = fmt.Errorf("docker provider panic: %v", recovered)
|
|
}
|
|
}()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
provider, err := testcontainers.ProviderDocker.GetProvider()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return provider.Health(ctx)
|
|
}
|