diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4a6733443..04f7cbb10 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -16,28 +16,30 @@ jobs: platform: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.platform }} steps: - - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # pin@v2 + - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a with: go-version: ${{ matrix.go-version }} - - uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # pin@v3 + - uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 with: node-version: ${{ matrix.node-version }} - name: set env vars run: echo "$(go env GOPATH)/bin" >> $GITHUB_PATH - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # pin@v3 + + - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b with: fetch-depth: 0 + - name: cache go binaries - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 # pin@v3 + uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 id: cache-go-bin with: path: ~/go/bin key: ${{ runner.os }}-${{ hashFiles('**/go.mod') }} restore-keys: ${{ runner.os }}-go-bin - - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 # pin@v3 + - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 with: path: | ~/go/pkg/mod @@ -45,12 +47,12 @@ jobs: ~/Library/Caches/go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- + - run: make deps-build - name: Lint if: runner.os == 'Linux' run: make lint - name: test - if: runner.os != 'Linux' run: make test cover: @@ -60,15 +62,15 @@ jobs: go-version: [1.18.x] node-version: [16.x] steps: - - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # pin@v2 + - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a with: go-version: ${{ matrix.go-version }} - - uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # pin@v3 + - uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 with: node-version: ${{ matrix.node-version }} - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # pin@v3 + - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b with: fetch-depth: 0 @@ -76,14 +78,14 @@ jobs: run: echo "$(go env GOPATH)/bin" >> $GITHUB_PATH - name: cache go binaries - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 # pin@v3 + uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 id: cache-go-bin with: path: ~/go/bin key: ${{ runner.os }}-${{ hashFiles('**/go.mod') }} restore-keys: ${{ runner.os }}-go-bin - - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 # pin@v3 + - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 with: path: | ~/go/pkg/mod @@ -95,14 +97,14 @@ jobs: - name: cover run: make cover - - uses: jandelgado/gcov2lcov-action@c680c0f7c7442485f1749eb2a13e54a686e76eb5 # pin@v1.0.8 + - uses: jandelgado/gcov2lcov-action@c680c0f7c7442485f1749eb2a13e54a686e76eb5 name: convert coverage to lcov with: infile: coverage.txt outfile: coverage.lcov - name: upload to coveralls - uses: coverallsapp/github-action@9ba913c152ae4be1327bfb9085dc806cedb44057 # pin@1.1.3 + uses: coverallsapp/github-action@9ba913c152ae4be1327bfb9085dc806cedb44057 with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: coverage.lcov @@ -118,20 +120,20 @@ jobs: idp: [auth0, azure, github, gitlab, google, oidc, okta, onelogin, ping] runs-on: ${{ matrix.platform }} steps: - - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # pin@v2 + - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a with: go-version: ${{ matrix.go-version }} - - uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # pin@v3 + - uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 with: node-version: ${{ matrix.node-version }} - name: set env vars run: echo "$(go env GOPATH)/bin" >> $GITHUB_PATH - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # pin@v3 + - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b with: fetch-depth: 0 - - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 # pin@v3 + - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 with: path: | ~/go/pkg @@ -164,18 +166,18 @@ jobs: platform: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.platform }} steps: - - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # pin@v2 + - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a with: go-version: ${{ matrix.go-version }} - - uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # pin@v3 + - uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 with: node-version: ${{ matrix.node-version }} - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # pin@v3 + - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b with: fetch-depth: 0 - - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 # pin@v3 + - uses: actions/cache@0865c47f36e68161719c5b124609996bb5c40129 with: path: | ~/go/pkg/mod @@ -191,7 +193,7 @@ jobs: make build - name: save binary - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # pin@v2 + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 with: path: bin/pomerium* name: pomerium ${{ github.run_id }} ${{ matrix.platform }} @@ -200,15 +202,15 @@ jobs: build-docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # pin@v3 + - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b with: fetch-depth: 0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6 # pin@v1 + uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6 - name: Docker Build - uses: docker/build-push-action@1cb9d22b932e4832bb29793b7777ec860fc1cde0 # pin@v2 + uses: docker/build-push-action@1cb9d22b932e4832bb29793b7777ec860fc1cde0 with: context: . file: ./Dockerfile @@ -218,16 +220,16 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'pull_request' steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # pin@v3 + - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b with: fetch-depth: 0 - - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # pin@v2 + - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a with: go-version: 1.18.x - - uses: actions/setup-python@c4e89fac7e8767b327bbad6cb4d859eda999cf08 # pin@v3 + - uses: actions/setup-python@c4e89fac7e8767b327bbad6cb4d859eda999cf08 with: python-version: "3.x" - - uses: pre-commit/action@876132a3c26aa072b09eab6c5395b4749eeb2435 # pin@release + - uses: pre-commit/action@876132a3c26aa072b09eab6c5395b4749eeb2435 with: extra_args: --show-diff-on-failure --from-ref ${{ github.event.pull_request.base.sha }} --to-ref ${{ @@ -244,14 +246,14 @@ jobs: needs: - build steps: - - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # pin@v2 + - uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a with: go-version: 1.18.x - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # pin@v3 + - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b - name: retrieve binary - uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 # pin@v2 + uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 with: name: pomerium ${{ github.run_id }} ${{ matrix.platform }} path: bin/ @@ -260,6 +262,6 @@ jobs: run: make get-envoy - name: FOSSA Scan - uses: fossa-contrib/fossa-action@6cffaa064112e1cf9b5798c6224f9487dc1ec316 # pin@v1 + uses: fossa-contrib/fossa-action@6cffaa064112e1cf9b5798c6224f9487dc1ec316 with: fossa-api-key: 18f4ef488f514d06874b75f5809cea93 diff --git a/Makefile b/Makefile index 8ed09dd11..75dfe7534 100644 --- a/Makefile +++ b/Makefile @@ -103,7 +103,7 @@ test: get-envoy ## Runs the go tests. .PHONY: cover cover: get-envoy ## Runs go test with coverage @echo "==> $@" - $(GO) test -race -coverprofile=coverage.txt -tags "$(BUILDTAGS)" $(shell $(GO) list ./... | grep -v vendor | grep -v github.com/pomerium/pomerium/integration | grep -v github.com/pomerium/pomerium/pkg/storage/postgres) + $(GO) test -race -coverprofile=coverage.txt -tags "$(BUILDTAGS)" $(shell $(GO) list ./... | grep -v vendor | grep -v github.com/pomerium/pomerium/integration) @sed -i.bak '/\.pb\.go\:/d' coverage.txt @sed -i.bak '/\/mock\.go\:/d' coverage.txt @sort -o coverage.txt coverage.txt diff --git a/databroker/cache.go b/databroker/cache.go index eff0be494..955a2ccf1 100644 --- a/databroker/cache.go +++ b/databroker/cache.go @@ -15,6 +15,7 @@ import ( "google.golang.org/grpc/metadata" "github.com/pomerium/pomerium/config" + "github.com/pomerium/pomerium/internal/atomicutil" "github.com/pomerium/pomerium/internal/directory" "github.com/pomerium/pomerium/internal/events" "github.com/pomerium/pomerium/internal/identity" @@ -36,11 +37,10 @@ type DataBroker struct { manager *manager.Manager eventsMgr *events.Manager - localListener net.Listener - localGRPCServer *grpc.Server - localGRPCConnection *grpc.ClientConn - dataBrokerStorageType string // TODO remove in v0.11 - deprecatedCacheClusterDomain string // TODO: remove in v0.11 + localListener net.Listener + localGRPCServer *grpc.Server + localGRPCConnection *grpc.ClientConn + sharedKey *atomicutil.Value[[]byte] mu sync.Mutex directoryProvider directory.Provider @@ -53,8 +53,6 @@ func New(cfg *config.Config, eventsMgr *events.Manager) (*DataBroker, error) { return nil, err } - sharedKey, _ := cfg.Options.GetSharedKey() - ui, si := grpcutil.AttachMetadataInterceptors( metadata.Pairs( grpcutil.MetadataKeyEnvoyVersion, files.FullVersion(), @@ -69,11 +67,17 @@ func New(cfg *config.Config, eventsMgr *events.Manager) (*DataBroker, error) { grpc.UnaryInterceptor(ui), ) + sharedKey, err := cfg.Options.GetSharedKey() + if err != nil { + return nil, err + } + + sharedKeyValue := atomicutil.NewValue(sharedKey) clientStatsHandler := telemetry.NewGRPCClientStatsHandler(cfg.Options.Services) clientDialOptions := []grpc.DialOption{ grpc.WithInsecure(), - grpc.WithChainUnaryInterceptor(clientStatsHandler.UnaryInterceptor, grpcutil.WithUnarySignedJWT(sharedKey)), - grpc.WithChainStreamInterceptor(grpcutil.WithStreamSignedJWT(sharedKey)), + grpc.WithChainUnaryInterceptor(clientStatsHandler.UnaryInterceptor, grpcutil.WithUnarySignedJWT(sharedKeyValue.Load)), + grpc.WithChainStreamInterceptor(grpcutil.WithStreamSignedJWT(sharedKeyValue.Load)), grpc.WithStatsHandler(clientStatsHandler.Handler), } @@ -90,19 +94,14 @@ func New(cfg *config.Config, eventsMgr *events.Manager) (*DataBroker, error) { } dataBrokerServer := newDataBrokerServer(cfg) - dataBrokerURLs, err := cfg.Options.GetInternalDataBrokerURLs() - if err != nil { - return nil, err - } c := &DataBroker{ - dataBrokerServer: dataBrokerServer, - localListener: localListener, - localGRPCServer: localGRPCServer, - localGRPCConnection: localGRPCConnection, - deprecatedCacheClusterDomain: dataBrokerURLs[0].Hostname(), - dataBrokerStorageType: cfg.Options.DataBrokerStorageType, - eventsMgr: eventsMgr, + dataBrokerServer: dataBrokerServer, + localListener: localListener, + localGRPCServer: localGRPCServer, + localGRPCConnection: localGRPCConnection, + sharedKey: sharedKeyValue, + eventsMgr: eventsMgr, } c.Register(c.localGRPCServer) @@ -153,6 +152,12 @@ func (c *DataBroker) update(ctx context.Context, cfg *config.Config) error { return fmt.Errorf("databroker: bad option: %w", err) } + sharedKey, err := cfg.Options.GetSharedKey() + if err != nil { + return fmt.Errorf("databroker: invalid shared key: %w", err) + } + c.sharedKey.Store(sharedKey) + oauthOptions, err := cfg.Options.GetOauthOptions() if err != nil { return fmt.Errorf("databroker: invalid oauth options: %w", err) diff --git a/databroker/cache_test.go b/databroker/cache_test.go index 3c9ffa3d3..308ebde12 100644 --- a/databroker/cache_test.go +++ b/databroker/cache_test.go @@ -24,7 +24,6 @@ func TestNew(t *testing.T) { }{ {"good", config.Options{SharedKey: cryptutil.NewBase64Key(), DataBrokerURLString: "http://example"}, false}, {"bad shared secret", config.Options{SharedKey: string([]byte(cryptutil.NewBase64Key())[:31]), DataBrokerURLString: "http://example"}, true}, - {"bad databroker url", config.Options{SharedKey: cryptutil.NewBase64Key(), DataBrokerURLString: "BAD"}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/atomicutil/value.go b/internal/atomicutil/value.go new file mode 100644 index 000000000..58dc71c6b --- /dev/null +++ b/internal/atomicutil/value.go @@ -0,0 +1,26 @@ +// Package atomicutil contains functions for working with the atomic package. +package atomicutil + +import "sync/atomic" + +// Value is a generic atomic.Value. +type Value[T any] struct { + value atomic.Value +} + +// NewValue creates a new Value. +func NewValue[T any](init T) *Value[T] { + v := new(Value[T]) + v.value.Store(init) + return v +} + +// Load loads the value atomically. +func (v *Value[T]) Load() T { + return v.value.Load().(T) +} + +// Store stores the value atomically. +func (v *Value[T]) Store(val T) { + v.value.Store(val) +} diff --git a/internal/testutil/redis.go b/internal/testutil/redis.go index db3024ad5..2565ad4ed 100644 --- a/internal/testutil/redis.go +++ b/internal/testutil/redis.go @@ -18,7 +18,7 @@ import ( "github.com/pomerium/pomerium/pkg/cryptutil" ) -const maxWait = time.Minute +const maxWait = 20 * time.Minute // WithTestRedis creates a test a test redis instance using docker. func WithTestRedis(useTLS bool, handler func(rawURL string) error) error { diff --git a/pkg/grpc/client.go b/pkg/grpc/client.go index c3a54d8d5..5ebbf289a 100644 --- a/pkg/grpc/client.go +++ b/pkg/grpc/client.go @@ -43,8 +43,8 @@ func NewGRPCClientConn(ctx context.Context, opts *Options, other ...grpc.DialOpt requestid.StreamClientInterceptor(), } if opts.SignedJWTKey != nil { - unaryClientInterceptors = append(unaryClientInterceptors, grpcutil.WithUnarySignedJWT(opts.SignedJWTKey)) - streamClientInterceptors = append(streamClientInterceptors, grpcutil.WithStreamSignedJWT(opts.SignedJWTKey)) + unaryClientInterceptors = append(unaryClientInterceptors, grpcutil.WithUnarySignedJWT(func() []byte { return opts.SignedJWTKey })) + streamClientInterceptors = append(streamClientInterceptors, grpcutil.WithStreamSignedJWT(func() []byte { return opts.SignedJWTKey })) } dialOptions := []grpc.DialOption{ diff --git a/pkg/grpcutil/client.go b/pkg/grpcutil/client.go index e9ca4dc30..187b376af 100644 --- a/pkg/grpcutil/client.go +++ b/pkg/grpcutil/client.go @@ -63,8 +63,8 @@ func NewGRPCClientConn(ctx context.Context, opts *Options, other ...grpc.DialOpt } streamClientInterceptors := []grpc.StreamClientInterceptor{} if opts.SignedJWTKey != nil { - unaryClientInterceptors = append(unaryClientInterceptors, WithUnarySignedJWT(opts.SignedJWTKey)) - streamClientInterceptors = append(streamClientInterceptors, WithStreamSignedJWT(opts.SignedJWTKey)) + unaryClientInterceptors = append(unaryClientInterceptors, WithUnarySignedJWT(func() []byte { return opts.SignedJWTKey })) + streamClientInterceptors = append(streamClientInterceptors, WithStreamSignedJWT(func() []byte { return opts.SignedJWTKey })) } dialOptions := []grpc.DialOption{ diff --git a/pkg/grpcutil/options.go b/pkg/grpcutil/options.go index 77873671d..c72b90c6e 100644 --- a/pkg/grpcutil/options.go +++ b/pkg/grpcutil/options.go @@ -13,7 +13,7 @@ import ( ) // WithStreamSignedJWT returns a StreamClientInterceptor that adds a JWT to requests. -func WithStreamSignedJWT(key []byte) grpc.StreamClientInterceptor { +func WithStreamSignedJWT(getKey func() []byte) grpc.StreamClientInterceptor { return func( ctx context.Context, desc *grpc.StreamDesc, @@ -21,7 +21,7 @@ func WithStreamSignedJWT(key []byte) grpc.StreamClientInterceptor { method string, streamer grpc.Streamer, opts ...grpc.CallOption, ) (grpc.ClientStream, error) { - ctx, err := withSignedJWT(ctx, key) + ctx, err := withSignedJWT(ctx, getKey()) if err != nil { return nil, err } @@ -31,9 +31,9 @@ func WithStreamSignedJWT(key []byte) grpc.StreamClientInterceptor { } // WithUnarySignedJWT returns a UnaryClientInterceptor that adds a JWT to requests. -func WithUnarySignedJWT(key []byte) grpc.UnaryClientInterceptor { +func WithUnarySignedJWT(getKey func() []byte) grpc.UnaryClientInterceptor { return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { - ctx, err := withSignedJWT(ctx, key) + ctx, err := withSignedJWT(ctx, getKey()) if err != nil { return err } diff --git a/pkg/grpcutil/options_test.go b/pkg/grpcutil/options_test.go index 7a1aed26e..35c715cd4 100644 --- a/pkg/grpcutil/options_test.go +++ b/pkg/grpcutil/options_test.go @@ -74,8 +74,8 @@ func TestSignedJWT(t *testing.T) { }) t.Run("authenticated", func(t *testing.T) { cc, err := grpc.Dial(li.Addr().String(), - grpc.WithUnaryInterceptor(WithUnarySignedJWT(key)), - grpc.WithStreamInterceptor(WithStreamSignedJWT(key)), + grpc.WithUnaryInterceptor(WithUnarySignedJWT(func() []byte { return key })), + grpc.WithStreamInterceptor(WithStreamSignedJWT(func() []byte { return key })), grpc.WithInsecure()) if !assert.NoError(t, err) { return diff --git a/pkg/storage/postgres/backend_test.go b/pkg/storage/postgres/backend_test.go index 331314021..0448fd817 100644 --- a/pkg/storage/postgres/backend_test.go +++ b/pkg/storage/postgres/backend_test.go @@ -20,12 +20,16 @@ import ( "github.com/pomerium/pomerium/pkg/storage" ) +const maxWait = time.Minute * 10 + func TestBackend(t *testing.T) { if os.Getenv("GITHUB_ACTION") != "" && runtime.GOOS == "darwin" { t.Skip("Github action can not run docker on MacOS") } - ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*10) + t.Parallel() + + ctx, clearTimeout := context.WithTimeout(context.Background(), maxWait) defer clearTimeout() require.NoError(t, testutil.WithTestPostgres(func(dsn string) error { diff --git a/pkg/storage/postgres/registry_test.go b/pkg/storage/postgres/registry_test.go index 1a3dfc9ff..dbf1963fc 100644 --- a/pkg/storage/postgres/registry_test.go +++ b/pkg/storage/postgres/registry_test.go @@ -7,7 +7,6 @@ import ( "os" "runtime" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -36,7 +35,9 @@ func TestRegistry(t *testing.T) { t.Skip("Github action can not run docker on MacOS") } - ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*10) + t.Parallel() + + ctx, clearTimeout := context.WithTimeout(context.Background(), maxWait) defer clearTimeout() require.NoError(t, testutil.WithTestPostgres(func(dsn string) error { diff --git a/pkg/storage/redis/redis_test.go b/pkg/storage/redis/redis_test.go index 0697be478..d6ea506be 100644 --- a/pkg/storage/redis/redis_test.go +++ b/pkg/storage/redis/redis_test.go @@ -79,12 +79,14 @@ func TestBackend(t *testing.T) { } t.Run("no-tls", func(t *testing.T) { + t.Parallel() require.NoError(t, testutil.WithTestRedis(false, func(rawURL string) error { return handler(t, false, rawURL) })) }) t.Run("tls", func(t *testing.T) { + t.Parallel() require.NoError(t, testutil.WithTestRedis(true, func(rawURL string) error { return handler(t, true, rawURL) })) @@ -92,12 +94,14 @@ func TestBackend(t *testing.T) { if runtime.GOOS == "linux" { t.Run("cluster", func(t *testing.T) { + t.Parallel() require.NoError(t, testutil.WithTestRedisCluster(func(rawURL string) error { return handler(t, false, rawURL) })) }) t.Run("sentinel", func(t *testing.T) { + t.Parallel() require.NoError(t, testutil.WithTestRedisSentinel(func(rawURL string) error { return handler(t, false, rawURL) })) @@ -110,6 +114,8 @@ func TestChangeSignal(t *testing.T) { t.Skip("Github action can not run docker on MacOS") } + t.Parallel() + ctx := context.Background() require.NoError(t, testutil.WithTestRedis(false, func(rawURL string) error { ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30) @@ -174,6 +180,8 @@ func TestExpiry(t *testing.T) { t.Skip("Github action can not run docker on MacOS") } + t.Parallel() + ctx := context.Background() require.NoError(t, testutil.WithTestRedis(false, func(rawURL string) error { backend, err := New(rawURL, WithExpiry(0)) @@ -219,6 +227,8 @@ func TestCapacity(t *testing.T) { t.Skip("Github action can not run docker on MacOS") } + t.Parallel() + ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*10) defer clearTimeout() @@ -263,6 +273,8 @@ func TestLease(t *testing.T) { t.Skip("Github action can not run docker on MacOS") } + t.Parallel() + ctx := context.Background() require.NoError(t, testutil.WithTestRedis(false, func(rawURL string) error { backend, err := New(rawURL)