Skip to content

Commit 13148d8

Browse files
authored
Merge pull request #56 from systemli/Add-context-timeout-for-HTTP-requests
⏱️ Add context timeout for HTTP requests (5s)
2 parents 3debb25 + 5a5c7b2 commit 13148d8

File tree

9 files changed

+348
-140
lines changed

9 files changed

+348
-140
lines changed

.mockery.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
all: false
2+
dir: "{{.InterfaceDir}}"
3+
filename: mock_UserliService.go
4+
force-file-write: true
5+
formatter: goimports
6+
include-auto-generated: false
7+
log-level: info
8+
structname: "{{.Mock}}{{.InterfaceName}}"
9+
pkgname: "{{.SrcPackageName}}"
10+
recursive: false
11+
require-template-schema-exists: true
12+
template: testify
13+
template-schema: "{{.Template}}.schema.json"
14+
packages:
15+
github.com/systemli/userli-postfix-adapter:
16+
config:
17+
all: true

adapter.go

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
56
"io"
67
"net"
@@ -84,29 +85,33 @@ func (s *SocketmapAdapter) HandleConnection(conn net.Conn) {
8485
"key": key,
8586
}).Debug("Processing socketmap request")
8687

88+
// Create context with timeout for this request
89+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
90+
8791
// Route to appropriate handler based on map name
8892
var response *SocketmapResponse
8993
switch mapName {
9094
case "alias":
91-
response = s.handleAlias(key)
95+
response = s.handleAlias(ctx, key)
9296
case "domain":
93-
response = s.handleDomain(key)
97+
response = s.handleDomain(ctx, key)
9498
case "mailbox":
95-
response = s.handleMailbox(key)
99+
response = s.handleMailbox(ctx, key)
96100
case "senders":
97-
response = s.handleSenders(key)
101+
response = s.handleSenders(ctx, key)
98102
default:
99103
log.WithField("map", mapName).Error("Unknown map name")
100104
response = &SocketmapResponse{Status: "PERM", Data: "Unknown map name"}
101105
}
102106

107+
cancel() // Always cancel context when done
103108
s.writeResponse(encoder, conn, response, now, mapName)
104109
}
105110
}
106111

107112
// handleAlias processes alias lookup requests
108-
func (s *SocketmapAdapter) handleAlias(key string) *SocketmapResponse {
109-
aliases, err := s.client.GetAliases(key)
113+
func (s *SocketmapAdapter) handleAlias(ctx context.Context, key string) *SocketmapResponse {
114+
aliases, err := s.client.GetAliases(ctx, key)
110115
if err != nil {
111116
log.WithError(err).WithField("key", key).Error("Error fetching aliases")
112117
return &SocketmapResponse{Status: "TEMP", Data: "Error fetching aliases"}
@@ -120,8 +125,8 @@ func (s *SocketmapAdapter) handleAlias(key string) *SocketmapResponse {
120125
}
121126

122127
// handleDomain processes domain lookup requests
123-
func (s *SocketmapAdapter) handleDomain(key string) *SocketmapResponse {
124-
exists, err := s.client.GetDomain(key)
128+
func (s *SocketmapAdapter) handleDomain(ctx context.Context, key string) *SocketmapResponse {
129+
exists, err := s.client.GetDomain(ctx, key)
125130
if err != nil {
126131
log.WithError(err).WithField("key", key).Error("Error fetching domain")
127132
return &SocketmapResponse{Status: "TEMP", Data: "Error fetching domain"}
@@ -135,8 +140,8 @@ func (s *SocketmapAdapter) handleDomain(key string) *SocketmapResponse {
135140
}
136141

137142
// handleMailbox processes mailbox lookup requests
138-
func (s *SocketmapAdapter) handleMailbox(key string) *SocketmapResponse {
139-
exists, err := s.client.GetMailbox(key)
143+
func (s *SocketmapAdapter) handleMailbox(ctx context.Context, key string) *SocketmapResponse {
144+
exists, err := s.client.GetMailbox(ctx, key)
140145
if err != nil {
141146
log.WithError(err).WithField("key", key).Error("Error fetching mailbox")
142147
return &SocketmapResponse{Status: "TEMP", Data: "Error fetching mailbox"}
@@ -150,8 +155,8 @@ func (s *SocketmapAdapter) handleMailbox(key string) *SocketmapResponse {
150155
}
151156

152157
// handleSenders processes senders lookup requests
153-
func (s *SocketmapAdapter) handleSenders(key string) *SocketmapResponse {
154-
senders, err := s.client.GetSenders(key)
158+
func (s *SocketmapAdapter) handleSenders(ctx context.Context, key string) *SocketmapResponse {
159+
senders, err := s.client.GetSenders(ctx, key)
155160
if err != nil {
156161
log.WithError(err).WithField("key", key).Error("Error fetching senders")
157162
return &SocketmapResponse{Status: "TEMP", Data: "Error fetching senders"}

adapter_test.go

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ package main
22

33
import (
44
"bytes"
5+
"context"
56
"errors"
67
"net"
78
"strings"
89
"testing"
910
"time"
11+
12+
"github.com/stretchr/testify/mock"
1013
)
1114

1215
// Mock connection for testing
@@ -90,23 +93,23 @@ func TestSocketmapAdapter_handleAlias(t *testing.T) {
9093
name: "existing alias",
9194
key: "alias@example.com",
9295
setup: func(m *MockUserliService) {
93-
m.On("GetAliases", "alias@example.com").Return([]string{"user1@example.com", "user2@example.com"}, nil)
96+
m.On("GetAliases", mock.Anything, "alias@example.com").Return([]string{"user1@example.com", "user2@example.com"}, nil)
9497
},
9598
expected: SocketmapResponse{Status: "OK", Data: "user1@example.com,user2@example.com"},
9699
},
97100
{
98101
name: "non-existing alias",
99102
key: "nonexistent@example.com",
100103
setup: func(m *MockUserliService) {
101-
m.On("GetAliases", "nonexistent@example.com").Return([]string{}, nil)
104+
m.On("GetAliases", mock.Anything, "nonexistent@example.com").Return([]string{}, nil)
102105
},
103106
expected: SocketmapResponse{Status: "NOTFOUND"},
104107
},
105108
{
106109
name: "service error",
107110
key: "error@example.com",
108111
setup: func(m *MockUserliService) {
109-
m.On("GetAliases", "error@example.com").Return([]string{}, errors.New("service error"))
112+
m.On("GetAliases", mock.Anything, "error@example.com").Return([]string{}, errors.New("service error"))
110113
},
111114
expected: SocketmapResponse{Status: "TEMP", Data: "Error fetching aliases"},
112115
},
@@ -118,7 +121,8 @@ func TestSocketmapAdapter_handleAlias(t *testing.T) {
118121
tt.setup(mock)
119122
adapter := NewSocketmapAdapter(mock)
120123

121-
result := adapter.handleAlias(tt.key)
124+
ctx := context.Background()
125+
result := adapter.handleAlias(ctx, tt.key)
122126

123127
if result.Status != tt.expected.Status {
124128
t.Errorf("handleAlias() status = %q, want %q", result.Status, tt.expected.Status)
@@ -142,23 +146,23 @@ func TestSocketmapAdapter_handleDomain(t *testing.T) {
142146
name: "existing domain",
143147
key: "example.com",
144148
setup: func(m *MockUserliService) {
145-
m.On("GetDomain", "example.com").Return(true, nil)
149+
m.On("GetDomain", mock.Anything, "example.com").Return(true, nil)
146150
},
147151
expected: SocketmapResponse{Status: "OK", Data: "1"},
148152
},
149153
{
150154
name: "non-existing domain",
151155
key: "nonexistent.com",
152156
setup: func(m *MockUserliService) {
153-
m.On("GetDomain", "nonexistent.com").Return(false, nil)
157+
m.On("GetDomain", mock.Anything, "nonexistent.com").Return(false, nil)
154158
},
155159
expected: SocketmapResponse{Status: "NOTFOUND"},
156160
},
157161
{
158162
name: "service error",
159163
key: "error.com",
160164
setup: func(m *MockUserliService) {
161-
m.On("GetDomain", "error.com").Return(false, errors.New("service error"))
165+
m.On("GetDomain", mock.Anything, "error.com").Return(false, errors.New("service error"))
162166
},
163167
expected: SocketmapResponse{Status: "TEMP", Data: "Error fetching domain"},
164168
},
@@ -170,7 +174,8 @@ func TestSocketmapAdapter_handleDomain(t *testing.T) {
170174
tt.setup(mock)
171175
adapter := NewSocketmapAdapter(mock)
172176

173-
result := adapter.handleDomain(tt.key)
177+
ctx := context.Background()
178+
result := adapter.handleDomain(ctx, tt.key)
174179

175180
if result.Status != tt.expected.Status {
176181
t.Errorf("handleDomain() status = %q, want %q", result.Status, tt.expected.Status)
@@ -194,23 +199,23 @@ func TestSocketmapAdapter_handleMailbox(t *testing.T) {
194199
name: "existing mailbox",
195200
key: "user@example.com",
196201
setup: func(m *MockUserliService) {
197-
m.On("GetMailbox", "user@example.com").Return(true, nil)
202+
m.On("GetMailbox", mock.Anything, "user@example.com").Return(true, nil)
198203
},
199204
expected: SocketmapResponse{Status: "OK", Data: "1"},
200205
},
201206
{
202207
name: "non-existing mailbox",
203208
key: "nonexistent@example.com",
204209
setup: func(m *MockUserliService) {
205-
m.On("GetMailbox", "nonexistent@example.com").Return(false, nil)
210+
m.On("GetMailbox", mock.Anything, "nonexistent@example.com").Return(false, nil)
206211
},
207212
expected: SocketmapResponse{Status: "NOTFOUND"},
208213
},
209214
{
210215
name: "service error",
211216
key: "error@example.com",
212217
setup: func(m *MockUserliService) {
213-
m.On("GetMailbox", "error@example.com").Return(false, errors.New("service error"))
218+
m.On("GetMailbox", mock.Anything, "error@example.com").Return(false, errors.New("service error"))
214219
},
215220
expected: SocketmapResponse{Status: "TEMP", Data: "Error fetching mailbox"},
216221
},
@@ -222,7 +227,8 @@ func TestSocketmapAdapter_handleMailbox(t *testing.T) {
222227
tt.setup(mock)
223228
adapter := NewSocketmapAdapter(mock)
224229

225-
result := adapter.handleMailbox(tt.key)
230+
ctx := context.Background()
231+
result := adapter.handleMailbox(ctx, tt.key)
226232

227233
if result.Status != tt.expected.Status {
228234
t.Errorf("handleMailbox() status = %q, want %q", result.Status, tt.expected.Status)
@@ -246,23 +252,23 @@ func TestSocketmapAdapter_handleSenders(t *testing.T) {
246252
name: "existing senders",
247253
key: "user@example.com",
248254
setup: func(m *MockUserliService) {
249-
m.On("GetSenders", "user@example.com").Return([]string{"sender1@example.com", "sender2@example.com"}, nil)
255+
m.On("GetSenders", mock.Anything, "user@example.com").Return([]string{"sender1@example.com", "sender2@example.com"}, nil)
250256
},
251257
expected: SocketmapResponse{Status: "OK", Data: "sender1@example.com,sender2@example.com"},
252258
},
253259
{
254260
name: "no senders",
255261
key: "nosenders@example.com",
256262
setup: func(m *MockUserliService) {
257-
m.On("GetSenders", "nosenders@example.com").Return([]string{}, nil)
263+
m.On("GetSenders", mock.Anything, "nosenders@example.com").Return([]string{}, nil)
258264
},
259265
expected: SocketmapResponse{Status: "NOTFOUND"},
260266
},
261267
{
262268
name: "service error",
263269
key: "error@example.com",
264270
setup: func(m *MockUserliService) {
265-
m.On("GetSenders", "error@example.com").Return([]string{}, errors.New("service error"))
271+
m.On("GetSenders", mock.Anything, "error@example.com").Return([]string{}, errors.New("service error"))
266272
},
267273
expected: SocketmapResponse{Status: "TEMP", Data: "Error fetching senders"},
268274
},
@@ -274,7 +280,8 @@ func TestSocketmapAdapter_handleSenders(t *testing.T) {
274280
tt.setup(mock)
275281
adapter := NewSocketmapAdapter(mock)
276282

277-
result := adapter.handleSenders(tt.key)
283+
ctx := context.Background()
284+
result := adapter.handleSenders(ctx, tt.key)
278285

279286
if result.Status != tt.expected.Status {
280287
t.Errorf("handleSenders() status = %q, want %q", result.Status, tt.expected.Status)
@@ -299,7 +306,7 @@ func TestSocketmapAdapter_HandleConnection(t *testing.T) {
299306
name: "single alias request",
300307
requests: []string{"22:alias test@example.com,"},
301308
setup: func(m *MockUserliService) {
302-
m.On("GetAliases", "test@example.com").Return([]string{"dest@example.com"}, nil)
309+
m.On("GetAliases", mock.Anything, "test@example.com").Return([]string{"dest@example.com"}, nil)
303310
},
304311
expectedCount: 1,
305312
expectedOutput: []string{"19:OK dest@example.com,"},
@@ -308,7 +315,7 @@ func TestSocketmapAdapter_HandleConnection(t *testing.T) {
308315
name: "single domain request",
309316
requests: []string{"18:domain example.com,"},
310317
setup: func(m *MockUserliService) {
311-
m.On("GetDomain", "example.com").Return(true, nil)
318+
m.On("GetDomain", mock.Anything, "example.com").Return(true, nil)
312319
},
313320
expectedCount: 1,
314321
expectedOutput: []string{"4:OK 1,"},
@@ -334,8 +341,8 @@ func TestSocketmapAdapter_HandleConnection(t *testing.T) {
334341
"18:domain example.com,",
335342
},
336343
setup: func(m *MockUserliService) {
337-
m.On("GetAliases", "test@example.com").Return([]string{"dest@example.com"}, nil)
338-
m.On("GetDomain", "example.com").Return(true, nil)
344+
m.On("GetAliases", mock.Anything, "test@example.com").Return([]string{"dest@example.com"}, nil)
345+
m.On("GetDomain", mock.Anything, "example.com").Return(true, nil)
339346
},
340347
expectedCount: 2,
341348
expectedOutput: []string{

0 commit comments

Comments
 (0)