diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 949adf9..f2a18c7 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -254,49 +254,44 @@ jobs: - name: Test working-directory: bugulma/backend run: | - # Check if we're skipping PostgreSQL (act environment) - if [ "$SKIP_POSTGRESQL" = "true" ]; then - echo "โš  PostgreSQL was skipped (local runner environment)" - echo "โš  Running only non-database tests..." - # Run only non-database dependent tests - # These packages don't require database: geospatial, financial, graph, matching/plugins, middleware, pkg - go test -v -coverprofile=coverage.out \ - ./internal/geospatial/... \ - ./internal/financial/... \ - ./internal/graph/... \ - ./internal/matching/plugins/... \ - ./internal/middleware/... \ - ./pkg/... \ - || echo "โš  Some non-database tests may have failed" + # Check if Docker is available for testcontainers + if command -v docker &> /dev/null && docker info &> /dev/null; then + echo "โœ… Docker available - running all tests with testcontainers" + echo "๐Ÿงช Testcontainers will provide isolated PostgreSQL instances" - echo "โš  Database-dependent tests were skipped due to PostgreSQL not being available" - echo "โœ… Non-database tests completed" - exit 0 - fi + # Check if CGO is available for race detector + CGO_AVAILABLE="${{ steps.cgo-setup.outputs.cgo_available || '0' }}" - # Normal testing with PostgreSQL available - # Check if CGO is available for race detector - CGO_AVAILABLE="${{ steps.cgo-setup.outputs.cgo_available || '0' }}" + # Build test command + TEST_CMD="go test -v" - # Build test command - TEST_CMD="go test -v" + # Add race detector if CGO is available + if [ "$CGO_AVAILABLE" = "1" ] && command -v gcc &> /dev/null; then + echo "Running tests with race detector..." + TEST_CMD="$TEST_CMD -race" + export CGO_ENABLED=1 + else + echo "Running tests without race detector (CGO not available)..." + export CGO_ENABLED=0 + fi + + # Add coverage + TEST_CMD="$TEST_CMD -coverprofile=coverage.out" + + # Run all tests (testcontainers will handle database isolation) + echo "Running all tests with testcontainers..." + $TEST_CMD ./... - # Add race detector if CGO is available - if [ "$CGO_AVAILABLE" = "1" ] && command -v gcc &> /dev/null; then - echo "Running tests with race detector..." - TEST_CMD="$TEST_CMD -race" - export CGO_ENABLED=1 else - echo "Running tests without race detector (CGO not available)..." - export CGO_ENABLED=0 + echo "โš  Docker not available - falling back to unit tests only" + echo "โš  Integration tests require Docker for testcontainers" + + # Run only unit tests (integration tests are excluded by build tags) + go test -v -coverprofile=coverage.out ./... + + echo "โš  Integration tests were skipped due to Docker not being available" + echo "โœ… Unit tests completed" fi - - # Add coverage - TEST_CMD="$TEST_CMD -coverprofile=coverage.out" - - # Run all tests - echo "Running all tests (including database tests)..." - $TEST_CMD ./... env: GO111MODULE: on GOPROXY: https://proxy.golang.org,direct diff --git a/bugulma/backend/TESTING.md b/bugulma/backend/TESTING.md index 12c6e59..0e67628 100644 --- a/bugulma/backend/TESTING.md +++ b/bugulma/backend/TESTING.md @@ -96,13 +96,15 @@ go test -parallel 4 ./... func TestMyFeature(t *testing.T) { t.Parallel() - // Setup PostgreSQL test database - db := testutils.SetupTestDB(t) + // Setup PostgreSQL test database with testcontainers + // Spins up an isolated PostgreSQL container for this test + db := testutils.SetupTestDBWithTestcontainers(t) // Use database - migrations already applied repo := repository.NewMyRepository(db) // Your test code here + // Container automatically cleaned up when test ends } ``` @@ -110,8 +112,9 @@ func TestMyFeature(t *testing.T) { ```go BeforeEach(func() { - // Setup PostgreSQL test database - db = testutils.SetupTestDB(GinkgoT()) + // Setup PostgreSQL test database with testcontainers + // Each test gets its own isolated PostgreSQL container + db = testutils.SetupTestDBWithTestcontainers(GinkgoT()) // Initialize repositories/services repo = repository.NewMyRepository(db) @@ -122,8 +125,9 @@ BeforeEach(func() { ```go func (suite *MyTestSuite) SetupTest() { - // Setup PostgreSQL test database - suite.db = testutils.SetupTestDB(suite.T()) + // Setup PostgreSQL test database with testcontainers + // Container automatically managed and cleaned up + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) suite.repo = repository.NewMyRepository(suite.db) } ``` @@ -236,15 +240,16 @@ env: - -c synchronous_commit=off ``` -## Migration from SQLite +## Migration to Testcontainers -All tests have been migrated from SQLite to PostgreSQL. Key changes: +All tests have been migrated to use **testcontainers** for database isolation. Key changes: -- โœ… `SetupTestDB()` now requires `*testing.T` parameter -- โœ… Tests use real PostgreSQL with all features -- โœ… PostGIS spatial operations work correctly -- โœ… GIN indexes and JSONB queries supported -- โœ… No more SQLite compatibility issues +- โœ… `SetupTestDBWithTestcontainers()` provides isolated PostgreSQL containers per test +- โœ… No local PostgreSQL setup required - works anywhere Docker is available +- โœ… Each test gets a fresh database with automatic cleanup +- โœ… Real PostgreSQL + PostGIS for accurate integration testing +- โœ… CI/CD runs all tests when Docker available, unit tests only when not +- โœ… Perfect test isolation prevents interference between tests ## Database Backup diff --git a/bugulma/backend/TEST_ISOLATION.md b/bugulma/backend/TEST_ISOLATION.md index 2fe025e..9f3ed94 100644 --- a/bugulma/backend/TEST_ISOLATION.md +++ b/bugulma/backend/TEST_ISOLATION.md @@ -4,19 +4,19 @@ ### How Tests Are Isolated -**pgtestdb** ensures complete isolation between tests and production data: +**Testcontainers** provides superior isolation by giving each test its own PostgreSQL container: -1. **Separate Databases**: Each test creates a unique temporary database - - Format: `pgtestdb_` - - Created in the `postgres` admin database - - Production database `turash` is NEVER accessed +1. **Container Isolation**: Each test gets a dedicated PostgreSQL + PostGIS container + - No shared databases between tests + - Complete process isolation (separate containers) + - Automatic cleanup when test finishes 2. **Connection Flow**: ``` - Test โ†’ Connects to 'postgres' database โ†’ Creates 'pgtestdb_abc123' โ†’ Runs migrations โ†’ Executes test โ†’ Drops 'pgtestdb_abc123' + Test โ†’ Starts PostgreSQL container โ†’ Runs migrations โ†’ Executes test โ†’ Stops & removes container ``` -3. **Production Database**: The `turash` database remains completely untouched +3. **Production Database**: Zero risk - containers are completely separate from any production setup ### Verification @@ -125,13 +125,10 @@ go run ./cmd/backup restore backups/turash_backup_20250124_120000.sql.gz --conn ### What Happens When You Run Tests -1. **Test Starts**: `SetupTestDB(t)` is called -2. **Connection**: Connects to `postgres` database (admin, not production) -3. **Template Check**: Checks if template database exists (by Hash()) -4. **Template Creation** (first time only): - - Creates `pgtestdb_template_` - - Runs all migrations - - Sets up PostGIS, indexes, constraints +1. **Test Starts**: `SetupTestDBWithTestcontainers(t)` is called +2. **Container Creation**: Spins up isolated PostgreSQL + PostGIS container +3. **Database Setup**: Creates fresh database with all migrations applied +4. **PostGIS Setup**: Enables PostGIS extension and runs spatial migrations 5. **Test Database**: Clones template โ†’ `pgtestdb_` 6. **Test Execution**: Your test code runs against cloned database 7. **Cleanup**: Test database is automatically dropped diff --git a/bugulma/backend/go.mod b/bugulma/backend/go.mod index c03415a..d29f9b1 100644 --- a/bugulma/backend/go.mod +++ b/bugulma/backend/go.mod @@ -19,6 +19,8 @@ require ( github.com/peterldowns/pgtestdb v0.1.1 github.com/spf13/cobra v1.10.1 github.com/stretchr/testify v1.11.1 + github.com/testcontainers/testcontainers-go v0.40.0 + github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 golang.org/x/crypto v0.45.0 gorm.io/datatypes v1.2.7 gorm.io/driver/postgres v1.6.0 @@ -27,18 +29,35 @@ require ( ) require ( + dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/bytedance/gopkg v0.1.3 // indirect github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.5.1+incompatible // indirect + github.com/docker/go-connections v0.6.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/gabriel-vasile/mimetype v1.4.11 // indirect github.com/gin-contrib/sse v1.1.0 // indirect github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.28.0 // indirect @@ -48,6 +67,7 @@ require ( github.com/goccy/go-yaml v1.18.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -57,19 +77,45 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.1.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/quic-go v0.57.0 // indirect + github.com/shirou/gopsutil/v4 v4.25.6 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/stretchr/objx v0.5.2 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect go.uber.org/mock v0.6.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.23.0 // indirect @@ -79,6 +125,7 @@ require ( golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect golang.org/x/tools v0.39.0 // indirect + google.golang.org/grpc v1.75.1 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/mysql v1.6.0 // indirect diff --git a/bugulma/backend/go.sum b/bugulma/backend/go.sum index 324c67c..b12206e 100644 --- a/bugulma/backend/go.sum +++ b/bugulma/backend/go.sum @@ -1,5 +1,9 @@ +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= @@ -12,6 +16,8 @@ github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPII github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980= github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o= github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= @@ -20,7 +26,15 @@ github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -30,12 +44,14 @@ github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4= github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= -github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM= +github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= @@ -52,10 +68,13 @@ github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZ github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -74,8 +93,6 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-migrate/migrate/v4 v4.19.0 h1:RcjOnCGz3Or6HQYEJ/EEVLfWnmw9KnoigPSjzhCuaSE= @@ -84,6 +101,7 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0kt github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -93,6 +111,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -118,6 +138,8 @@ github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -128,18 +150,36 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= +github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -161,8 +201,8 @@ github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/peterldowns/pgtestdb v0.1.1 h1:+hBCD1DcbKeg5Sfg0G+5WNIy/Cm0ORgwMkF4ygihrmU= @@ -173,6 +213,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= github.com/quic-go/quic-go v0.57.0 h1:AsSSrrMs4qI/hLrKlTH/TGQeTMY0ib1pAOX7vA3AdqE= @@ -180,6 +222,10 @@ github.com/quic-go/quic-go v0.57.0/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlo github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs= +github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= @@ -197,6 +243,10 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= +github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= +github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 h1:s2bIayFXlbDFexo96y+htn7FzuhpXLYJNnIuglNKqOk= +github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0/go.mod h1:h+u/2KoREGTnTl9UwrQ/g+XhasAT8E6dClclAADeXoQ= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -205,20 +255,34 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= @@ -235,15 +299,31 @@ golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4 h1:8XJ4pajGwOlasW+L13MnEGA8W4115jJySQtVfS2/IBU= +google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4/go.mod h1:NnuHhy+bxcg30o7FnVAZbXsPHUDQ9qKWAQKCD7VxFtk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 h1:i8QOKZfYg6AbGVZzUAY3LrNWCKF8O6zFisU9Wl9RER4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= +google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -266,3 +346,5 @@ gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc= gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw= gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= diff --git a/bugulma/backend/internal/handler/auth_handler_test.go b/bugulma/backend/internal/handler/auth_handler_test.go index d2fcf46..8f5953c 100644 --- a/bugulma/backend/internal/handler/auth_handler_test.go +++ b/bugulma/backend/internal/handler/auth_handler_test.go @@ -33,7 +33,7 @@ var _ = Describe("AuthHandler", func() { gin.SetMode(gin.TestMode) // Setup PostgreSQL test database using pgtestdb - db = testutils.SetupTestDBForGinkgo(GinkgoT()) + db = testutils.SetupTestDBWithTestcontainers(GinkgoT()) userRepo = repository.NewUserRepository(db) authService = service.NewAuthService(userRepo, "secret-key") diff --git a/bugulma/backend/internal/handler/heritage_handler_test.go b/bugulma/backend/internal/handler/heritage_handler_test.go index a000ac4..bf5e1ac 100644 --- a/bugulma/backend/internal/handler/heritage_handler_test.go +++ b/bugulma/backend/internal/handler/heritage_handler_test.go @@ -33,7 +33,7 @@ var _ = Describe("HeritageHandler", func() { gin.SetMode(gin.TestMode) // Setup PostgreSQL test database - db = testutils.SetupTestDBForGinkgo(GinkgoT()) + db = testutils.SetupTestDBWithTestcontainers(GinkgoT()) heritageRepo = repository.NewHeritageRepository(db) heritageHandler = handler.NewHeritageHandler(heritageRepo) diff --git a/bugulma/backend/internal/handler/matching_handler_test.go b/bugulma/backend/internal/handler/matching_handler_test.go index 7fe1a4f..e00693a 100644 --- a/bugulma/backend/internal/handler/matching_handler_test.go +++ b/bugulma/backend/internal/handler/matching_handler_test.go @@ -1,3 +1,4 @@ + package handler_test import ( @@ -40,7 +41,7 @@ var _ = Describe("MatchingHandler", func() { // Setup PostgreSQL test database using pgtestdb // Each test gets an isolated database with migrations already applied - db = testutils.SetupTestDBForGinkgo(GinkgoT()) + db = testutils.SetupTestDBWithTestcontainers(GinkgoT()) matchRepo = repository.NewMatchRepository(db) resourceRepo = repository.NewResourceFlowRepository(db) diff --git a/bugulma/backend/internal/handler/organization_handler_test.go b/bugulma/backend/internal/handler/organization_handler_test.go index f6edc5f..5db331f 100644 --- a/bugulma/backend/internal/handler/organization_handler_test.go +++ b/bugulma/backend/internal/handler/organization_handler_test.go @@ -1,3 +1,4 @@ + package handler_test import ( @@ -32,7 +33,7 @@ var _ = Describe("OrganizationHandler", func() { gin.SetMode(gin.TestMode) // Setup PostgreSQL test database using pgtestdb - db = testutils.SetupTestDBForGinkgo(GinkgoT()) + db = testutils.SetupTestDBWithTestcontainers(GinkgoT()) orgRepo = repository.NewOrganizationRepository(db) orgService = service.NewOrganizationService(orgRepo, nil) // No graph repo for tests diff --git a/bugulma/backend/internal/handler/resource_flow_handler_test.go b/bugulma/backend/internal/handler/resource_flow_handler_test.go index 9be2f5d..074ef1c 100644 --- a/bugulma/backend/internal/handler/resource_flow_handler_test.go +++ b/bugulma/backend/internal/handler/resource_flow_handler_test.go @@ -36,7 +36,7 @@ var _ = Describe("ResourceFlowHandler", func() { gin.SetMode(gin.TestMode) // Setup PostgreSQL test database using pgtestdb - db = testutils.SetupTestDBForGinkgo(GinkgoT()) + db = testutils.SetupTestDBWithTestcontainers(GinkgoT()) resourceRepo = repository.NewResourceFlowRepository(db) organizationRepo = repository.NewOrganizationRepository(db) diff --git a/bugulma/backend/internal/handler/site_handler_test.go b/bugulma/backend/internal/handler/site_handler_test.go index 9b5a0b7..fb836ba 100644 --- a/bugulma/backend/internal/handler/site_handler_test.go +++ b/bugulma/backend/internal/handler/site_handler_test.go @@ -34,7 +34,7 @@ var _ = Describe("SiteHandler", func() { gin.SetMode(gin.TestMode) // Setup PostgreSQL test database using pgtestdb - db = testutils.SetupTestDBForGinkgo(GinkgoT()) + db = testutils.SetupTestDBWithTestcontainers(GinkgoT()) siteRepo = repository.NewSiteRepository(db) organizationRepo = repository.NewOrganizationRepository(db) diff --git a/bugulma/backend/internal/repository/geographical_feature_repository_test.go b/bugulma/backend/internal/repository/geographical_feature_repository_test.go index 3609386..be08fa4 100644 --- a/bugulma/backend/internal/repository/geographical_feature_repository_test.go +++ b/bugulma/backend/internal/repository/geographical_feature_repository_test.go @@ -1,3 +1,4 @@ + package repository_test import ( @@ -21,7 +22,7 @@ type GeographicalFeatureRepositoryTestSuite struct { } func (suite *GeographicalFeatureRepositoryTestSuite) SetupTest() { - suite.db = testutils.SetupTestDB(suite.T()) + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) // Ensure geographical_features table exists (without PostGIS if not available) suite.ensureGeographicalFeaturesTable() diff --git a/bugulma/backend/internal/repository/resource_flow_repository_test.go b/bugulma/backend/internal/repository/resource_flow_repository_test.go index 634a099..45da316 100644 --- a/bugulma/backend/internal/repository/resource_flow_repository_test.go +++ b/bugulma/backend/internal/repository/resource_flow_repository_test.go @@ -1,3 +1,4 @@ + package repository_test import ( @@ -25,7 +26,7 @@ type ResourceFlowRepositoryTestSuite struct { func (suite *ResourceFlowRepositoryTestSuite) SetupTest() { // Setup PostgreSQL test database using pgtestdb - suite.db = testutils.SetupTestDB(suite.T()) + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) suite.repo = repository.NewResourceFlowRepository(suite.db) suite.orgRepo = repository.NewOrganizationRepository(suite.db) suite.siteRepo = repository.NewSiteRepository(suite.db) diff --git a/bugulma/backend/internal/repository/site_repository_test.go b/bugulma/backend/internal/repository/site_repository_test.go index 6ce2613..6f5fcfb 100644 --- a/bugulma/backend/internal/repository/site_repository_test.go +++ b/bugulma/backend/internal/repository/site_repository_test.go @@ -1,3 +1,4 @@ + package repository_test import ( @@ -23,7 +24,7 @@ type SiteRepositoryTestSuite struct { func (suite *SiteRepositoryTestSuite) SetupTest() { // Setup PostgreSQL test database using pgtestdb - suite.db = testutils.SetupTestDB(suite.T()) + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) suite.repo = repository.NewSiteRepository(suite.db) suite.orgRepo = repository.NewOrganizationRepository(suite.db) } diff --git a/bugulma/backend/internal/service/environmental_impact_service_test.go b/bugulma/backend/internal/service/environmental_impact_service_test.go index 05caeef..9dce208 100644 --- a/bugulma/backend/internal/service/environmental_impact_service_test.go +++ b/bugulma/backend/internal/service/environmental_impact_service_test.go @@ -1,3 +1,4 @@ + package service_test import ( @@ -27,7 +28,7 @@ type EnvironmentalImpactServiceTestSuite struct { } func (suite *EnvironmentalImpactServiceTestSuite) SetupTest() { - suite.db = testutils.SetupTestDB(suite.T()) + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) suite.siteRepo = repository.NewSiteRepository(suite.db) suite.geoRepo = repository.NewGeographicalFeatureRepository(suite.db) suite.geospatialSvc = service.NewGeospatialService(suite.db, suite.geoRepo) diff --git a/bugulma/backend/internal/service/facility_location_optimizer_test.go b/bugulma/backend/internal/service/facility_location_optimizer_test.go index 3ed5f43..159c757 100644 --- a/bugulma/backend/internal/service/facility_location_optimizer_test.go +++ b/bugulma/backend/internal/service/facility_location_optimizer_test.go @@ -1,3 +1,4 @@ + package service_test import ( @@ -30,7 +31,7 @@ type FacilityLocationOptimizerTestSuite struct { } func (suite *FacilityLocationOptimizerTestSuite) SetupTest() { - suite.db = testutils.SetupTestDB(suite.T()) + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) suite.siteRepo = repository.NewSiteRepository(suite.db) suite.geoRepo = repository.NewGeographicalFeatureRepository(suite.db) suite.geoSvc = service.NewGeospatialService(suite.db, suite.geoRepo) diff --git a/bugulma/backend/internal/service/geographical_data_migration_service_test.go b/bugulma/backend/internal/service/geographical_data_migration_service_test.go index 765a9cd..f49a9e2 100644 --- a/bugulma/backend/internal/service/geographical_data_migration_service_test.go +++ b/bugulma/backend/internal/service/geographical_data_migration_service_test.go @@ -1,3 +1,4 @@ + package service_test import ( @@ -29,7 +30,7 @@ type GeographicalDataMigrationServiceTestSuite struct { } func (suite *GeographicalDataMigrationServiceTestSuite) SetupTest() { - suite.db = testutils.SetupTestDB(suite.T()) + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) suite.siteRepo = repository.NewSiteRepository(suite.db) suite.geoRepo = repository.NewGeographicalFeatureRepository(suite.db) diff --git a/bugulma/backend/internal/service/resource_flow_service_test.go b/bugulma/backend/internal/service/resource_flow_service_test.go index 2937a1b..b93c09a 100644 --- a/bugulma/backend/internal/service/resource_flow_service_test.go +++ b/bugulma/backend/internal/service/resource_flow_service_test.go @@ -1,3 +1,4 @@ + package service_test import ( @@ -26,7 +27,7 @@ type ResourceFlowServiceTestSuite struct { func (suite *ResourceFlowServiceTestSuite) SetupTest() { // Setup PostgreSQL test database using pgtestdb - suite.db = testutils.SetupTestDB(suite.T()) + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) suite.repo = repository.NewResourceFlowRepository(suite.db) suite.orgRepo = repository.NewOrganizationRepository(suite.db) suite.siteRepo = repository.NewSiteRepository(suite.db) diff --git a/bugulma/backend/internal/service/site_service_test.go b/bugulma/backend/internal/service/site_service_test.go index 00f68a7..0b0887f 100644 --- a/bugulma/backend/internal/service/site_service_test.go +++ b/bugulma/backend/internal/service/site_service_test.go @@ -1,3 +1,4 @@ + package service_test import ( @@ -26,7 +27,7 @@ type SiteServiceTestSuite struct { func (suite *SiteServiceTestSuite) SetupTest() { // Setup PostgreSQL test database using pgtestdb - suite.db = testutils.SetupTestDB(suite.T()) + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) suite.repo = repository.NewSiteRepository(suite.db) suite.orgRepo = repository.NewOrganizationRepository(suite.db) suite.svc = service.NewSiteService(suite.repo) diff --git a/bugulma/backend/internal/service/spatial_resource_matcher_test.go b/bugulma/backend/internal/service/spatial_resource_matcher_test.go index 19a7d60..3aa72c9 100644 --- a/bugulma/backend/internal/service/spatial_resource_matcher_test.go +++ b/bugulma/backend/internal/service/spatial_resource_matcher_test.go @@ -28,7 +28,7 @@ type SpatialResourceMatcherTestSuite struct { } func (suite *SpatialResourceMatcherTestSuite) SetupTest() { - suite.db = testutils.SetupTestDB(suite.T()) + suite.db = testutils.SetupTestDBWithTestcontainers(suite.T()) suite.siteRepo = repository.NewSiteRepository(suite.db) suite.flowRepo = repository.NewResourceFlowRepository(suite.db) suite.geoSvc = service.NewGeospatialService(suite.db, nil) // We'll test without geo features for basic functionality diff --git a/bugulma/backend/internal/testutils/db.go b/bugulma/backend/internal/testutils/db.go index bbe2ffb..c9be6ba 100644 --- a/bugulma/backend/internal/testutils/db.go +++ b/bugulma/backend/internal/testutils/db.go @@ -10,11 +10,15 @@ import ( "strings" "syscall" "testing" + "time" "bugulma/backend/internal/domain" _ "github.com/jackc/pgx/v5/stdlib" "github.com/peterldowns/pgtestdb" + "github.com/testcontainers/testcontainers-go" + tcpostgres "github.com/testcontainers/testcontainers-go/modules/postgres" + "github.com/testcontainers/testcontainers-go/wait" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" @@ -314,6 +318,7 @@ func (w *ginkgoTBWrapper) Skipf(format string, args ...interface{}) { } // SetupTestDB creates an isolated PostgreSQL database for testing using pgtestdb +// DEPRECATED: Use SetupTestDBWithTestcontainers() for better isolation and no local PostgreSQL requirement // Each test gets its own temporary database with migrations already applied // This function accepts testing.TB interface, compatible with *testing.T // @@ -329,6 +334,7 @@ func SetupTestDB(t testing.TB) *gorm.DB { } // SetupTestDBForGinkgo creates an isolated PostgreSQL database for Ginkgo tests +// DEPRECATED: Use SetupTestDBWithTestcontainers() for better isolation and no local PostgreSQL requirement // Use this function in Ginkgo BeforeEach blocks // // Example usage: @@ -458,15 +464,80 @@ func setupTestDBWithTB(t interface { return gormDB } -// getFreeDiskBytes returns number of free bytes available on the filesystem -// containing the given path. Returns error if unable to determine. -func getFreeDiskBytes(path string) (uint64, error) { - var stat syscall.Statfs_t - if err := syscall.Statfs(path, &stat); err != nil { - return 0, err +// SetupTestDBWithTestcontainers creates an isolated PostgreSQL database for testing using testcontainers +// This spins up a PostgreSQL container for each test, providing perfect isolation +// Recommended for CI environments where Docker is available +// +// Example usage: +// +// func TestWithTestcontainers(t *testing.T) { +// db := testutils.SetupTestDBWithTestcontainers(t) +// // Your test code here - will have its own PostgreSQL container +// } +func SetupTestDBWithTestcontainers(t testing.TB) *gorm.DB { + t.Helper() + + ctx := context.Background() + + // Start PostgreSQL container with PostGIS support + pgContainer, err := tcpostgres.Run(ctx, + "postgis/postgis:15-3.4-alpine", // Use PostGIS-enabled image + tcpostgres.WithDatabase("testdb"), + tcpostgres.WithUsername("testuser"), + tcpostgres.WithPassword("testpass"), + testcontainers.WithWaitStrategy( + wait.ForLog("database system is ready to accept connections"). + WithOccurrence(2). + WithStartupTimeout(30*time.Second)), // Longer timeout for PostGIS + ) + if err != nil { + t.Fatalf("Failed to start PostgreSQL container: %v", err) } - // Available blocks * block size - return stat.Bavail * uint64(stat.Bsize), nil + + t.Cleanup(func() { + if err := pgContainer.Terminate(ctx); err != nil { + t.Logf("Failed to terminate PostgreSQL container: %v", err) + } + }) + + // Get connection string directly from container + dsn, err := pgContainer.ConnectionString(ctx, "sslmode=disable") + if err != nil { + t.Fatalf("Failed to get connection string: %v", err) + } + + // Connect to database + sqlDB, err := sql.Open("pgx", dsn) + if err != nil { + t.Fatalf("Failed to connect to database: %v", err) + } + + // Verify PostGIS is available + if err := enablePostGISExtension(sqlDB); err != nil { + t.Logf("Warning: Failed to enable PostGIS: %v", err) + } + + // Create GORM connection + gormDB, err := gorm.Open(postgres.New(postgres.Config{ + Conn: sqlDB, + }), &gorm.Config{ + Logger: logger.Default.LogMode(logger.Silent), + }) + if err != nil { + t.Fatalf("Failed to create GORM connection: %v", err) + } + + // Run migrations + if err := domain.AutoMigrate(gormDB); err != nil { + t.Fatalf("Failed to run migrations: %v", err) + } + + // Try to enable PostGIS extensions + if err := domain.RunPostGISMigrations(gormDB); err != nil { + t.Logf("Warning: PostGIS migrations failed (expected in test environment): %v", err) + } + + return gormDB } // cleanupGeometryColumns removes geometry-related columns and constraints when PostGIS is not available @@ -521,3 +592,14 @@ func cleanupGeometryColumns(db *gorm.DB) error { return nil } + +// getFreeDiskBytes returns number of free bytes available on the filesystem +// containing the given path. Returns error if unable to determine. +func getFreeDiskBytes(path string) (uint64, error) { + var stat syscall.Statfs_t + if err := syscall.Statfs(path, &stat); err != nil { + return 0, err + } + // Available blocks * block size + return stat.Bavail * uint64(stat.Bsize), nil +} diff --git a/bugulma/backend/internal/testutils/db_test.go b/bugulma/backend/internal/testutils/db_test.go index 56aa46d..d650cb2 100644 --- a/bugulma/backend/internal/testutils/db_test.go +++ b/bugulma/backend/internal/testutils/db_test.go @@ -8,10 +8,12 @@ import ( "github.com/stretchr/testify/assert" ) -func TestSetupTestDB(t *testing.T) { +func TestSetupTestDBWithTestcontainers(t *testing.T) { t.Parallel() - db := SetupTestDB(t) + // Test the testcontainers-based database setup + // This verifies that PostgreSQL containers start correctly and migrations run + db := SetupTestDBWithTestcontainers(t) assert.NotNil(t, db) // Test creating an organization first (required for foreign key constraints)