Skip to content

Commit 17b3dce

Browse files
Merge pull request #41 from priyanshujain/refactor-tests
fix: flaky and dead test code
2 parents 4987d6f + 7ecc365 commit 17b3dce

File tree

9 files changed

+57
-47
lines changed

9 files changed

+57
-47
lines changed
Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
"github.com/priyanshujain/openbotkit/provider/openai"
1818
)
1919

20-
// providerTestCase holds a provider instance and model name for table-driven integration tests.
20+
// providerTestCase holds a provider instance and model name for provider conformance tests.
2121
type providerTestCase struct {
2222
name string
2323
provider provider.Provider
@@ -81,15 +81,14 @@ func availableProviders(t *testing.T) []providerTestCase {
8181
}
8282

8383
if len(providers) == 0 {
84-
t.Skip("no API keys set (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY) — skipping integration tests")
84+
t.Skip("no API keys set (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY) — skipping provider tests")
8585
}
8686
return providers
8787
}
8888

89-
// TestIntegration_AgentLoop tests the full agent loop with a real LLM API.
90-
// The agent is given a bash tool, asked to run "echo hello", and should
91-
// return a response containing the command output.
92-
func TestIntegration_AgentLoop(t *testing.T) {
89+
// TestProvider_AgentToolExecution verifies each provider can drive the agent
90+
// loop: user request → tool call → tool execution → text response.
91+
func TestProvider_AgentToolExecution(t *testing.T) {
9392
for _, tc := range availableProviders(t) {
9493
t.Run(tc.name, func(t *testing.T) {
9594
reg := tools.NewRegistry()
@@ -115,9 +114,9 @@ func TestIntegration_AgentLoop(t *testing.T) {
115114
}
116115
}
117116

118-
// TestIntegration_ToolUseRoundtrip verifies the provider correctly handles a
119-
// tool_use → tool_result → text response cycle via the real API.
120-
func TestIntegration_ToolUseRoundtrip(t *testing.T) {
117+
// TestProvider_ToolUseRoundtrip verifies each provider correctly handles the
118+
// tool_use → tool_result → text response cycle against the real API.
119+
func TestProvider_ToolUseRoundtrip(t *testing.T) {
121120
for _, tc := range availableProviders(t) {
122121
t.Run(tc.name, func(t *testing.T) {
123122
toolSchema := provider.Tool{
@@ -170,6 +169,7 @@ func TestIntegration_ToolUseRoundtrip(t *testing.T) {
170169
Type: provider.ContentToolResult,
171170
ToolResult: &provider.ToolResult{
172171
ToolUseID: calls[0].ID,
172+
Name: calls[0].Name,
173173
Content: `{"temperature": "22°C", "condition": "Sunny"}`,
174174
},
175175
},
@@ -205,8 +205,9 @@ func TestIntegration_ToolUseRoundtrip(t *testing.T) {
205205
}
206206
}
207207

208-
// TestIntegration_Streaming verifies streaming works with the real API.
209-
func TestIntegration_Streaming(t *testing.T) {
208+
// TestProvider_Streaming verifies each provider's streaming implementation
209+
// delivers text deltas and a done event.
210+
func TestProvider_Streaming(t *testing.T) {
210211
for _, tc := range availableProviders(t) {
211212
t.Run(tc.name, func(t *testing.T) {
212213
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)

channel/telegram/integration_test.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ import (
1818
"github.com/priyanshujain/openbotkit/store"
1919
)
2020

21-
// TestIntegration_SessionWithRealLLM tests the full session lifecycle:
22-
// message → agent with real Gemini API → response → history saved.
23-
func TestIntegration_SessionWithRealLLM(t *testing.T) {
21+
// TestSession_MessageAndHistorySaved verifies the full session lifecycle:
22+
// message → agent with real Gemini API → response → history saved to DB.
23+
func TestSession_MessageAndHistorySaved(t *testing.T) {
2424
key := testutil.RequireGeminiKey(t)
2525

2626
dir := t.TempDir()
@@ -105,7 +105,9 @@ func TestIntegration_SessionWithRealLLM(t *testing.T) {
105105

106106
// TestIntegration_SessionWithMemoryInjection tests that user memories are injected
107107
// into the system prompt when the agent processes a message.
108-
func TestIntegration_SessionWithMemoryInjection(t *testing.T) {
108+
// TestSession_MemoryInjectedIntoPrompt verifies memories from the DB appear
109+
// in the system prompt and the agent can reference them.
110+
func TestSession_MemoryInjectedIntoPrompt(t *testing.T) {
109111
key := testutil.RequireGeminiKey(t)
110112

111113
dir := t.TempDir()
@@ -171,7 +173,9 @@ func TestIntegration_SessionWithMemoryInjection(t *testing.T) {
171173

172174
// TestIntegration_SessionWithToolUse tests that the agent can use tools
173175
// (like bash) when processing a Telegram message.
174-
func TestIntegration_SessionWithToolUse(t *testing.T) {
176+
// TestSession_ToolUseViaBash verifies the agent can execute bash commands
177+
// through the tool use loop within a Telegram session.
178+
func TestSession_ToolUseViaBash(t *testing.T) {
175179
key := testutil.RequireGeminiKey(t)
176180

177181
dir := t.TempDir()

channel/telegram/telegram_test.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,27 @@ import (
44
"io"
55
"sync"
66
"testing"
7+
"time"
78

89
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
910
)
1011

1112
type mockBot struct {
12-
mu sync.Mutex
13-
sent []tgbotapi.Chattable
13+
mu sync.Mutex
14+
sent []tgbotapi.Chattable
15+
notify chan struct{}
1416
}
1517

1618
func (m *mockBot) Send(c tgbotapi.Chattable) (tgbotapi.Message, error) {
1719
m.mu.Lock()
1820
defer m.mu.Unlock()
1921
m.sent = append(m.sent, c)
22+
if m.notify != nil {
23+
select {
24+
case m.notify <- struct{}{}:
25+
default:
26+
}
27+
}
2028
return tgbotapi.Message{}, nil
2129
}
2230

@@ -74,7 +82,7 @@ func TestReceive_EOFOnClose(t *testing.T) {
7482
}
7583

7684
func TestRequestApproval_SendsKeyboard(t *testing.T) {
77-
bot := &mockBot{}
85+
bot := &mockBot{notify: make(chan struct{}, 1)}
7886
ch := NewChannel(bot, 123)
7987

8088
done := make(chan bool, 1)
@@ -87,14 +95,10 @@ func TestRequestApproval_SendsKeyboard(t *testing.T) {
8795
done <- approved
8896
}()
8997

90-
// Wait for the approval message to be sent
91-
for {
92-
bot.mu.Lock()
93-
n := len(bot.sent)
94-
bot.mu.Unlock()
95-
if n > 0 {
96-
break
97-
}
98+
select {
99+
case <-bot.notify:
100+
case <-time.After(5 * time.Second):
101+
t.Fatal("timed out waiting for approval message")
98102
}
99103

100104
bot.mu.Lock()
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ func newLocalBackend(t *testing.T) servertest.Backend {
7070
}
7171
}
7272

73-
// TestServer_Local runs the full server test suite against a local httptest server.
74-
func TestServer_Local(t *testing.T) {
73+
// TestServerAPI runs the server API contract tests (auth, CRUD, validation,
74+
// DB proxy) against a local httptest server.
75+
func TestServerAPI(t *testing.T) {
7576
if _, err := exec.LookPath("sqlite3"); err != nil {
7677
t.Skip("sqlite3 not in PATH")
7778
}

internal/server/docker_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import (
1515
"github.com/testcontainers/testcontainers-go/wait"
1616
)
1717

18-
// TestServer_Docker runs the full server test suite against a Docker container
19-
// built from the repo's Dockerfile. Requires Docker to be running.
20-
func TestServer_Docker(t *testing.T) {
18+
// TestServerAPI_Docker runs the server API contract tests against a Docker
19+
// container built from the repo's Dockerfile. Requires Docker to be running.
20+
func TestServerAPI_Docker(t *testing.T) {
2121
if testing.Short() {
2222
t.Skip("skipping Docker test in short mode")
2323
}

internal/servertest/suite.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import (
66
"github.com/priyanshujain/openbotkit/remote"
77
)
88

9-
// Backend provides a configured client for running the server test suite.
10-
// The suite exercises all server functionality through the remote.Client,
11-
// making it backend-agnostic: the same tests run against a local httptest
12-
// server and a Docker container.
9+
// Backend provides a configured client for running the server API contract
10+
// tests. The suite verifies auth, CRUD, validation, and DB proxy behavior
11+
// through the remote.Client — backend-agnostic so the same tests run against
12+
// a local httptest server and a Docker container.
1313
type Backend struct {
1414
Client *remote.Client
1515
NoAuthClient *remote.Client

memory/integration_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ func (pl *providerLLM) Chat(ctx context.Context, req provider.ChatRequest) (*pro
7373
return pl.p.Chat(ctx, req)
7474
}
7575

76-
func TestIntegration_Extract(t *testing.T) {
76+
// TestExtract_WithRealLLM verifies fact extraction from conversation messages
77+
// produces valid categorized facts.
78+
func TestExtract_WithRealLLM(t *testing.T) {
7779
for _, tc := range availableProviders(t) {
7880
t.Run(tc.name, func(t *testing.T) {
7981
llm := &providerLLM{p: tc.provider, model: tc.model}
@@ -110,7 +112,10 @@ func TestIntegration_Extract(t *testing.T) {
110112
}
111113
}
112114

113-
func TestIntegration_ExtractAndReconcile(t *testing.T) {
115+
// TestExtractAndReconcile_WithRealLLM verifies the full pipeline: extract facts
116+
// from messages, reconcile against existing DB (add new, update changed, skip
117+
// duplicates).
118+
func TestExtractAndReconcile_WithRealLLM(t *testing.T) {
114119
for _, tc := range availableProviders(t) {
115120
t.Run(tc.name, func(t *testing.T) {
116121
db := testDB(t)

source/whatsapp/auth_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ func TestWaitForHistorySync_QuietPeriod(t *testing.T) {
218218
waitForHistorySync(ch, 5*time.Second, 100*time.Millisecond)
219219
elapsed := time.Since(start)
220220

221-
if elapsed < 100*time.Millisecond || elapsed > 500*time.Millisecond {
221+
if elapsed < 100*time.Millisecond || elapsed > 5*time.Second {
222222
t.Fatalf("expected ~100ms quiet period, got %v", elapsed)
223223
}
224224
}
@@ -238,7 +238,7 @@ func TestWaitForHistorySync_ResetOnMultipleEvents(t *testing.T) {
238238

239239
// First signal at t=0 starts 100ms quiet timer; second at t=80ms resets it.
240240
// Should return around t=180ms.
241-
if elapsed < 150*time.Millisecond || elapsed > 500*time.Millisecond {
241+
if elapsed < 150*time.Millisecond || elapsed > 5*time.Second {
242242
t.Fatalf("expected ~180ms (reset quiet period), got %v", elapsed)
243243
}
244244
}
@@ -265,7 +265,7 @@ func TestWaitForHistorySync_DeadlineExpires(t *testing.T) {
265265
elapsed := time.Since(start)
266266
close(stop)
267267

268-
if elapsed < 180*time.Millisecond || elapsed > 500*time.Millisecond {
268+
if elapsed < 180*time.Millisecond || elapsed > 5*time.Second {
269269
t.Fatalf("expected ~200ms deadline, got %v", elapsed)
270270
}
271271
}
@@ -277,7 +277,7 @@ func TestWaitForHistorySync_NoSignal(t *testing.T) {
277277
waitForHistorySync(ch, 200*time.Millisecond, 100*time.Millisecond)
278278
elapsed := time.Since(start)
279279

280-
if elapsed < 180*time.Millisecond || elapsed > 500*time.Millisecond {
280+
if elapsed < 180*time.Millisecond || elapsed > 5*time.Second {
281281
t.Fatalf("expected ~200ms deadline (no signal), got %v", elapsed)
282282
}
283283
}

source/whatsapp/sync_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,3 @@ func TestTruncate(t *testing.T) {
168168
}
169169
}
170170

171-
func TestChatName(t *testing.T) {
172-
// chatName is not exported, but we test it via the events.Message path.
173-
// For now, test the helper directly since we're in the same package.
174-
// chatName returns push name for non-group chats.
175-
}

0 commit comments

Comments
 (0)