Skip to content

Commit

Permalink
fix(cache): pass deadline to context in load function (#440)
Browse files Browse the repository at this point in the history
* feat(cache): pass deadline to context in load function

* chore: fix tests

* chore: fix lints

* chore: fix lints

* chore: fix lints

* chore: remove context from test

---------

Co-authored-by: Karol Nowak <karol.nowak@omnevo.net>
  • Loading branch information
KarolNowakk and Karol Nowak authored Sep 16, 2024
1 parent 9d26eaf commit 41c5fe2
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
9 changes: 9 additions & 0 deletions core/cache/httpFrontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ func (hf *HTTPFrontend) load(ctx context.Context, key string, loader HTTPLoader,
oldSpan := trace.FromContext(ctx)
newContext := trace.NewContext(context.Background(), oldSpan)

deadline, hasDeadline := ctx.Deadline()
if hasDeadline {
var cancel context.CancelFunc

newContext, cancel = context.WithDeadline(newContext, deadline)

defer cancel()
}

newContextWithSpan, span := trace.StartSpan(newContext, "flamingo/cache/httpFrontend/load")
span.Annotate(nil, key)
defer span.End()
Expand Down
89 changes: 89 additions & 0 deletions core/cache/httpFrontend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -120,6 +121,27 @@ func createResponse(statusCode int, body string) *http.Response {
return response
}

func loaderWithWatingTime(ctx context.Context) (*http.Response, *Meta, error) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(5 * time.Second)
w.WriteHeader(http.StatusOK)

_, _ = w.Write([]byte("Test 123"))
}))

defer server.Close()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, server.URL, nil)
if err != nil {
return nil, nil, err
}

client := &http.Client{}
resp, err := client.Do(req)

return resp, nil, err
}

func TestHTTPFrontend_Get(t *testing.T) {
// wait channel top check async cache setting
cacheSetComplete := make(chan struct{}, 1)
Expand Down Expand Up @@ -279,3 +301,70 @@ func TestHTTPFrontend_Get(t *testing.T) {
})
}
}

//nolint:bodyclose // response might be nil so we cannot close the body
func TestContextDeadlineExceeded(t *testing.T) {
t.Parallel()

t.Run("exceeded, throw error", func(t *testing.T) {
t.Parallel()

entry := &Entry{
Meta: Meta{
lifetime: time.Now().Add(-24 * time.Hour),
gracetime: time.Now().Add(-24 * time.Hour),
},
Data: nil,
}

backendMock := &MockBackend{}
backendMock.On("Get", "test").Return(entry, true)
backendMock.On("Set", "test", mock.Anything).Return(func(string, *Entry) error {
return nil
})

contextWithDeadline, cancel := context.WithDeadline(context.Background(), time.Now().Add(4*time.Second))
t.Cleanup(cancel)

hf := new(HTTPFrontend).Inject(
backendMock,
&flamingo.NullLogger{},
)

got, err := hf.Get(contextWithDeadline, "test", loaderWithWatingTime)

assert.ErrorIs(t, err, context.DeadlineExceeded)
assert.Nil(t, got)
})

t.Run("did not exceed, no error", func(t *testing.T) {
t.Parallel()

entry := &Entry{
Meta: Meta{
lifetime: time.Now().Add(-24 * time.Hour),
gracetime: time.Now().Add(-24 * time.Hour),
},
Data: nil,
}

backendMock := &MockBackend{}
backendMock.On("Get", "test").Return(entry, true)
backendMock.On("Set", "test", mock.Anything).Return(func(string, *Entry) error {
return nil
})

contextWithDeadline, cancel := context.WithDeadline(context.Background(), time.Now().Add(7*time.Second))
t.Cleanup(cancel)

hf := new(HTTPFrontend).Inject(
backendMock,
&flamingo.NullLogger{},
)

got, err := hf.Get(contextWithDeadline, "test", loaderWithWatingTime)

assert.NoError(t, err)
assert.Equal(t, got.StatusCode, http.StatusOK)
})
}

0 comments on commit 41c5fe2

Please # to comment.