You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/plugin/loopback/testing_grpc_stream_test.go

603 lines
15 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package loopback
import (
"fmt"
"io"
"sync"
"testing"
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
tr "github.com/stretchr/testify/require"
)
func Test_GetObjectStream_Client(t *testing.T) {
require := tr.New(t)
stream := newGetObjectStream()
require.NotNil(stream)
require.NotNil(stream.client)
// Validate Header is not nil and does not return an error
header, err := stream.client.Header()
require.NotNil(header)
require.NoError(err)
// Validate Trailer is not nil
trailer := stream.client.Trailer()
require.NotNil(trailer)
// Validate Context is not nil
ctx := stream.client.Context()
require.NotNil(ctx)
// validate SendMsg does not write to the channel messages
err = stream.client.SendMsg(nil)
require.NoError(err)
require.Empty(stream.messages)
// Validate RecvMsg does not read from the channel messages
streamSize := len(stream.messages)
var msg *getObjectStreamResponse
err = stream.client.RecvMsg(msg)
require.NoError(err)
require.Nil(msg)
require.Equal(streamSize, len(stream.messages))
// Validate Recv reads a message from the channel messages
var wg sync.WaitGroup
wg.Add(1)
go func() {
stream.messages <- &getObjectStreamResponse{
msg: &plgpb.GetObjectResponse{},
}
}()
go func() {
defer wg.Done()
resp, err := stream.client.Recv()
require.NoError(err)
require.NotNil(resp)
}()
wg.Wait()
// Validates Recv reads a error from the channel messages
wg.Add(1)
go func() {
stream.messages <- &getObjectStreamResponse{
err: fmt.Errorf("mock error"),
}
}()
go func() {
defer wg.Done()
resp, err := stream.client.Recv()
require.Error(err)
require.Nil(resp)
}()
wg.Wait()
// Validate CloseSend does not return an error
// Validate streamClosed is set to true
// Validate the channel messages is closed
var ok bool
err = stream.client.CloseSend()
require.NoError(err)
require.True(stream.streamClosed)
_, ok = <-stream.messages
require.False(ok)
// Validate CloseSend does return an error when the channel is closed
// Validate streamClosed is set to true
// Validate the channel messages is closed
err = stream.client.CloseSend()
require.Error(err)
require.Contains(err.Error(), "stream is closed")
require.True(stream.streamClosed)
_, ok = <-stream.messages
require.False(ok)
// Validate Recv returns EOF error when the channel is closed
resp, err := stream.client.Recv()
require.Equal(io.EOF, err)
require.Nil(resp)
}
func Test_GetObjectStream_Server(t *testing.T) {
require := tr.New(t)
stream := newGetObjectStream()
require.NotNil(stream)
require.NotNil(stream.server)
// Validate SetHeader does not return an error
err := stream.server.SetHeader(nil)
require.NoError(err)
// Validate SendHeader does not return an error
err = stream.server.SendHeader(nil)
require.NoError(err)
// Validate Context returns a context
ctx := stream.server.Context()
require.NotNil(ctx)
// Validate RecvMsg does not read from the channel messages
streamSize := len(stream.messages)
var msg *getObjectStreamResponse
err = stream.server.RecvMsg(msg)
require.NoError(err)
require.Nil(msg)
require.Equal(streamSize, len(stream.messages))
// Validate Send writes to the channel messages
var wg sync.WaitGroup
go func() {
err = stream.server.Send(&plgpb.GetObjectResponse{})
require.NoError(err)
}()
wg.Add(1)
go func() {
defer wg.Done()
resp, ok := <-stream.messages
require.True(ok)
require.NotNil(resp)
require.NotNil(resp.msg)
require.Nil(resp.err)
}()
wg.Wait()
// Validate Send returns an error when the channel is closed
stream.Close()
require.True(stream.streamClosed)
err = stream.server.Send(&plgpb.GetObjectResponse{})
require.Error(err)
require.Contains(err.Error(), "stream is closed")
// Validate SendMsg returns an error when the channel is closed
err = stream.server.SendMsg(&plgpb.GetObjectResponse{})
require.Error(err)
require.Contains(err.Error(), "stream is closed")
err = stream.server.SendMsg(fmt.Errorf("mock error"))
require.Error(err)
require.Contains(err.Error(), "stream is closed")
// Reset stream
stream = newGetObjectStream()
// Validate SendMsg returns an error for unknown message type
err = stream.server.SendMsg(map[string]string{})
require.False(stream.streamClosed)
require.Error(err)
require.Contains(err.Error(), "invalid argument")
// Validate SendMsg writes to the channel messages for GetObjectResponse type
go func() {
err = stream.server.SendMsg(&plgpb.GetObjectResponse{})
require.NoError(err)
}()
wg.Add(1)
go func() {
defer wg.Done()
resp, ok := <-stream.messages
require.True(ok)
require.NotNil(resp)
require.NotNil(resp.msg)
require.Nil(resp.err)
}()
wg.Wait()
// Validate SendMsg closes the channel messages for error type
go func() {
err = stream.server.SendMsg(fmt.Errorf("mock error"))
require.NoError(err)
}()
wg.Add(1)
go func() {
defer wg.Done()
resp, ok := <-stream.messages
require.True(ok)
require.NotNil(resp)
require.NotNil(resp.err)
require.Nil(resp.msg)
}()
wg.Wait()
require.True(stream.streamClosed)
_, ok := <-stream.messages
require.False(ok)
}
func TestNewGetObjectStream(t *testing.T) {
require := tr.New(t)
stream := newGetObjectStream()
require.NotNil(stream)
require.NotNil(stream.m)
require.NotNil(stream.client)
require.NotNil(stream.server)
require.NotNil(stream.messages)
require.False(stream.streamClosed)
require.False(stream.IsStreamClosed())
// Validate Close() closes the channel messages
stream.Close()
require.True(stream.streamClosed)
require.True(stream.IsStreamClosed())
_, ok := <-stream.messages
require.False(ok)
}
func Test_PutObjectStream_Client(t *testing.T) {
require := tr.New(t)
stream := newPutObjectStream()
require.NotNil(stream)
require.NotNil(stream.client)
// Validate Header is not nil and does not return an error
header, err := stream.client.Header()
require.NotNil(header)
require.NoError(err)
// Validate Trailer is not nil
trailer := stream.client.Trailer()
require.NotNil(trailer)
// Validate Context is not nil
ctx := stream.client.Context()
require.NotNil(ctx)
// Validate SendMsg does not write to the channel requests
err = stream.client.SendMsg(nil)
require.NoError(err)
require.Empty(stream.requests)
// Validate RecvMsg does not read from the channel requests
streamSize := len(stream.requests)
var msg *putObjectStreamResponse
err = stream.client.RecvMsg(msg)
require.NoError(err)
require.Nil(msg)
require.Equal(streamSize, len(stream.requests))
// Validate Send returns an error when the request is nil
err = stream.client.Send(nil)
require.Error(err)
// Validate Send writes to the channel requests
var wg sync.WaitGroup
go func() {
err = stream.client.Send(&plgpb.PutObjectRequest{})
require.NoError(err)
}()
wg.Add(1)
go func() {
defer wg.Done()
req, ok := <-stream.requests
require.True(ok)
require.NotNil(req)
require.NotNil(req.msg)
require.Nil(req.err)
}()
wg.Wait()
// Validate CloseSend does not return an error
// Validate clientClosed is set to true
// Validate the channel requests is closed
var ok bool
err = stream.client.CloseSend()
require.NoError(err)
require.True(stream.clientClosed)
_, ok = <-stream.requests
require.False(ok)
// Validate CloseSend does return an error when the channel is closed
// Validate clientClosed is set to true
// Validate the channel requests is closed
err = stream.client.CloseSend()
require.Error(err)
require.Contains(err.Error(), "stream is closed")
require.True(stream.clientClosed)
_, ok = <-stream.requests
require.False(ok)
// Validate Send returns an error when the channel is closed
err = stream.client.Send(&plgpb.PutObjectRequest{})
require.Error(err)
require.Contains(err.Error(), "stream is closed")
require.Empty(stream.requests)
// Reset stream
stream = newPutObjectStream()
// Validate CloseAndRecv returns an EOF error when the channel responses is closed
// Validate CloseAndRecv closes the channel requests
stream.CloseServer()
resp, err := stream.client.CloseAndRecv()
require.Equal(io.EOF, err)
require.Nil(resp)
require.True(stream.clientClosed)
require.True(stream.IsClientClosed())
require.True(stream.serverClosed)
require.True(stream.IsServerClosed())
}
func Test_PutObjectStream_Server(t *testing.T) {
require := tr.New(t)
stream := newPutObjectStream()
require.NotNil(stream)
require.NotNil(stream.server)
// Validate SetHeader does not return an error
err := stream.server.SetHeader(nil)
require.NoError(err)
// Validate SendHeader does not return an error
err = stream.server.SendHeader(nil)
require.NoError(err)
// Validate Context returns a context
ctx := stream.server.Context()
require.NotNil(ctx)
// Validate RecvMsg does not read from the channel requests
streamSize := len(stream.requests)
var msg *putObjectStreamRequest
err = stream.server.RecvMsg(msg)
require.NoError(err)
require.Nil(msg)
require.Equal(streamSize, len(stream.requests))
// Validate SendMsg returns an error for unknown message types
err = stream.server.SendMsg(map[string]string{})
require.Error(err)
require.Contains(err.Error(), "invalid argument")
// Validate SendMsg does write a message to the channel responses
var wg sync.WaitGroup
go func() {
err = stream.server.SendMsg(&plgpb.PutObjectResponse{})
require.NoError(err)
}()
wg.Add(1)
go func() {
defer wg.Done()
resp, ok := <-stream.responses
require.True(ok)
require.NotNil(resp)
require.NotNil(resp.msg)
require.Nil(resp.err)
}()
wg.Wait()
// Validate SendMsg does write a error to the channel responses
// Validate SendMsg closes the channel responses
go func() {
err = stream.server.SendMsg(fmt.Errorf("mock error"))
require.NoError(err)
}()
wg.Add(1)
go func() {
defer wg.Done()
resp, ok := <-stream.responses
require.True(ok)
require.NotNil(resp)
require.NotNil(resp.err)
require.Nil(resp.msg)
}()
wg.Wait()
_, ok := <-stream.responses
require.False(ok)
require.True(stream.serverClosed)
require.True(stream.IsServerClosed())
// Validate SendMsg does return an error when the channel responses is closed
err = stream.server.SendMsg(&plgpb.PutObjectResponse{})
require.Error(err)
require.Contains(err.Error(), "stream is closed")
err = stream.server.SendMsg(fmt.Errorf("mock error"))
require.Error(err)
require.Contains(err.Error(), "stream is closed")
// Validate SendAndClose returns an error when response is nil
err = stream.server.SendAndClose(nil)
require.Error(err)
// Validate SendAndClose returns an error when the channel responses is closed
err = stream.server.SendAndClose(&plgpb.PutObjectResponse{})
require.Error(err)
require.Contains(err.Error(), "stream is closed")
// Reset stream
stream = newPutObjectStream()
// Validate SendAndClose closes the responses channel
go func() {
err = stream.server.SendAndClose(&plgpb.PutObjectResponse{})
require.NoError(err)
}()
wg.Add(1)
go func() {
defer wg.Done()
resp, ok := <-stream.responses
require.True(ok)
require.NotNil(resp)
require.NotNil(resp.msg)
require.Nil(resp.err)
}()
wg.Wait()
require.True(stream.serverClosed)
require.True(stream.IsServerClosed())
_, ok = <-stream.responses
require.False(ok)
}
func TestNewPutObjectStream(t *testing.T) {
require := tr.New(t)
stream := newPutObjectStream()
require.NotNil(stream)
require.NotNil(stream.m)
require.NotNil(stream.client)
require.NotNil(stream.server)
require.NotNil(stream.requests)
require.NotNil(stream.responses)
require.False(stream.clientClosed)
require.False(stream.IsClientClosed())
require.False(stream.serverClosed)
require.False(stream.IsServerClosed())
// Validate CloseClient() closes the requests channel
stream.CloseClient()
require.True(stream.clientClosed)
require.True(stream.IsClientClosed())
_, ok := <-stream.requests
require.False(ok)
// Validate CloseServer() closes the responses channel
stream.CloseServer()
require.True(stream.serverClosed)
require.True(stream.IsServerClosed())
_, ok = <-stream.responses
require.False(ok)
}
func Test_GetObjectStream(t *testing.T) {
require := tr.New(t)
stream := newGetObjectStream()
// Validate the server receives an error when the client closes the stream
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for {
err := stream.server.Send(&plgpb.GetObjectResponse{})
if err == nil {
continue
}
require.Error(err)
require.Contains(err.Error(), "stream is closed")
break
}
}()
stream.client.CloseSend()
wg.Wait()
require.True(stream.streamClosed)
require.True(stream.IsStreamClosed())
_, ok := <-stream.messages
require.False(ok)
// Reset Stream
stream = newGetObjectStream()
// Validate the client recieves an error when the server sends an error
// Validate the channel messages is closed
go func() {
err := stream.server.SendMsg(fmt.Errorf("mock error"))
require.NoError(err)
}()
resp, err := stream.client.Recv()
require.Nil(resp)
require.Error(err)
require.Contains(err.Error(), "mock error")
require.True(stream.streamClosed)
require.True(stream.IsStreamClosed())
_, ok = <-stream.messages
require.False(ok)
}
func Test_PutObjectStream(t *testing.T) {
require := tr.New(t)
stream := newPutObjectStream()
// Validate the client recieves the response when the server closes the stream
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
for {
resp, err := stream.client.CloseAndRecv()
require.NotNil(resp)
require.NoError(err)
break
}
}()
go func() {
defer wg.Done()
err := stream.server.SendAndClose(&plgpb.PutObjectResponse{})
require.NoError(err)
}()
wg.Wait()
require.True(stream.clientClosed)
require.True(stream.IsClientClosed())
require.True(stream.serverClosed)
require.True(stream.IsServerClosed())
_, ok := <-stream.requests
require.False(ok)
_, ok = <-stream.responses
require.False(ok)
// Reset Stream
stream = newPutObjectStream()
// Validate the client recieves an error when the server sends an error
wg.Add(2)
go func() {
defer wg.Done()
for {
resp, err := stream.client.CloseAndRecv()
require.Nil(resp)
require.Error(err)
require.Contains(err.Error(), "mock error")
break
}
}()
go func() {
defer wg.Done()
err := stream.server.SendMsg(fmt.Errorf("mock error"))
require.NoError(err)
}()
wg.Wait()
require.True(stream.clientClosed)
require.True(stream.IsClientClosed())
require.True(stream.serverClosed)
require.True(stream.IsServerClosed())
_, ok = <-stream.requests
require.False(ok)
_, ok = <-stream.responses
require.False(ok)
// Reset Stream
stream = newPutObjectStream()
// Validate the server recieves an EOF error when the client closes the stream
wg.Add(2)
go func() {
defer wg.Done()
for {
req, err := stream.server.Recv()
if err != nil {
require.Nil(req)
require.Equal(io.EOF, err)
break
}
}
}()
go func() {
wg.Done()
err := stream.client.CloseSend()
require.NoError(err)
}()
wg.Wait()
require.True(stream.clientClosed)
require.True(stream.IsClientClosed())
require.False(stream.serverClosed)
require.False(stream.IsServerClosed())
_, ok = <-stream.requests
require.False(ok)
}