converge/pkg/support/iowrappers/channelreadwriter_test.go
Erik Brakkee 45595a34aa table testing with go routines only really works well when standard
assertions are ued. With suite.Required() there are issues in getting
the test results correct.

Instead, use standard assertions and use suite.T().Failed() to do
early returns.
2024-08-20 00:52:57 +02:00

135 lines
2.9 KiB
Go

package iowrappers
import (
"context"
"github.com/stretchr/testify/suite"
"log"
"sync"
"testing"
"time"
)
type ChannelReadWriterTestSuite struct {
suite.Suite
ctx context.Context
cancelFunc context.CancelFunc
toChannel chan<- []byte
fromChannel <-chan []byte
conn *ChannelReadWriter
}
func TestChannelReadWriterSuite(t *testing.T) {
suite.Run(t, &ChannelReadWriterTestSuite{})
}
func (suite *ChannelReadWriterTestSuite) createChannel() {
toChannel := make(chan []byte)
fromChannel := make(chan []byte)
suite.toChannel = toChannel
suite.fromChannel = fromChannel
ctx, cancelFunc := context.WithCancel(context.Background())
ctx, timeoutCancelFunc := context.WithTimeout(ctx, 10*time.Second)
suite.ctx = ctx
suite.cancelFunc = func() {
timeoutCancelFunc()
cancelFunc()
}
suite.conn = NewChannelReadWriter(ctx, toChannel, fromChannel)
}
func (suite *ChannelReadWriterTestSuite) SetupTest() {
suite.createChannel()
}
func (suite *ChannelReadWriterTestSuite) TearDownTest() {
suite.cancelFunc()
}
type TestFunc func() any
func (suite *ChannelReadWriterTestSuite) runAndWait(functions ...TestFunc) []any {
wg := sync.WaitGroup{}
wg.Add(len(functions))
res := make([]any, len(functions))
for i, function := range functions {
go func() {
defer func() {
wg.Done()
}()
res[i] = function()
}()
}
wg.Wait()
return res
}
func (suite *ChannelReadWriterTestSuite) Test_SuccessfulCommunication() {
tests := []struct {
name string
data string
chunkSizes []int
chunks []string
}{
{
name: "buffer_large_enough",
data: "hello",
chunkSizes: []int{10},
chunks: []string{"hello"},
},
{
name: "two_reads_required",
data: "hello",
chunkSizes: []int{3, 10},
chunks: []string{"hel", "lo"},
},
{
name: "many_reads_required",
data: "hello",
chunkSizes: []int{1, 1, 1, 1, 1},
chunks: []string{"h", "e", "l", "l", "o"},
},
}
for _, test := range tests {
suite.Run(test.name, func() {
suite.runAndWait(
func() any {
select {
case <-suite.ctx.Done():
suite.FailNow("deadline reached")
log.Println("Write deadline exceeded")
case suite.toChannel <- []byte(test.data):
}
return nil
},
func() any {
remainder := test.data
for i, chunkSize := range test.chunkSizes {
buf := make([]byte, chunkSize)
n, err := suite.conn.Read(buf)
suite.Nil(err)
suite.Equal(n, len(test.chunks[i]))
suite.Equal([]byte(remainder[:n]), buf[:n])
remainder = remainder[n:]
}
return nil
},
)
})
}
}
func (suite *ChannelReadWriterTestSuite) Test_Close() {
suite.FailNow("todo")
}
func (suite *ChannelReadWriterTestSuite) Test_CloseTwice() {
suite.FailNow("todo")
}
func (suite *ChannelReadWriterTestSuite) Test_ContextCanceled() {
suite.FailNow("todo")
}