constellation/cli/proto/respclients_test.go
2022-04-27 13:25:18 +02:00

242 lines
6.3 KiB
Go

package proto
import (
"bytes"
"errors"
"io"
"testing"
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
)
// dummyActivateAsCoordinatorClient is a dummy and panics if Recv() is called.
type dummyActivateAsCoordinatorClient struct {
grpc.ClientStream
}
func (c dummyActivateAsCoordinatorClient) Recv() (*pubproto.ActivateAsCoordinatorResponse, error) {
panic("i'm a dummy, Recv() not implemented")
}
// dummyActivateAsCoordinatorClient is a dummy and panics if Recv() is called.
type dummyActivateAdditionalNodesClient struct {
grpc.ClientStream
}
func (c dummyActivateAdditionalNodesClient) Recv() (*pubproto.ActivateAdditionalNodesResponse, error) {
panic("i'm a dummy, Recv() not implemented")
}
// stubActivationAsCoordinatorClient recives responses from an predefined
// response stream iterator or a stub error.
type stubActivationAsCoordinatorClient struct {
grpc.ClientStream
stream *stubActivateAsCoordinatorResponseIter
recvErr error
}
func (c stubActivationAsCoordinatorClient) Recv() (*pubproto.ActivateAsCoordinatorResponse, error) {
if c.recvErr != nil {
return nil, c.recvErr
}
return c.stream.Next()
}
// stubActivateAsCoordinatorResponseIter is an iterator over a slice of
// ActivateAsCoordinatorResponses. It returns the messages in the order
// they occur in the slice and returns an io.EOF error when no response
// is left.
type stubActivateAsCoordinatorResponseIter struct {
msgs []*pubproto.ActivateAsCoordinatorResponse
}
// Next returns the next message from the message slice or an io.EOF error
// if the message slice is empty.
func (q *stubActivateAsCoordinatorResponseIter) Next() (*pubproto.ActivateAsCoordinatorResponse, error) {
if len(q.msgs) == 0 {
return nil, io.EOF
}
msg := q.msgs[0]
q.msgs = q.msgs[1:]
return msg, nil
}
func TestNextLog(t *testing.T) {
testClientVpnIp := "192.0.2.1"
testCoordinatorVpnKey := []byte("32bytesWireGuardKeyForTheTesting")
testCoordinatorVpnKey64 := []byte("MzJieXRlc1dpcmVHdWFyZEtleUZvclRoZVRlc3Rpbmc=")
testKubeconfig := []byte("apiVersion:v1 kind:Config...")
testConfigResp := &pubproto.ActivateAsCoordinatorResponse{
Content: &pubproto.ActivateAsCoordinatorResponse_AdminConfig{
AdminConfig: &pubproto.AdminConfig{
AdminVpnIp: testClientVpnIp,
CoordinatorVpnPubKey: testCoordinatorVpnKey,
Kubeconfig: testKubeconfig,
},
},
}
testLogMessage := "some log message"
testLogResp := &pubproto.ActivateAsCoordinatorResponse{
Content: &pubproto.ActivateAsCoordinatorResponse_Log{
Log: &pubproto.Log{
Message: testLogMessage,
},
},
}
someErr := errors.New("failed")
testCases := map[string]struct {
msgs []*pubproto.ActivateAsCoordinatorResponse
wantLogLen int
wantState bool
recvErr error
wantErr bool
}{
"some logs": {
msgs: []*pubproto.ActivateAsCoordinatorResponse{testLogResp, testLogResp, testLogResp},
wantLogLen: 3,
},
"only admin config": {
msgs: []*pubproto.ActivateAsCoordinatorResponse{testConfigResp},
wantState: true,
},
"logs and configs": {
msgs: []*pubproto.ActivateAsCoordinatorResponse{testLogResp, testConfigResp, testLogResp, testConfigResp},
wantLogLen: 2,
wantState: true,
},
"no response": {
msgs: []*pubproto.ActivateAsCoordinatorResponse{},
wantLogLen: 0,
},
"recv fail": {
recvErr: someErr,
wantErr: true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
respClient := stubActivationAsCoordinatorClient{
stream: &stubActivateAsCoordinatorResponseIter{
msgs: tc.msgs,
},
recvErr: tc.recvErr,
}
client := NewActivationRespClient(respClient)
var logs []string
var err error
for err == nil {
var log string
log, err = client.NextLog()
if err == nil {
logs = append(logs, log)
}
}
assert.Error(err)
if tc.wantErr {
assert.NotErrorIs(err, io.EOF)
return
}
assert.ErrorIs(err, io.EOF)
assert.Len(logs, tc.wantLogLen)
if tc.wantState {
ip, err := client.GetClientVpnIp()
assert.NoError(err)
assert.Equal(testClientVpnIp, ip)
config, err := client.GetKubeconfig()
assert.NoError(err)
assert.Equal(string(testKubeconfig), config)
key, err := client.GetCoordinatorVpnKey()
assert.NoError(err)
assert.Equal(string(testCoordinatorVpnKey64), key)
}
})
}
}
func TestPrintLogStream(t *testing.T) {
assert := assert.New(t)
//
// 10 logs a 10 byte
//
var msgs []*pubproto.ActivateAsCoordinatorResponse
for i := 0; i < 10; i++ {
msgs = append(msgs, &pubproto.ActivateAsCoordinatorResponse{
Content: &pubproto.ActivateAsCoordinatorResponse_Log{
Log: &pubproto.Log{
Message: "10BytesLog",
},
},
})
}
respClient := stubActivationAsCoordinatorClient{
stream: &stubActivateAsCoordinatorResponseIter{
msgs: msgs,
},
}
client := NewActivationRespClient(respClient)
out := &bytes.Buffer{}
assert.NoError(client.WriteLogStream(out))
assert.Equal(out.Len(), 10*11) // 10 messages * (len(message) + 1 newline)
//
// Check error handling.
//
someErr := errors.New("failed")
respClient = stubActivationAsCoordinatorClient{
recvErr: someErr,
}
client = NewActivationRespClient(respClient)
assert.Error(client.WriteLogStream(&bytes.Buffer{}))
}
func TestGetKubeconfig(t *testing.T) {
assert := assert.New(t)
client := NewActivationRespClient(dummyActivateAsCoordinatorClient{})
_, err := client.GetKubeconfig()
assert.Error(err)
client.kubeconfig = "apiVersion:v1 kind:Config..."
config, err := client.GetKubeconfig()
assert.NoError(err)
assert.Equal("apiVersion:v1 kind:Config...", config)
}
func TestGetCoordinatorVpnKey(t *testing.T) {
assert := assert.New(t)
client := NewActivationRespClient(dummyActivateAsCoordinatorClient{})
_, err := client.GetCoordinatorVpnKey()
assert.Error(err)
client.coordinatorVpnKey = "32bytesWireGuardKeyForTheTesting"
key, err := client.GetCoordinatorVpnKey()
assert.NoError(err)
assert.Equal("32bytesWireGuardKeyForTheTesting", key)
}
func TestGetClientVpnIp(t *testing.T) {
assert := assert.New(t)
client := NewActivationRespClient(dummyActivateAsCoordinatorClient{})
_, err := client.GetClientVpnIp()
assert.Error(err)
client.clientVpnIp = "192.0.2.1"
ip, err := client.GetClientVpnIp()
assert.NoError(err)
assert.Equal("192.0.2.1", ip)
}