update
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
This commit is contained in:
168
utils/pl/pipelines_test.go
Normal file
168
utils/pl/pipelines_test.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package pl_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/navidrome/navidrome/utils/pl"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestPipeline(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Pipeline Tests Suite")
|
||||
}
|
||||
|
||||
var _ = Describe("Pipeline", func() {
|
||||
Describe("Stage", func() {
|
||||
Context("happy path", func() {
|
||||
It("calls the 'transform' function and returns values and errors", func() {
|
||||
inC := make(chan int, 4)
|
||||
for i := 0; i < 4; i++ {
|
||||
inC <- i
|
||||
}
|
||||
close(inC)
|
||||
|
||||
outC, errC := pl.Stage(context.Background(), 1, inC, func(ctx context.Context, i int) (int, error) {
|
||||
if i%2 == 0 {
|
||||
return 0, errors.New("even number")
|
||||
}
|
||||
return i * 2, nil
|
||||
})
|
||||
|
||||
Expect(<-errC).To(MatchError("even number"))
|
||||
Expect(<-outC).To(Equal(2))
|
||||
Expect(<-errC).To(MatchError("even number"))
|
||||
Expect(<-outC).To(Equal(6))
|
||||
|
||||
Eventually(outC).Should(BeClosed())
|
||||
Eventually(errC).Should(BeClosed())
|
||||
})
|
||||
})
|
||||
Context("Multiple workers", func() {
|
||||
const maxWorkers = 2
|
||||
const numJobs = 100
|
||||
It("starts multiple workers, respecting the limit", func() {
|
||||
inC := make(chan int, numJobs)
|
||||
for i := 0; i < numJobs; i++ {
|
||||
inC <- i
|
||||
}
|
||||
close(inC)
|
||||
|
||||
current := atomic.Int32{}
|
||||
count := atomic.Int32{}
|
||||
max := atomic.Int32{}
|
||||
outC, _ := pl.Stage(context.Background(), maxWorkers, inC, func(ctx context.Context, in int) (int, error) {
|
||||
defer current.Add(-1)
|
||||
c := current.Add(1)
|
||||
count.Add(1)
|
||||
if c > max.Load() {
|
||||
max.Store(c)
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond) // Slow process
|
||||
return 0, nil
|
||||
})
|
||||
// Discard output and wait for completion
|
||||
for range outC {
|
||||
}
|
||||
|
||||
Expect(count.Load()).To(Equal(int32(numJobs)))
|
||||
Expect(current.Load()).To(Equal(int32(0)))
|
||||
Expect(max.Load()).To(Equal(int32(maxWorkers)))
|
||||
})
|
||||
})
|
||||
When("the context is canceled", func() {
|
||||
It("closes its output", func() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
inC := make(chan int)
|
||||
outC, errC := pl.Stage(ctx, 1, inC, func(ctx context.Context, i int) (int, error) {
|
||||
return i, nil
|
||||
})
|
||||
cancel()
|
||||
Eventually(outC).Should(BeClosed())
|
||||
Eventually(errC).Should(BeClosed())
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
Describe("Merge", func() {
|
||||
var in1, in2 chan int
|
||||
BeforeEach(func() {
|
||||
in1 = make(chan int, 4)
|
||||
in2 = make(chan int, 4)
|
||||
for i := 0; i < 4; i++ {
|
||||
in1 <- i
|
||||
in2 <- i + 4
|
||||
}
|
||||
close(in1)
|
||||
close(in2)
|
||||
})
|
||||
When("ranging through the output channel", func() {
|
||||
It("copies values from all input channels to its output channel", func() {
|
||||
var values []int
|
||||
for v := range pl.Merge(context.Background(), in1, in2) {
|
||||
values = append(values, v)
|
||||
}
|
||||
|
||||
Expect(values).To(ConsistOf(0, 1, 2, 3, 4, 5, 6, 7))
|
||||
})
|
||||
})
|
||||
When("there's a blocked channel and the context is closed", func() {
|
||||
It("closes its output", func() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
in3 := make(chan int)
|
||||
out := pl.Merge(ctx, in1, in2, in3)
|
||||
cancel()
|
||||
Eventually(out).Should(BeClosed())
|
||||
})
|
||||
})
|
||||
})
|
||||
Describe("ReadOrDone", func() {
|
||||
When("values are sent", func() {
|
||||
It("copies them to its output channel", func() {
|
||||
in := make(chan int)
|
||||
out := pl.ReadOrDone(context.Background(), in)
|
||||
for i := 0; i < 4; i++ {
|
||||
in <- i
|
||||
j := <-out
|
||||
Expect(i).To(Equal(j))
|
||||
}
|
||||
close(in)
|
||||
Eventually(out).Should(BeClosed())
|
||||
})
|
||||
})
|
||||
When("the context is canceled", func() {
|
||||
It("closes its output", func() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
in := make(chan int)
|
||||
out := pl.ReadOrDone(ctx, in)
|
||||
cancel()
|
||||
Eventually(out).Should(BeClosed())
|
||||
})
|
||||
})
|
||||
})
|
||||
Describe("SendOrDone", func() {
|
||||
When("out is unblocked", func() {
|
||||
It("puts the value in the channel", func() {
|
||||
out := make(chan int)
|
||||
value := 1234
|
||||
go pl.SendOrDone(context.Background(), out, value)
|
||||
Eventually(out).Should(Receive(&value))
|
||||
})
|
||||
})
|
||||
When("out is blocked", func() {
|
||||
It("can be canceled by the context", func() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
out := make(chan int)
|
||||
go pl.SendOrDone(ctx, out, 1234)
|
||||
cancel()
|
||||
|
||||
Consistently(out).ShouldNot(Receive())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user