Skip to content

Commit 1d4fa1f

Browse files
Thomas StrombergThomas Stromberg
authored andcommitted
improve test coverage
1 parent 569d301 commit 1d4fa1f

32 files changed

+5332
-158
lines changed

.github/workflows/test.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [main, master]
6+
pull_request:
7+
branches: [main, master]
8+
9+
jobs:
10+
test:
11+
name: Unit and Integration Tests
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Check out code
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Go
19+
uses: actions/setup-go@v5
20+
with:
21+
go-version: '1.23'
22+
cache: true
23+
24+
- name: Install dependencies
25+
run: |
26+
sudo apt-get update
27+
sudo apt-get install -y bc
28+
29+
- name: Download dependencies
30+
run: go mod download
31+
32+
- name: Run tests with coverage
33+
run: make test
34+
35+
- name: Upload coverage to Codecov
36+
uses: codecov/codecov-action@v4
37+
with:
38+
file: ./coverage.out
39+
flags: unittests
40+
name: codecov-slacker
41+
fail_ci_if_error: false
42+
continue-on-error: true
43+
44+
- name: Archive coverage results
45+
uses: actions/upload-artifact@v4
46+
with:
47+
name: coverage-report
48+
path: coverage.out
49+
retention-days: 30

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11

22
# added by lint-install
33
out/
4+
coverage.out

Makefile

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,37 @@ build-server:
1414
build-registrar:
1515
go build -v -o bin/slack-registrar ./cmd/registrar
1616

17-
# Run tests with race detection
17+
# Run tests with race detection and coverage
1818
test:
19-
go test -v -race ./...
19+
@echo "Running tests with race detection and coverage..."
20+
@go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
21+
@echo ""
22+
@echo "Coverage by package:"
23+
@go test -coverprofile=coverage.out -covermode=atomic ./... 2>&1 | grep -E "coverage:" | awk '{print $$2 "\t" $$5}' | column -t
24+
@echo ""
25+
@echo "Checking for packages below 80% coverage..."
26+
@failed=0; \
27+
packages=$$(go list ./... | grep -v "/cmd/"); \
28+
for pkg in $$packages; do \
29+
output=$$(go test -coverprofile=/dev/null "$$pkg" 2>&1); \
30+
if echo "$$output" | grep -q "\[no test files\]"; then \
31+
continue; \
32+
fi; \
33+
coverage=$$(echo "$$output" | grep "coverage:" | awk '{print $$5}' | sed 's/%//'); \
34+
if [ -n "$$coverage" ] && [ "$$coverage" != "statements" ]; then \
35+
pkg_short=$$(echo "$$pkg" | sed 's|github.com/codeGROOVE-dev/slacker/||'); \
36+
if [ "$$(echo "$$coverage < 80.0" | bc -l 2>/dev/null || echo 0)" -eq 1 ]; then \
37+
echo "❌ FAIL: $$pkg_short has $$coverage% coverage (minimum: 80%)"; \
38+
failed=1; \
39+
fi; \
40+
fi; \
41+
done; \
42+
if [ $$failed -eq 1 ]; then \
43+
echo ""; \
44+
echo "Coverage check failed. All packages must have at least 80% coverage."; \
45+
exit 1; \
46+
fi
47+
@echo "✅ All packages meet 80% coverage threshold"
2048

2149
# Format code
2250
fmt:

cmd/server/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ func run(ctx context.Context, cancel context.CancelFunc, cfg *config.ServerConfi
256256
slog.Info("configured Slack manager with state store for DM tracking")
257257

258258
// Initialize notification manager for multi-workspace notifications.
259-
notifier := notify.New(slackManager, configManager)
259+
notifier := notify.New(notify.WrapSlackManager(slackManager), configManager)
260260

261261
// Initialize event router for multi-workspace event handling.
262262
eventRouter := slack.NewEventRouter(slackManager)
@@ -711,7 +711,7 @@ func runBotCoordinators(
711711
}
712712

713713
// Initialize daily digest scheduler
714-
dailyDigest := notify.NewDailyDigestScheduler(notifier, githubManager, configManager, stateStore, slackManager)
714+
dailyDigest := notify.NewDailyDigestScheduler(notifier, github.WrapManager(githubManager), configManager, stateStore, notify.WrapSlackManager(slackManager))
715715

716716
// Start initial coordinators
717717
cm.startCoordinators(ctx)

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ require (
66
cloud.google.com/go/datastore v1.21.0
77
github.com/codeGROOVE-dev/gh-mailto v0.0.0-20251024133418-149270eb16a9
88
github.com/codeGROOVE-dev/gsm v0.0.0-20251019065141-833fe2363d22
9+
github.com/codeGROOVE-dev/prx v0.0.0-20251028202628-9f237ee71356
910
github.com/codeGROOVE-dev/retry v1.3.0
10-
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251028184624-4d8c8315a53a
11+
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251028194710-957b79f7bf56
1112
github.com/codeGROOVE-dev/turnclient v0.0.0-20251028130307-1f85c9aa43c4
1213
github.com/golang-jwt/jwt/v5 v5.3.0
1314
github.com/google/go-github/v50 v50.2.0
@@ -27,7 +28,6 @@ require (
2728
cloud.google.com/go/compute/metadata v0.9.0 // indirect
2829
github.com/ProtonMail/go-crypto v1.3.0 // indirect
2930
github.com/cloudflare/circl v1.6.1 // indirect
30-
github.com/codeGROOVE-dev/prx v0.0.0-20251027204543-4e6165f046e5 // indirect
3131
github.com/felixge/httpsnoop v1.0.4 // indirect
3232
github.com/go-logr/logr v1.4.3 // indirect
3333
github.com/go-logr/stdr v1.2.2 // indirect

go.sum

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,16 @@ github.com/codeGROOVE-dev/gh-mailto v0.0.0-20251024133418-149270eb16a9 h1:eyWcEZ
1919
github.com/codeGROOVE-dev/gh-mailto v0.0.0-20251024133418-149270eb16a9/go.mod h1:4Hr2ySB8dcpeZqZq/7UbXdEJ/5RK9coYGHvW90ZfieE=
2020
github.com/codeGROOVE-dev/gsm v0.0.0-20251019065141-833fe2363d22 h1:gtN3rOc6YspO646BkcOxBhPjEqKUz+jl175jIqglfDg=
2121
github.com/codeGROOVE-dev/gsm v0.0.0-20251019065141-833fe2363d22/go.mod h1:KV+w19ubP32PxZPE1hOtlCpTaNpF0Bpb32w5djO8UTg=
22-
github.com/codeGROOVE-dev/prx v0.0.0-20251024000018-35ba2605d031 h1:wLeo/dwpE5F2E/j/W+lb2HJ9nEX8KYIfJ1yEtyZYdrg=
23-
github.com/codeGROOVE-dev/prx v0.0.0-20251024000018-35ba2605d031/go.mod h1:7qLbi18baOyS8yO/6/64SBIqtyzSzLFdsDST15NPH3w=
24-
github.com/codeGROOVE-dev/prx v0.0.0-20251027012315-7b273aabfc7d h1:kUaCKFRxWFrWEyl4fVHi+eY/D5tKhBU29a8YbQyihEk=
25-
github.com/codeGROOVE-dev/prx v0.0.0-20251027012315-7b273aabfc7d/go.mod h1:7qLbi18baOyS8yO/6/64SBIqtyzSzLFdsDST15NPH3w=
2622
github.com/codeGROOVE-dev/prx v0.0.0-20251027204543-4e6165f046e5 h1:tjxTLJ5NXx1xhReL4M+J4LTl/JGNSZjPrznAoci06OA=
2723
github.com/codeGROOVE-dev/prx v0.0.0-20251027204543-4e6165f046e5/go.mod h1:FEy3gz9IYDXWnKWkoDSL+pWu6rujxbBSrF4w5A8QSK0=
28-
github.com/codeGROOVE-dev/retry v1.2.0 h1:xYpYPX2PQZmdHwuiQAGGzsBm392xIMl4nfMEFApQnu8=
29-
github.com/codeGROOVE-dev/retry v1.2.0/go.mod h1:8OgefgV1XP7lzX2PdKlCXILsYKuz6b4ZpHa/20iLi8E=
24+
github.com/codeGROOVE-dev/prx v0.0.0-20251028202628-9f237ee71356 h1:lHoHnylLAp7/7BMhdiTh9Z2+p4ATcQ7aFcgqxOFGzE4=
25+
github.com/codeGROOVE-dev/prx v0.0.0-20251028202628-9f237ee71356/go.mod h1:FEy3gz9IYDXWnKWkoDSL+pWu6rujxbBSrF4w5A8QSK0=
3026
github.com/codeGROOVE-dev/retry v1.3.0 h1:/+ipAWRJLL6y1R1vprYo0FSjSBvH6fE5j9LKXjpD54g=
3127
github.com/codeGROOVE-dev/retry v1.3.0/go.mod h1:8OgefgV1XP7lzX2PdKlCXILsYKuz6b4ZpHa/20iLi8E=
32-
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027150242-98f387d0502a h1:bMRtyBA38hvuXZJUH5UDFpOAuwNINg2j/ecug31wp+M=
33-
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027150242-98f387d0502a/go.mod h1:/kd3ncsRNldD0MUpbtp5ojIzfCkyeXB7JdOrpuqG7Gg=
34-
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027213037-05bb80a9db89 h1:8Z3SM90hy1nuK2r2yhtv4HwitnO9si4GzVRktRDQ68g=
35-
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251027213037-05bb80a9db89/go.mod h1:/kd3ncsRNldD0MUpbtp5ojIzfCkyeXB7JdOrpuqG7Gg=
3628
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251028184624-4d8c8315a53a h1:P1qUAC4QG4zNH31y0R4ZJdnqpqHM+chKrTiI86GlIaw=
3729
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251028184624-4d8c8315a53a/go.mod h1:/kd3ncsRNldD0MUpbtp5ojIzfCkyeXB7JdOrpuqG7Gg=
38-
github.com/codeGROOVE-dev/turnclient v0.0.0-20251022064427-5a712e1e10e6 h1:7FCmaftkl362oTZHVJyUg+xhxqfQFx+JisBf7RgklL8=
39-
github.com/codeGROOVE-dev/turnclient v0.0.0-20251022064427-5a712e1e10e6/go.mod h1:fYwtN9Ql6lY8t2WvCfENx+mP5FUwjlqwXCLx9CVLY20=
30+
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251028194710-957b79f7bf56 h1:4/xJ+ZOrG8QNPLqQgTu28WNocO6G/iZBD0SUNKpluhk=
31+
github.com/codeGROOVE-dev/sprinkler v0.0.0-20251028194710-957b79f7bf56/go.mod h1:/kd3ncsRNldD0MUpbtp5ojIzfCkyeXB7JdOrpuqG7Gg=
4032
github.com/codeGROOVE-dev/turnclient v0.0.0-20251028130307-1f85c9aa43c4 h1:si9tMEo5SXpDuDXGkJ1zNnnpP8TbmakrkNujAbpKlqA=
4133
github.com/codeGROOVE-dev/turnclient v0.0.0-20251028130307-1f85c9aa43c4/go.mod h1:bFWMd0JeaJY0kSIO5AcRQdJLXF3Fo3eKclE49vmIZes=
4234
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -129,8 +121,6 @@ golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
129121
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
130122
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
131123
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
132-
google.golang.org/api v0.253.0 h1:apU86Eq9Q2eQco3NsUYFpVTfy7DwemojL7LmbAj7g/I=
133-
google.golang.org/api v0.253.0/go.mod h1:PX09ad0r/4du83vZVAaGg7OaeyGnaUmT/CYPNvtLCbw=
134124
google.golang.org/api v0.254.0 h1:jl3XrGj7lRjnlUvZAbAdhINTLbsg5dbjmR90+pTQvt4=
135125
google.golang.org/api v0.254.0/go.mod h1:5BkSURm3D9kAqjGvBNgf0EcbX6Rnrf6UArKkwBzAyqQ=
136126
google.golang.org/genproto v0.0.0-20251022142026-3a174f9686a8 h1:a12a2/BiVRxRWIqBbfqoSK6tgq8cyUgMnEI81QlPge0=

internal/bot/bot.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,8 @@ func (c *Coordinator) processPRForChannel(
13531353
domain := c.configManager.Domain(owner)
13541354
if len(blockedUsers) > 0 {
13551355
// Record tags for blocked users synchronously to prevent race with DM sending
1356-
lookupCtx, lookupCancel := context.WithTimeout(ctx, 5*time.Second)
1356+
// Generous timeout: GitHub email lookup (~5-10s) + Slack API lookups (~5-10s)
1357+
lookupCtx, lookupCancel := context.WithTimeout(ctx, 30*time.Second)
13571358
defer lookupCancel()
13581359

13591360
for _, githubUser := range blockedUsers {

internal/bot/format_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package bot
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/codeGROOVE-dev/turnclient/pkg/turn"
8+
)
9+
10+
// TestFormatNextActionsEarlyReturn tests the formatNextActions utility function early return cases.
11+
func TestFormatNextActionsEarlyReturn(t *testing.T) {
12+
// Create a coordinator - userMapper will be nil but that's OK for these early return tests
13+
c := &Coordinator{}
14+
15+
ctx := context.Background()
16+
17+
tests := []struct {
18+
name string
19+
check *turn.CheckResponse
20+
owner string
21+
domain string
22+
expected string
23+
}{
24+
{
25+
name: "nil check response",
26+
check: nil,
27+
owner: "org",
28+
domain: "example.com",
29+
expected: "",
30+
},
31+
{
32+
name: "empty next actions",
33+
check: &turn.CheckResponse{
34+
Analysis: turn.Analysis{
35+
NextAction: map[string]turn.Action{},
36+
},
37+
},
38+
owner: "org",
39+
domain: "example.com",
40+
expected: "",
41+
},
42+
}
43+
44+
for _, tt := range tests {
45+
t.Run(tt.name, func(t *testing.T) {
46+
result := c.formatNextActions(ctx, tt.check, tt.owner, tt.domain)
47+
if result != tt.expected {
48+
t.Errorf("expected %q, got %q", tt.expected, result)
49+
}
50+
})
51+
}
52+
}

internal/bot/integration_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ func TestDMDelayLogicIntegration(t *testing.T) {
231231
dmDelay: 65, // 65 minute delay
232232
}
233233

234-
notifier := notify.New(slackManager, configMgr)
234+
notifier := notify.New(notify.WrapSlackManager(slackManager), configMgr)
235235

236236
prInfo := notify.PRInfo{
237237
Owner: "test",
@@ -291,7 +291,7 @@ func TestDMDelayLogicIntegration(t *testing.T) {
291291
// Create fresh tracker with initialized maps
292292
notifier.Tracker = &notify.NotificationTracker{}
293293
// Initialize the tracker by creating a new notifier
294-
notifier = notify.New(slackManager, configMgr)
294+
notifier = notify.New(notify.WrapSlackManager(slackManager), configMgr)
295295

296296
// Setup test scenario
297297
if tt.setupFunc != nil {

0 commit comments

Comments
 (0)