diff --git a/internal/urlutil/url.go b/internal/urlutil/url.go index 8920dbe19..6c4d8a25f 100644 --- a/internal/urlutil/url.go +++ b/internal/urlutil/url.go @@ -6,6 +6,7 @@ import ( "net/http" "net/url" "strings" + "sync" "time" "github.com/pomerium/pomerium/internal/cryptutil" @@ -65,18 +66,35 @@ func DeepCopy(u *url.URL) (*url.URL, error) { return ParseAndValidateURL(u.String()) } -// testTimeNow can be used in tests to set a specific int64 time -var testTimeNow int64 +var mockNow testTime + +// testTime is safe to use concurrently. +type testTime struct { + sync.Mutex + mockNow int64 +} + +func (tt *testTime) setNow(n int64) { + tt.Lock() + tt.mockNow = n + tt.Unlock() +} + +func (tt *testTime) now() int64 { + tt.Lock() + defer tt.Unlock() + return tt.mockNow +} // timestamp returns the current timestamp, in seconds. // // For testing purposes, the function that generates the timestamp can be // overridden. If not set, it will return time.Now().UTC().Unix(). func timestamp() int64 { - if testTimeNow == 0 { + if mockNow.now() == 0 { return time.Now().UTC().Unix() } - return testTimeNow + return mockNow.now() } // SignedRedirectURL takes a destination URL and adds redirect_uri to it's diff --git a/internal/urlutil/url_test.go b/internal/urlutil/url_test.go index 95f77d8a8..5935fc86c 100644 --- a/internal/urlutil/url_test.go +++ b/internal/urlutil/url_test.go @@ -122,7 +122,7 @@ func TestSignedRedirectURL(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - testTimeNow = tt.mockedTime + mockNow.setNow(tt.mockedTime) got := SignedRedirectURL(tt.key, tt.destination, tt.urlToSign) if diff := cmp.Diff(got, tt.want); diff != "" { t.Errorf("SignedRedirectURL() = diff %v", diff) @@ -142,7 +142,7 @@ func Test_timestamp(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - testTimeNow = tt.dontWant + mockNow.setNow(tt.dontWant) if got := timestamp(); got == tt.dontWant { t.Errorf("timestamp() = %v, dontWant %v", got, tt.dontWant) }