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") }