Documentation
¶
Overview ¶
Package httpmock provides small, in-process mock HTTP servers standing in for GitHub (and GitHub-adjacent services like Artifactory) in tests, so the acceptance and unit-test suites never depend on live network access.
Index ¶
- func BuildTarGz(files map[string]string) ([]byte, error)
- func BuildZip(files map[string]string) ([]byte, error)
- func IsolatedCacheEnv(t *testing.T) []string
- type AquaTool
- type ArtifactoryMockServer
- type GitHubMockServer
- func (m *GitHubMockServer) EnvForSubprocess() map[string]string
- func (m *GitHubMockServer) FailWith(pathPrefix string, status int)
- func (m *GitHubMockServer) FailWithHeaders(pathPrefix string, status int, headers map[string]string)
- func (m *GitHubMockServer) FailWithTimes(pathPrefix string, status, times int)
- func (m *GitHubMockServer) HTTPClient() *http.Client
- func (m *GitHubMockServer) HttpGetter() *getter.HttpGetter
- func (m *GitHubMockServer) RegisterAquaTool(tool *AquaTool)
- func (m *GitHubMockServer) RegisterArchive(owner, repo, tag string, data []byte)
- func (m *GitHubMockServer) RegisterFile(pathSuffix, content string)
- func (m *GitHubMockServer) RegisterRawFile(owner, repo, ref, path, content string)
- func (m *GitHubMockServer) RegisterRelease(owner, repo string, spec ReleaseSpec)
- func (m *GitHubMockServer) RegisterReleaseAsset(owner, repo, tag, asset string, data []byte)
- func (m *GitHubMockServer) RegisterTag(owner, repo, name string)
- func (m *GitHubMockServer) RequestCount(pathPrefix string) int
- func (m *GitHubMockServer) Requests() []RequestLogEntry
- func (m *GitHubMockServer) SetAquaPrefix(prefix string)
- func (m *GitHubMockServer) SetRateLimit(remaining int, reset time.Time)
- func (m *GitHubMockServer) Setenv(t *testing.T)
- func (m *GitHubMockServer) Transport() http.RoundTripper
- func (m *GitHubMockServer) URL() string
- type ReleaseSpec
- type RequestLogEntry
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildTarGz ¶ added in v1.229.0
BuildTarGz builds a minimal gzip-compressed tar archive containing files (archive path -> content), suitable for registering as a fake release asset via RegisterReleaseAsset or RegisterArchive. The result is a tiny stand-in for a real tool's release tarball: tests should assert atmos extracted/placed a file at the expected path, never execute it. Entries are written in sorted name order so identical inputs always produce identical archive bytes.
func BuildZip ¶ added in v1.229.0
BuildZip builds a minimal zip archive containing files (archive path -> content), suitable for registering as a fake release asset via RegisterReleaseAsset. See BuildTarGz for the "never execute the fake binary" caveat and the sorted-write-order determinism rationale.
func IsolatedCacheEnv ¶ added in v1.229.0
IsolatedCacheEnv returns environment entries that point atmos's XDG cache and data directories at a private temp dir for a subprocess driven against this mock. Without it, a subprocess `atmos toolchain install` fetches the mock's aqua registry index and installs the mock's fake release asset into the developer's REAL ~/.cache/atmos/toolchain, poisoning the registry index cache (24h TTL) and the toolchain bin directory for every atmos invocation on that machine until they expire or are removed. Append the result to cmd.Env alongside EnvForSubprocess.
Types ¶
type AquaTool ¶ added in v1.229.0
type AquaTool struct {
// Owner is repo_owner; Repo is repo_name.
Owner string
Repo string
// Name is the full registry package path (e.g. "jqlang/jq", or "kubernetes/kubernetes/kubectl"
// for a monorepo binary). Defaults to "Owner/Repo" when empty.
Name string
// Type defaults to "github_release" when empty.
Type string
Asset string
Format string
BinaryName string
SupportedEnvs []string
VersionConstraint string
VersionPrefix string
}
AquaTool describes a fake aqua-registry package the mock serves from its aqua-registry endpoints ({aquaPrefix}/registry.yaml and {aquaPrefix}/pkgs/{path}/registry.yaml). Field names mirror the subset of aquaproj/aqua-registry YAML keys that pkg/toolchain/registry/aqua consumes (see aquaPackageYAML's yaml tags).
Checksum verification is intentionally not modeled here: leaving it unset (the zero value) means the registered package has no checksum config, so the installer's checksum verification -- which is opt-in per package -- never activates. This keeps the mock from having to fake a matching checksum file, without weakening production verification: real registry entries that do configure a checksum are unaffected, and callers who genuinely need to exercise checksum verification would extend this struct rather than route around it.
type ArtifactoryMockServer ¶ added in v1.205.1
type ArtifactoryMockServer struct {
Server *httptest.Server
// contains filtered or unexported fields
}
ArtifactoryMockServer provides a mock HTTP server that implements enough of the JFrog Artifactory Generic repository API to test the Atmos Artifactory store integration.
func NewArtifactoryMockServer ¶ added in v1.205.1
func NewArtifactoryMockServer(t *testing.T) *ArtifactoryMockServer
NewArtifactoryMockServer creates a mock Artifactory server. The server is automatically cleaned up when the test completes.
func (*ArtifactoryMockServer) Clear ¶ added in v1.205.1
func (m *ArtifactoryMockServer) Clear()
Clear removes all files from the mock store.
func (*ArtifactoryMockServer) GetFile ¶ added in v1.205.1
func (m *ArtifactoryMockServer) GetFile(path string) ([]byte, bool)
GetFile retrieves a file from the mock store (useful for test assertions).
func (*ArtifactoryMockServer) ListFiles ¶ added in v1.205.1
func (m *ArtifactoryMockServer) ListFiles() map[string][]byte
ListFiles returns all files currently stored in the mock.
func (*ArtifactoryMockServer) SetFile ¶ added in v1.205.1
func (m *ArtifactoryMockServer) SetFile(path string, content []byte)
SetFile directly sets a file in the mock store (useful for test setup).
func (*ArtifactoryMockServer) URL ¶ added in v1.205.1
func (m *ArtifactoryMockServer) URL() string
URL returns the mock server URL.
type GitHubMockServer ¶
GitHubMockServer is a small GitHub HTTP façade for tests. It started as a raw-content-only mock (suffix-matched files served over what looked like raw.githubusercontent.com) and has grown path-prefix handlers for the toolchain/registry/raw-fetch surface that pkg/github.Endpoints, pkg/toolchain/registry/aqua, and pkg/toolchain/installer talk to:
- GET /api/v3/repos/{owner}/{repo}/releases[?page=&per_page=]
- GET /api/v3/repos/{owner}/{repo}/releases/latest
- GET /api/v3/repos/{owner}/{repo}/tags[?per_page=]
- GET /{owner}/{repo}/releases/download/{tag}/{asset}
- GET /{owner}/{repo}/archive/refs/tags/{tag}.tar.gz
- GET /raw/{owner}/{repo}/{ref}/{path} (GitHub Enterprise Server raw-content shape)
- GET {aquaPrefix}/registry.yaml (aqua-registry package index)
- GET {aquaPrefix}/pkgs/{path}/registry.yaml (aqua-registry per-package file)
Legacy suffix-matched raw files (RegisterFile, Transport, HTTPClient, HttpGetter) keep working unchanged: the new path-prefix routes are tried first, and any request that misses all of them falls through to the original suffix-match loop.
func NewGitHubMockServer ¶
func NewGitHubMockServer(t *testing.T) *GitHubMockServer
NewGitHubMockServer creates a mock server that intercepts GitHub requests. The server is automatically cleaned up when the test completes.
func NewGitHubMockServerStandalone ¶ added in v1.229.0
func NewGitHubMockServerStandalone() (mock *GitHubMockServer, closeServer func())
NewGitHubMockServerStandalone creates a mock server without requiring a *testing.T, returning a close func the caller must invoke itself. For use in contexts with no *testing.T available, such as TestMain, where NewGitHubMockServer cannot be called.
func (*GitHubMockServer) EnvForSubprocess ¶ added in v1.229.0
func (m *GitHubMockServer) EnvForSubprocess() map[string]string
EnvForSubprocess returns the environment variables a subprocess needs to route GitHub, toolchain, and aqua-registry traffic at this mock: GITHUB_SERVER_URL/GITHUB_API_URL (the repo endpoints resolved by pkg/github.RepoEndpoints), ATMOS_TOOLCHAIN_GITHUB_URL/ ATMOS_TOOLCHAIN_GITHUB_API_URL (pkg/github.ToolchainEndpoints), and ATMOS_TOOLCHAIN_AQUA_REGISTRY_URL (pkg/github.AquaRegistryURL).
func (*GitHubMockServer) FailWith ¶ added in v1.229.0
func (m *GitHubMockServer) FailWith(pathPrefix string, status int)
FailWith makes every request whose path starts with pathPrefix fail with status, indefinitely, instead of being routed normally. Use FailWithTimes for a failure that recovers after N hits (e.g. to test an unauthenticated-retry path).
func (*GitHubMockServer) FailWithHeaders ¶ added in v1.229.0
func (m *GitHubMockServer) FailWithHeaders(pathPrefix string, status int, headers map[string]string)
FailWithHeaders makes every request whose path starts with pathPrefix fail with status, indefinitely, carrying the given extra response headers -- e.g. a secondary GitHub rate limit, which signals via `Retry-After` rather than `X-RateLimit-Remaining: 0`:
mock.FailWithHeaders("/api/v3/repos/owner/repo", http.StatusForbidden, map[string]string{"Retry-After": "30"})
A copy of headers is stored, not the caller-owned map: matchFailure/applyFailureInjection read it later, outside any lock the caller might (or might not) hold, so mutating the map after registration must never change the response or race with a request being served.
func (*GitHubMockServer) FailWithTimes ¶ added in v1.229.0
func (m *GitHubMockServer) FailWithTimes(pathPrefix string, status, times int)
FailWithTimes makes the first `times` requests whose path starts with pathPrefix fail with status; subsequent requests are routed normally. Useful for testing a retry-without-auth path: the first hit returns 403, the retry (a fresh, unauthenticated request) succeeds.
times must be non-negative: matchFailure treats a negative `remaining` as the -1 sentinel reserved for FailWith/FailWithHeaders (an unlimited failure), so a negative times here would otherwise silently become an unlimited failure instead of erroring loudly. This is a test helper with no *testing.T to fail through, so a caller mistake panics instead.
func (*GitHubMockServer) HTTPClient ¶
func (m *GitHubMockServer) HTTPClient() *http.Client
HTTPClient returns an http.Client that intercepts GitHub URLs. Use this with go-getter's HttpGetter or any HTTP client that needs to have GitHub requests redirected to the mock server.
func (*GitHubMockServer) HttpGetter ¶
func (m *GitHubMockServer) HttpGetter() *getter.HttpGetter
HttpGetter returns a go-getter HttpGetter configured to use the mock. Use this when you need to inject a custom getter into go-getter's client.
func (*GitHubMockServer) RegisterAquaTool ¶ added in v1.229.0
func (m *GitHubMockServer) RegisterAquaTool(tool *AquaTool)
RegisterAquaTool registers a fake aqua-registry package, servable at both {aquaPrefix}/registry.yaml (as one index entry) and {aquaPrefix}/pkgs/{path}/registry.yaml (the full per-package file).
A copy of tool is stored (including its SupportedEnvs slice), not the caller-owned pointer: mutating the struct or slice the caller passed in after registration must never change what the mock serves, and must never race with the handler goroutine reading it.
func (*GitHubMockServer) RegisterArchive ¶ added in v1.229.0
func (m *GitHubMockServer) RegisterArchive(owner, repo, tag string, data []byte)
RegisterArchive registers data to be served at /{owner}/{repo}/archive/refs/tags/{tag}.tar.gz. The bytes are copied so that later mutations to the caller's slice (e.g. a reused test buffer) never change what is served.
func (*GitHubMockServer) RegisterFile ¶
func (m *GitHubMockServer) RegisterFile(pathSuffix, content string)
RegisterFile registers content to be served for a given path suffix. The path suffix is matched against the end of incoming request paths. For example, RegisterFile("stacks/deploy/nonprod.yaml", content) will match requests to /cloudposse/atmos/main/tests/fixtures/scenarios/stack-templates-2/stacks/deploy/nonprod.yaml.
func (*GitHubMockServer) RegisterRawFile ¶ added in v1.229.0
func (m *GitHubMockServer) RegisterRawFile(owner, repo, ref, path, content string)
RegisterRawFile registers content to be served at /raw/{owner}/{repo}/{ref}/{path}, the GitHub Enterprise Server raw-content shape pkg/github.Endpoints.RawURL builds when GITHUB_SERVER_URL resolves to a non-default (non-github.com) host. Unlike the legacy RegisterFile suffix match, this is an exact match on owner/repo/ref/path.
func (*GitHubMockServer) RegisterRelease ¶ added in v1.229.0
func (m *GitHubMockServer) RegisterRelease(owner, repo string, spec ReleaseSpec)
RegisterRelease appends one fake release for owner/repo, in the order GitHub's "most recent first" release list is normally returned in: register newest first for GetLatestVersion/ GetLatestRelease-style "first non-draft, non-prerelease wins" semantics to behave as expected.
func (*GitHubMockServer) RegisterReleaseAsset ¶ added in v1.229.0
func (m *GitHubMockServer) RegisterReleaseAsset(owner, repo, tag, asset string, data []byte)
RegisterReleaseAsset registers data to be served at /{owner}/{repo}/releases/download/{tag}/{asset}. The bytes are copied so that later mutations to the caller's slice (e.g. a reused test buffer) never change what is served.
func (*GitHubMockServer) RegisterTag ¶ added in v1.229.0
func (m *GitHubMockServer) RegisterTag(owner, repo, name string)
RegisterTag appends one fake tag name for owner/repo.
func (*GitHubMockServer) RequestCount ¶ added in v1.229.0
func (m *GitHubMockServer) RequestCount(pathPrefix string) int
RequestCount returns how many logged requests have a path starting with pathPrefix.
func (*GitHubMockServer) Requests ¶ added in v1.229.0
func (m *GitHubMockServer) Requests() []RequestLogEntry
Requests returns a copy of every request the mock has received so far, in order.
func (*GitHubMockServer) SetAquaPrefix ¶ added in v1.229.0
func (m *GitHubMockServer) SetAquaPrefix(prefix string)
SetAquaPrefix overrides the path prefix used for the aqua-registry endpoints (default "/aqua"). Must be called before any RegisterAquaTool/aqua request. The prefix is normalized to have a leading slash and no trailing slash (e.g. "registry" and "/registry/" both become "/registry"), except an empty prefix, which is preserved as-is to mean the server root -- tryAqua's path matching and EnvForSubprocess's URL construction both require this shape.
func (*GitHubMockServer) SetRateLimit ¶ added in v1.229.0
func (m *GitHubMockServer) SetRateLimit(remaining int, reset time.Time)
SetRateLimit configures the core rate-limit budget the mock reports: `remaining` requests left out of a 5,000 budget, resetting at `reset`. Call with remaining=0 and a past `reset` to simulate an already-recovered exhausted limit (WaitForRateLimit returns immediately); call with remaining=0 and a future `reset` to simulate a still-active primary limit.
func (*GitHubMockServer) Setenv ¶ added in v1.229.0
func (m *GitHubMockServer) Setenv(t *testing.T)
Setenv applies EnvForSubprocess via t.Setenv, for in-process tests (or tests that build the atmos binary in-process via exec.Command inheriting os.Environ()).
func (*GitHubMockServer) Transport ¶
func (m *GitHubMockServer) Transport() http.RoundTripper
Transport returns an http.RoundTripper that intercepts GitHub URLs. Can be used to replace http.DefaultTransport in tests to intercept all HTTP requests to GitHub without modifying the code under test.
func (*GitHubMockServer) URL ¶
func (m *GitHubMockServer) URL() string
URL returns the mock server URL.
type ReleaseSpec ¶ added in v1.229.0
ReleaseSpec describes one fake GitHub release served by the mock's /api/v3/repos/{owner}/{repo}/releases[/latest] endpoints.
type RequestLogEntry ¶ added in v1.229.0
RequestLogEntry records one request the mock received, for egress/routing assertions.