github.com/jordan-bonecutter/can-go@v0.0.0-20230901155856-d83995b18e50/pkg/canrunner/run_test.go (about)

     1  package canrunner_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/golang/mock/gomock"
    11  	"go.einride.tech/can"
    12  	"go.einride.tech/can/internal/mocks/gen/mockcanrunner"
    13  	"go.einride.tech/can/internal/mocks/gen/mockclock"
    14  	"go.einride.tech/can/pkg/canrunner"
    15  	"go.einride.tech/can/pkg/descriptor"
    16  	"golang.org/x/sync/errgroup"
    17  	"gotest.tools/v3/assert"
    18  )
    19  
    20  func TestRunMessageReceiver_NoMessages(t *testing.T) {
    21  	ctrl := gomock.NewController(t)
    22  	defer ctrl.Finish()
    23  	rx := mockcanrunner.NewMockFrameReceiver(ctrl)
    24  	node := mockcanrunner.NewMockNode(ctrl)
    25  	clock := mockclock.NewMockClock(ctrl)
    26  	ctx := context.Background()
    27  	// when the first receive fails
    28  	rx.EXPECT().Receive().Return(false)
    29  	rx.EXPECT().Err().Return(os.ErrClosed)
    30  	// then an error is returned
    31  	assert.Assert(t, errors.Is(canrunner.RunMessageReceiver(ctx, rx, node, clock), os.ErrClosed))
    32  }
    33  
    34  func TestRunMessageReceiver_ReceiveMessage(t *testing.T) {
    35  	ctrl := gomock.NewController(t)
    36  	defer ctrl.Finish()
    37  	rx := mockcanrunner.NewMockFrameReceiver(ctrl)
    38  	node := mockcanrunner.NewMockNode(ctrl)
    39  	clock := mockclock.NewMockClock(ctrl)
    40  	msg := mockcanrunner.NewMockReceivedMessage(ctrl)
    41  	ctx := context.Background()
    42  	// when the first receive succeeds
    43  	frame := can.Frame{ID: 42}
    44  	rx.EXPECT().Receive().Return(true)
    45  	rx.EXPECT().Frame().Return(frame)
    46  	// then the receiver should do a message lookup
    47  	node.EXPECT().ReceivedMessage(frame.ID).Return(msg, true)
    48  	// and the node should be locked
    49  	node.EXPECT().Lock()
    50  	// and the message should be queried for a hook with the same context
    51  	afterReceiveHook := func(c context.Context) error {
    52  		assert.DeepEqual(t, ctx, c)
    53  		return nil
    54  	}
    55  	msg.EXPECT().AfterReceiveHook().Return(afterReceiveHook)
    56  	// and the receive time should be set
    57  	now := time.Unix(0, 1)
    58  	clock.EXPECT().Now().Return(now)
    59  	msg.EXPECT().SetReceiveTime(now)
    60  	// and the message should be called to unmarshal the frame
    61  	msg.EXPECT().UnmarshalFrame(frame)
    62  	// and the node should be unlocked
    63  	node.EXPECT().Unlock()
    64  	// when the next receive fails
    65  	rx.EXPECT().Receive().Return(false)
    66  	rx.EXPECT().Err().Return(nil)
    67  	// then the receiver should return
    68  	assert.NilError(t, canrunner.RunMessageReceiver(ctx, rx, node, clock))
    69  }
    70  
    71  func TestRunMessageTransmitter_TransmitEventMessage(t *testing.T) {
    72  	t.Skip() // TODO: fix deadlock flakynes.
    73  	ctrl := gomock.NewController(t)
    74  	defer ctrl.Finish()
    75  	tx := mockcanrunner.NewMockFrameTransmitter(ctrl)
    76  	node := mockcanrunner.NewMockNode(ctrl)
    77  	msg := mockcanrunner.NewMockTransmittedMessage(ctrl)
    78  	clock := mockclock.NewMockClock(ctrl)
    79  	desc := &descriptor.Message{
    80  		Name:     "TestMessage",
    81  		SendType: descriptor.SendTypeEvent,
    82  	}
    83  	transmitEventChan := make(chan struct{})
    84  	wakeUpChan := make(chan struct{})
    85  	msg.EXPECT().Descriptor().AnyTimes().Return(desc)
    86  	msg.EXPECT().TransmitEventChan().Return(transmitEventChan)
    87  	msg.EXPECT().WakeUpChan().Return(wakeUpChan)
    88  	// given a running transmitter
    89  	ctx, cancel := context.WithCancel(context.Background())
    90  	var g errgroup.Group
    91  	g.Go(func() error {
    92  		return canrunner.RunMessageTransmitter(ctx, tx, node, msg, clock)
    93  	})
    94  	// then message should be queried for if it has cyclic transmission enabled
    95  	node.EXPECT().Lock()
    96  	msg.EXPECT().IsCyclicTransmissionEnabled()
    97  	node.EXPECT().Unlock()
    98  	// then the node should be locked
    99  	node.EXPECT().Lock()
   100  	// and the time should be queried
   101  	now := time.Unix(0, 1)
   102  	clock.EXPECT().Now().Return(now)
   103  	// and the transmit hook should be queried with the same context
   104  	hook := func(c context.Context) error {
   105  		assert.Equal(t, ctx, c)
   106  		return nil
   107  	}
   108  	msg.EXPECT().BeforeTransmitHook().Return(hook)
   109  	// and the message should be marshaled to a CAN frame
   110  	frame := can.Frame{ID: 42}
   111  	// and the transmit time should be set
   112  	msg.EXPECT().SetTransmitTime(now)
   113  	// and the node should be unlocked
   114  	node.EXPECT().Unlock()
   115  	node.EXPECT().Lock()
   116  	msg.EXPECT().Frame().Return(frame)
   117  	node.EXPECT().Unlock()
   118  	// and the CAN frame should be transmitted
   119  	tx.EXPECT().TransmitFrame(gomock.Any(), frame)
   120  	// when the transmitter receives a transmit event
   121  	transmitEventChan <- struct{}{}
   122  	cancel()
   123  	assert.NilError(t, g.Wait())
   124  }