Skip to content

Commit

Permalink
Adjust SetAvailableComponents and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mrsillydog committed Jan 13, 2025
1 parent 26a7996 commit b189b21
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 8 deletions.
103 changes: 103 additions & 0 deletions client/clientimpl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2306,6 +2306,109 @@ func TestSetFlagsBeforeStart(t *testing.T) {
})
}

func TestSetAvailableComponents(t *testing.T) {
testCases := []struct {
desc string
capabilities protobufs.AgentCapabilities
testFunc func(t *testing.T, client OpAMPClient, srv *internal.MockServer)
}{
{
desc: "apply nil AvailableComponents",
capabilities: protobufs.AgentCapabilities_AgentCapabilities_ReportsAvailableComponents,
testFunc: func(t *testing.T, client OpAMPClient, _ *internal.MockServer) {
require.ErrorIs(t, client.SetAvailableComponents(nil), types.ErrAvailableComponentsMissing)
},
},
{
desc: "apply AvailableComponents with empty hash",
capabilities: protobufs.AgentCapabilities_AgentCapabilities_ReportsAvailableComponents,
testFunc: func(t *testing.T, client OpAMPClient, _ *internal.MockServer) {
require.ErrorIs(t, client.SetAvailableComponents(&protobufs.AvailableComponents{}), types.ErrNoAvailableComponentHash)
},
},
{
desc: "apply AvailableComponents without required capability",
testFunc: func(t *testing.T, client OpAMPClient, _ *internal.MockServer) {
require.ErrorIs(t, client.SetAvailableComponents(generateTestAvailableComponents()), types.ErrReportsAvailableComponentsNotSet)
},
},
{
desc: "apply AvailableComponents with cached AvailableComponents",
capabilities: protobufs.AgentCapabilities_AgentCapabilities_ReportsAvailableComponents,
testFunc: func(t *testing.T, client OpAMPClient, _ *internal.MockServer) {
require.NoError(t, client.SetAvailableComponents(generateTestAvailableComponents()))
},
},
{
desc: "apply AvailableComponents with new AvailableComponents",
capabilities: protobufs.AgentCapabilities_AgentCapabilities_ReportsAvailableComponents,
testFunc: func(t *testing.T, client OpAMPClient, srv *internal.MockServer) {
availableComponents := generateTestAvailableComponents()
availableComponents.Hash = []byte("different")
require.NoError(t, client.SetAvailableComponents(availableComponents))
srv.Expect(func(msg *protobufs.AgentToServer) *protobufs.ServerToAgent {
assert.EqualValues(t, 1, msg.SequenceNum)
msgAvailableComponents := msg.GetAvailableComponents()
require.NotNil(t, msgAvailableComponents)
require.Equal(t, msgAvailableComponents.GetHash(), availableComponents.GetHash())
require.Nil(t, msgAvailableComponents.GetComponents())
return nil
})
},
},
}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
testClients(t, func(t *testing.T, client OpAMPClient) {

// Start a Server.
srv := internal.StartMockServer(t)
srv.EnableExpectMode()

availableComponents := generateTestAvailableComponents()

// Start a client.
settings := types.StartSettings{
OpAMPServerURL: "ws://" + srv.Endpoint,
Callbacks: types.Callbacks{
OnMessage: func(ctx context.Context, msg *types.MessageData) {},
},
Capabilities: tc.capabilities,
AvailableComponents: availableComponents,
}
prepareClient(t, &settings, client)

// Client --->
assert.NoError(t, client.Start(context.Background(), settings))

// ---> Server
srv.Expect(func(msg *protobufs.AgentToServer) *protobufs.ServerToAgent {
assert.EqualValues(t, 0, msg.SequenceNum)
msgAvailableComponents := msg.GetAvailableComponents()
if tc.capabilities&protobufs.AgentCapabilities_AgentCapabilities_ReportsAvailableComponents != 0 {
require.NotNil(t, msgAvailableComponents)
require.Equal(t, msgAvailableComponents.GetHash(), availableComponents.GetHash())
require.Nil(t, msgAvailableComponents.GetComponents())
} else {
require.Nil(t, msgAvailableComponents)
}
return nil
})

tc.testFunc(t, client, srv)

// Shutdown the Server.
srv.Close()

// Shutdown the client.
err := client.Stop(context.Background())
assert.NoError(t, err)
})
})
}
}

func generateTestAvailableComponents() *protobufs.AvailableComponents {
return &protobufs.AvailableComponents{
Hash: []byte("fake-hash"),
Expand Down
23 changes: 16 additions & 7 deletions client/internal/clientcommon.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ var (
ErrAcceptsPackagesNotSet = errors.New("AcceptsPackages and ReportsPackageStatuses must be set")
ErrAvailableComponentsMissing = errors.New("AvailableComponents is nil")

errAlreadyStarted = errors.New("already started")
errCannotStopNotStarted = errors.New("cannot stop because not started")
errReportsPackageStatusesNotSet = errors.New("ReportsPackageStatuses capability is not set")
errReportsAvailableComponentsNotSet = errors.New("ReportsAvailableComponents capability is not set")
errAlreadyStarted = errors.New("already started")
errCannotStopNotStarted = errors.New("cannot stop because not started")
errReportsPackageStatusesNotSet = errors.New("ReportsPackageStatuses capability is not set")
)

// ClientCommon contains the OpAMP logic that is common between WebSocket and
Expand Down Expand Up @@ -459,11 +458,15 @@ func (c *ClientCommon) SendCustomMessage(message *protobufs.CustomMessage) (mess
// SetAvailableComponents sends a message to the server with the available components for the agent
func (c *ClientCommon) SetAvailableComponents(components *protobufs.AvailableComponents) error {
if c.Capabilities&protobufs.AgentCapabilities_AgentCapabilities_ReportsAvailableComponents == 0 {
return errReportsAvailableComponentsNotSet
return types.ErrReportsAvailableComponentsNotSet
}

if components == nil {
return types.ErrAvailableComponentsMissing
}

if len(components.Hash) == 0 {
return errNoAvailableComponentHash
return types.ErrNoAvailableComponentHash
}

// implement agent status compression, don't send the message if it hasn't changed from the previous message
Expand All @@ -474,9 +477,15 @@ func (c *ClientCommon) SetAvailableComponents(components *protobufs.AvailableCom
return err
}

Check warning on line 478 in client/internal/clientcommon.go

View check run for this annotation

Codecov / codecov/patch

client/internal/clientcommon.go#L477-L478

Added lines #L477 - L478 were not covered by tests

// initially, do not send the full component state - just send the hash.
// full state is available on request from the server using the corresponding ServerToAgent flag
availableComponents := &protobufs.AvailableComponents{
Hash: c.ClientSyncedState.AvailableComponents().GetHash(),
}

c.sender.NextMessage().Update(
func(msg *protobufs.AgentToServer) {
msg.AvailableComponents = c.ClientSyncedState.AvailableComponents()
msg.AvailableComponents = availableComponents
},
)

Expand Down
1 change: 0 additions & 1 deletion client/internal/clientstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ var (
errServerProvidedAllPackagesHashNil = errors.New("ServerProvidedAllPackagesHash is nil")
errCustomCapabilitiesMissing = errors.New("CustomCapabilities is not set")
errAvailableComponentsMissing = errors.New("AvailableComponents is not set")
errNoAvailableComponentHash = errors.New("AvailableComponents.Hash is empty")
)

// ClientSyncedState stores the state of the Agent messages that the OpAMP Client needs to
Expand Down
9 changes: 9 additions & 0 deletions client/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,13 @@ var (
// ErrCustomMessagePending is returned by SendCustomMessage when called before the previous
// message has been sent.
ErrCustomMessagePending = errors.New("custom message already set")

// ErrReportsAvailableComponentsNotSet is returned by SetAvailableComponents without the ReportsAvailableComponents capability set
ErrReportsAvailableComponentsNotSet = errors.New("ReportsAvailableComponents capability is not set")

// ErrAvailableComponentsMissing is returned by SetAvailableComponents when called with a nil message
ErrAvailableComponentsMissing = errors.New("AvailableComponents is nil")

// ErrNoAvailableComponentHash is returned by SetAvailableComponents when called with a message with an empty hash
ErrNoAvailableComponentHash = errors.New("AvailableComponents.Hash is empty")
)

0 comments on commit b189b21

Please sign in to comment.