package test_test import ( "crypto/rand" "encoding/hex" "fmt" "net" _ "net/http/pprof" "strconv" "testing" "pggat/lib/auth" "pggat/lib/auth/credentials" "pggat/lib/bouncer/backends/v0" "pggat/lib/bouncer/frontends/v0" "pggat/lib/gat" "pggat/lib/gat/pool" "pggat/lib/gat/pool/dialer" "pggat/lib/gat/pool/pools/session" "pggat/lib/gat/pool/pools/transaction" "pggat/lib/gat/pool/recipe" "pggat/test" "pggat/test/tests" ) func daisyChain(creds auth.Credentials, control dialer.Net, n int) (dialer.Net, error) { for i := 0; i < n; i++ { var g gat.PoolsMap var options = pool.Options{ Credentials: creds, } if i%2 == 0 { options = transaction.Apply(options) } else { options.ServerResetQuery = "DISCARD ALL" options = session.Apply(options) } p := pool.NewPool(options) p.AddRecipe("runner", recipe.NewRecipe(recipe.Options{ Dialer: control, })) g.Add("runner", "pool", p) listener, err := gat.Listen("tcp", ":0", frontends.AcceptOptions{}) if err != nil { return dialer.Net{}, err } port := listener.Listener.Addr().(*net.TCPAddr).Port go func() { err := gat.Serve(listener, &g) if err != nil { panic(err) } }() control = dialer.Net{ Network: "tcp", Address: ":" + strconv.Itoa(port), AcceptOptions: backends.AcceptOptions{ Credentials: creds, Database: "pool", }, } } return control, nil } func TestTester(t *testing.T) { control := dialer.Net{ Network: "tcp", Address: "localhost:5432", AcceptOptions: backends.AcceptOptions{ Credentials: credentials.Cleartext{ Username: "postgres", Password: "password", }, Database: "postgres", }, } // generate random password for testing var raw [32]byte _, err := rand.Read(raw[:]) if err != nil { t.Error(err) return } password := hex.EncodeToString(raw[:]) creds := credentials.Cleartext{ Username: "runner", Password: password, } parent, err := daisyChain(creds, control, 16) if err != nil { t.Error(err) return } var g gat.PoolsMap transactionPool := pool.NewPool(transaction.Apply(pool.Options{ Credentials: creds, })) transactionPool.AddRecipe("runner", recipe.NewRecipe(recipe.Options{ Dialer: parent, })) g.Add("runner", "transaction", transactionPool) sessionPool := pool.NewPool(session.Apply(pool.Options{ Credentials: creds, ServerResetQuery: "discard all", })) sessionPool.AddRecipe("runner", recipe.NewRecipe(recipe.Options{ Dialer: parent, })) g.Add("runner", "session", sessionPool) listener, err := gat.Listen("tcp", ":0", frontends.AcceptOptions{}) if err != nil { t.Error(err) return } port := listener.Listener.Addr().(*net.TCPAddr).Port go func() { err := gat.Serve(listener, &g) if err != nil { t.Error(err) } }() transactionDialer := dialer.Net{ Network: "tcp", Address: ":" + strconv.Itoa(port), AcceptOptions: backends.AcceptOptions{ Credentials: creds, Database: "transaction", }, } sessionDialer := dialer.Net{ Network: "tcp", Address: ":" + strconv.Itoa(port), AcceptOptions: backends.AcceptOptions{ Credentials: creds, Database: "session", }, } tester := test.NewTester(test.Config{ Stress: 8, Modes: map[string]dialer.Dialer{ "control": control, "transaction": transactionDialer, "session": sessionDialer, }, }) if err = tester.Run( tests.SimpleQuery, tests.Transaction, tests.Sync, tests.EQP0, tests.EQP1, tests.EQP2, tests.EQP3, tests.EQP4, tests.EQP5, tests.EQP6, tests.EQP7, tests.EQP8, tests.CopyOut0, tests.CopyOut1, tests.CopyIn0, tests.CopyIn1, tests.DiscardAll, ); err != nil { fmt.Print(err.Error()) t.Fail() } }