Skip to content
quarry Artifact [f7c224617e]
Login

Artifact [f7c224617e]

Artifact f7c224617e103c49f0baf91913acb267ad78cd02ca9e06b351816b96b6b00550:


package oltp

import (
	"context"
	"database/sql"
	"path/filepath"
	"testing"
	"time"
)

func pragmaInt(t *testing.T, db *sql.DB, q string) int {
	t.Helper()
	var n int
	if err := db.QueryRow(q).Scan(&n); err != nil {
		t.Fatalf("%s: %v", q, err)
	}
	return n
}

func TestAccountPoolsRecycle(t *testing.T) {
	oi, ol := connMaxIdleTime, connMaxLifetime
	connMaxIdleTime, connMaxLifetime = 20*time.Millisecond, time.Nanosecond
	defer func() { connMaxIdleTime, connMaxLifetime = oi, ol }()
	d, err := Open(filepath.Join(t.TempDir(), "oltp.db"))
	if err != nil {
		t.Fatal(err)
	}
	defer d.Close()

	var conns []*sql.Conn
	for range 3 {
		c, err := d.db.Conn(context.Background())
		if err != nil {
			t.Fatal(err)
		}
		conns = append(conns, c)
	}
	for _, c := range conns {
		c.Close()
	}
	if got := d.db.Stats().Idle; got > 1 {
		t.Errorf("FAIL: reader pool keeps %d idle, want at most 1", got)
	}
	if got := d.w.Stats().MaxOpenConnections; got != 1 {
		t.Errorf("FAIL: writer pool max open = %d, want 1", got)
	}
	for name, db := range map[string]*sql.DB{"reader": d.db, "writer": d.w} {
		for range 3 {
			// busy_timeout is a per-connection pragma from the DSN; a
			// recycled connection must still carry it.
			if got := pragmaInt(t, db, `PRAGMA busy_timeout`); got != 5000 {
				t.Errorf("FAIL: %s busy_timeout = %d on a recycled connection, want 5000", name, got)
			}
			time.Sleep(2 * time.Millisecond)
		}
		if st := db.Stats(); st.MaxLifetimeClosed == 0 {
			t.Errorf("FAIL: %s pool recycled nothing: policy not applied", name)
		}
	}
	// Idle closure and reopening.
	deadline := time.Now().Add(5 * time.Second)
	for d.db.Stats().OpenConnections != 0 && time.Now().Before(deadline) {
		time.Sleep(10 * time.Millisecond)
	}
	if got := d.db.Stats().OpenConnections; got != 0 {
		t.Errorf("FAIL: %d reader connections open after idle time", got)
	}
	if got := pragmaInt(t, d.db, `PRAGMA busy_timeout`); got != 5000 {
		t.Errorf("FAIL: busy_timeout after reopen = %d", got)
	}
	if !t.Failed() {
		t.Log("ok")
	}
}