Tier: Platform · Status: Full · Java original:
spring-boot-starter-test· .NET project:Microsoft.AspNetCore.Mvc.Testing
testkit is the framework's shared testing toolkit — the helpers
every _test.go file in every Firefly service ends up needing:
| Group | Helper |
|---|---|
| HMAC signers | SignHMAC / SignStripe / SignGitHub / SignTwilio |
| Event spy | SpyBroker.Record(...), .FindByType(...), .Reset(), .Len() |
| JSON | MustEncode(t, v) / MustDecode(t, data, &out) |
Every signer matches the wire shape of its corresponding webhooks
validator — drop them into a test handler and a real Stripe / GitHub /
Twilio webhook will validate identically.
// HMAC signers
func SignHMAC(secret, body []byte) string // "sha256=<hex>"
func SignStripe(secret, body []byte, ts time.Time) string // "t=<unix>,v1=<hex>"
func SignGitHub(secret, body []byte) string // alias of SignHMAC
func SignTwilio(authToken []byte, postURL string, form url.Values) string // base64
// Event-recording broker
type RecordedEvent struct{ Topic, Type string; Payload []byte }
type SpyBroker struct{ Items []RecordedEvent }
func NewSpyBroker() *SpyBroker
func (*SpyBroker) Record(ctx, topic, eventType string, payload []byte)
func (*SpyBroker) FindByType(eventType string) []RecordedEvent
func (*SpyBroker) Reset()
func (*SpyBroker) Len() int
// JSON helpers
func MustEncode(t *testing.T, v any) []byte
func MustDecode(t *testing.T, data []byte, target any)Verify a webhook receiver:
import (
"bytes"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/fireflyframework/fireflyframework-go/testkit"
)
func TestStripeWebhook(t *testing.T) {
secret := []byte("whsec_test")
body := []byte(`{"type":"charge.succeeded"}`)
req := httptest.NewRequest(http.MethodPost, "/api/webhooks/stripe", bytes.NewReader(body))
req.Header.Set("Stripe-Signature", testkit.SignStripe(secret, body, time.Now()))
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if rr.Code != http.StatusAccepted {
t.Fatalf("status %d", rr.Code)
}
}Assert which events a handler emitted:
func TestPlaceOrderEmits(t *testing.T) {
spy := testkit.NewSpyBroker()
placeOrder := func(ctx context.Context, order Order) error {
body := testkit.MustEncode(t, order)
spy.Record(ctx, "orders", "OrderPlaced", body)
return nil
}
_ = placeOrder(ctx, sample)
if got := spy.FindByType("OrderPlaced"); len(got) != 1 {
t.Fatalf("emit count: %d", len(got))
}
}cd testkit
go test ./...Covers each signer against a known-good HMAC fixture, SpyBroker record/filter/reset, and the JSON helpers.