test

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package releasetest provides an in-memory forge.Provider test double and asset builders for exercising the self-update pipeline without network or disk access. It serves releases, tar.gz binary assets, checksum manifests and detached signatures entirely from memory, including the security-relevant corrupt-checksum and bad-signature variants.

The double is public (pkg/) so downstream tools building on GTB can test their own self-update wiring hermetically — the same reasoning that keeps forge.Provider public. It is usable both from tests and at runtime (the builders take no *testing.T), which lets the e2e binary inject a stub release source behind an env gate.

A Source always satisfies forge.ChecksumProvider and forge.SignatureProvider, but returns forge.ErrNotSupported unless configured with WithChecksumManifest / WithSignatureManifest. Per the provider contract, the update flow treats forge.ErrNotSupported exactly like "provider does not implement this interface" and falls back to locating checksums.txt / checksums.txt.sig by filename in the asset list — so a Source exercises both the manifest-provider path and the asset-by-name fallback.

See docs/development/specs/2026-06-19-injectable-release-source.md.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AssetName

func AssetName(toolName string) string

AssetName returns the OS/arch release-asset name the updater's findReleaseAsset expects for toolName on the current platform — e.g. "mytool_Linux_x86_64.tar.gz". It mirrors the naming convention in pkg/setup so a built asset is the one Update will look for.

func Manifest

func Manifest(corrupt bool, over ...Asset) []byte

Manifest builds a GoReleaser-style checksums.txt over the given assets (one "sha256 name" line each). When corrupt is true the recorded hashes intentionally cover a different payload, so verification against the real asset bodies fails.

func RunProviderConformance

func RunProviderConformance(t *testing.T, cfg ConformanceConfig)

RunProviderConformance asserts that a forge.Provider honours the parts of the contract that are otherwise documented only in prose.

It exists because the contract has two halves, and only one is checkable by the compiler. The method set is enforced by the type system; the *protocol* — which error to return when an operation does not apply, that a nil result and a nil error may never be returned together, that a caller-supplied size bound is actually enforced — is enforced by nothing at all. A provider can satisfy forge.Provider completely and still be wrong in every way that matters to a caller.

Run it from the provider's own test suite:

func TestConformance(t *testing.T) {
    forgetest.RunProviderConformance(t, forgetest.ConformanceConfig{
        NewProvider: func() forge.Provider { return newTestProvider(t) },
        Capabilities: forgetest.Capabilities{GetReleaseByTag: true, ListReleases: true},
        Owner: "acme", Repo: "tool", Tag: "v1.0.0",
    })
}

The harness never asserts on payload contents — that is the provider's own business — only on the contract every caller relies upon.

Types

type Asset

type Asset struct {
	Name string
	Body []byte
}

Asset is a single downloadable release asset served verbatim by a Source.

func ChecksumsAsset

func ChecksumsAsset(corrupt bool, over ...Asset) Asset

ChecksumsAsset wraps Manifest as a "checksums.txt" asset.

func SignatureAsset

func SignatureAsset(entity *openpgp.Entity, manifest []byte, bad bool) Asset

SignatureAsset builds a "checksums.txt.sig" ASCII-armored detached signature over manifest using entity. When bad is true it signs a different payload, so the signature does not verify against the served manifest.

func TarGzAsset

func TarGzAsset(toolName, binName, binBody string) Asset

TarGzAsset builds the platform release-binary asset for toolName: its Name is AssetName(toolName) and its Body is a .tar.gz archive whose single entry is binName with binBody as its contents.

type Capabilities

type Capabilities struct {
	// GetReleaseByTag is false for platforms with no addressable tag concept.
	GetReleaseByTag bool

	// ListReleases is false for platforms that expose no release listing.
	ListReleases bool

	// Checksums is true when the provider implements [forge.ChecksumProvider]
	// AND is configured such that it will serve a manifest.
	Checksums bool

	// Signatures is true when the provider implements
	// [forge.SignatureProvider] AND is configured to serve one.
	Signatures bool
}

Capabilities declares what a provider under test supports, so the harness can tell "correctly reports it cannot do this" apart from "is broken".

Declare capabilities honestly. Claiming support the provider lacks makes the harness assert real behaviour it cannot deliver; claiming less than it supports means the harness checks the opt-out protocol instead, which is weaker but never wrong.

type ConformanceConfig

type ConformanceConfig struct {
	// NewProvider returns a provider ready to serve the fixtures below. It is
	// called once per check, so each gets an independent instance. Close over
	// *testing.T if construction needs it for cleanup.
	NewProvider func() forge.Provider

	// Capabilities describes what this provider can do.
	Capabilities Capabilities

	// Owner, Repo and Tag are passed to the provider's methods. Tag must name
	// a release the provider will find when GetReleaseByTag is supported.
	Owner, Repo, Tag string

	// MissingTag names a tag the provider will NOT find. Optional: when empty,
	// the not-found check is skipped rather than guessed at.
	MissingTag string
}

ConformanceConfig parameterises RunProviderConformance.

type Option

type Option func(*Source)

Option configures a Source.

func WithChecksumManifest

func WithChecksumManifest(manifest []byte) Option

WithChecksumManifest puts the Source in checksum manifest-provider mode: it implements forge.ChecksumProvider by returning these bytes instead of the default asset-by-name fallback.

func WithDownloadError

func WithDownloadError(err error) Option

WithDownloadError makes Source.DownloadReleaseAsset fail with err.

func WithLatestTag

func WithLatestTag(tag string) Option

WithLatestTag sets which registered tag Source.GetLatestRelease returns.

func WithMissingTag

func WithMissingTag(tag string) Option

WithMissingTag makes Source.GetReleaseByTag(tag) return a not-found error wrapping forge.ErrReleaseNotFound.

func WithRelease

func WithRelease(tag string, assets ...Asset) Option

WithRelease registers a release at tag exposing the given assets. The first registered release becomes the "latest" unless WithLatestTag overrides it.

func WithSignatureManifest

func WithSignatureManifest(signature []byte) Option

WithSignatureManifest puts the Source in signature manifest-provider mode: it implements forge.SignatureProvider by returning these bytes instead of the default asset-by-name fallback.

type Source

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

Source is a fully in-memory forge.Provider for tests and the e2e stub. Construct it with New and one or more [Option]s.

func New

func New(opts ...Option) *Source

New constructs a Source from the given options.

func (*Source) DownloadChecksumManifest

func (s *Source) DownloadChecksumManifest(_ context.Context, _ forge.Release, _ int64) ([]byte, error)

DownloadChecksumManifest implements forge.ChecksumProvider. It returns forge.ErrNotSupported unless the Source was built with WithChecksumManifest, so the default Source uses the asset-by-name fallback.

func (*Source) DownloadReleaseAsset

func (s *Source) DownloadReleaseAsset(_ context.Context, _, _ string, a forge.ReleaseAsset) (io.ReadCloser, string, error)

DownloadReleaseAsset returns the in-memory body registered for the asset.

func (*Source) DownloadSignature

func (s *Source) DownloadSignature(_ context.Context, _ forge.Release, _ int64) ([]byte, error)

DownloadSignature implements forge.SignatureProvider. It returns forge.ErrNotSupported unless the Source was built with WithSignatureManifest, so the default Source uses the asset-by-name fallback.

func (*Source) GetLatestRelease

func (s *Source) GetLatestRelease(_ context.Context, _, _ string) (forge.Release, error)

GetLatestRelease returns the release at the configured latest tag.

func (*Source) GetReleaseByTag

func (s *Source) GetReleaseByTag(_ context.Context, _, _, tag string) (forge.Release, error)

GetReleaseByTag returns the release registered at tag, or a not-found error when the tag is unknown or was marked missing.

func (*Source) ListReleases

func (s *Source) ListReleases(_ context.Context, _, _ string, limit int) ([]forge.Release, error)

ListReleases returns the registered releases in registration order, capped at limit when limit > 0.

Jump to

Keyboard shortcuts

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