2022-12-01 20:36:10 +00:00
|
|
|
/*
|
|
|
|
Copyright 2022 CAcert Inc.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package protocol
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/sirupsen/logrus/hooks/test"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
|
|
|
"git.cacert.org/cacert-gosigner/pkg/messages"
|
|
|
|
)
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func AssertLogs(t *testing.T, hook *test.Hook, expected []logrus.Entry) {
|
2022-12-01 20:36:10 +00:00
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
logEntries := hook.AllEntries()
|
|
|
|
assert.Len(t, logEntries, len(expected))
|
|
|
|
|
|
|
|
for i, e := range expected {
|
2022-12-04 18:17:36 +00:00
|
|
|
assert.Equal(t, e.Level, logEntries[i].Level)
|
|
|
|
assert.Equal(t, e.Message, logEntries[i].Message)
|
|
|
|
|
|
|
|
for k, v := range e.Data {
|
|
|
|
assert.Contains(t, logEntries[i].Data, k)
|
|
|
|
assert.Equal(t, logEntries[i].Data[k], v)
|
|
|
|
}
|
2022-12-01 20:36:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCommand_String(t *testing.T) {
|
|
|
|
c := &Command{
|
|
|
|
Announce: messages.BuildCommandAnnounce(messages.CmdUndef),
|
|
|
|
Command: "my undefined command",
|
|
|
|
}
|
|
|
|
|
|
|
|
str := c.String()
|
|
|
|
|
|
|
|
assert.NotEmpty(t, str)
|
|
|
|
assert.Contains(t, str, c.Announce.String())
|
|
|
|
assert.Contains(t, str, c.Command)
|
|
|
|
assert.Contains(t, str, "announce")
|
|
|
|
assert.Contains(t, str, "data")
|
|
|
|
assert.Contains(t, str, "Cmd[")
|
|
|
|
assert.True(t, strings.HasSuffix(str, "}]"))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResponse_String(t *testing.T) {
|
|
|
|
r := &Response{
|
|
|
|
Announce: messages.BuildResponseAnnounce(messages.RespUndef, uuid.NewString()),
|
|
|
|
Response: "my undefined response",
|
|
|
|
}
|
|
|
|
|
|
|
|
str := r.String()
|
|
|
|
|
|
|
|
assert.NotEmpty(t, str)
|
|
|
|
assert.Contains(t, str, r.Announce.String())
|
|
|
|
assert.Contains(t, str, r.Response)
|
|
|
|
assert.Contains(t, str, "announce")
|
|
|
|
assert.Contains(t, str, "data")
|
|
|
|
assert.Contains(t, str, "Rsp[")
|
|
|
|
assert.True(t, strings.HasSuffix(str, "}]"))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProtocolState_String(t *testing.T) {
|
|
|
|
goodStates := []struct {
|
|
|
|
name string
|
|
|
|
state protocolState
|
|
|
|
}{
|
|
|
|
{"command announce", cmdAnnounce},
|
|
|
|
{"command data", cmdData},
|
|
|
|
{"handle command", handleCommand},
|
|
|
|
{"respond", respond},
|
|
|
|
{"response announce", respAnnounce},
|
|
|
|
{"response data", respData},
|
|
|
|
{"handle response", handleResponse},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, s := range goodStates {
|
|
|
|
t.Run(s.name, func(t *testing.T) {
|
|
|
|
str := s.state.String()
|
|
|
|
|
|
|
|
assert.NotEmpty(t, str)
|
|
|
|
assert.NotContains(t, str, "unknown")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("unsupported state", func(t *testing.T) {
|
|
|
|
str := protocolState(-1).String()
|
|
|
|
|
|
|
|
assert.NotEmpty(t, str)
|
|
|
|
assert.Contains(t, str, "unknown")
|
|
|
|
assert.Contains(t, str, "-1")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
type NoopServerHandler struct{}
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func (h *NoopServerHandler) CommandAnnounce(context.Context, <-chan []byte) (*Command, error) {
|
2022-12-01 20:36:10 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func (h *NoopServerHandler) CommandData(context.Context, <-chan []byte, *Command) error {
|
2022-12-01 20:36:10 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func (h *NoopServerHandler) HandleCommand(context.Context, *Command) (*Response, error) {
|
2022-12-01 20:36:10 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func (h *NoopServerHandler) Respond(context.Context, *Response, chan<- []byte) error {
|
2022-12-01 20:36:10 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func TestServerProtocol_HandleUnknownProtocolState(t *testing.T) {
|
|
|
|
protoLog, pHook := test.NewNullLogger()
|
|
|
|
protoLog.SetLevel(logrus.TraceLevel)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("skipping test in short mode")
|
2022-12-01 20:36:10 +00:00
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
in, out := make(chan []byte), make(chan []byte)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
var err error
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
p := NewServer(&NoopServerHandler{}, in, out, protoLog)
|
|
|
|
p.state = protocolState(100)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
wg.Add(1)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
go func() {
|
|
|
|
err = p.Handle(ctx)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
wg.Done()
|
|
|
|
}()
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
time.Sleep(10 * time.Millisecond)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
cancel()
|
|
|
|
wg.Wait()
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
assert.ErrorContains(t, err, "unknown protocol state")
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
AssertLogs(t, pHook, []logrus.Entry{
|
|
|
|
{
|
|
|
|
Level: logrus.DebugLevel,
|
|
|
|
Message: "handling protocol state",
|
|
|
|
Data: map[string]interface{}{"state": protocolState(100)},
|
|
|
|
},
|
|
|
|
})
|
2022-12-01 20:36:10 +00:00
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
type NoopClientHandler struct{}
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func (h *NoopClientHandler) Send(context.Context, *Command, chan<- []byte) error {
|
|
|
|
return nil
|
2022-12-01 20:36:10 +00:00
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func (h *NoopClientHandler) ResponseAnnounce(context.Context, <-chan []byte) (*Response, error) {
|
2022-12-01 20:36:10 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func (h *NoopClientHandler) ResponseData(context.Context, <-chan []byte, *Response) error {
|
|
|
|
return nil
|
|
|
|
}
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func (h *NoopClientHandler) HandleResponse(context.Context, *Response) error {
|
|
|
|
return nil
|
2022-12-01 20:36:10 +00:00
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
func TestClientProtocol_HandleUnknownProtocolState(t *testing.T) {
|
2022-12-01 20:36:10 +00:00
|
|
|
protoLog, pHook := test.NewNullLogger()
|
|
|
|
protoLog.SetLevel(logrus.TraceLevel)
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
t.Run("unknown-protocol-state", func(t *testing.T) {
|
2022-12-01 20:36:10 +00:00
|
|
|
t.Cleanup(func() {
|
|
|
|
pHook.Reset()
|
|
|
|
})
|
|
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("skipping test in short mode")
|
|
|
|
}
|
|
|
|
|
|
|
|
in, out := make(chan []byte), make(chan []byte)
|
2022-12-04 18:17:36 +00:00
|
|
|
commands := make(chan *Command, 10)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
sent []byte
|
|
|
|
)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
c := NewClient(&NoopClientHandler{}, commands, in, out, protoLog)
|
|
|
|
c.state = protocolState(100)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
wg.Add(2)
|
|
|
|
|
|
|
|
go func() {
|
2022-12-04 18:17:36 +00:00
|
|
|
err = c.Handle(ctx)
|
2022-12-01 20:36:10 +00:00
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
|
|
|
|
go func() {
|
2022-12-04 18:17:36 +00:00
|
|
|
defer wg.Done()
|
2022-12-01 20:36:10 +00:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
2022-12-04 18:17:36 +00:00
|
|
|
return
|
|
|
|
case sent = <-out:
|
|
|
|
return
|
2022-12-01 20:36:10 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
|
|
|
|
cancel()
|
|
|
|
wg.Wait()
|
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
assert.ErrorContains(t, err, "unknown protocol state")
|
|
|
|
assert.Nil(t, sent)
|
2022-12-01 20:36:10 +00:00
|
|
|
|
2022-12-04 18:17:36 +00:00
|
|
|
AssertLogs(t, pHook, []logrus.Entry{
|
|
|
|
{
|
|
|
|
Level: logrus.DebugLevel,
|
|
|
|
Message: "handling protocol state",
|
|
|
|
Data: map[string]interface{}{"state": protocolState(100)},
|
|
|
|
},
|
2022-12-01 20:36:10 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|