Skip to content

Commit 2d79c28

Browse files
chore: test for core::execFunc() covering case with errCh drain
Signed-off-by: Artur Melanchyk <13834276+arturmelanchyk@users.noreply.github.com>
1 parent de2463f commit 2d79c28

1 file changed

Lines changed: 110 additions & 0 deletions

File tree

client/core_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package client
22

33
import (
44
"context"
5+
"crypto/tls"
56
"errors"
67
"net"
8+
"sync"
79
"testing"
810
"time"
911

1012
"github.com/stretchr/testify/assert"
1113
"github.com/stretchr/testify/require"
14+
"github.com/valyala/fasthttp"
1215
"github.com/valyala/fasthttp/fasthttputil"
1316

1417
"github.com/gofiber/fiber/v3"
@@ -154,6 +157,59 @@ func Test_Exec_Func(t *testing.T) {
154157

155158
require.Equal(t, ErrTimeoutOrCancel, err)
156159
})
160+
161+
t.Run("cancel drains errChan", func(t *testing.T) {
162+
core, client, req := newCore(), New(), AcquireRequest()
163+
ctx, cancel := context.WithCancel(context.Background())
164+
defer cancel()
165+
166+
core.ctx = ctx
167+
core.client = client
168+
core.req = req
169+
170+
req.RawRequest.SetRequestURI("http://example.com/drain-err")
171+
172+
blockingTransport := newBlockingErrTransport(errors.New("upstream failure"))
173+
client.transport = blockingTransport
174+
defer blockingTransport.release()
175+
176+
type execResult struct {
177+
resp *Response
178+
err error
179+
}
180+
181+
resultCh := make(chan execResult, 1)
182+
go func() {
183+
resp, err := core.execFunc()
184+
resultCh <- execResult{resp: resp, err: err}
185+
}()
186+
187+
select {
188+
case <-blockingTransport.called:
189+
case <-time.After(time.Second):
190+
t.Fatal("transport Do was not invoked")
191+
}
192+
193+
cancel()
194+
195+
var result execResult
196+
select {
197+
case result = <-resultCh:
198+
case <-time.After(time.Second):
199+
t.Fatal("execFunc did not return")
200+
}
201+
202+
require.Nil(t, result.resp)
203+
require.ErrorIs(t, result.err, ErrTimeoutOrCancel)
204+
205+
blockingTransport.release()
206+
207+
select {
208+
case <-blockingTransport.finished:
209+
case <-time.After(time.Second):
210+
t.Fatal("transport Do did not finish")
211+
}
212+
})
157213
}
158214

159215
func Test_Execute(t *testing.T) {
@@ -269,3 +325,57 @@ func Test_Execute(t *testing.T) {
269325
require.Equal(t, "example.com hang up", string(resp.RawResponse.Body()))
270326
})
271327
}
328+
329+
type blockingErrTransport struct {
330+
err error
331+
332+
called chan struct{}
333+
unblock chan struct{}
334+
finished chan struct{}
335+
336+
calledOnce sync.Once
337+
releaseOnce sync.Once
338+
finishedOnce sync.Once
339+
}
340+
341+
func newBlockingErrTransport(err error) *blockingErrTransport {
342+
return &blockingErrTransport{
343+
err: err,
344+
called: make(chan struct{}),
345+
unblock: make(chan struct{}),
346+
finished: make(chan struct{}),
347+
}
348+
}
349+
350+
func (b *blockingErrTransport) Do(req *fasthttp.Request, resp *fasthttp.Response) error {
351+
b.calledOnce.Do(func() { close(b.called) })
352+
<-b.unblock
353+
b.finishedOnce.Do(func() { close(b.finished) })
354+
return b.err
355+
}
356+
357+
func (b *blockingErrTransport) DoTimeout(req *fasthttp.Request, resp *fasthttp.Response, timeout time.Duration) error {
358+
return b.Do(req, resp)
359+
}
360+
361+
func (b *blockingErrTransport) DoDeadline(req *fasthttp.Request, resp *fasthttp.Response, deadline time.Time) error {
362+
return b.Do(req, resp)
363+
}
364+
365+
func (b *blockingErrTransport) DoRedirects(req *fasthttp.Request, resp *fasthttp.Response, maxRedirects int) error {
366+
return b.Do(req, resp)
367+
}
368+
369+
func (b *blockingErrTransport) CloseIdleConnections() {}
370+
371+
func (b *blockingErrTransport) TLSConfig() *tls.Config { return nil }
372+
373+
func (b *blockingErrTransport) SetTLSConfig(_ *tls.Config) {}
374+
375+
func (b *blockingErrTransport) SetDial(_ fasthttp.DialFunc) {}
376+
377+
func (b *blockingErrTransport) Client() any { return nil }
378+
379+
func (b *blockingErrTransport) release() {
380+
b.releaseOnce.Do(func() { close(b.unblock) })
381+
}

0 commit comments

Comments
 (0)