Files
buildkit/util/progress/progress_test.go
Tibor Vass d59eee2985 util/progress: silence go test -race
Without this commit, `go test -race ./util/progress` sees a race due to the
shadowed `ctx` variable.

```
==================
WARNING: DATA RACE
Read at 0x00c000206040 by goroutine 25:
  github.com/moby/buildkit/util/progress.TestProgress.func1()
      github.com/moby/buildkit/util/progress/progress_test.go:25 +0x44
  golang.org/x/sync/errgroup.(*Group).Go.func1()
      golang.org/x/sync@v0.1.0/errgroup/errgroup.go:75 +0x6c

Previous write at 0x00c000206040 by goroutine 6:
  github.com/moby/buildkit/util/progress.TestProgress()
      github.com/moby/buildkit/util/progress/progress_test.go:28 +0x4a0
  testing.tRunner()
      testing/testing.go:1576 +0x188
  testing.(*T).Run.func1()
      testing/testing.go:1629 +0x40

Goroutine 25 (running) created at:
  golang.org/x/sync/errgroup.(*Group).Go()
      golang.org/x/sync@v0.1.0/errgroup/errgroup.go:72 +0x10c
  github.com/moby/buildkit/util/progress.TestProgress()
      github.com/moby/buildkit/util/progress/progress_test.go:24 +0x360
  testing.tRunner()
      testing/testing.go:1576 +0x188
  testing.(*T).Run.func1()
      testing/testing.go:1629 +0x40

Goroutine 6 (running) created at:
  testing.(*T).Run()
      testing/testing.go:1629 +0x5e4
  testing.runTests.func1()
      testing/testing.go:2036 +0x80
  testing.tRunner()
      testing/testing.go:1576 +0x188
  testing.runTests()
      testing/testing.go:2034 +0x700
  testing.(*M).Run()
      testing/testing.go:1906 +0x950
  main.main()
      _testmain.go:49 +0x300
==================
==================
WARNING: DATA RACE
Read at 0x00c000202390 by goroutine 26:
  context.(*valueCtx).Done()
      <autogenerated>:1 +0x34
  github.com/moby/buildkit/util/progress.(*progressReader).Read.func1()
      github.com/moby/buildkit/util/progress/progress.go:126 +0xac

Previous write at 0x00c000202390 by goroutine 6:
  context.WithValue()
      context/context.go:593 +0xac
  github.com/moby/buildkit/util/progress.FromContext.func1()
      github.com/moby/buildkit/util/progress/progress.go:42 +0x168
  github.com/moby/buildkit/util/progress.NewFromContext()
      github.com/moby/buildkit/util/progress/progress.go:51 +0x60
  github.com/moby/buildkit/util/progress.TestProgress()
      github.com/moby/buildkit/util/progress/progress_test.go:28 +0x488
  testing.tRunner()
      testing/testing.go:1576 +0x188
  testing.(*T).Run.func1()
      testing/testing.go:1629 +0x40

Goroutine 26 (running) created at:
  github.com/moby/buildkit/util/progress.(*progressReader).Read()
      github.com/moby/buildkit/util/progress/progress.go:120 +0x15c
  github.com/moby/buildkit/util/progress.saveProgress()
      github.com/moby/buildkit/util/progress/progress_test.go:125 +0x48
  github.com/moby/buildkit/util/progress.TestProgress.func1()
      github.com/moby/buildkit/util/progress/progress_test.go:25 +0x60
  golang.org/x/sync/errgroup.(*Group).Go.func1()
      golang.org/x/sync@v0.1.0/errgroup/errgroup.go:75 +0x6c

Goroutine 6 (running) created at:
  testing.(*T).Run()
      testing/testing.go:1629 +0x5e4
  testing.runTests.func1()
      testing/testing.go:2036 +0x80
  testing.tRunner()
      testing/testing.go:1576 +0x188
  testing.runTests()
      testing/testing.go:2034 +0x700
  testing.(*M).Run()
      testing/testing.go:1906 +0x950
  main.main()
      _testmain.go:49 +0x300
==================
--- FAIL: TestProgressNested (0.07s)
    testing.go:1446: race detected during execution of test
--- FAIL: TestProgress (0.10s)
    testing.go:1446: race detected during execution of test
FAIL
FAIL    github.com/moby/buildkit/util/progress  0.112s
FAIL
```

Signed-off-by: Tibor Vass <teabee89@gmail.com>
2023-08-25 10:16:00 -07:00

135 lines
2.6 KiB
Go

package progress
import (
"context"
"fmt"
"io"
"testing"
"time"
"github.com/stretchr/testify/assert"
"golang.org/x/sync/errgroup"
)
func TestProgress(t *testing.T) {
t.Parallel()
s, err := calc(context.TODO(), 4, "calc")
assert.NoError(t, err)
assert.Equal(t, 10, s)
eg, ctx := errgroup.WithContext(context.Background())
pr, ctx, cancelProgress := NewContext(ctx)
var trace trace
eg.Go(func() error {
return saveProgress(ctx, pr, &trace)
})
pw, _, ctx2 := NewFromContext(ctx, WithMetadata("tag", "foo"))
s, err = calc(ctx2, 5, "calc")
pw.Close()
assert.NoError(t, err)
assert.Equal(t, 15, s)
cancelProgress()
err = eg.Wait()
assert.NoError(t, err)
assert.True(t, len(trace.items) > 5)
assert.True(t, len(trace.items) <= 7)
for _, p := range trace.items {
v, ok := p.Meta("tag")
assert.True(t, ok)
assert.Equal(t, v.(string), "foo")
}
}
func TestProgressNested(t *testing.T) {
t.Parallel()
eg, ctx := errgroup.WithContext(context.Background())
pr, ctx, cancelProgress := NewContext(ctx)
var trace trace
eg.Go(func() error {
return saveProgress(ctx, pr, &trace)
})
s, err := reduceCalc(ctx, 3)
assert.NoError(t, err)
assert.Equal(t, 6, s)
cancelProgress()
err = eg.Wait()
assert.NoError(t, err)
assert.True(t, len(trace.items) > 9) // usually 14
assert.True(t, len(trace.items) <= 15)
}
func calc(ctx context.Context, total int, name string) (int, error) {
pw, _, ctx := NewFromContext(ctx)
defer pw.Close()
sum := 0
pw.Write(name, Status{Action: "starting", Total: total})
for i := 1; i <= total; i++ {
select {
case <-ctx.Done():
return 0, ctx.Err()
case <-time.After(10 * time.Millisecond):
}
if i == total {
pw.Write(name, Status{Action: "done", Total: total, Current: total})
} else {
pw.Write(name, Status{Action: "calculating", Total: total, Current: i})
}
sum += i
}
return sum, nil
}
func reduceCalc(ctx context.Context, total int) (int, error) {
eg, ctx := errgroup.WithContext(ctx)
pw, _, ctx := NewFromContext(ctx)
defer pw.Close()
pw.Write("reduce", Status{Action: "starting"})
// sync step
sum, err := calc(ctx, total, "synccalc")
if err != nil {
return 0, err
}
// parallel steps
for i := 0; i < 2; i++ {
func(i int) {
eg.Go(func() error {
_, err := calc(ctx, total, fmt.Sprintf("calc-%d", i))
return err
})
}(i)
}
if err := eg.Wait(); err != nil {
return 0, err
}
return sum, nil
}
type trace struct {
items []*Progress
}
func saveProgress(ctx context.Context, pr Reader, t *trace) error {
for {
p, err := pr.Read(ctx)
if err != nil {
if err == io.EOF {
return nil
}
return err
}
t.items = append(t.items, p...)
}
}