From 793a644587c8ff41fffcc464e7856a68e69d90b4 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Wed, 14 Feb 2024 05:13:51 -0800 Subject: [PATCH 1/5] test: add a custom mock clock implementation (#1154) benbjohnson/clock has been archived and no longer maintained. Removing that dependency is desirable. This change adds a mock clock adapted from Zap's mock clock (uber-go/zap#1349), but with operations specific to Fx's needs. There are two areas that require more scrutiny because of divergence from Zap's mock clock: WithTimeout requires us to implement a custom `context.Context` so that it can report context.DeadlineExceeded when it's time. We cannot just use `context.WithCancelCause` here because the cause for a context failure is considered different from `ctx.Err`, so `ctx.Err` would still report `context.Canceled` for a timeout. When testing that a sleep behaves as expected, there's a data race between the `Sleep` and the `Add` that progresses time. To resolve this, this change adds an `AwaitScheduled` method that blocks until there are operations scheduled for the future. This is done by using a `sync.Cond`. This gives us a way to wait until the sleep is scheduled before we progress time. This change also had to update Zap to pick up the release with the custom clock to drop the benbjohnson/clock dependency from the go.mod completely. Refs uber-go/zap#1349 Resolves #1135 --------- Co-authored-by: Jacob Oaks Co-authored-by: Sung Yoon Whang --- app_test.go | 22 ++-- docs/go.mod | 7 +- docs/go.sum | 18 ++- go.mod | 9 +- go.sum | 52 ++------ internal/e2e/go.mod | 5 +- internal/e2e/go.sum | 14 +-- internal/fxclock/clock.go | 210 ++++++++++++++++++++++++++++++++- internal/fxclock/clock_test.go | 172 +++++++++++++++++++++++---- 9 files changed, 401 insertions(+), 108 deletions(-) diff --git a/app_test.go b/app_test.go index c9b9000b0..a45b4cd37 100644 --- a/app_test.go +++ b/app_test.go @@ -35,13 +35,13 @@ import ( "testing" "time" - "github.com/benbjohnson/clock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" . "go.uber.org/fx" "go.uber.org/fx/fxevent" "go.uber.org/fx/fxtest" + "go.uber.org/fx/internal/fxclock" "go.uber.org/fx/internal/fxlog" "go.uber.org/goleak" "go.uber.org/multierr" @@ -1221,7 +1221,7 @@ func TestAppRunTimeout(t *testing.T) { } // Builds a hook that takes much longer than the application timeout. - takeVeryLong := func(clock *clock.Mock) func() error { + takeVeryLong := func(clock *fxclock.Mock) func() error { return func() error { // We'll exceed the start and stop timeouts, // and then some. @@ -1237,7 +1237,7 @@ func TestAppRunTimeout(t *testing.T) { desc string // buildHook builds and returns the hooks for this test case. - buildHooks func(*clock.Mock) []Hook + buildHooks func(*fxclock.Mock) []Hook // Type of the fxevent we want. // Does not reflect the exact value. @@ -1246,7 +1246,7 @@ func TestAppRunTimeout(t *testing.T) { { // Timeout starting an application. desc: "OnStart timeout", - buildHooks: func(clock *clock.Mock) []Hook { + buildHooks: func(clock *fxclock.Mock) []Hook { return []Hook{ StartHook(takeVeryLong(clock)), } @@ -1256,7 +1256,7 @@ func TestAppRunTimeout(t *testing.T) { { // Timeout during a rollback because start failed. desc: "rollback timeout", - buildHooks: func(clock *clock.Mock) []Hook { + buildHooks: func(clock *fxclock.Mock) []Hook { return []Hook{ // The hooks are separate because // OnStop will not be run if that hook failed. @@ -1269,7 +1269,7 @@ func TestAppRunTimeout(t *testing.T) { { // Timeout during a stop. desc: "OnStop timeout", - buildHooks: func(clock *clock.Mock) []Hook { + buildHooks: func(clock *fxclock.Mock) []Hook { return []Hook{ StopHook(takeVeryLong(clock)), } @@ -1283,7 +1283,7 @@ func TestAppRunTimeout(t *testing.T) { t.Run(tt.desc, func(t *testing.T) { t.Parallel() - mockClock := clock.NewMock() + mockClock := fxclock.NewMock() var ( exitCode int @@ -1351,7 +1351,7 @@ func TestAppStart(t *testing.T) { t.Run("Timeout", func(t *testing.T) { t.Parallel() - mockClock := clock.NewMock() + mockClock := fxclock.NewMock() type A struct{} blocker := func(lc Lifecycle) *A { @@ -1388,7 +1388,7 @@ func TestAppStart(t *testing.T) { t.Run("TimeoutWithFinishedHooks", func(t *testing.T) { t.Parallel() - mockClock := clock.NewMock() + mockClock := fxclock.NewMock() type A struct{} type B struct{ A *A } @@ -1540,7 +1540,7 @@ func TestAppStart(t *testing.T) { t.Parallel() var ran bool - mockClock := clock.NewMock() + mockClock := fxclock.NewMock() app := New( WithClock(mockClock), Invoke(func(lc Lifecycle) { @@ -1820,7 +1820,7 @@ func TestAppStop(t *testing.T) { t.Run("Timeout", func(t *testing.T) { t.Parallel() - mockClock := clock.NewMock() + mockClock := fxclock.NewMock() block := func(ctx context.Context) error { mockClock.Add(5 * time.Second) diff --git a/docs/go.mod b/docs/go.mod index 865b30b7b..1f4d20db5 100644 --- a/docs/go.mod +++ b/docs/go.mod @@ -3,17 +3,16 @@ module go.uber.org/fx/docs go 1.20 require ( - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.1 go.uber.org/fx v1.18.2 - go.uber.org/zap v1.23.0 + go.uber.org/zap v1.26.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.uber.org/atomic v1.7.0 // indirect go.uber.org/dig v1.17.1 // indirect - go.uber.org/multierr v1.6.0 // indirect + go.uber.org/multierr v1.10.0 // indirect golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/docs/go.sum b/docs/go.sum index 83453e186..2e829754b 100644 --- a/docs/go.sum +++ b/docs/go.sum @@ -1,25 +1,23 @@ -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/go.mod b/go.mod index 777417de1..e322f63d5 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,12 @@ module go.uber.org/fx go 1.20 require ( - github.com/benbjohnson/clock v1.3.0 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.1 go.uber.org/atomic v1.7.0 go.uber.org/dig v1.17.1 - go.uber.org/goleak v1.1.11 - go.uber.org/multierr v1.6.0 - go.uber.org/zap v1.23.0 + go.uber.org/goleak v1.2.0 + go.uber.org/multierr v1.10.0 + go.uber.org/zap v1.26.0 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad ) diff --git a/go.sum b/go.sum index 443ecde43..b20efccb7 100644 --- a/go.sum +++ b/go.sum @@ -1,66 +1,34 @@ -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/e2e/go.mod b/internal/e2e/go.mod index 5335cc330..3f0ed8f99 100644 --- a/internal/e2e/go.mod +++ b/internal/e2e/go.mod @@ -10,10 +10,9 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.uber.org/atomic v1.7.0 // indirect go.uber.org/dig v1.17.1 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.23.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.26.0 // indirect golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/internal/e2e/go.sum b/internal/e2e/go.sum index 36c0e3960..e5abd8557 100644 --- a/internal/e2e/go.sum +++ b/internal/e2e/go.sum @@ -1,27 +1,23 @@ -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/internal/fxclock/clock.go b/internal/fxclock/clock.go index bf1c7058f..8d9e6e1d8 100644 --- a/internal/fxclock/clock.go +++ b/internal/fxclock/clock.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Uber Technologies, Inc. +// Copyright (c) 2024 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -22,13 +22,13 @@ package fxclock import ( "context" + "sort" + "sync" "time" ) // Clock defines how Fx accesses time. -// The interface is pretty minimal but it matches github.com/benbjohnson/clock. -// We intentionally don't use that interface directly; -// this keeps it a test dependency for us. +// We keep the interface pretty minimal. type Clock interface { Now() time.Time Since(time.Time) time.Duration @@ -56,3 +56,205 @@ func (systemClock) Sleep(d time.Duration) { func (systemClock) WithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) { return context.WithTimeout(ctx, d) } + +// Mock adapted from +// https://github.com/uber-go/zap/blob/7db06bc9b095571d3dc3d4eebdfbe4dd9bd20405/internal/ztest/clock.go. + +// Mock is a fake source of time. +// It implements standard time operations, +// but allows the user to control the passage of time. +// +// Use the [Add] method to progress time. +type Mock struct { + mu sync.RWMutex + now time.Time + + // The MockClock works by maintaining a list of waiters. + // Each waiter knows the time at which it should be resolved. + // When the clock advances, all waiters that are in range are resolved + // in chronological order. + waiters []waiter + waiterAdded *sync.Cond +} + +var _ Clock = (*Mock)(nil) + +// NewMock builds a new mock clock +// using the current actual time as the initial time. +func NewMock() *Mock { + m := &Mock{now: time.Now()} + m.waiterAdded = sync.NewCond(&m.mu) + return m +} + +// Now reports the current time. +func (c *Mock) Now() time.Time { + c.mu.RLock() + defer c.mu.RUnlock() + return c.now +} + +// Since reports the time elapsed since t. +// This is short for Now().Sub(t). +func (c *Mock) Since(t time.Time) time.Duration { + return c.Now().Sub(t) +} + +// Sleep pauses the current goroutine for the given duration. +// +// With the mock clock, this will freeze +// until the clock is advanced with [Add] past the deadline. +func (c *Mock) Sleep(d time.Duration) { + ch := make(chan struct{}) + c.runAt(c.Now().Add(d), func() { close(ch) }) + <-ch +} + +// WithTimeout returns a new context with a deadline of now + d. +// +// When the deadline is passed, the returned context's Done channel is closed +// and the context's Err method returns context.DeadlineExceeded. +// If the cancel function is called before the deadline is passed, +// the context's Err method returns context.Canceled. +func (c *Mock) WithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) { + // Unfortunately, we can't use context.WithCancelCause here. + // Per its documentation (and verified by trying it): + // + // ctx, cancel := context.WithCancelCause(parent) + // cancel(myError) + // ctx.Err() // returns context.Canceled + // context.Cause(ctx) // returns myError + // + // So it won't do for our purposes. + deadline := c.Now().Add(d) + inner, cancelInner := context.WithCancel(ctx) + dctx := &deadlineCtx{ + inner: inner, + cancelInner: cancelInner, + done: make(chan struct{}), + deadline: deadline, + } + ctx = dctx + + c.runAt(deadline, func() { + dctx.cancel(context.DeadlineExceeded) + }) + return ctx, func() { dctx.cancel(context.Canceled) } +} + +type deadlineCtx struct { + inner context.Context + cancelInner func() + + done chan struct{} + deadline time.Time + + mu sync.Mutex // guards err; the rest is immutable + err error +} + +var _ context.Context = (*deadlineCtx)(nil) + +func (c *deadlineCtx) Deadline() (deadline time.Time, ok bool) { return c.deadline, true } +func (c *deadlineCtx) Done() <-chan struct{} { return c.done } +func (c *deadlineCtx) Value(key any) any { return c.inner.Value(key) } + +func (c *deadlineCtx) Err() error { + c.mu.Lock() + defer c.mu.Unlock() + return c.err +} + +func (c *deadlineCtx) cancel(err error) { + c.mu.Lock() + if c.err == nil { + c.err = err + close(c.done) + c.cancelInner() + } + c.mu.Unlock() +} + +// runAt schedules the given function to be run at the given time. +// The function runs without a lock held, so it may schedule more work. +func (c *Mock) runAt(t time.Time, fn func()) { + c.mu.Lock() + defer c.mu.Unlock() + + c.waiters = append(c.waiters, waiter{until: t, fn: fn}) + c.waiterAdded.Broadcast() +} + +// AwaitScheduled blocks until there are at least N +// operations scheduled for the future. +func (c *Mock) AwaitScheduled(n int) { + c.mu.Lock() + defer c.mu.Unlock() + + // Note: waiterAdded is associated with c.mu, + // the same lock we're holding here. + // + // When we call Wait(), it'll release the lock + // and block until signaled by runAt, + // at which point it'll reacquire the lock + // (waiting until runAt has released it). + for len(c.waiters) < n { + c.waiterAdded.Wait() + } +} + +type waiter struct { + until time.Time + fn func() +} + +// Add progresses time by the given duration. +// Other operations waiting for the time to advance +// will be resolved if they are within range. +// +// Side effects of operations waiting for the time to advance +// will take effect on a best-effort basis. +// Avoid racing with operations that have side effects. +// +// Panics if the duration is negative. +func (c *Mock) Add(d time.Duration) { + if d < 0 { + panic("cannot add negative duration") + } + + c.mu.Lock() + defer c.mu.Unlock() + + sort.Slice(c.waiters, func(i, j int) bool { + return c.waiters[i].until.Before(c.waiters[j].until) + }) + + newTime := c.now.Add(d) + // newTime won't be recorded until the end of this method. + // This ensures that any waiters that are resolved + // are resolved at the time they were expecting. + + for len(c.waiters) > 0 { + w := c.waiters[0] + if w.until.After(newTime) { + break + } + c.waiters[0] = waiter{} // avoid memory leak + c.waiters = c.waiters[1:] + + // The waiter is within range. + // Travel to the time of the waiter and resolve it. + c.now = w.until + + // The waiter may schedule more work + // so we must release the lock. + c.mu.Unlock() + w.fn() + // Sleeping here is necessary to let the side effects of waiters + // take effect before we continue. + time.Sleep(1 * time.Millisecond) + c.mu.Lock() + } + + c.now = newTime +} diff --git a/internal/fxclock/clock_test.go b/internal/fxclock/clock_test.go index 560867ecd..22a538a2e 100644 --- a/internal/fxclock/clock_test.go +++ b/internal/fxclock/clock_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Uber Technologies, Inc. +// Copyright (c) 2024 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -22,44 +22,176 @@ package fxclock import ( "context" + "sync" "testing" "time" - "github.com/benbjohnson/clock" "github.com/stretchr/testify/assert" ) -var _ Clock = clock.Clock(nil) - -// Just a basic sanity check that everything is in order. func TestSystemClock(t *testing.T) { - t.Parallel() - clock := System + testClock(t, System, clock.Sleep) +} + +func TestMockClock(t *testing.T) { + clock := NewMock() + testClock(t, clock, clock.Add) +} - t.Run("Now and Since", func(t *testing.T) { - t.Parallel() +func testClock(t *testing.T, clock Clock, advance func(d time.Duration)) { + now := clock.Now() + assert.False(t, now.IsZero()) - before := clock.Now() - assert.GreaterOrEqual(t, clock.Since(before), time.Duration(0)) + t.Run("Since", func(t *testing.T) { + advance(1 * time.Millisecond) + assert.NotZero(t, clock.Since(now), "time must have advanced") }) t.Run("Sleep", func(t *testing.T) { - t.Parallel() + start := clock.Now() - assert.NotPanics(t, func() { - clock.Sleep(time.Millisecond) - }) + go func() { + // For the mock clock, there's a chance that advance will be + // too fast and the Sleep will block forever, waiting for + // another advance. The mock clock provides + // AwaitScheduled to help with this. + // + // Since that function is not available on the system clock, + // we'll use upcasting to check for it. + if awaiter, ok := clock.(interface{ AwaitScheduled(int) }); ok { + awaiter.AwaitScheduled(1) + } + + advance(1 * time.Millisecond) + }() + clock.Sleep(1 * time.Millisecond) + + assert.NotZero(t, clock.Since(start), "time must have advanced") }) t.Run("WithTimeout", func(t *testing.T) { - t.Parallel() + ctx, cancel := clock.WithTimeout(context.Background(), 1*time.Millisecond) + defer cancel() - ctx := context.Background() - ctx, cancel := clock.WithTimeout(ctx, time.Second) + t.Run("Deadline", func(t *testing.T) { + dl, ok := ctx.Deadline() + assert.True(t, ok, "must have a deadline") + assert.True(t, dl.After(now), "deadline must be in the future") + }) + + advance(1 * time.Millisecond) + + select { + case <-ctx.Done(): + assert.Error(t, ctx.Err(), "done context must error") + assert.ErrorIs(t, ctx.Err(), context.DeadlineExceeded, + "context must have exceeded its deadline") + + case <-time.After(10 * time.Millisecond): + t.Fatal("expected context to be done") + } + }) + + t.Run("WithTimeout/Value", func(t *testing.T) { + type contextKey string + key := contextKey("foo") + + ctx1 := context.WithValue(context.Background(), key, "bar") + + ctx2, cancel := clock.WithTimeout(ctx1, 1*time.Millisecond) defer cancel() - _, ok := ctx.Deadline() - assert.True(t, ok, "must have deadline") + assert.Equal(t, "bar", ctx2.Value(key), "value must be preserved") }) + + t.Run("WithTimeout/Cancel", func(t *testing.T) { + ctx, cancel := clock.WithTimeout(context.Background(), 1*time.Millisecond) + cancel() + + select { + case <-ctx.Done(): + assert.Error(t, ctx.Err(), "done context must error") + assert.ErrorIs(t, ctx.Err(), context.Canceled, + "context must have been canceled") + + case <-time.After(10 * time.Millisecond): + t.Fatal("expected context to be done") + } + }) +} + +func TestMock_Sleep(t *testing.T) { + clock := NewMock() + + ch := make(chan struct{}) + go func() { + clock.Sleep(2 * time.Millisecond) + close(ch) + }() + + // We cannot advance time until we're certain + // that the Sleep call has started waiting. + // Otherwise, we'll advance that one millisecond, + // and then the Sleep will start waiting for another Advance, + // which will never come. + // + // AwaitScheduled will block until there is at least one + // scheduled event. + clock.AwaitScheduled(1) + + // Advance only one millisecond, the Sleep should not return. + clock.Add(1 * time.Millisecond) + select { + case <-ch: + t.Fatal("sleep should not have returned") + case <-time.After(1 * time.Millisecond): + // ok + } + + // Avance to the next millisecond, the Sleep should return. + clock.Add(1 * time.Millisecond) + select { + case <-ch: + // ok + case <-time.After(10 * time.Millisecond): + t.Fatal("expected Sleep to return") + } +} + +func TestMock_AddNegative(t *testing.T) { + clock := NewMock() + assert.Panics(t, func() { clock.Add(-1) }) +} + +func TestMock_ManySleepers(t *testing.T) { + const N = 100 + + clock := NewMock() + + var wg sync.WaitGroup + wg.Add(N) + for i := 0; i < N; i++ { + go func() { + defer wg.Done() + + clock.Sleep(1 * time.Millisecond) + }() + } + + clock.AwaitScheduled(N) + clock.Add(1 * time.Millisecond) + + done := make(chan struct{}) + go func() { + defer close(done) + wg.Wait() + }() + + select { + case <-done: + // ok + case <-time.After(10 * time.Millisecond): + t.Fatal("expected all sleepers to be done") + } } From d6beb49c4803b49f2262cef8291915b9e43bcb3d Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Wed, 14 Feb 2024 06:08:49 -0800 Subject: [PATCH 2/5] doc: Add FAQ page (#1160) Adds an FAQ page to the Fx documentation, aiming to address frequently asked questions. This includes two entries that came up at work recently. Includes a test for the `fx.Supply` entry because I couldn't find the test for it right away. (I found it in annotated_test.go later but you won't hear me complain about additional tests.) --------- Co-authored-by: Jacob Oaks --- docs/.vuepress/config.js | 1 + docs/faq.md | 76 ++++++++++++++++++++++++++++++++++++++++ supply_test.go | 21 +++++++++++ 3 files changed, 98 insertions(+) create mode 100644 docs/faq.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 430a0efb3..0fff1e7fe 100755 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -106,6 +106,7 @@ module.exports = { 'modules.md', ], }, + ['faq.md', 'FAQ'], { title: 'Community', children: [ diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 000000000..133d7fff3 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,76 @@ +# Frequently Asked Questions + +This page contains answers to common questions and issues with using Fx. + +## Does the order of `fx.Option`s matter? + +No, the order in which you provide Fx options +to `fx.Options`, `fx.New`, `fx.Module`, and others does not matter. + +Ordering of options relative to each other is as follows: + +* Adding values: + Operations like `fx.Provide` and `fx.Supply` are run in dependency order. + Dependencies are determined by the function parameters and results. + + ```go + // The following are all equivalent: + fx.Options(fx.Provide(ParseConfig, NewLogger)) + fx.Options(fx.Provide(NewLogger, ParseConfig)) + fx.Options(fx.Provide(ParseConfig), fx.Provide(NewLogger)) + fx.Options(fx.Provide(NewLogger), fx.Provide(ParseConfig)) + ``` + +* Consuming values: + Operations like `fx.Invoke` and `fx.Populate` are run + after their dependencies have been satisfied: after `fx.Provide`s. + + Relative to each other, invokes are run in the order they were specified. + + ```go + fx.Invoke(a, b) + // a() is run before b() + ``` + + `fx.Module` hierarchies affect invocation order: + invocations in a parent module are run after those of a child module. + + ```go + fx.Options( + fx.Invoke(a), + fx.Module("child", fx.Invoke(b)), + ), + // b() is run before a() + ``` + +* Replacing values: + Operations like `fx.Decorate` and `fx.Replace` are run + after the Provide operations that they depend on, + but before the Invoke operations that consume those values. + + Ordering of decorations relative to each other + is determined by `fx.Module` hierarchies: + decorations in a parent module are applied after those of a child module. + +## Why does `fx.Supply` not accept interfaces? + +This is a technical limitation of how reflection in Go works. +Suppose you have: + +```go +var redisClient ClientInterface = &redis.Client{ ... } +``` + +When you call `fx.Supply(redisClient)`, +the knowledge that you intended to use this as a `ClientInterface` is lost. +Fx has to use runtime reflection to inspect the type of the value, +and at that point the Go runtime only tells it that it’s a `*redis.Client`. + +You can work around this with the `fx.Annotate` function +and the `fx.As` annotation. + +```go +fx.Supply( + fx.Annotate(redisClient, fx.As(new(ClientInterface))), +) +``` diff --git a/supply_test.go b/supply_test.go index 563417907..1b988db8b 100644 --- a/supply_test.go +++ b/supply_test.go @@ -21,7 +21,9 @@ package fx_test import ( + "bytes" "errors" + "io" "testing" "github.com/stretchr/testify/assert" @@ -110,6 +112,25 @@ func TestSupply(t *testing.T) { require.Same(t, thirdIn, out.Third) }) + t.Run("AnnotateIsSupported", func(t *testing.T) { + t.Parallel() + + var out struct { + fx.In + + Got io.Writer + } + + var give bytes.Buffer + app := fxtest.New(t, + fx.Supply(fx.Annotate(&give, fx.As(new(io.Writer)))), + fx.Populate(&out), + ) + defer app.RequireStart().RequireStop() + + require.Same(t, &give, out.Got) + }) + t.Run("InvalidArgumentIsSupplied", func(t *testing.T) { t.Parallel() From 91121fcd7b0ed72cb75629deff854b096bb409c7 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Wed, 14 Feb 2024 16:01:38 -0800 Subject: [PATCH 3/5] go.uber.org/atomic => sync/atomic (#1161) --- annotated_test.go | 6 +++--- docs/go.sum | 1 - go.mod | 1 - go.sum | 3 --- internal/e2e/go.sum | 1 - 5 files changed, 3 insertions(+), 9 deletions(-) diff --git a/annotated_test.go b/annotated_test.go index 2ad36af65..3294d5b67 100644 --- a/annotated_test.go +++ b/annotated_test.go @@ -28,11 +28,11 @@ import ( "io" "strconv" "strings" + "sync/atomic" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.uber.org/atomic" "go.uber.org/fx" "go.uber.org/fx/fxevent" "go.uber.org/fx/fxtest" @@ -2384,10 +2384,10 @@ func TestHookAnnotationFunctionFlexibility(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { var ( - called = atomic.NewBool(false) + called atomic.Bool opts = fx.Options( fx.Provide(tt.annotation), - fx.Supply(called), + fx.Supply(&called), fx.Invoke(func(A) {}), ) ) diff --git a/docs/go.sum b/docs/go.sum index 2e829754b..1b03e7f6b 100644 --- a/docs/go.sum +++ b/docs/go.sum @@ -10,7 +10,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= diff --git a/go.mod b/go.mod index e322f63d5..aec2fc784 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.20 require ( github.com/stretchr/testify v1.8.1 - go.uber.org/atomic v1.7.0 go.uber.org/dig v1.17.1 go.uber.org/goleak v1.2.0 go.uber.org/multierr v1.10.0 diff --git a/go.sum b/go.sum index b20efccb7..985836119 100644 --- a/go.sum +++ b/go.sum @@ -8,13 +8,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= diff --git a/internal/e2e/go.sum b/internal/e2e/go.sum index e5abd8557..3415d8e2c 100644 --- a/internal/e2e/go.sum +++ b/internal/e2e/go.sum @@ -10,7 +10,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= From aa2324e07b640e6e4df98659d1c9ad244d7334a6 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Tue, 20 Feb 2024 08:15:55 -0800 Subject: [PATCH 4/5] docs/sidebar: Move concepts before features (#1164) In reading order, concepts like container and lifecycle should come before we talk about parameter objects, value groups, etc. (It's also okay to merge concepts and features, but I'm not doing that here.) Separately, make the lifecycle page appear as "Lifecycle" in the sidebar while still having the title "Application Lifecycle". --- docs/.vuepress/config.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 0fff1e7fe..0c637ec7c 100755 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -76,6 +76,14 @@ module.exports = { ], }, 'intro.md', + { + title: 'Concepts', + children: [ + 'container.md', + ['lifecycle.md', 'Lifecycle'], + 'modules.md', + ], + }, { title: 'Features', children: [ @@ -98,14 +106,6 @@ module.exports = { }, ], }, - { - title: 'Concepts', - children: [ - 'container.md', - 'lifecycle.md', - 'modules.md', - ], - }, ['faq.md', 'FAQ'], { title: 'Community', From 2d14fb7dbc93a34960abdd079d0e2060117bd521 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 11:29:27 -0500 Subject: [PATCH 5/5] chore(deps): Bump golang.org/x/tools from 0.17.0 to 0.18.0 in /tools (#1165) Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.17.0 to 0.18.0.
Commits
  • c5643e9 gopls/internal/server: fix two bugs related to dynamic configuration
  • 50b4f1b gopls/internal/golang: close open file
  • f0ef3c6 gopls: update x/telemetry dependency to fix crash
  • 8cf0a8e gopls: record that v0.15 will be the last to support go1.18
  • 730dc3c gopls/internal/settings: add a hidden option to disable zero config
  • 95f04f4 gopls/internal/golang: add resolve support for inline refactorings
  • 9619683 gopls/internal/cache: treat local replaces as workspace modules
  • a5af84e gopls/internal/cache: check views on any on-disk change to go.mod files
  • a7407fa gopls: update telemetry
  • 314368d go/analysis/passes/deepequalerrors: audit for types.Alias safety
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/tools&package-manager=go_modules&previous-version=0.17.0&new-version=0.18.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacob Oaks --- tools/go.mod | 8 ++++---- tools/go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/go.mod b/tools/go.mod index 044474fc0..65771b97d 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/bwplotka/mdox v0.9.0 - golang.org/x/tools v0.17.0 + golang.org/x/tools v0.18.0 ) require ( @@ -71,9 +71,9 @@ require ( github.com/yuin/goldmark v1.4.13 // indirect github.com/yuin/goldmark-emoji v1.0.1 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.0 // indirect diff --git a/tools/go.sum b/tools/go.sum index aecb86c03..f918ab5a5 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -745,8 +745,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -798,8 +798,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -883,8 +883,8 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -956,8 +956,8 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=