good morning!!!!

Skip to content
Snippets Groups Projects
tester_test.go 5.38 KiB
Newer Older
Garet Halliday's avatar
Garet Halliday committed
package test_test

import (
	"crypto/rand"
Garet Halliday's avatar
Garet Halliday committed
	"encoding/base64"
Garet Halliday's avatar
Garet Halliday committed
	"fmt"
	_ "net/http/pprof"
Garet Halliday's avatar
Garet Halliday committed
	"strings"
Garet Halliday's avatar
Garet Halliday committed
	"github.com/caddyserver/caddy/v2"
Garet Halliday's avatar
Garet Halliday committed
	"github.com/caddyserver/caddy/v2/caddyconfig"
Garet Halliday's avatar
Garet Halliday committed

Garet Halliday's avatar
Garet Halliday committed
	"gfx.cafe/gfx/pggat/lib/auth/credentials"
	"gfx.cafe/gfx/pggat/lib/gat"
Garet Halliday's avatar
Garet Halliday committed
	"gfx.cafe/gfx/pggat/lib/gat/gatcaddyfile"
	pool_handler "gfx.cafe/gfx/pggat/lib/gat/handlers/pool"
	"gfx.cafe/gfx/pggat/lib/gat/handlers/rewrite_password"
	"gfx.cafe/gfx/pggat/lib/gat/matchers"
Garet Halliday's avatar
Garet Halliday committed
	"gfx.cafe/gfx/pggat/lib/gat/pool"
	"gfx.cafe/gfx/pggat/lib/gat/pool/recipe"
Garet Halliday's avatar
Garet Halliday committed
	"gfx.cafe/gfx/pggat/lib/gat/poolers/session"
	"gfx.cafe/gfx/pggat/lib/gat/poolers/transaction"
Garet Halliday's avatar
Garet Halliday committed
	"gfx.cafe/gfx/pggat/test"
	"gfx.cafe/gfx/pggat/test/tests"
Garet Halliday's avatar
Garet Halliday committed
)

Garet Halliday's avatar
Garet Halliday committed
type dialer struct {
	Address  string
	Username string
	Password string
	Database string
}
Garet Halliday's avatar
Garet Halliday committed

Garet Halliday's avatar
Garet Halliday committed
var nextPort int

func randAddress() string {
	nextPort++
	return "/tmp/.s.PGGAT." + strconv.Itoa(nextPort)
}

func resolveNetwork(address string) string {
	if strings.HasPrefix(address, "/") {
		return "unix"
	} else {
		return "tcp"
	}
}

func randPassword() (string, error) {
	var b [20]byte
	_, err := rand.Read(b[:])
	if err != nil {
		return "", err
	}

	return base64.StdEncoding.EncodeToString(b[:]), nil
}

func createServer(parent dialer, poolers map[string]caddy.Module) (server gat.ServerConfig, dialers map[string]dialer, err error) {
	address := randAddress()

	server.Listen = []gat.ListenerConfig{
		{
			Address: address,
		},
	}

	var password string
	password, err = randPassword()
	if err != nil {
		return
	}

	server.Routes = append(
		server.Routes,
		gat.RouteConfig{
			Handle: gatcaddyfile.JSONModuleObject(
				&rewrite_password.Module{
					Password: password,
				},
				gatcaddyfile.Handler,
				"handler",
				nil,
			),
		},
	)

	for name, pooler := range poolers {
		p := pool_handler.Module{
			Config: pool_handler.Config{
				Pooler: gatcaddyfile.JSONModuleObject(
					pooler,
					gatcaddyfile.Pooler,
					"pooler",
					nil,
				),

				ServerAddress: parent.Address,

				ServerUsername: parent.Username,
				ServerPassword: parent.Password,
				ServerDatabase: parent.Database,
			},
Garet Halliday's avatar
Garet Halliday committed

Garet Halliday's avatar
Garet Halliday committed
		server.Routes = append(server.Routes, gat.RouteConfig{
			Match: gatcaddyfile.JSONModuleObject(
				&matchers.Database{
					Database: name,
				},
				gatcaddyfile.Matcher,
				"matcher",
				nil,
			),
			Handle: gatcaddyfile.JSONModuleObject(
				&p,
				gatcaddyfile.Handler,
				"handler",
				nil,
			),
		})

		if dialers == nil {
			dialers = make(map[string]dialer)
		}
		dialers[name] = dialer{
			Address:  address,
			Username: "pooler",
			Password: password,
			Database: name,
		}
	}

	return
}

func daisyChain(config *gat.Config, control dialer, n int) (dialer, error) {
	for i := 0; i < n; i++ {
Garet Halliday's avatar
Garet Halliday committed
		poolConfig := pool.ManagementConfig{}
Garet Halliday's avatar
Garet Halliday committed
		var pooler caddy.Module
		if i%2 == 0 {
Garet Halliday's avatar
Garet Halliday committed
			pooler = &transaction.Module{
				ManagementConfig: poolConfig,
			}
		} else {
Garet Halliday's avatar
Garet Halliday committed
			poolConfig.ServerResetQuery = "DISCARD ALL"
			pooler = &session.Module{
				ManagementConfig: poolConfig,
			}
Garet Halliday's avatar
Garet Halliday committed
		server, dialers, err := createServer(control, map[string]caddy.Module{
			"pool": pooler,
		})
Garet Halliday's avatar
Garet Halliday committed
		if err != nil {
			return dialer{}, err
Garet Halliday's avatar
Garet Halliday committed

		control = dialers["pool"]
		config.Servers = append(config.Servers, server)
Garet Halliday's avatar
Garet Halliday committed
	return control, nil
}

func TestTester(t *testing.T) {
Garet Halliday's avatar
Garet Halliday committed
	control := recipe.Dialer{
Garet Halliday's avatar
Garet Halliday committed
		Network:  "tcp",
		Address:  "localhost:5432",
		Username: "postgres",
		Credentials: credentials.Cleartext{
Garet Halliday's avatar
Garet Halliday committed
			Password: "password",
Garet Halliday's avatar
Garet Halliday committed
		},
Garet Halliday's avatar
Garet Halliday committed
		Database: "postgres",
Garet Halliday's avatar
Garet Halliday committed
	config := gat.Config{}

	parent, err := daisyChain(&config, dialer{
		Address:  "localhost:5432",
		Username: "postgres",
		Password: "password",
		Database: "postgres",
	}, 16)
Garet Halliday's avatar
Garet Halliday committed
	if err != nil {
		t.Error(err)
		return
	}

Garet Halliday's avatar
Garet Halliday committed
	server, dialers, err := createServer(parent, map[string]caddy.Module{
		"transaction": &transaction.Module{},
		"session": &session.Module{
			ManagementConfig: pool.ManagementConfig{
				ServerResetQuery: "discard all",
			},
		},
	})
Garet Halliday's avatar
Garet Halliday committed
	if err != nil {
		t.Error(err)
		return
	}

Garet Halliday's avatar
Garet Halliday committed
	config.Servers = append(config.Servers, server)

	transactionDialer := recipe.Dialer{
		Network:  resolveNetwork(dialers["transaction"].Address),
		Address:  dialers["transaction"].Address,
		Username: dialers["transaction"].Username,
		Credentials: credentials.FromString(
			dialers["transaction"].Username,
			dialers["transaction"].Password,
		),
		Database: "transaction",
Garet Halliday's avatar
Garet Halliday committed
	sessionDialer := recipe.Dialer{
		Network:  resolveNetwork(dialers["transaction"].Address),
		Address:  dialers["session"].Address,
		Username: dialers["session"].Username,
		Credentials: credentials.FromString(
			dialers["session"].Username,
			dialers["session"].Password,
		),
		Database: "session",
Garet Halliday's avatar
Garet Halliday committed
	caddyConfig := caddy.Config{
		AppsRaw: caddy.ModuleMap{
			"pggat": caddyconfig.JSON(config, nil),
		},
	}
Garet Halliday's avatar
Garet Halliday committed
	if err = caddy.Run(&caddyConfig); err != nil {
Garet Halliday's avatar
Garet Halliday committed
		t.Error(err)
		return
	}
Garet Halliday's avatar
Garet Halliday committed
	defer func() {
		_ = caddy.Stop()
	}()

	tester := test.NewTester(test.Config{
Garet Halliday's avatar
Garet Halliday committed
		Stress: 8,
Garet Halliday's avatar
Garet Halliday committed

Garet Halliday's avatar
Garet Halliday committed
		Modes: map[string]recipe.Dialer{
			"control":     control,
			"transaction": transactionDialer,
			"session":     sessionDialer,
Garet Halliday's avatar
Garet Halliday committed
		},
	})
	if err = tester.Run(
Garet Halliday's avatar
Garet Halliday committed
		tests.SimpleQuery,
Garet Halliday's avatar
Garet Halliday committed
		tests.Transaction,
		tests.Sync,
		tests.EQP0,
		tests.EQP1,
		tests.EQP2,
		tests.EQP3,
		tests.EQP4,
		tests.EQP5,
		tests.EQP6,
		tests.EQP7,
Garet Halliday's avatar
Garet Halliday committed
		tests.CopyOut0,
		tests.CopyOut1,
		tests.CopyIn0,
		tests.CopyIn1,
Garet Halliday's avatar
Garet Halliday committed
	); err != nil {
Garet Halliday's avatar
Garet Halliday committed
		fmt.Print(err.Error())
		t.Fail()
Garet Halliday's avatar
Garet Halliday committed
	}
}