Help us shape the future of Go! Take the 2026 Go Developer Survey

stack

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Overview

Package stack runs the whole Web UI for integration tests, the way the program does: a real PostgreSQL (see pgenv), the scripted ADK agent behind a switch that can make it vanish, and the application served by the production server type, so that starting and shutting down are tested too.

Tests talk to it over HTTP with a Client. They can also look into the database through Pool, and at what the agent saw through Model.

It needs Docker (for PostgreSQL).

Index

Constants

View Source
const (
	Email    = "owner@example.com"
	Password = "a-long-enough-password"
)

The first user of every stack.

Variables

This section is empty.

Functions

func Attr

func Attr(n *html.Node, key string) string

Attr is the value of an attribute, or "".

func Doc

func Doc(t testing.TB, markup string) *html.Node

Doc parses an HTML page or fragment, as a browser would.

func Find

func Find(n *html.Node, match func(*html.Node) bool) *html.Node

Find returns the first node under n (n included) that match accepts, or nil.

func FindAll

func FindAll(n *html.Node, match func(*html.Node) bool) []*html.Node

FindAll returns every node under n (n included) that match accepts, in document order.

func TestID

func TestID(id string) func(*html.Node) bool

TestID matches the element with the data-testid.

func Text

func Text(n *html.Node) string

Text is the text under n that a reader would see: not what is in scripts or styles. Runs of white space are kept as they are.

Types

type Agent

type Agent struct {
	*httptest.Server
	// contains filtered or unexported fields
}

Agent is the scripted agent behind a switch. While it is down, a request is dropped without an answer, as when the process is gone.

func (*Agent) Down

func (a *Agent) Down()

Down makes the agent stop answering.

func (*Agent) Up

func (a *Agent) Up()

Up makes it answer again.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client talks to the Web UI the way a browser does: it keeps cookies, and it does not follow redirects, so that tests see them.

func NewClient

func NewClient(t testing.TB, base string) *Client

NewClient returns a client of the Web UI at base, such as http://127.0.0.1:8300.

func (*Client) Cookie

func (c *Client) Cookie(name string) string

Cookie returns the value of a cookie the client holds, or "".

func (*Client) Do

func (c *Client) Do(method, path string, form url.Values, headers ...string) *Response

Do sends a request. form, when not nil, is the urlencoded body. headers are pairs of a name and a value.

func (*Client) Get

func (c *Client) Get(path string, headers ...string) *Response

Get is Do for a GET.

func (*Client) LatestReply

func (c *Client) LatestReply(conv string) string

LatestReply is the id of the last message of a conversation.

func (*Client) Messages

func (c *Client) Messages(conv string) []Message

Messages lists the messages of a conversation as its page shows them.

func (*Client) OpenStream

func (c *Client) OpenStream(ctx context.Context, conv, reply string) *Stream

OpenStream asks for a reply's event stream, as the browser's EventSource does. The stream is closed when the test ends or ctx is done.

func (*Client) Post

func (c *Client) Post(path string, form url.Values, headers ...string) *Response

Post is Do for a POST of a form.

func (*Client) Raw

func (c *Client) Raw(conv, reply string) *Response

Raw fetches the text of a finished reply exactly as stored.

func (*Client) Regenerate

func (c *Client) Regenerate(conv, reply string) *Response

Regenerate presses Regenerate (or Retry) on a reply. A new reply takes its place; the answer is its wrapper.

func (*Client) Send

func (c *Client) Send(conv, content string) (reply string)

Send adds a message to a conversation the way the composer does (htmx), and returns the id of the reply being written.

func (*Client) SignIn

func (c *Client) SignIn(email, password string) *Client

SignIn signs the client in and fails the test if the Web UI refuses.

func (*Client) Start

func (c *Client) Start(content string) (conv, reply string)

Start opens a conversation with its first message, as the empty-state form does, and returns the ids of the conversation and of the reply being written.

func (*Client) Stop

func (c *Client) Stop(conv, reply string) *Response

Stop presses Stop on a reply.

type Event

type Event struct {
	// Name is the event's name, "message" when it has none.
	Name string
	Data string
	// At is when the last line of the event arrived.
	At time.Time
}

Event is one server-sent event.

func Named

func Named(events []Event, name string) []Event

Named returns the events of a stream that have the name.

type Message

type Message struct {
	ID     string
	Role   string // "user" or "assistant"
	Status string
	// Text is what the reader sees in the message body.
	Text string
	// Node is the whole article, for anything else a test wants to look at.
	Node *html.Node
}

Message is a message as a page shows it.

func MessagesIn

func MessagesIn(t testing.TB, markup string) []Message

MessagesIn lists the messages in a page or fragment, in order.

type Option

type Option func(*settings)

Option customizes a Stack.

func WithAgentServer

func WithAgentServer(opts ...testagent.HandlerOption) Option

WithAgentServer sets how the scripted agent's server behaves, such as how long it lets one reply stream.

func WithExternalAgent

func WithExternalAgent(baseURL, appName string) Option

WithExternalAgent uses a real agent (its ADK REST base URL, such as http://localhost:9093/api, and its application name) instead of the scripted one. Agent and Model are then nil.

func WithLogs

func WithLogs(w io.Writer) Option

WithLogs sends the application's log to w, as the program's own logger would write it, at the debug level so that nothing is held back. Read w once the stack is shut down; until then the server may be writing to it.

func WithModel

func WithModel(opts ...testagent.Option) Option

WithModel sets the pace and script of the scripted agent.

func WithSetting

func WithSetting(key, value string) Option

WithSetting sets a configuration key, as if it were in .env.

type Response

type Response struct {
	Status int
	Header http.Header
	Body   string
}

Response is a finished HTTP exchange.

type Stack

type Stack struct {
	// URL is where a browser reaches it, such as http://127.0.0.1:41233.
	URL string
	// Config is what the application was built from.
	Config config.Config
	// Agent is the scripted agent behind the Web UI. It can be taken down.
	Agent *Agent
	// Model is the model the agent runs, for assertions on what it saw.
	Model *testagent.Model
	// Pool reads the database the Web UI writes.
	Pool *pgxpool.Pool
	// contains filtered or unexported fields
}

Stack is a running Web UI.

func Start

func Start(t testing.TB, opts ...Option) *Stack

Start runs the Web UI and its agent until the test ends.

Pattern: Test Through Serve

func (*Stack) AddUser

func (s *Stack) AddUser(email, password string)

AddUser creates another user, the way an operator would with SQL: the Web UI has no sign-up, and the first user comes from the settings.

func (*Stack) Anonymous

func (s *Stack) Anonymous() *Client

Anonymous returns a client that has not signed in.

func (*Stack) Shutdown

func (s *Stack) Shutdown() time.Duration

Shutdown does what SIGTERM does to the program: it ends the replies being written, lets requests finish, and returns how long that took. Calling it again returns the same answer. It is also called when the test ends.

func (*Stack) SignedIn

func (s *Stack) SignedIn() *Client

SignedIn returns a client signed in as the first user.

func (*Stack) SignedInAs

func (s *Stack) SignedInAs(email, password string) *Client

SignedInAs returns a client signed in as the user.

type Stream

type Stream struct {
	Status int
	Header http.Header
	// Retry is the last retry: value the server sent, 0 if none.
	Retry time.Duration
	// contains filtered or unexported fields
}

Stream is an open event stream, read one event at a time.

func (*Stream) Close

func (s *Stream) Close()

Close ends the stream, as a browser does when the tab goes away.

func (*Stream) Drain

func (s *Stream) Drain() []Event

Drain reads the stream to its end.

func (*Stream) Next

func (s *Stream) Next() (Event, bool)

Next returns the next event, or false when the stream has ended.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL