From 97ea1c1aa8f4f781e3c1a8f1e70c7f2961ed5424 Mon Sep 17 00:00:00 2001 From: Craig Ferguson Date: Wed, 29 Jan 2025 09:08:16 +0000 Subject: [PATCH 1/3] fix: implement nil-safe Context methods on typhon.Request --- request.go | 40 +++++++++++++++++++++++++++++++---- request_test.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/request.go b/request.go index b3ba5e66..ea9352ca 100644 --- a/request.go +++ b/request.go @@ -4,14 +4,14 @@ import ( "context" "encoding/json" "fmt" + legacyproto "github.com/golang/protobuf/proto" + "github.com/monzo/terrors" + "google.golang.org/protobuf/proto" "io" "io/ioutil" "net/http" "strings" - - legacyproto "github.com/golang/protobuf/proto" - "github.com/monzo/terrors" - "google.golang.org/protobuf/proto" + "time" ) // A Request is Typhon's wrapper around http.Request, used by both clients and servers. @@ -262,3 +262,35 @@ func NewRawRequest(ctx context.Context, method, url string, body io.ReadCloser) // as an io.ReadCloser, the body won't be encoded as JSON return NewRequest(ctx, method, url, body) } + +// Deadline wraps the embedded context.Context method to return no deadline if the inner context is nil. +func (r Request) Deadline() (time.Time, bool) { + if r.Context == nil { + return time.Time{}, false + } + return r.Context.Deadline() +} + +// Done wraps the embedded context.Context method to return nil if the inner context is nil. +func (r Request) Done() <-chan struct{} { + if r.Context == nil { + return nil + } + return r.Context.Done() +} + +// Err wraps the embedded context.Context method to return nil if the inner context is nil. +func (r Request) Err() error { + if r.Context == nil { + return nil + } + return r.Context.Err() +} + +// Value wraps the embedded context.Context method to return a nil if the inner context is nil. +func (r Request) Value(key any) any { + if r.Context == nil { + return nil + } + return r.Context.Value(key) +} diff --git a/request_test.go b/request_test.go index e83ca296..3d732e77 100644 --- a/request_test.go +++ b/request_test.go @@ -10,6 +10,7 @@ import ( "net/http" "strings" "testing" + "time" "github.com/monzo/terrors" @@ -245,6 +246,61 @@ func TestRequestMethod(t *testing.T) { assert.Equal(t, http.MethodGet, req.RequestMethod()) } +func TestRequestContextImplementation(t *testing.T) { + // This test asserts that typhon.Request correctly implements the `context.Context` + // interface (including not panicking when these methods are called on the empty + // request). + + t.Run("Deadline", func(t *testing.T) { + t.Run("returns false on an empty Request", func(t *testing.T) { + _, ok := Request{}.Deadline() + assert.False(t, ok) + }) + + t.Run("passes through a non-zero deadline", func(t *testing.T) { + ctx, cancel := context.WithDeadline(context.Background(), time.Time{}) + defer cancel() + _, ok := Request{Context: ctx}.Deadline() + assert.True(t, ok) + }) + }) + + t.Run("Done", func(t *testing.T) { + t.Run("returns nil on an empty Request", func(t *testing.T) { + assert.Nil(t, Request{}.Done()) + }) + + t.Run("passes through a non-zero Done", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + assert.NotNil(t, Request{Context: ctx}.Done()) + }) + }) + + t.Run("Err", func(t *testing.T) { + t.Run("returns nil on an empty Request", func(t *testing.T) { + assert.Nil(t, Request{}.Err()) + }) + + t.Run("passes through a non-zero Err", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + assert.NotNil(t, Request{Context: ctx}.Err()) + }) + }) + + t.Run("Value", func(t *testing.T) { + t.Run("returns nil on an empty Request", func(t *testing.T) { + assert.Nil(t, Request{}.Value(struct{}{})) + }) + + t.Run("passes through a non-zero Value", func(t *testing.T) { + ctx := context.WithValue(context.Background(), struct{}{}, true) + assert.NotNil(t, Request{Context: ctx}.Value(struct{}{})) + }) + }) +} + func jsonStreamMarshal(v interface{}) ([]byte, error) { var buffer bytes.Buffer writer := bufio.NewWriter(&buffer) From c13c172573eb8f99e68975e9e6e02b591f65a93a Mon Sep 17 00:00:00 2001 From: Craig Ferguson Date: Wed, 29 Jan 2025 09:15:13 +0000 Subject: [PATCH 2/3] update CI to match minimum Go version declared in go.mod --- .github/workflows/actions.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/actions.yaml b/.github/workflows/actions.yaml index 57b8603b..32246d84 100644 --- a/.github/workflows/actions.yaml +++ b/.github/workflows/actions.yaml @@ -1,11 +1,11 @@ name: Run Tests -on: +on: - pull_request jobs: test: strategy: matrix: - go-version: [1.17.x, 1.18.x] + go-version: [1.19.x, 1.23.x] os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: From 62b63252ee7b66cb9599a0ab14800dddd90218cb Mon Sep 17 00:00:00 2001 From: Craig Ferguson Date: Thu, 30 Jan 2025 17:42:56 +0000 Subject: [PATCH 3/3] Bump CI?