Skip to content

Commit 5f12bb9

Browse files
authored
feat(provider): add SoftFail mode for downstream-gated verification (#580)
Callers that have a downstream authoritative gate (e.g. a Pact Broker can-i-merge / can-i-deploy check) want verification mismatches to be recorded to the broker and reported in the test framework, but NOT to fail CI locally — the downstream gate makes the real decision. Previously the only way to suppress local failure was at the shell layer (turning off pipefail around `go test`), which also silenced verifier panics, broker auth failures, and any other infrastructure problem. That made "tests didn't actually run but CI is green" a common failure mode. New behavior — `VerifyRequest.SoftFail` (default false, preserves existing behavior): - SoftFail = false (default): err == nil → subtest PASS err != nil → subtest FAIL (t.Error) - SoftFail = true: err == nil → subtest PASS ErrVerifierFailed → subtest SKIP (t.Skipf, message preserved) any other err → subtest FAIL (t.Error) Infrastructure errors (ErrVerifierFailedToRun, panics, broker auth) always fail the subtest, regardless of SoftFail — they signal the verifier could not produce a result for the downstream gate to act on. The discrimination uses `errors.Is(err, native.ErrVerifierFailed)`, which leverages the mutual-exclusivity invariant of the two verifier sentinels documented in #579.
1 parent 6f25926 commit 5f12bb9

2 files changed

Lines changed: 40 additions & 1 deletion

File tree

provider/verifier.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package provider
22

33
import (
44
"encoding/json"
5+
"errors"
56
"fmt"
67
"io"
78
"log"
@@ -172,14 +173,35 @@ func (v *Verifier) verifyProviderRaw(request VerifyRequest, writer outputWriter)
172173
// VerifyProvider accepts an instance of `*testing.T`
173174
// running the provider verification with granular test reporting and
174175
// automatic failure reporting for nice, simple tests.
176+
//
177+
// The subtest "Provider pact verification" renders as:
178+
// - PASS when verification succeeded;
179+
// - SKIP (with the underlying error in the skip message) when
180+
// request.SoftFail is true AND the error is a verification mismatch
181+
// (errors.Is(err, ErrVerifierFailed)) — i.e. a downstream gate owns
182+
// the authoritative compatibility decision;
183+
// - FAIL otherwise — strict mode for any error, or soft-fail mode when
184+
// the verifier itself could not produce a result (infrastructure
185+
// error, panic, etc.).
175186
func (v *Verifier) VerifyProvider(t *testing.T, request VerifyRequest) error {
176187
err := v.verifyProviderRaw(request, t)
177188

178189
// TODO: granular test reporting
179190
// runTestCases(t, res)
180191

181192
t.Run("Provider pact verification", func(t *testing.T) {
182-
if err != nil {
193+
switch {
194+
case err == nil:
195+
// PASS — verification succeeded.
196+
case request.SoftFail && errors.Is(err, native.ErrVerifierFailed):
197+
// Soft-fail mode + verification mismatch: render as SKIP so the
198+
// test framework does not propagate failure. The caller is
199+
// responsible for gating elsewhere (e.g. broker can-i-merge).
200+
t.Skipf("pact verification failed (soft-fail enabled, broker has the record): %v", err)
201+
default:
202+
// Strict mode + any error, OR soft-fail mode + infrastructure
203+
// error: fail loudly. Infrastructure errors signal the verifier
204+
// could not produce a result for downstream gates to act on.
183205
t.Error(err)
184206
}
185207
})

provider/verify_request.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@ type VerifyRequest struct {
112112
// PublishVerificationResults to the Pact Broker.
113113
PublishVerificationResults bool
114114

115+
// SoftFail, when true, renders a verification mismatch (one or more
116+
// consumer expectations not satisfied by the provider, returned by the
117+
// verifier as ErrVerifierFailed) as a SKIPped subtest rather than a
118+
// failed one. Use when the caller has a downstream gate — e.g. a Pact
119+
// Broker can-i-merge / can-i-deploy check — that owns the authoritative
120+
// compatibility decision, and local CI failure on the mismatch would
121+
// duplicate or contradict that gate.
122+
//
123+
// Infrastructure errors (ErrVerifierFailedToRun, panics, broker auth
124+
// failures, etc.) always fail the subtest regardless of this flag —
125+
// they signal that the verifier could not produce a result for the
126+
// downstream gate to act on.
127+
//
128+
// Default false preserves existing behavior: any verifier error fails
129+
// the subtest.
130+
SoftFail bool
131+
115132
// ProviderVersion is the semantical version of the Provider API.
116133
ProviderVersion string
117134

0 commit comments

Comments
 (0)