Documentation
¶
Overview ¶
Package brokertest provides a controllable HTTP stub for the GitHub Actions broker protocol used in integration tests.
Index ¶
- type Server
- func (s *Server) AcknowledgeCalls() int
- func (s *Server) AcquireJobCalls() int
- func (s *Server) ActiveSessionCount() int
- func (s *Server) ActiveSessionsForOwner(name string) []string
- func (s *Server) Close()
- func (s *Server) CompleteJobCalls() int
- func (s *Server) DeliveryResults(planID string) map[string]broker.TaskResult
- func (s *Server) EnableFanoutAccounting()
- func (s *Server) EnqueueFanoutJob(planID string, n int) []string
- func (s *Server) EnqueueJob(sessionID string, payload broker.RunnerJobRequestBody)
- func (s *Server) ExpireUnstartedDeliveries(planID string)
- func (s *Server) FailCreateSessionForOwner(prefix string)
- func (s *Server) GetMessageCalls() int
- func (s *Server) HTTPClient() *http.Client
- func (s *Server) JobState(planID string) string
- func (s *Server) LastCompleteJob() (broker.CompleteJobRequest, bool)
- func (s *Server) RegisteredSessions() []string
- func (s *Server) RenewJobCalls() int
- func (s *Server) SetAcquireJobResponse(v any)
- func (s *Server) WaitForFirstPoll(sessionID string, timeout time.Duration) bool
- func (s *Server) WaitForSessionDelete(sessionID string, timeout time.Duration) bool
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Server ¶
type Server struct {
URL string
// contains filtered or unexported fields
}
Server is a test HTTP server that implements the broker v2 protocol endpoints.
func (*Server) AcknowledgeCalls ¶
AcknowledgeCalls returns the number of delete-message ("acknowledge") calls served — DELETE {poolBase}/messages/{id}. The probe issues this call only after AcquireJob has returned client-side, so observing it reach 1 guarantees the AcquireJob round-trip completed and its context is safe to cancel (Q258).
func (*Server) AcquireJobCalls ¶
AcquireJobCalls returns the number of /acquirejob calls the stub has fully served — like CompleteJobCalls, the counter is published only after the call's fan-out accounting is committed, so waiting on it and then reading the accounting is race-free.
func (*Server) ActiveSessionCount ¶
ActiveSessionCount returns the number of goroutines that have registered a session but not yet called DELETE /session. It is computed as (#POST /session − #DELETE /session) so each listener goroutine contributes +1 on start and −1 on exit, regardless of v2 mode.
func (*Server) ActiveSessionsForOwner ¶
ActiveSessionsForOwner returns the IDs of currently-active sessions owned by the runner name of the given stem. A listener owns its session as its own registered runner name, so a session matches when its ownerName is that stem, a "-", and a decimal index. The index segment is matched exactly rather than by prefix, so a stem that extends this one ("<name>-set") keeps its own bucket. Scoping by owner lets a test assert on only its own CR's sessions, immune to sessions other tests left active on this shared stub — the global RegisteredSessions/ActiveSessionCount counters accumulate across the whole package and cause cross-test flakes when used for exact-count assertions.
The stem is the registered name's, not the CR's, and the two differ by kind: pass "<name>" for a RunnerGroup and "rs-<name>" for a RunnerSet, matching what Q466 kind-scoped and Q677 carried onto the wire. A same-named group and set are now separable, which they were not before Q677.
func (*Server) CompleteJobCalls ¶
CompleteJobCalls returns the number of /completejob calls the stub has FULLY SERVED — the counter is published only after the call's effects are committed, so waiting on it and then reading LastCompleteJob or the fan-out accounting is race-free. The AGC issues completejob for a deduplicated duplicate delivery it abandons (Q260 follow-up), so a test can assert the loser released its dangling assignment.
It counts calls, not resolved deliveries: a call whose body never arrives (the client's context was cancelled mid-request) is served and counted, yet resolves nothing. Assert on DeliveryResults when what you mean is "these deliveries are resolved" (Q490).
func (*Server) DeliveryResults ¶
func (s *Server) DeliveryResults(planID string) map[string]broker.TaskResult
DeliveryResults returns, for the fan-out job identified by planID, each delivery's resolved completejob result keyed by its RunnerRequestID — only deliveries a completejob has resolved appear. Empty when the job is unknown or none resolved. It lets a test assert the winner completed each deduped sibling delivery keyed on its OWN RunnerRequestID with the expected result (Q260 Option A). Read-only.
func (*Server) EnableFanoutAccounting ¶
func (s *Server) EnableFanoutAccounting()
EnableFanoutAccounting turns on the per-delivery fan-out job-accounting model (Q260). Off by default. Call once before enqueuing a fan-out job. When on, the server tracks a logical job per planID with one assignment per delivery and only concludes the job when the accounting is reconciled — modeling GitHub's real fan-out completion semantics that the default stub omits (the gap that let the Q260 dedup pass envtest yet wedge production).
func (*Server) EnqueueFanoutJob ¶
EnqueueFanoutJob registers one logical job (planID) that GitHub fans out to n sibling sessions as n deliveries with DISTINCT RunnerRequestIDs. The deliveries are handed to pollers on GET /message (one per poll, to whichever sessions poll), so a burst of n concurrent pollers each receives one delivery of the same job — exactly the shape the planID dedup must collapse. Returns the n RunnerRequestIDs. Requires EnableFanoutAccounting. Safe to call once per planID.
func (*Server) EnqueueJob ¶
func (s *Server) EnqueueJob(sessionID string, payload broker.RunnerJobRequestBody)
EnqueueJob places a job message onto the given session's queue. The RunServiceURL in the payload is overridden to point back to the stub so that /acquirejob calls come back here.
func (*Server) ExpireUnstartedDeliveries ¶
ExpireUnstartedDeliveries fires GitHub's ~15-minute unstarted-job timeout deterministically (no real timer): if any delivery of the job was acquired but never resolved with a terminal result, the whole job is CANCELLED — GitHub is still waiting on that phantom assignment even though a sibling already ran the job. A no-op once the job has concluded. This is the mechanism that turns the Q260 dedup's silently-abandoned sibling deliveries into a cancelled job.
func (*Server) FailCreateSessionForOwner ¶
FailCreateSessionForOwner makes POST /session return 401 Unauthorized for any session whose ownerName has the given prefix, simulating a broker that rejects a tenant's session creation. createSession maps the 401 to a NonRetriableError, so the listener's permanent baseline exits without being auto-restarted — letting a test drive the controller's baseline-revival path (Q137). An empty prefix clears the override. The prefix is matched against ownerName, which is the listener's registered runner name and so kind-scoped: pass "<name>-" for a RunnerGroup and "rs-<name>-" for a RunnerSet (Q677) to scope it to one CR's pool.
func (*Server) GetMessageCalls ¶
GetMessageCalls returns the number of GET /message polls served. The stub answers 202 at once rather than holding the poll, so a caller with no pacing of its own shows up here as a request storm — the rate a poll-loop test measures against.
func (*Server) HTTPClient ¶
HTTPClient returns an *http.Client suitable for use with the stub server. Since the stub uses a real TCP listener via httptest, the default client works and the unbounded read timeout is harmless — the test bounds the call (Q138).
func (*Server) JobState ¶
JobState returns the accounting state of the logical fan-out job: "queued", "in_progress", "completed", "failed", or "cancelled" (or "" if unknown). See EnableFanoutAccounting.
func (*Server) LastCompleteJob ¶
func (s *Server) LastCompleteJob() (broker.CompleteJobRequest, bool)
LastCompleteJob returns the request body of the most recent /completejob call, and false if none has been received. AuthToken is never populated (the client sends it as a header, not in the body).
func (*Server) RegisteredSessions ¶
RegisteredSessions returns the IDs of sessions that are currently active (i.e. POST /session was called but DELETE /session has not been called yet). Deleted sessions from prior tests are not included.
func (*Server) RenewJobCalls ¶
RenewJobCalls returns the number of times /renewjob was called.
func (*Server) SetAcquireJobResponse ¶
SetAcquireJobResponse configures the JSON body returned by the next /acquirejob call. Pass nil to reset to the default response. The value is serialised with json.Marshal.
func (*Server) WaitForFirstPoll ¶
WaitForFirstPoll blocks until the session with the given ID sends its first GET /message request, or until the timeout elapses. Returns true on success. Use this to confirm a listener goroutine has fully started (passed createSession and entered the poll loop) before simulating SIGTERM, so the goroutine is guaranteed to have registered its cleanup defer and will send DELETE /session.
func (*Server) WaitForSessionDelete ¶
WaitForSessionDelete blocks until the given sessionID is deleted via DELETE /session or the timeout elapses. Returns true if the session was deleted in time. If the DELETE already arrived before this call, returns true immediately.