Skip to content

Commit 5322dee

Browse files
committed
feat: 8s backoff cap, scheduled production smoke
Aligns the retry backoff cap with the other spoo SDKs. The daily smoke runs behind the smoke build tag against production: create, per-link stats, emoji catalogue, delete.
1 parent b2f21b3 commit 5322dee

3 files changed

Lines changed: 93 additions & 1 deletion

File tree

.github/workflows/smoke.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Production smoke
2+
3+
# Runs the SDK against production daily behind the smoke build tag:
4+
# create, per-link stats, emoji catalogue, delete. Requires the
5+
# SPOO_SMOKE_API_KEY secret (dedicated low-scope key).
6+
on:
7+
schedule:
8+
- cron: "20 3 * * *"
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
smoke:
16+
runs-on: ubuntu-latest
17+
if: github.repository == 'spoo-me/spoo-go'
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v7
21+
22+
- name: Set up Go
23+
uses: actions/setup-go@v6
24+
with:
25+
go-version: stable
26+
27+
- name: Smoke against production
28+
env:
29+
SPOO_SMOKE_API_KEY: ${{ secrets.SPOO_SMOKE_API_KEY }}
30+
run: go test -tags smoke -run TestProdSmoke -v -count=1 .

internal/transport/transport.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const (
1717
// RetryBaseDelay is the exponential-backoff unit.
1818
RetryBaseDelay = 500 * time.Millisecond
1919
// retryMaxDelay caps a single computed backoff.
20-
retryMaxDelay = 10 * time.Second
20+
retryMaxDelay = 8 * time.Second
2121
)
2222

2323
// IdempotentMethod reports whether an HTTP method is safe to replay

smoke_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//go:build smoke
2+
3+
package spoo_test
4+
5+
// Scheduled production smoke: create a link, read its stats, fetch the emoji
6+
// catalogue, delete the link. Runs only with -tags smoke and a dedicated
7+
// low-scope key in SPOO_SMOKE_API_KEY; it is not part of the offline suite.
8+
9+
import (
10+
"context"
11+
"fmt"
12+
"os"
13+
"testing"
14+
"time"
15+
16+
spoo "github.com/spoo-me/spoo-go"
17+
"github.com/spoo-me/spoo-go/option"
18+
)
19+
20+
func TestProdSmoke(t *testing.T) {
21+
key := os.Getenv("SPOO_SMOKE_API_KEY")
22+
if key == "" {
23+
t.Skip("SPOO_SMOKE_API_KEY not set")
24+
}
25+
client := spoo.NewClient(
26+
option.WithAPIKey(key),
27+
option.WithClientTag("sdk-go-smoke"),
28+
)
29+
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
30+
defer cancel()
31+
32+
link, err := client.Shorten(ctx, spoo.ShortenRequest{
33+
LongURL: fmt.Sprintf("https://example.com/?smoke=%d", time.Now().UnixNano()),
34+
})
35+
if err != nil {
36+
t.Fatalf("shorten: %v", err)
37+
}
38+
defer func() {
39+
if err := client.DeleteURL(ctx, link.ID); err != nil {
40+
t.Errorf("cleanup delete: %v", err)
41+
}
42+
}()
43+
if link.ShortURL == "" {
44+
t.Fatal("shorten: empty short_url")
45+
}
46+
47+
stats, err := client.LinkStats(ctx, link.ID, spoo.StatsQuery{GroupBy: []string{"time"}})
48+
if err != nil {
49+
t.Fatalf("link stats: %v", err)
50+
}
51+
if stats.Summary.TotalClicks != 0 {
52+
t.Fatalf("link stats: expected 0 clicks on a fresh link, got %d", stats.Summary.TotalClicks)
53+
}
54+
55+
set, err := client.EmojiSet(ctx)
56+
if err != nil {
57+
t.Fatalf("emoji set: %v", err)
58+
}
59+
if len(set.Emoji) == 0 {
60+
t.Fatal("emoji set: empty catalogue")
61+
}
62+
}

0 commit comments

Comments
 (0)