testutil

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package testutil has helpers shared by tests: isolated config/cache/data dirs, in-process command runs, and golden files.

Index

Constants

View Source
const (
	EndpointRecognize  = "recognize"  // POST https://api.audd.io/
	EndpointEnterprise = "enterprise" // POST https://enterprise.audd.io/
	EndpointUpload     = "upload"     // POST https://api.audd.io/upload/
)

Endpoints of the fake API. Any other path is a raw method name, such as "getStreams".

View Source
const FakeAPIToken = PlaceholderToken

FakeAPIToken is the account API token the fake MCP server hands out.

View Source
const FakePaymentURL = "https://checkout.stripe.com/c/pay/cs_test_example"

FakePaymentURL is the link the fake payment tools return.

View Source
const FakeRotatedToken = "your-api-token"

FakeRotatedToken is the token rotate_api_token returns: the other allowed placeholder, so tests can tell the old and new tokens apart.

View Source
const FirstPartyClientID = "audd-cli"

FirstPartyClientID is AudD's pre-registered CLI client.

View Source
const PlaceholderToken = "0123456789abcdef0123456789abcdef"

PlaceholderToken is the only token value tests and docs use.

Variables

View Source
var DefaultGrantScopes = []string{"openid", "profile:read", "account:read", "usage:read", "billing:read", "token:read"}

DefaultGrantScopes are granted to a client registered without a scope list: like the AudD service, they leave out billing:pay and token:write.

View Source
var FirstPartyScopes = []string{"openid", "email", "profile:read", "account:read", "usage:read", "billing:read", "billing:pay", "token:read", "token:write"}

FirstPartyScopes are the scopes audd-cli may ask for.

View Source
var LiveInputSchemas, FakeOutputSchemas = func() (in, out map[string]map[string]any) {
	in, out = map[string]map[string]any{}, map[string]map[string]any{}
	for name, t := range liveTools() {
		in[name], out[name] = t.InputSchema, t.OutputSchema
	}
	in["rotate_api_token"] = in["get_api_token"]
	out["rotate_api_token"] = out["get_api_token"]
	return in, out
}()

LiveInputSchemas and FakeOutputSchemas are the account tools' schemas as the live server publishes them. rotate_api_token was not in the recording (it is listed only with token:write); it is assumed to answer like get_api_token.

Functions

func APIError

func APIError(code int, message string) map[string]any

APIError is an AudD error body.

func AuthorizeRedirect

func AuthorizeRedirect(authURL string) (string, error)

AuthorizeRedirect requests the authorization URL without following the redirect and returns the redirect URL (what a user would paste).

func EnterpriseChunk

func EnterpriseChunk(offset string, songs ...map[string]any) map[string]any

EnterpriseChunk is one chunk of an enterprise response.

func EnterpriseSong

func EnterpriseSong(artist, title string, startMS, endMS int) map[string]any

EnterpriseSong is one enterprise match inside a chunk.

func FollowAuthorize

func FollowAuthorize(authURL string) error

FollowAuthorize plays the user's browser: it requests the authorization URL and follows the redirect to the CLI's loopback listener. Use it as the browser opener in tests.

func Golden

func Golden(t testing.TB, name string, got []byte)

Golden compares got with testdata/<name>.golden next to the test. Run tests with AUDD_UPDATE_GOLDEN=1 to rewrite the files.

func Isolate

func Isolate(t testing.TB) string

Isolate points config, cache, and data dirs at fresh temp dirs, forces the file-based secrets store, and clears environment variables that change CLI behavior. It returns the config dir.

func LiveFixture

func LiveFixture(tool string) map[string]any

LiveFixture returns the structuredContent of a recorded tools/call response, freshly decoded (callers may change it).

func MatchResult

func MatchResult() map[string]any

MatchResult is a typical standard-endpoint match.

func ReleaseArchive

func ReleaseArchive(t testing.TB, version string, bin []byte) (name string, archive, checksums []byte)

ReleaseArchive builds the release archive for this system holding bin as the audd binary, and a checksums.txt that lists it.

func Success

func Success(result any) map[string]any

Success wraps a result in {"status":"success","result":...}.

Types

type FakeAPI

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

FakeAPI is an httptest server that stands in for api.audd.io and enterprise.audd.io. NewFakeAPI points the CLI at it through the AUDD_API_BASE_URL and AUDD_ENTERPRISE_BASE_URL environment variables.

func NewFakeAPI

func NewFakeAPI(t testing.TB) *FakeAPI

NewFakeAPI starts a fake API for the test. Unhandled endpoints answer with error 1000 (unknown method).

func (*FakeAPI) AcceptTokens

func (f *FakeAPI) AcceptTokens(tokens ...string)

AcceptTokens limits the tokens the fake accepts; others get error 900.

func (*FakeAPI) Count

func (f *FakeAPI) Count(endpoint string) int

Count returns how many requests hit endpoint.

func (*FakeAPI) On

func (f *FakeAPI) On(endpoint string, h FakeHandler)

On sets the handler for an endpoint (EndpointRecognize, EndpointEnterprise, EndpointUpload, or a raw method name).

func (*FakeAPI) Reply

func (f *FakeAPI) Reply(endpoint string, body any)

Reply sets a handler that always answers 200 with body.

func (*FakeAPI) Requests

func (f *FakeAPI) Requests() []FakeRequest

Requests returns every request received so far.

type FakeHandler

type FakeHandler func(r FakeRequest) (status int, body any)

FakeHandler answers a request with an HTTP status and a JSON body.

type FakeMCP

type FakeMCP struct {
	Server *httptest.Server
	OAuth  *FakeOAuth

	SSE   bool // answer requests as text/event-stream
	Calls []FakeMCPCall
	Inits int
	Lists int
	// contains filtered or unexported fields
}

FakeMCP is a Streamable HTTP MCP server for tests. It checks bearer tokens against a FakeOAuth, issues Mcp-Session-Id on initialize, rejects unknown sessions with 404, scopes tools like the AudD MCP server, and can answer as JSON or as an SSE stream.

func NewFakeMCP

func NewFakeMCP(t testing.TB, oauth *FakeOAuth) *FakeMCP

NewFakeMCP starts a fake MCP server using oauth for tokens, with the default AudD account tools (see DefaultFakeTools).

func (*FakeMCP) CallsTo

func (f *FakeMCP) CallsTo(name string) []FakeMCPCall

CallsTo returns the recorded calls to a tool.

func (*FakeMCP) ExpireSessions

func (f *FakeMCP) ExpireSessions()

ExpireSessions forgets every session, as a server restart would.

func (*FakeMCP) SetSSE

func (f *FakeMCP) SetSSE(on bool)

SetSSE switches between JSON and SSE responses.

func (*FakeMCP) SetTool

func (f *FakeMCP) SetTool(tool FakeTool)

SetTool adds or replaces a tool.

func (*FakeMCP) Stats

func (f *FakeMCP) Stats() (inits, lists int)

Stats returns the number of initialize and tools/list requests.

func (*FakeMCP) URL

func (f *FakeMCP) URL() string

URL is the MCP endpoint (and protected resource identifier).

type FakeMCPCall

type FakeMCPCall struct {
	Tool string
	Args map[string]any
}

FakeMCPCall records one tools/call.

type FakeOAuth

type FakeOAuth struct {
	Server *httptest.Server

	// Behavior knobs; set before the flow starts.
	IssOverride   string   // iss sent on the redirect ("" = the real issuer)
	OmitIss       bool     // leave iss off the redirect
	StateOverride string   // state sent on the redirect ("" = echo)
	DenyScopes    []string // scopes the server refuses with invalid_scope
	// RejectRegistrationScope refuses registrations that name a scope list
	// (invalid_client_metadata); clients registered without one get
	// DefaultGrantScopes.
	RejectRegistrationScope bool
	AccessTTL               time.Duration // access token lifetime (default 1h)
	RefreshDelay            time.Duration // slow down refresh responses

	// NoFirstPartyClient models a server that does not know audd-cli.
	NoFirstPartyClient bool
	// NoDeviceEndpoint leaves device authorization out of the metadata.
	NoDeviceEndpoint bool
	// Untick lists scopes the user unticks on the consent or approval
	// screen: they are left out of the grant.
	Untick []string
	// DeviceScript is the answer to each device poll in turn: "pending",
	// "slow_down", "slow_down_429" (429 with no interval), "deny",
	// "expire", "invalid_grant", or "approve". After the script, polls
	// are approved.
	DeviceScript []string
	// DeviceInterval and DeviceExpiresIn are sent with each device code
	// (default 5 and 900, like AudD's server).
	DeviceInterval, DeviceExpiresIn int
	// DeviceRetryAfter, when set, answers device authorization with 429
	// and this Retry-After.
	DeviceRetryAfter int
	// RegisterReturns makes registration answer with this client_id
	// without creating a client (AudD's answer to an "AudD CLI"
	// registration is audd-cli itself).
	RegisterReturns string
	// RegisterError refuses registrations with 400 and this error code.
	RegisterError, RegisterErrorDescription string

	Counters FakeOAuthCounters
	Revoked  []string
	// Revocations lists each revocation request.
	Revocations []Revocation
	// Scopes lists the scope parameter of each authorization and device
	// authorization request, in order.
	Scopes []string
	// ClientIDs lists the client_id of each authorization and device
	// authorization request, in order.
	ClientIDs []string
	// contains filtered or unexported fields
}

FakeOAuth is an OAuth 2.0 authorization server for tests, shaped like AudD's: RFC 8414 metadata, the pre-registered public client audd-cli, dynamic client registration, an /authorize endpoint that approves immediately (a 302 to the client's redirect URI), device authorization (RFC 8628) whose polls follow DeviceScript, a token endpoint with PKCE checks and single-use rotating refresh tokens, and a revocation endpoint that only revokes for the issuing client.

func NewFakeOAuth

func NewFakeOAuth(t testing.TB) *FakeOAuth

NewFakeOAuth starts a fake authorization server; it stops when the test ends.

func (*FakeOAuth) AccessScopes

func (f *FakeOAuth) AccessScopes(token string) ([]string, bool)

AccessScopes returns the scopes of a valid access token.

func (*FakeOAuth) DropAccess

func (f *FakeOAuth) DropAccess()

DropAccess invalidates every access token but keeps refresh tokens, as when the server revokes access tokens early.

func (*FakeOAuth) ForgetClients

func (f *FakeOAuth) ForgetClients()

ForgetClients drops every registered client, as when the server no longer knows a client ID the CLI cached.

func (*FakeOAuth) HasRefresh

func (f *FakeOAuth) HasRefresh(token string) bool

HasRefresh reports whether a refresh token is still valid.

func (*FakeOAuth) IssueAccess

func (f *FakeOAuth) IssueAccess(scopes ...string) string

IssueAccess mints an access token directly (for MCP tests that skip login).

func (*FakeOAuth) IssueSession

func (f *FakeOAuth) IssueSession(clientID string, scopes ...string) (access, refresh string)

IssueSession mints a session for clientID directly, as a sign-in by an earlier version would have, and returns its access and refresh tokens.

func (*FakeOAuth) RegisterClient

func (f *FakeOAuth) RegisterClient(scopes ...string) string

RegisterClient adds a registered client, as an earlier sign-in would have.

func (*FakeOAuth) RequestedClientIDs

func (f *FakeOAuth) RequestedClientIDs() []string

RequestedClientIDs returns the client_id of each authorization and device authorization request.

func (*FakeOAuth) RequestedScopes

func (f *FakeOAuth) RequestedScopes() []string

RequestedScopes returns the scope parameter of each authorization and device authorization request.

func (*FakeOAuth) RestrictClient

func (f *FakeOAuth) RestrictClient(id string, scopes ...string)

RestrictClient limits the scopes a registered client may ask for.

func (*FakeOAuth) RevocationRequests

func (f *FakeOAuth) RevocationRequests() []Revocation

RevocationRequests returns each revocation request.

func (*FakeOAuth) RevokeAll

func (f *FakeOAuth) RevokeAll()

RevokeAll invalidates every access and refresh token (an ended session).

func (*FakeOAuth) RevokedTokens

func (f *FakeOAuth) RevokedTokens() []string

RevokedTokens returns tokens sent to the revocation endpoint.

func (*FakeOAuth) Set

func (f *FakeOAuth) Set(fn func(f *FakeOAuth))

Set changes behavior knobs under the server's lock.

func (*FakeOAuth) Snapshot

func (f *FakeOAuth) Snapshot() FakeOAuthCounters

Snapshot returns a copy of the counters.

func (*FakeOAuth) URL

func (f *FakeOAuth) URL() string

URL is the issuer.

type FakeOAuthCounters

type FakeOAuthCounters struct {
	Register, Authorize, CodeExchange, Refresh, RefreshRejected, Revoke int
	// DeviceAuthorize counts device authorization requests, DevicePoll
	// device-code token requests, DeviceSuccess polls answered 200, and
	// DevicePollAfterSuccess polls for a code that was already redeemed.
	DeviceAuthorize, DevicePoll, DeviceSuccess, DevicePollAfterSuccess int
}

FakeOAuthCounters counts requests per endpoint.

type FakeRequest

type FakeRequest struct {
	Endpoint string
	Token    string
	Form     map[string]string // form fields except api_token and file
	FileName string
	FileSize int // bytes of the uploaded file; -1 when no file was sent
}

FakeRequest is one request the fake API received.

type FakeTool

type FakeTool struct {
	Name         string
	Scope        string // tool is listed and callable only with this scope
	InputSchema  map[string]any
	OutputSchema map[string]any
	// Handle returns structuredContent (nil for text-only), text, and isError.
	Handle func(args map[string]any) (structured map[string]any, text string, isError bool)
}

FakeTool is one tool served by FakeMCP.

func DefaultFakeTools

func DefaultFakeTools() []FakeTool

DefaultFakeTools returns the AudD account tools with the live schemas and the recorded results.

type Main

type Main func(args []string, stdin io.Reader, stdout, stderr io.Writer) int

Main is the signature of cli.Main; tests pass it in, which keeps this package free of a dependency on internal/cli.

type Result

type Result struct {
	Code           int
	Stdout, Stderr string
}

Result is the outcome of an in-process run.

func Exec

func Exec(t testing.TB, main Main, stdin string, args ...string) Result

Exec runs the CLI in-process with stdin text and args (no TTYs).

type Revocation

type Revocation struct{ Token, ClientID string }

Revocation is one request to the revocation endpoint.

Jump to

Keyboard shortcuts

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