From abd097240c42bce0f02b39434fb7f3a3357d1ea9 Mon Sep 17 00:00:00 2001 From: joshvanl Date: Mon, 22 Jul 2024 16:23:46 +0100 Subject: [PATCH 1/8] Lock by key when executing cron queue Use a per job key mutex to lock execution of a trigger. A per key lock prevents writes of new jobs from being blocked by actively executing triggers. Signed-off-by: joshvanl --- api.go | 2 +- cron.go | 41 +++-- cron_test.go | 437 +++++++++++++++++++------------------------------ go.mod | 23 +-- go.sum | 62 ++++--- gomod2nix.toml | 38 ++--- 6 files changed, 259 insertions(+), 344 deletions(-) diff --git a/api.go b/api.go index f661e1b..981080b 100644 --- a/api.go +++ b/api.go @@ -99,7 +99,7 @@ func (c *cron) Delete(ctx context.Context, name string) error { return err } - return c.queue.Dequeue(c.key.JobKey(name)) + return nil } // validateName validates the name of a job. diff --git a/cron.go b/cron.go index 8071a1c..4b19154 100644 --- a/cron.go +++ b/cron.go @@ -107,7 +107,7 @@ type cron struct { wg sync.WaitGroup // queueLock prevents an informed schedule from overwriting a job as it is // being triggered, i.e. prevent a PUT and mid-trigger race condition. - queueLock sync.RWMutex + queueLock concurrency.MutexMap[string] } // New creates a new cron instance. @@ -178,6 +178,7 @@ func New(opts Options) (Interface, error) { readyCh: make(chan struct{}), closeCh: make(chan struct{}), errCh: make(chan error), + queueLock: concurrency.NewMutexMap[string](), }, nil } @@ -190,12 +191,20 @@ func (c *cron) Run(ctx context.Context) error { c.queue = queue.NewProcessor[string, *counter.Counter]( func(counter *counter.Counter) { - c.queueLock.RLock() + c.queueLock.Lock(counter.Key()) + if ctx.Err() != nil { + c.queueLock.Unlock(counter.Key()) + return + } + c.wg.Add(1) go func() { - defer c.queueLock.RUnlock() defer c.wg.Done() - c.handleTrigger(ctx, counter) + if c.handleTrigger(ctx, counter) { + c.queueLock.Unlock(counter.Key()) + } else { + c.queueLock.DeleteUnlock(counter.Key()) + } }() }, ).WithClock(c.clock) @@ -259,7 +268,8 @@ func (c *cron) Run(ctx context.Context) error { } // handleTrigger handles triggering a schedule job. -func (c *cron) handleTrigger(ctx context.Context, counter *counter.Counter) { +// Returns true if the job is being re-enqueued, false otherwise. +func (c *cron) handleTrigger(ctx context.Context, counter *counter.Counter) bool { if !c.triggerFn(ctx, counter.TriggerRequest()) { // If the trigger function returns false, i.e. failed client side, // re-enqueue the job immediately. @@ -269,7 +279,7 @@ func (c *cron) handleTrigger(ctx context.Context, counter *counter.Counter) { case c.errCh <- err: } } - return + return true } ok, err := counter.Trigger(ctx) @@ -283,29 +293,26 @@ func (c *cron) handleTrigger(ctx context.Context, counter *counter.Counter) { case c.errCh <- err: } } + + return true } + + return false } // handleInformerEvent handles an etcd informed event. -// TODO: @joshvanl: add a safe per key read lock to prevent locking all -// triggers and an unrelated write. Must be able to handle a key being -// de-queued and unlocked (deleted) whilst an Add schedule is waiting on the -// lock, and visa versa. I don't think there is much if any we gain though as -// we _always_ hack to lock somewhere.. func (c *cron) handleInformerEvent(ctx context.Context, e *informer.Event) error { - c.queueLock.Lock() - defer c.queueLock.Unlock() - - select { - case <-ctx.Done(): + if ctx.Err() != nil { return ctx.Err() - default: } + c.queueLock.Lock(string(e.Key)) if e.IsPut { + defer c.queueLock.Unlock(string(e.Key)) return c.schedule(ctx, c.key.JobName(e.Key), e.Job) } + defer c.queueLock.DeleteUnlock(string(e.Key)) return c.queue.Dequeue(string(e.Key)) } diff --git a/cron_test.go b/cron_test.go index 8a6494e..d29b1bc 100644 --- a/cron_test.go +++ b/cron_test.go @@ -23,83 +23,41 @@ import ( "google.golang.org/protobuf/types/known/wrapperspb" "github.com/diagridio/go-etcd-cron/api" + "github.com/diagridio/go-etcd-cron/internal/client" "github.com/diagridio/go-etcd-cron/internal/tests" ) func Test_retry(t *testing.T) { t.Parallel() - client := tests.EmbeddedETCDBareClient(t) - var triggerd atomic.Int64 - cron, err := New(Options{ - Log: logr.Discard(), - Client: client, - Namespace: "abc", - PartitionID: 0, - PartitionTotal: 1, - TriggerFn: func(context.Context, *api.TriggerRequest) bool { - triggerd.Add(1) - return triggerd.Load() != 1 - }, + var ok atomic.Bool + helper := testCronWithOptions(t, testCronOptions{ + total: 1, + returnOk: &ok, }) - require.NoError(t, err) - - errCh := make(chan error) - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - select { - case err := <-errCh: - require.NoError(t, err) - case <-time.After(5 * time.Second): - t.Fatal("timeout waiting for cron to stop") - } - }) - go func() { - errCh <- cron.Run(ctx) - }() job := &api.Job{ DueTime: ptr.Of(time.Now().Format(time.RFC3339)), } - require.NoError(t, cron.Add(ctx, "yoyo", job)) + require.NoError(t, helper.cron.Add(helper.ctx, "yoyo", job)) + assert.EventuallyWithT(t, func(c *assert.CollectT) { + assert.Greater(c, helper.triggered.Load(), int64(2)) + }, 5*time.Second, 10*time.Millisecond) + ok.Store(true) + triggered := helper.triggered.Load() <-time.After(3 * time.Second) - assert.Equal(t, int64(2), triggerd.Load()) + assert.Equal(t, triggered+1, helper.triggered.Load()) } func Test_payload(t *testing.T) { t.Parallel() - client := tests.EmbeddedETCDBareClient(t) gotCh := make(chan *api.TriggerRequest, 1) - cron, err := New(Options{ - Log: logr.Discard(), - Client: client, - Namespace: "abc", - PartitionID: 0, - PartitionTotal: 1, - TriggerFn: func(_ context.Context, api *api.TriggerRequest) bool { - gotCh <- api - return true - }, - }) - require.NoError(t, err) - - errCh := make(chan error) - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - select { - case err := <-errCh: - require.NoError(t, err) - case <-time.After(5 * time.Second): - t.Fatal("timeout waiting for cron to stop") - } + helper := testCronWithOptions(t, testCronOptions{ + total: 1, + gotCh: gotCh, }) - go func() { - errCh <- cron.Run(ctx) - }() payload, err := anypb.New(wrapperspb.String("hello")) require.NoError(t, err) @@ -110,7 +68,7 @@ func Test_payload(t *testing.T) { Payload: payload, Metadata: meta, } - require.NoError(t, cron.Add(ctx, "yoyo", job)) + require.NoError(t, helper.cron.Add(helper.ctx, "yoyo", job)) select { case got := <-gotCh: @@ -129,95 +87,38 @@ func Test_payload(t *testing.T) { func Test_remove(t *testing.T) { t.Parallel() - client := tests.EmbeddedETCDBareClient(t) - var triggered atomic.Int64 - cron, err := New(Options{ - Log: logr.Discard(), - Client: client, - Namespace: "abc", - PartitionID: 0, - PartitionTotal: 1, - TriggerFn: func(context.Context, *api.TriggerRequest) bool { - triggered.Add(1) - return true - }, - }) - require.NoError(t, err) - - errCh := make(chan error) - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - select { - case err := <-errCh: - require.NoError(t, err) - case <-time.After(5 * time.Second): - t.Fatal("timeout waiting for cron to stop") - } - }) - go func() { - errCh <- cron.Run(ctx) - }() + helper := testCron(t, 1) job := &api.Job{ DueTime: ptr.Of(time.Now().Add(time.Second * 2).Format(time.RFC3339)), } - require.NoError(t, cron.Add(ctx, "def", job)) - require.NoError(t, cron.Delete(ctx, "def")) + require.NoError(t, helper.cron.Add(helper.ctx, "def", job)) + require.NoError(t, helper.cron.Delete(helper.ctx, "def")) <-time.After(3 * time.Second) - assert.Equal(t, int64(0), triggered.Load()) + assert.Equal(t, int64(0), helper.triggered.Load()) } func Test_upsert(t *testing.T) { t.Parallel() - client := tests.EmbeddedETCDBareClient(t) - var triggered atomic.Int64 - cron, err := New(Options{ - Log: logr.Discard(), - Client: client, - Namespace: "abc", - PartitionID: 0, - PartitionTotal: 1, - TriggerFn: func(context.Context, *api.TriggerRequest) bool { - triggered.Add(1) - - return true - }, - }) - require.NoError(t, err) - - errCh := make(chan error) - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - select { - case err := <-errCh: - require.NoError(t, err) - case <-time.After(5 * time.Second): - t.Fatal("timeout waiting for cron to stop") - } - }) - go func() { - errCh <- cron.Run(ctx) - }() + helper := testCron(t, 1) job := &api.Job{ DueTime: ptr.Of(time.Now().Add(time.Hour).Format(time.RFC3339)), } - require.NoError(t, cron.Add(ctx, "def", job)) + require.NoError(t, helper.cron.Add(helper.ctx, "def", job)) job = &api.Job{ DueTime: ptr.Of(time.Now().Add(time.Second).Format(time.RFC3339)), } - require.NoError(t, cron.Add(ctx, "def", job)) + require.NoError(t, helper.cron.Add(helper.ctx, "def", job)) assert.Eventually(t, func() bool { - return triggered.Load() == 1 + return helper.triggered.Load() == 1 }, 5*time.Second, 1*time.Second) - resp, err := client.Get(context.Background(), "abc/jobs/def") + resp, err := helper.client.Get(context.Background(), "abc/jobs/def") require.NoError(t, err) assert.Empty(t, resp.Kvs) } @@ -225,57 +126,20 @@ func Test_upsert(t *testing.T) { func Test_patition(t *testing.T) { t.Parallel() - client := tests.EmbeddedETCDBareClient(t) - var triggered atomic.Int64 - - crons := make([]Interface, 100) - for i := 0; i < 100; i++ { - cron, err := New(Options{ - Log: logr.Discard(), - Client: client, - Namespace: "abc", - PartitionID: uint32(i), - PartitionTotal: 100, - TriggerFn: func(context.Context, *api.TriggerRequest) bool { - triggered.Add(1) - return true - }, - }) - require.NoError(t, err) - crons[i] = cron - } - - errCh := make(chan error) - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - for i := 0; i < 100; i++ { - select { - case err := <-errCh: - require.NoError(t, err) - case <-time.After(5 * time.Second): - t.Fatal("timeout waiting for cron to stop") - } - } - }) - for i := 0; i < 100; i++ { - go func(i int) { - errCh <- crons[i].Run(ctx) - }(i) - } + helper := testCron(t, 100) for i := 0; i < 100; i++ { job := &api.Job{ DueTime: ptr.Of(time.Now().Add(time.Second).Format(time.RFC3339)), } - require.NoError(t, crons[0].Add(ctx, "test-"+strconv.Itoa(i), job)) + require.NoError(t, helper.allCrons[i].Add(helper.ctx, "test-"+strconv.Itoa(i), job)) } assert.Eventually(t, func() bool { - return triggered.Load() == 100 + return helper.triggered.Load() == 100 }, 5*time.Second, 1*time.Second) - resp, err := client.Get(context.Background(), "abc/jobs", clientv3.WithPrefix()) + resp, err := helper.client.Get(context.Background(), "abc/jobs", clientv3.WithPrefix()) require.NoError(t, err) assert.Empty(t, resp.Kvs) } @@ -283,47 +147,19 @@ func Test_patition(t *testing.T) { func Test_oneshot(t *testing.T) { t.Parallel() - client := tests.EmbeddedETCDBareClient(t) - var triggered atomic.Int64 - cron, err := New(Options{ - Log: logr.Discard(), - Client: client, - Namespace: "abc", - PartitionID: 0, - PartitionTotal: 1, - TriggerFn: func(context.Context, *api.TriggerRequest) bool { - triggered.Add(1) - return true - }, - }) - require.NoError(t, err) - - errCh := make(chan error) - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - select { - case err := <-errCh: - require.NoError(t, err) - case <-time.After(5 * time.Second): - t.Fatal("timeout waiting for cron to stop") - } - }) - go func() { - errCh <- cron.Run(ctx) - }() + helper := testCron(t, 1) job := &api.Job{ DueTime: ptr.Of(time.Now().Add(time.Second).Format(time.RFC3339)), } - require.NoError(t, cron.Add(ctx, "def", job)) + require.NoError(t, helper.cron.Add(helper.ctx, "def", job)) assert.Eventually(t, func() bool { - return triggered.Load() == 1 + return helper.triggered.Load() == 1 }, 5*time.Second, 1*time.Second) - resp, err := client.Get(context.Background(), "abc/jobs/def") + resp, err := helper.client.Get(context.Background(), "abc/jobs/def") require.NoError(t, err) assert.Empty(t, resp.Kvs) } @@ -331,48 +167,20 @@ func Test_oneshot(t *testing.T) { func Test_repeat(t *testing.T) { t.Parallel() - client := tests.EmbeddedETCDBareClient(t) - var triggered atomic.Int64 - cron, err := New(Options{ - Log: logr.Discard(), - Client: client, - Namespace: "abc", - PartitionID: 0, - PartitionTotal: 1, - TriggerFn: func(context.Context, *api.TriggerRequest) bool { - triggered.Add(1) - return true - }, - }) - require.NoError(t, err) - - errCh := make(chan error) - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - select { - case err := <-errCh: - require.NoError(t, err) - case <-time.After(5 * time.Second): - t.Fatal("timeout waiting for cron to stop") - } - }) - go func() { - errCh <- cron.Run(ctx) - }() + helper := testCron(t, 1) job := &api.Job{ Schedule: ptr.Of("@every 1s"), Repeats: ptr.Of(uint32(3)), } - require.NoError(t, cron.Add(ctx, "def", job)) + require.NoError(t, helper.cron.Add(helper.ctx, "def", job)) - assert.Eventually(t, func() bool { - return triggered.Load() == 3 + assert.EventuallyWithT(t, func(c *assert.CollectT) { + assert.Equal(c, int64(3), helper.triggered.Load()) }, 5*time.Second, 1*time.Second) - resp, err := client.Get(context.Background(), "abc/jobs/def") + resp, err := helper.client.Get(context.Background(), "abc/jobs/def") require.NoError(t, err) assert.Empty(t, resp.Kvs) } @@ -671,55 +479,154 @@ func Test_schedule(t *testing.T) { func Test_zeroDueTime(t *testing.T) { t.Parallel() - client := tests.EmbeddedETCDBareClient(t) - var triggerd atomic.Int64 - cron, err := New(Options{ - Log: logr.Discard(), - Client: client, - Namespace: "abc", - PartitionID: 0, - PartitionTotal: 1, - TriggerFn: func(context.Context, *api.TriggerRequest) bool { - triggerd.Add(1) - return true - }, - }) - require.NoError(t, err) + helper := testCron(t, 1) - errCh := make(chan error) - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(func() { - cancel() - select { - case err := <-errCh: - require.NoError(t, err) - case <-time.After(5 * time.Second): - t.Fatal("timeout waiting for cron to stop") - } - }) - go func() { - errCh <- cron.Run(ctx) - }() - - require.NoError(t, cron.Add(ctx, "yoyo", &api.Job{ + require.NoError(t, helper.cron.Add(helper.ctx, "yoyo", &api.Job{ Schedule: ptr.Of("@every 1h"), DueTime: ptr.Of("0s"), })) assert.Eventually(t, func() bool { - return triggerd.Load() == 1 + return helper.triggered.Load() == 1 }, 3*time.Second, time.Millisecond*10) - require.NoError(t, cron.Add(ctx, "yoyo2", &api.Job{ + require.NoError(t, helper.cron.Add(helper.ctx, "yoyo2", &api.Job{ Schedule: ptr.Of("@every 1h"), DueTime: ptr.Of("1s"), })) assert.Eventually(t, func() bool { - return triggerd.Load() == 2 + return helper.triggered.Load() == 2 }, 3*time.Second, time.Millisecond*10) - require.NoError(t, cron.Add(ctx, "yoyo3", &api.Job{ + require.NoError(t, helper.cron.Add(helper.ctx, "yoyo3", &api.Job{ Schedule: ptr.Of("@every 1h"), })) <-time.After(2 * time.Second) - assert.Equal(t, int64(2), triggerd.Load()) + assert.Equal(t, int64(2), helper.triggered.Load()) +} + +func Test_parallel(t *testing.T) { + t.Parallel() + + for _, test := range []struct { + name string + total uint32 + }{ + {"1 queue", 1}, + {"multi queue", 50}, + } { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + releaseCh := make(chan struct{}) + var waiting atomic.Int32 + var done atomic.Int32 + helper := testCronWithOptions(t, testCronOptions{ + total: test.total, + triggerFn: func() { + waiting.Add(1) + <-releaseCh + done.Add(1) + }, + }) + + for i := 0; i < 100; i++ { + require.NoError(t, helper.cron.Add(helper.ctx, strconv.Itoa(i), &api.Job{ + DueTime: ptr.Of("0s"), + })) + } + + assert.EventuallyWithT(t, func(c *assert.CollectT) { + assert.Equal(c, int32(100), waiting.Load()) + }, 5*time.Second, 10*time.Millisecond) + close(releaseCh) + assert.EventuallyWithT(t, func(c *assert.CollectT) { + assert.Equal(c, int32(100), done.Load()) + }, 5*time.Second, 10*time.Millisecond) + }) + } +} + +type testCronOptions struct { + total uint32 + returnOk *atomic.Bool + gotCh chan *api.TriggerRequest + triggerFn func() +} + +type helper struct { + ctx context.Context + client client.Interface + cron Interface + allCrons []Interface + triggered *atomic.Int64 +} + +func testCron(t *testing.T, total uint32) *helper { + return testCronWithOptions(t, testCronOptions{ + total: total, + }) +} + +func testCronWithOptions(t *testing.T, opts testCronOptions) *helper { + t.Helper() + + require.Greater(t, opts.total, uint32(0)) + cl := tests.EmbeddedETCDBareClient(t) + + var triggered atomic.Int64 + var cron Interface + allCrns := make([]Interface, opts.total) + for i := uint32(0); i < opts.total; i++ { + c, err := New(Options{ + Log: logr.Discard(), + Client: cl, + Namespace: "abc", + PartitionID: i, + PartitionTotal: opts.total, + TriggerFn: func(_ context.Context, req *api.TriggerRequest) bool { + ok := opts.returnOk == nil || opts.returnOk.Load() + triggered.Add(1) + if opts.gotCh != nil { + opts.gotCh <- req + } + if opts.triggerFn != nil { + opts.triggerFn() + } + return ok + }, + }) + require.NoError(t, err) + allCrns[i] = c + if i == 0 { + cron = c + } + } + + errCh := make(chan error, opts.total) + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(func() { + cancel() + for i := uint32(0); i < opts.total; i++ { + select { + case err := <-errCh: + require.NoError(t, err) + case <-time.After(5 * time.Second): + t.Fatal("timeout waiting for cron to stop") + } + } + }) + for i := uint32(0); i < opts.total; i++ { + go func(i uint32) { + errCh <- allCrns[i].Run(ctx) + }(i) + } + + return &helper{ + ctx: ctx, + client: client.New(cl), + cron: cron, + allCrons: allCrns, + triggered: &triggered, + } } diff --git a/go.mod b/go.mod index 0743451..36c8253 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,12 @@ module github.com/diagridio/go-etcd-cron -go 1.21.9 +go 1.22 require ( - github.com/dapr/kit v0.13.0 + github.com/dapr/kit v0.13.1-0.20240624212434-e2508d6e9e79 github.com/go-logr/logr v1.3.0 github.com/go-logr/zapr v1.3.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 go.etcd.io/etcd/api/v3 v3.5.13 go.etcd.io/etcd/client/pkg/v3 v3.5.13 go.etcd.io/etcd/client/v3 v3.5.13 @@ -63,17 +63,20 @@ require ( go.opentelemetry.io/otel/trace v1.20.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/grpc v1.59.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/grpc v1.64.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) + +replace github.com/dapr/kit => ../../dapr/kit diff --git a/go.sum b/go.sum index 6b956a2..47fd3cb 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -25,16 +25,14 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 h1:DBmgJDC9dTfkVyGgipamEh2BpGYxScCH1TOF1LL1cXc= +github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM= github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/dapr/kit v0.13.0 h1:4S+5QqDCreva+MBONtIgxeg6B2b1W89bB8F5lqKgTa0= -github.com/dapr/kit v0.13.0/go.mod h1:VyHrelNXPbtS/VcQX0Y/uzW0lfEVuveJ+1E5bDys8mo= 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= @@ -44,8 +42,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -68,8 +66,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -182,8 +180,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= @@ -235,8 +233,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf 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= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= @@ -259,13 +257,13 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= 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-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -273,8 +271,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -289,13 +287,13 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -312,26 +310,26 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/gomod2nix.toml b/gomod2nix.toml index ba02d05..0fdbb5f 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -16,9 +16,6 @@ schema = 3 [mod."github.com/coreos/go-systemd/v22"] version = "v22.3.2" hash = "sha256-rPrbVhxorJrdhUCrTH67imhVIuu4j5brPf4fJtpgnA4=" - [mod."github.com/dapr/kit"] - version = "v0.13.0" - hash = "sha256-P9Hd/tY1oN9Jkw8Bfbo57WAYC4WrUb+RkJTJVrsVV/g=" [mod."github.com/davecgh/go-spew"] version = "v1.1.1" hash = "sha256-nhzSUrE1fCkN0+RL04N4h8jWmRFPPPWbCuDc7Ss0akI=" @@ -101,8 +98,8 @@ schema = 3 version = "v1.0.5" hash = "sha256-w9LLYzxxP74WHT4ouBspH/iQZXjuAh2WQCHsuvyEjAw=" [mod."github.com/stretchr/testify"] - version = "v1.8.4" - hash = "sha256-MoOmRzbz9QgiJ+OOBo5h5/LbilhJfRUryvzHJmXAWjo=" + version = "v1.9.0" + hash = "sha256-uUp/On+1nK+lARkTVtb5RxlW15zxtw2kaAFuIASA+J0=" [mod."github.com/tmc/grpc-websocket-proxy"] version = "v0.0.0-20201229170055-e5319fda7802" hash = "sha256-1Jbjj24wahHEoFGP5YdK+TuZq27d5M684jQfUfVr3ds=" @@ -164,17 +161,20 @@ schema = 3 version = "v1.26.0" hash = "sha256-EUQnALSDtoJryWp01K/PMbRUvQYG1uDbqGnlJ/7thE4=" [mod."golang.org/x/crypto"] - version = "v0.21.0" - hash = "sha256-Z4k1LvFh4Jai7HUe6TTuXSG3VnuiRpMwdARIdZZqSYk=" + version = "v0.24.0" + hash = "sha256-wpxJApwSmmn9meVdpFdOU0gzeJbIXcKuFfYUUVogSss=" + [mod."golang.org/x/exp"] + version = "v0.0.0-20231006140011-7918f672742d" + hash = "sha256-2SO1etTQ6UCUhADR5sgvDEDLHcj77pJKCIa/8mGDbAo=" [mod."golang.org/x/net"] - version = "v0.23.0" - hash = "sha256-ZB4504rtgsHbcRfijjlqt4/2ddb8tyQB5IBn126uVTQ=" + version = "v0.26.0" + hash = "sha256-WfY33QERNbcIiDkH3+p2XGrAVqvWBQfc8neUt6TH6dQ=" [mod."golang.org/x/sys"] - version = "v0.18.0" - hash = "sha256-bIFhfFp7Sj0E1gcE3X3l/jecCfSRLgrkb8f0Yr6tVR0=" + version = "v0.21.0" + hash = "sha256-gapzPWuEqY36V6W2YhIDYR49sEvjJRd7bSuf9K1f4JY=" [mod."golang.org/x/text"] - version = "v0.14.0" - hash = "sha256-yh3B0tom1RfzQBf1RNmfdNWF1PtiqxV41jW1GVS6JAg=" + version = "v0.16.0" + hash = "sha256-hMTO45upjEuA4sJzGplJT+La2n3oAfHccfYWZuHcH+8=" [mod."golang.org/x/time"] version = "v0.0.0-20210220033141-f8bda1e9f3ba" hash = "sha256-EXcg0EH7WIgc2raopkjaOX3uPORJPM6PKzvJQy5QazQ=" @@ -182,14 +182,14 @@ schema = 3 version = "v0.0.0-20230822172742-b8732ec3820d" hash = "sha256-NI7h/WXGdDI8UgJrvwW4wziuOVOr1617NaAWBP0nAyo=" [mod."google.golang.org/genproto/googleapis/api"] - version = "v0.0.0-20230822172742-b8732ec3820d" - hash = "sha256-qd9dJezVHNJZNMkywXapT1rsyD+lb25AU8aG8NJlhm4=" + version = "v0.0.0-20240318140521-94a12d6c2237" + hash = "sha256-Tl2ABoESriYlPfeawE9xd5gPQYGzW4j/Il6gXEw33f0=" [mod."google.golang.org/genproto/googleapis/rpc"] - version = "v0.0.0-20230822172742-b8732ec3820d" - hash = "sha256-1kP7lqQ+fKtARDzTrRNob0owX4GsUnxzOwLyBZSmHOc=" + version = "v0.0.0-20240318140521-94a12d6c2237" + hash = "sha256-P5SBku16dYnK4koUQxTeGwPxAAWH8rxbDm2pOzFLo/Q=" [mod."google.golang.org/grpc"] - version = "v1.59.0" - hash = "sha256-IcwmXyeroUg742wqU4Zikwxm7y0i7x4axOPdWOGPkzE=" + version = "v1.64.0" + hash = "sha256-04Noi8lrzr+4ac2BA7KNXUXN/xZL/A2SsEpC2Hern84=" [mod."google.golang.org/protobuf"] version = "v1.33.0" hash = "sha256-cWwQjtUwSIEkAlAadrlxK1PYZXTRrV4NKzt7xDpJgIU=" From b5a2b9b2e033860340c68483d2c887eb987a4e10 Mon Sep 17 00:00:00 2001 From: joshvanl Date: Mon, 22 Jul 2024 17:52:39 +0100 Subject: [PATCH 2/8] Update go.mod Signed-off-by: joshvanl --- go.mod | 4 +--- go.sum | 2 ++ gomod2nix.toml | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 36c8253..8bcd038 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/diagridio/go-etcd-cron go 1.22 require ( - github.com/dapr/kit v0.13.1-0.20240624212434-e2508d6e9e79 + github.com/dapr/kit v0.13.1-0.20240722163453-58c6d9df14d3 github.com/go-logr/logr v1.3.0 github.com/go-logr/zapr v1.3.0 github.com/stretchr/testify v1.9.0 @@ -78,5 +78,3 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) - -replace github.com/dapr/kit => ../../dapr/kit diff --git a/go.sum b/go.sum index 47fd3cb..ea6c2ef 100644 --- a/go.sum +++ b/go.sum @@ -33,6 +33,8 @@ github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmf github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/dapr/kit v0.13.1-0.20240722163453-58c6d9df14d3 h1:+HZd67sGtxQq7UoEXpby0x0pE0XcZwTY03UuZc48P/M= +github.com/dapr/kit v0.13.1-0.20240722163453-58c6d9df14d3/go.mod h1:Hz1W2LmWfA4UX/12MdA+brsf+np6f/1dJt6C6F63cjI= 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= diff --git a/gomod2nix.toml b/gomod2nix.toml index 0fdbb5f..15d18e8 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -16,6 +16,9 @@ schema = 3 [mod."github.com/coreos/go-systemd/v22"] version = "v22.3.2" hash = "sha256-rPrbVhxorJrdhUCrTH67imhVIuu4j5brPf4fJtpgnA4=" + [mod."github.com/dapr/kit"] + version = "v0.13.1-0.20240722163453-58c6d9df14d3" + hash = "sha256-1prx4cSDT8yTGwUDvVCs5zW0fAIsRMcYaQIaEZC8bw8=" [mod."github.com/davecgh/go-spew"] version = "v1.1.1" hash = "sha256-nhzSUrE1fCkN0+RL04N4h8jWmRFPPPWbCuDc7Ss0akI=" From abf1b15af19288687b631a37dbd9ba155d455d3c Mon Sep 17 00:00:00 2001 From: joshvanl Date: Mon, 22 Jul 2024 17:59:51 +0100 Subject: [PATCH 3/8] Lint Signed-off-by: joshvanl --- .golangci.yaml | 1 + api_test.go | 1 - cron_test.go | 1 - internal/counter/counter_test.go | 1 - internal/grave/yard_test.go | 1 - internal/informer/informer_test.go | 1 - internal/key/key_test.go | 6 ------ internal/partitioner/partitioner_test.go | 1 - internal/scheduler/builder_test.go | 3 --- internal/scheduler/oneshot_test.go | 1 - internal/scheduler/repeats_test.go | 1 - 11 files changed, 1 insertion(+), 17 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 6dbf6f9..2e2fe06 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -19,6 +19,7 @@ linters: - gci - funlen - maintidx + - containedctx linters-settings: goimports: local-prefixes: github.com/diagridio diff --git a/api_test.go b/api_test.go index 2a155d9..0708c67 100644 --- a/api_test.go +++ b/api_test.go @@ -495,7 +495,6 @@ func Test_validateName(t *testing.T) { } for _, test := range tests { - test := test t.Run(test.name, func(t *testing.T) { t.Parallel() c, err := New(Options{ diff --git a/cron_test.go b/cron_test.go index d29b1bc..f72c236 100644 --- a/cron_test.go +++ b/cron_test.go @@ -514,7 +514,6 @@ func Test_parallel(t *testing.T) { {"1 queue", 1}, {"multi queue", 50}, } { - test := test t.Run(test.name, func(t *testing.T) { t.Parallel() diff --git a/internal/counter/counter_test.go b/internal/counter/counter_test.go index 03acb25..559d67f 100644 --- a/internal/counter/counter_test.go +++ b/internal/counter/counter_test.go @@ -880,7 +880,6 @@ func Test_updateNext(t *testing.T) { } for name, test := range tests { - test := test t.Run(name, func(t *testing.T) { t.Parallel() c := test.counter diff --git a/internal/grave/yard_test.go b/internal/grave/yard_test.go index c32d63a..a7e2e3e 100644 --- a/internal/grave/yard_test.go +++ b/internal/grave/yard_test.go @@ -120,7 +120,6 @@ func Test_HasJustDeleted(t *testing.T) { } for name, test := range tests { - test := test t.Run(name, func(t *testing.T) { t.Parallel() yard := New() diff --git a/internal/informer/informer_test.go b/internal/informer/informer_test.go index 18975f9..a630698 100644 --- a/internal/informer/informer_test.go +++ b/internal/informer/informer_test.go @@ -333,7 +333,6 @@ func Test_handleEvent(t *testing.T) { } for name, test := range tests { - test := test t.Run(name, func(t *testing.T) { t.Parallel() part, err := partitioner.New(partitioner.Options{ diff --git a/internal/key/key_test.go b/internal/key/key_test.go index 34f9ff2..e77f19d 100644 --- a/internal/key/key_test.go +++ b/internal/key/key_test.go @@ -42,7 +42,6 @@ func Test_JobKey(t *testing.T) { } for _, test := range tests { - test := test t.Run(test.namespace+"/"+test.jobName, func(t *testing.T) { t.Parallel() key := New(Options{ @@ -84,7 +83,6 @@ func Test_CounterKey(t *testing.T) { } for _, test := range tests { - test := test t.Run(test.namespace+"/"+test.jobName, func(t *testing.T) { t.Parallel() key := New(Options{ @@ -118,7 +116,6 @@ func Test_LeadershipNamespace(t *testing.T) { } for _, test := range tests { - test := test t.Run(test.namespace, func(t *testing.T) { t.Parallel() key := New(Options{ @@ -156,7 +153,6 @@ func Test_LeadershipKey(t *testing.T) { } for _, test := range tests { - test := test t.Run(fmt.Sprintf("%s/%d", test.namespace, test.partitionID), func(t *testing.T) { t.Parallel() key := New(Options{ @@ -190,7 +186,6 @@ func Test_JobNamespace(t *testing.T) { } for _, test := range tests { - test := test t.Run(test.namespace, func(t *testing.T) { t.Parallel() key := New(Options{ @@ -224,7 +219,6 @@ func Test_JobName(t *testing.T) { } for _, test := range tests { - test := test t.Run(test.key, func(t *testing.T) { t.Parallel() key := New(Options{ diff --git a/internal/partitioner/partitioner_test.go b/internal/partitioner/partitioner_test.go index 0d5694f..189687c 100644 --- a/internal/partitioner/partitioner_test.go +++ b/internal/partitioner/partitioner_test.go @@ -53,7 +53,6 @@ func Test_New(t *testing.T) { } for name, test := range tests { - test := test t.Run(name, func(t *testing.T) { t.Parallel() parter, err := New(Options{ diff --git a/internal/scheduler/builder_test.go b/internal/scheduler/builder_test.go index 4eb7bae..c7436bd 100644 --- a/internal/scheduler/builder_test.go +++ b/internal/scheduler/builder_test.go @@ -97,7 +97,6 @@ func Test_Scheduler(t *testing.T) { } for name, test := range tests { - test := test t.Run(name, func(t *testing.T) { t.Parallel() builder := &Builder{clock: clock} @@ -294,7 +293,6 @@ func Test_Parse(t *testing.T) { } for name, test := range tests { - test := test t.Run(name, func(t *testing.T) { t.Parallel() builder := &Builder{clock: clock} @@ -352,7 +350,6 @@ func Test_parsePointInTime(t *testing.T) { } for name, test := range tests { - test := test t.Run(name, func(t *testing.T) { t.Parallel() gotTime, gotErr := parsePointInTime(test.str, now) diff --git a/internal/scheduler/oneshot_test.go b/internal/scheduler/oneshot_test.go index eafad4e..8c7d4cc 100644 --- a/internal/scheduler/oneshot_test.go +++ b/internal/scheduler/oneshot_test.go @@ -37,7 +37,6 @@ func Test_oneshot(t *testing.T) { } for _, test := range tests { - test := test t.Run(strconv.Itoa(int(test.count)), func(t *testing.T) { t.Parallel() oneshot := &oneshot{dueTime: dueTime} diff --git a/internal/scheduler/repeats_test.go b/internal/scheduler/repeats_test.go index fd68695..ad9d0c5 100644 --- a/internal/scheduler/repeats_test.go +++ b/internal/scheduler/repeats_test.go @@ -133,7 +133,6 @@ func Test_repeats(t *testing.T) { } for name, test := range tests { - test := test t.Run(name, func(t *testing.T) { t.Parallel() cron, err := cron.ParseStandard(test.schedule) From f0df3fb1e18e2b097c2c72612605c34abaac9d3d Mon Sep 17 00:00:00 2001 From: joshvanl Date: Mon, 22 Jul 2024 18:10:05 +0100 Subject: [PATCH 4/8] Lint Signed-off-by: joshvanl --- .golangci.yaml | 2 ++ cron_test.go | 9 +++++---- internal/client/client_test.go | 2 -- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 2e2fe06..ad1e152 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -20,6 +20,8 @@ linters: - funlen - maintidx - containedctx + # TODO: Add intrange linter back + - intrange linters-settings: goimports: local-prefixes: github.com/diagridio diff --git a/cron_test.go b/cron_test.go index f72c236..ceb0aa0 100644 --- a/cron_test.go +++ b/cron_test.go @@ -128,7 +128,7 @@ func Test_patition(t *testing.T) { helper := testCron(t, 100) - for i := 0; i < 100; i++ { + for i := range 100 { job := &api.Job{ DueTime: ptr.Of(time.Now().Add(time.Second).Format(time.RFC3339)), } @@ -529,7 +529,7 @@ func Test_parallel(t *testing.T) { }, }) - for i := 0; i < 100; i++ { + for i := range 100 { require.NoError(t, helper.cron.Add(helper.ctx, strconv.Itoa(i), &api.Job{ DueTime: ptr.Of("0s"), })) @@ -562,6 +562,7 @@ type helper struct { } func testCron(t *testing.T, total uint32) *helper { + t.Helper() return testCronWithOptions(t, testCronOptions{ total: total, }) @@ -576,7 +577,7 @@ func testCronWithOptions(t *testing.T, opts testCronOptions) *helper { var triggered atomic.Int64 var cron Interface allCrns := make([]Interface, opts.total) - for i := uint32(0); i < opts.total; i++ { + for i := range opts.total { c, err := New(Options{ Log: logr.Discard(), Client: cl, @@ -606,7 +607,7 @@ func testCronWithOptions(t *testing.T, opts testCronOptions) *helper { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(func() { cancel() - for i := uint32(0); i < opts.total; i++ { + for range opts.total { select { case err := <-errCh: require.NoError(t, err) diff --git a/internal/client/client_test.go b/internal/client/client_test.go index 28e11af..8b9a392 100644 --- a/internal/client/client_test.go +++ b/internal/client/client_test.go @@ -83,8 +83,6 @@ func Test_Delete(t *testing.T) { } for name, test := range tests { - name, test := name, test - t.Run(name, func(t *testing.T) { t.Parallel() From c8f2592cca1ebe26b4dc77f21cc1d3b6fc72d29c Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Mon, 22 Jul 2024 17:02:20 -0300 Subject: [PATCH 5/8] Fix go.mod + update dapr/kit Signed-off-by: Artur Souza --- go.mod | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go.mod b/go.mod index 8bcd038..6dfe4fc 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/diagridio/go-etcd-cron go 1.22 +toolchain go1.22.5 + require ( github.com/dapr/kit v0.13.1-0.20240722163453-58c6d9df14d3 github.com/go-logr/logr v1.3.0 From 7c48d990dae1ccdbbd39f175c798c59c884d10da Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Mon, 22 Jul 2024 17:18:02 -0300 Subject: [PATCH 6/8] Fix .golangci.yaml to match pinned lint version. Signed-off-by: Artur Souza --- .golangci.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index ad1e152..2e2fe06 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -20,8 +20,6 @@ linters: - funlen - maintidx - containedctx - # TODO: Add intrange linter back - - intrange linters-settings: goimports: local-prefixes: github.com/diagridio From 979f53368edb085b9fb67da48efe4da55bdf1534 Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Mon, 22 Jul 2024 17:28:17 -0300 Subject: [PATCH 7/8] Pin go version without using toolchain. Signed-off-by: Artur Souza --- go.mod | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6dfe4fc..e963da1 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/diagridio/go-etcd-cron -go 1.22 - -toolchain go1.22.5 +go 1.22.5 require ( github.com/dapr/kit v0.13.1-0.20240722163453-58c6d9df14d3 From f86d0868bdb743062b0897f17c26ee5e1ca3231a Mon Sep 17 00:00:00 2001 From: Artur Souza Date: Mon, 22 Jul 2024 17:59:14 -0300 Subject: [PATCH 8/8] Fix a bunch of lint after go update. Signed-off-by: Artur Souza --- api_test.go | 6 +++-- cron_test.go | 13 ++++----- internal/client/client_test.go | 9 ++++--- internal/counter/counter_test.go | 8 +++--- internal/grave/yard_test.go | 7 ++--- internal/informer/informer_test.go | 13 ++++----- internal/key/key_test.go | 34 ++++++++++++++---------- internal/partitioner/partitioner_test.go | 9 ++++--- internal/scheduler/builder_test.go | 21 ++++++++------- internal/scheduler/oneshot_test.go | 3 ++- internal/scheduler/repeats_test.go | 13 ++++----- 11 files changed, 78 insertions(+), 58 deletions(-) diff --git a/api_test.go b/api_test.go index 0708c67..ce1ac0f 100644 --- a/api_test.go +++ b/api_test.go @@ -495,6 +495,8 @@ func Test_validateName(t *testing.T) { } for _, test := range tests { + name := test.name + expErr := test.expErr t.Run(test.name, func(t *testing.T) { t.Parallel() c, err := New(Options{ @@ -505,8 +507,8 @@ func Test_validateName(t *testing.T) { TriggerFn: func(context.Context, *api.TriggerRequest) bool { return true }, }) require.NoError(t, err) - err = c.(*cron).validateName(test.name) - assert.Equal(t, test.expErr, err != nil, "%v", err) + err = c.(*cron).validateName(name) + assert.Equal(t, expErr, err != nil, "%v", err) }) } } diff --git a/cron_test.go b/cron_test.go index ceb0aa0..db5f942 100644 --- a/cron_test.go +++ b/cron_test.go @@ -128,7 +128,7 @@ func Test_patition(t *testing.T) { helper := testCron(t, 100) - for i := range 100 { + for i := 0; i < 100; i++ { job := &api.Job{ DueTime: ptr.Of(time.Now().Add(time.Second).Format(time.RFC3339)), } @@ -514,6 +514,7 @@ func Test_parallel(t *testing.T) { {"1 queue", 1}, {"multi queue", 50}, } { + total := test.total t.Run(test.name, func(t *testing.T) { t.Parallel() @@ -521,7 +522,7 @@ func Test_parallel(t *testing.T) { var waiting atomic.Int32 var done atomic.Int32 helper := testCronWithOptions(t, testCronOptions{ - total: test.total, + total: total, triggerFn: func() { waiting.Add(1) <-releaseCh @@ -529,7 +530,7 @@ func Test_parallel(t *testing.T) { }, }) - for i := range 100 { + for i := 0; i < 100; i++ { require.NoError(t, helper.cron.Add(helper.ctx, strconv.Itoa(i), &api.Job{ DueTime: ptr.Of("0s"), })) @@ -577,12 +578,12 @@ func testCronWithOptions(t *testing.T, opts testCronOptions) *helper { var triggered atomic.Int64 var cron Interface allCrns := make([]Interface, opts.total) - for i := range opts.total { + for i := 0; i < int(opts.total); i++ { c, err := New(Options{ Log: logr.Discard(), Client: cl, Namespace: "abc", - PartitionID: i, + PartitionID: uint32(i), PartitionTotal: opts.total, TriggerFn: func(_ context.Context, req *api.TriggerRequest) bool { ok := opts.returnOk == nil || opts.returnOk.Load() @@ -607,7 +608,7 @@ func testCronWithOptions(t *testing.T, opts testCronOptions) *helper { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(func() { cancel() - for range opts.total { + for i := 0; i < int(opts.total); i++ { select { case err := <-errCh: require.NoError(t, err) diff --git a/internal/client/client_test.go b/internal/client/client_test.go index 8b9a392..363debe 100644 --- a/internal/client/client_test.go +++ b/internal/client/client_test.go @@ -83,6 +83,7 @@ func Test_Delete(t *testing.T) { } for name, test := range tests { + testInLoop := test t.Run(name, func(t *testing.T) { t.Parallel() @@ -90,7 +91,7 @@ func Test_Delete(t *testing.T) { t.Parallel() kv := new(mock) - require.NoError(t, test(&client{kv: kv})) + require.NoError(t, testInLoop(&client{kv: kv})) assert.Equal(t, uint32(1), kv.calls.Load()) }) @@ -99,7 +100,7 @@ func Test_Delete(t *testing.T) { kv := new(mock) kv.err = errors.New("this is an error") - require.Error(t, test(&client{kv: kv})) + require.Error(t, testInLoop(&client{kv: kv})) assert.Equal(t, uint32(1), kv.calls.Load()) }) @@ -120,7 +121,7 @@ func Test_Delete(t *testing.T) { }) go func() { - errCh <- test(&client{kv: kv, clock: clock}) + errCh <- testInLoop(&client{kv: kv, clock: clock}) }() assert.Eventually(t, clock.HasWaiters, time.Second, time.Millisecond*10) @@ -149,7 +150,7 @@ func Test_Delete(t *testing.T) { }) go func() { - errCh <- test(&client{kv: kv, clock: clock}) + errCh <- testInLoop(&client{kv: kv, clock: clock}) }() assert.Eventually(t, clock.HasWaiters, time.Second, time.Millisecond*10) diff --git a/internal/counter/counter_test.go b/internal/counter/counter_test.go index 559d67f..568c30d 100644 --- a/internal/counter/counter_test.go +++ b/internal/counter/counter_test.go @@ -880,11 +880,13 @@ func Test_updateNext(t *testing.T) { } for name, test := range tests { + counter := test.counter + exp := test.exp + expNext := test.expNext t.Run(name, func(t *testing.T) { t.Parallel() - c := test.counter - assert.Equal(t, test.exp, c.updateNext()) - assert.Equal(t, test.expNext, c.next) + assert.Equal(t, exp, counter.updateNext()) + assert.Equal(t, expNext, counter.next) }) } } diff --git a/internal/grave/yard_test.go b/internal/grave/yard_test.go index a7e2e3e..4d5d7c5 100644 --- a/internal/grave/yard_test.go +++ b/internal/grave/yard_test.go @@ -120,16 +120,17 @@ func Test_HasJustDeleted(t *testing.T) { } for name, test := range tests { + testInLoop := test t.Run(name, func(t *testing.T) { t.Parallel() yard := New() - for _, key := range test.deletes { + for _, key := range testInLoop.deletes { yard.Deleted(key) } - assert.Equal(t, test.expBool, yard.HasJustDeleted(test.key)) - assert.Equal(t, test.expMap, yard.deletesMap) + assert.Equal(t, testInLoop.expBool, yard.HasJustDeleted(testInLoop.key)) + assert.Equal(t, testInLoop.expMap, yard.deletesMap) }) } } diff --git a/internal/informer/informer_test.go b/internal/informer/informer_test.go index a630698..0268d5f 100644 --- a/internal/informer/informer_test.go +++ b/internal/informer/informer_test.go @@ -333,6 +333,7 @@ func Test_handleEvent(t *testing.T) { } for name, test := range tests { + testInLoop := test t.Run(name, func(t *testing.T) { t.Parallel() part, err := partitioner.New(partitioner.Options{ @@ -344,8 +345,8 @@ func Test_handleEvent(t *testing.T) { collector := fake.New() yard := grave.New() - if test.yardDelete != nil { - yard.Deleted(*test.yardDelete) + if testInLoop.yardDelete != nil { + yard.Deleted(*testInLoop.yardDelete) } i := New(Options{ @@ -357,10 +358,10 @@ func Test_handleEvent(t *testing.T) { PartitionID: 0, }), }) - gotEvent, err := i.handleEvent(test.ev) - assert.Equal(t, test.expEvent, gotEvent) - assert.Equal(t, test.expErr, err != nil, "%v", err) - assert.Equal(t, test.expCollectorPops, collector.HasPoped()) + gotEvent, err := i.handleEvent(testInLoop.ev) + assert.Equal(t, testInLoop.expEvent, gotEvent) + assert.Equal(t, testInLoop.expErr, err != nil, "%v", err) + assert.Equal(t, testInLoop.expCollectorPops, collector.HasPoped()) }) } } diff --git a/internal/key/key_test.go b/internal/key/key_test.go index e77f19d..34e947d 100644 --- a/internal/key/key_test.go +++ b/internal/key/key_test.go @@ -42,13 +42,14 @@ func Test_JobKey(t *testing.T) { } for _, test := range tests { + testInLoop := test t.Run(test.namespace+"/"+test.jobName, func(t *testing.T) { t.Parallel() key := New(Options{ - Namespace: test.namespace, - PartitionID: test.partitionID, + Namespace: testInLoop.namespace, + PartitionID: testInLoop.partitionID, }) - assert.Equal(t, test.expJobKey, key.JobKey(test.jobName)) + assert.Equal(t, testInLoop.expJobKey, key.JobKey(testInLoop.jobName)) }) } } @@ -83,13 +84,14 @@ func Test_CounterKey(t *testing.T) { } for _, test := range tests { + testInLoop := test t.Run(test.namespace+"/"+test.jobName, func(t *testing.T) { t.Parallel() key := New(Options{ - Namespace: test.namespace, - PartitionID: test.partitionID, + Namespace: testInLoop.namespace, + PartitionID: testInLoop.partitionID, }) - assert.Equal(t, test.expCounterKey, key.CounterKey(test.jobName)) + assert.Equal(t, testInLoop.expCounterKey, key.CounterKey(testInLoop.jobName)) }) } } @@ -116,13 +118,14 @@ func Test_LeadershipNamespace(t *testing.T) { } for _, test := range tests { + testInLoop := test t.Run(test.namespace, func(t *testing.T) { t.Parallel() key := New(Options{ - Namespace: test.namespace, + Namespace: testInLoop.namespace, PartitionID: 123, }) - assert.Equal(t, test.expLeadershipNS, key.LeadershipNamespace()) + assert.Equal(t, testInLoop.expLeadershipNS, key.LeadershipNamespace()) }) } } @@ -153,13 +156,14 @@ func Test_LeadershipKey(t *testing.T) { } for _, test := range tests { + testInLoop := test t.Run(fmt.Sprintf("%s/%d", test.namespace, test.partitionID), func(t *testing.T) { t.Parallel() key := New(Options{ - Namespace: test.namespace, - PartitionID: test.partitionID, + Namespace: testInLoop.namespace, + PartitionID: testInLoop.partitionID, }) - assert.Equal(t, test.expLeadershipKey, key.LeadershipKey()) + assert.Equal(t, testInLoop.expLeadershipKey, key.LeadershipKey()) }) } } @@ -186,13 +190,14 @@ func Test_JobNamespace(t *testing.T) { } for _, test := range tests { + testInLoop := test t.Run(test.namespace, func(t *testing.T) { t.Parallel() key := New(Options{ - Namespace: test.namespace, + Namespace: testInLoop.namespace, PartitionID: 123, }) - assert.Equal(t, test.expJobNS, key.JobNamespace()) + assert.Equal(t, testInLoop.expJobNS, key.JobNamespace()) }) } } @@ -219,13 +224,14 @@ func Test_JobName(t *testing.T) { } for _, test := range tests { + testInLoop := test t.Run(test.key, func(t *testing.T) { t.Parallel() key := New(Options{ Namespace: "/123", PartitionID: 123, }) - assert.Equal(t, test.expJobName, key.JobName([]byte(test.key))) + assert.Equal(t, testInLoop.expJobName, key.JobName([]byte(testInLoop.key))) }) } } diff --git a/internal/partitioner/partitioner_test.go b/internal/partitioner/partitioner_test.go index 189687c..dac10bf 100644 --- a/internal/partitioner/partitioner_test.go +++ b/internal/partitioner/partitioner_test.go @@ -53,14 +53,15 @@ func Test_New(t *testing.T) { } for name, test := range tests { + testInLoop := test t.Run(name, func(t *testing.T) { t.Parallel() parter, err := New(Options{ - ID: test.id, - Total: test.total, + ID: testInLoop.id, + Total: testInLoop.total, }) - assert.Equal(t, test.exp, parter) - assert.Equal(t, test.expErr, err != nil, "%v", err) + assert.Equal(t, testInLoop.exp, parter) + assert.Equal(t, testInLoop.expErr, err != nil, "%v", err) }) } } diff --git a/internal/scheduler/builder_test.go b/internal/scheduler/builder_test.go index c7436bd..245bf51 100644 --- a/internal/scheduler/builder_test.go +++ b/internal/scheduler/builder_test.go @@ -97,12 +97,13 @@ func Test_Scheduler(t *testing.T) { } for name, test := range tests { + testInLoop := test t.Run(name, func(t *testing.T) { t.Parallel() builder := &Builder{clock: clock} - gotScheduler, gotErr := builder.Scheduler(test.job) - assert.Equal(t, test.expScheduler, gotScheduler) - assert.Equal(t, test.expErr, gotErr != nil, "%v", gotErr) + gotScheduler, gotErr := builder.Scheduler(testInLoop.job) + assert.Equal(t, testInLoop.expScheduler, gotScheduler) + assert.Equal(t, testInLoop.expErr, gotErr != nil, "%v", gotErr) }) } } @@ -293,16 +294,17 @@ func Test_Parse(t *testing.T) { } for name, test := range tests { + testInLoop := test t.Run(name, func(t *testing.T) { t.Parallel() builder := &Builder{clock: clock} - gotStored, gotErr := builder.Parse(test.job) + gotStored, gotErr := builder.Parse(testInLoop.job) if gotStored != nil { assert.NotEqual(t, uint32(0), gotStored.GetPartitionId()) gotStored.PartitionId = 0 } - assert.Equal(t, test.expStored, gotStored) - assert.Equal(t, test.expErr, gotErr != nil, "%v", gotErr) + assert.Equal(t, testInLoop.expStored, gotStored) + assert.Equal(t, testInLoop.expErr, gotErr != nil, "%v", gotErr) }) } } @@ -350,11 +352,12 @@ func Test_parsePointInTime(t *testing.T) { } for name, test := range tests { + testInLoop := test t.Run(name, func(t *testing.T) { t.Parallel() - gotTime, gotErr := parsePointInTime(test.str, now) - assert.Equal(t, test.expTime, gotTime) - assert.Equal(t, test.expErr, gotErr != nil, "%v", gotErr) + gotTime, gotErr := parsePointInTime(testInLoop.str, now) + assert.Equal(t, testInLoop.expTime, gotTime) + assert.Equal(t, testInLoop.expErr, gotErr != nil, "%v", gotErr) }) } } diff --git a/internal/scheduler/oneshot_test.go b/internal/scheduler/oneshot_test.go index 8c7d4cc..d88a595 100644 --- a/internal/scheduler/oneshot_test.go +++ b/internal/scheduler/oneshot_test.go @@ -37,10 +37,11 @@ func Test_oneshot(t *testing.T) { } for _, test := range tests { + testInLoop := test t.Run(strconv.Itoa(int(test.count)), func(t *testing.T) { t.Parallel() oneshot := &oneshot{dueTime: dueTime} - assert.Equal(t, test.expNext, oneshot.Next(test.count, nil)) + assert.Equal(t, testInLoop.expNext, oneshot.Next(testInLoop.count, nil)) }) } } diff --git a/internal/scheduler/repeats_test.go b/internal/scheduler/repeats_test.go index ad9d0c5..34e2b1c 100644 --- a/internal/scheduler/repeats_test.go +++ b/internal/scheduler/repeats_test.go @@ -133,20 +133,21 @@ func Test_repeats(t *testing.T) { } for name, test := range tests { + testInLoop := test t.Run(name, func(t *testing.T) { t.Parallel() - cron, err := cron.ParseStandard(test.schedule) + cron, err := cron.ParseStandard(testInLoop.schedule) require.NoError(t, err) repeats := &repeats{ - start: test.start, - dueTime: test.dueTime, - exp: test.exp, + start: testInLoop.start, + dueTime: testInLoop.dueTime, + exp: testInLoop.exp, cron: cron, - total: test.total, + total: testInLoop.total, } - assert.Equal(t, test.expNext, repeats.Next(test.count, test.last)) + assert.Equal(t, testInLoop.expNext, repeats.Next(testInLoop.count, testInLoop.last)) }) } }