mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
# Which Problems Are Solved This PR provides an example for testing DB reduction to relational tables without exploiting integration tests. # How the Problems Are Solved - Set up a disposable embedded Postgres DB used to store the results of the calls to the reducers and verify such results - Add utility method to return transactions from the existing DB pool. These transactions can be used by the single test cases to insert and read data from DB - Add a test to verify that the handler contains the expected reducers (checking also that they are on the right aggregate type) - Add tests to verify the single reduce functions. A parent test creates the required objects to satisfy the foreign key constraints. # Additional Changes - Typo fixed in `postgres.DecodeConfig()` - Discard unneeded `projectionName` parameter for `Executor` function # Additional Context - Closes #11430
117 lines
2.9 KiB
Go
117 lines
2.9 KiB
Go
package projection
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
|
"github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres/embedded"
|
|
v3_sql "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/sql"
|
|
"github.com/zitadel/zitadel/internal/eventstore"
|
|
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
|
)
|
|
|
|
var (
|
|
pool database.PoolTest
|
|
rawDB *sql.DB
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
os.Exit(runTests(m))
|
|
}
|
|
|
|
func runTests(m *testing.M) int {
|
|
var stop func()
|
|
var err error
|
|
ctx := context.Background()
|
|
pool, stop, err = newEmbeddedDB(ctx)
|
|
if err != nil {
|
|
log.Printf("error with embedded postgres database: %v", err)
|
|
return 1
|
|
}
|
|
defer stop()
|
|
|
|
rawDB = pool.RawDB()
|
|
defer rawDB.Close()
|
|
defer pool.Close(ctx)
|
|
|
|
return m.Run()
|
|
}
|
|
|
|
func newEmbeddedDB(ctx context.Context) (pool database.PoolTest, stop func(), err error) {
|
|
connector, stop, err := embedded.StartEmbedded()
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("unable to start embedded postgres: %w", err)
|
|
}
|
|
|
|
dummyPool, err := connector.Connect(ctx)
|
|
if err != nil {
|
|
return nil, stop, fmt.Errorf("unable to connect to embedded postgres: %w", err)
|
|
}
|
|
|
|
pool, ok := dummyPool.(database.PoolTest)
|
|
if !ok {
|
|
return nil, stop, fmt.Errorf("expecting database.PoolTest, got %T", dummyPool)
|
|
}
|
|
|
|
err = pool.MigrateTest(ctx)
|
|
if err != nil {
|
|
return nil, stop, fmt.Errorf("unable to migrate database: %w", err)
|
|
}
|
|
|
|
return pool, stop, err
|
|
}
|
|
|
|
func getTransactions(t *testing.T) (rawTx *sql.Tx, v3SQLTx *v3_sql.Transaction) {
|
|
rawTx, err := rawDB.Begin()
|
|
require.NoError(t, err)
|
|
v3SQLTx = v3_sql.SQLTx(rawTx)
|
|
return
|
|
}
|
|
|
|
// callReduce on the input projection tests that:
|
|
//
|
|
// 1. the aggregate type of the input event exists
|
|
// 2. the event type of the input event exists for that aggregate type
|
|
// 3. the reducer function for the input event is not nil
|
|
// 4. the reducer function for the input event executes without errors
|
|
//
|
|
// Returns false if any of the above checks fails
|
|
func callReduce(t *testing.T, ctx context.Context, tx *sql.Tx, projection handler.Projection, event eventstore.Event) bool {
|
|
reducers := projection.Reducers()
|
|
aggregateReducerIdx := slices.IndexFunc(reducers, func(r handler.AggregateReducer) bool {
|
|
return r.Aggregate == event.Aggregate().Type
|
|
})
|
|
if !assert.Greater(t, aggregateReducerIdx, -1) {
|
|
return false
|
|
}
|
|
|
|
eventReducerIdx := slices.IndexFunc(reducers[aggregateReducerIdx].EventReducers, func(er handler.EventReducer) bool {
|
|
return er.Event == event.Type()
|
|
})
|
|
if !assert.Greater(t, eventReducerIdx, -1) {
|
|
return false
|
|
}
|
|
|
|
reduceFn := reducers[aggregateReducerIdx].EventReducers[eventReducerIdx].Reduce
|
|
if !assert.NotNil(t, reduceFn) {
|
|
return false
|
|
}
|
|
|
|
stmt, err := reduceFn(event)
|
|
if !assert.NoError(t, err) {
|
|
return false
|
|
}
|
|
|
|
err = stmt.Execute(ctx, tx, "")
|
|
return assert.NoError(t, err)
|
|
}
|