module PG::Testing

A PostgreSQL server for tests: the one PG_TEST_URL names, or else a throwaway cluster this module makes with the server's own programs (initdb and pg_ctl from /usr/lib/postgresql/*/bin), in a temporary directory, on a random port of 127.0.0.1 and a private socket directory, with SCRAM-SHA-256 for every connection, removed when it is stopped. For tests only: it starts processes and writes files, and its password comes from the default random generator, which a test's srand makes predictable.

PG::Testing.with_cluster do |url|
  conn = PG.connect(url)
  conn.exec("CREATE TABLE t (id int)")
end

In a Test::Case, start one for the class and omit its tests when there is none:

class UsersTest < Test::Case
  SERVER = Atom[PG::Testing::Server | String].new("not started")

  def self.startup
    SERVER.set(PG::Testing.start_or_reason)
  end

  def self.shutdown
    case SERVER.get
    in PG::Testing::Server => s then s.stop
    else nil
    end
  end

  def url -> String
    case SERVER.get
    in PG::Testing::Server => s then s.url
    in String => why then omit(why)
    end
  end
end

src/testing.qz:43

Classes and modules

Class methods

def self.start(*, hba: Array[String] = …, certificate: String? = …, private_key: String? = …) -> PG::Testing::Server

A server: PG_TEST_URL's when it is set, else a new cluster, whose superuser is quarz and whose pg_hba.conf starts with the lines hba gives ("host all md5_user 127.0.0.1/32 md5"), before SCRAM-SHA-256 for every connection (hba does nothing to PG_TEST_URL's server: check Server#ours? before relying on it). Raises Unavailable when there is neither.

Given a certificate (PEM, the server's own first) and its private_key (PEM), it is always a new cluster, with TLS on (ssl = on, those files as ssl_cert_file and ssl_key_file): PG_TEST_URL's server is not used, and a hostssl line in hba takes effect.

src/testing.qz:98

def self.start_or_reason(*, hba: Array[String] = …, certificate: String? = …, private_key: String? = …) -> PG::Testing::Server | String

start, or why there is no server: for a test class's startup, whose tests then omit with the reason.

src/testing.qz:144

def self.with_cluster[R](*, hba: Array[String] = …, certificate: String? = …, private_key: String? = …, &: (String) -> R) -> R

Runs the block with the URL of a server (start), and stops it afterwards (hba, certificate and private_key as for start).

src/testing.qz:153