mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
8eb1fac9ad
* Refactor and update dependencies in the project - Updated go.sum to replace `github.com/absmach/magistrala` with `github.com/absmach/supermq` across various modules. - Removed VSock configuration from environment variables and QEMU arguments. - Updated QEMU configuration and related tests to remove references to guest CID and VSock. - Added new HTTP transport layer for API endpoints in the manager. - Introduced Prometheus monitoring configuration with alert rules and Alertmanager setup. - Updated service and VM interfaces to remove unused methods and references. - Refactored tests to align with the new structure and dependencies. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Add MaxVMs configuration and enforce limit on VM creation Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Add comprehensive tests for HTTP transport handlers and endpoints Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Add test case for exceeding maximum number of VMs in TestRun Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Improve error handling in TestHandlerWithCustomRouter to ensure response writing is checked Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Update dependencies to latest versions - Upgrade cel.dev/expr from v0.23.0 to v0.24.0 - Upgrade github.com/absmach/supermq from v0.16.0 to v0.17.0 - Upgrade github.com/cenkalti/backoff from v4.3.0 to v5.0.2 - Upgrade github.com/cncf/xds/go to v0.0.0-20250501225837-2ac532fd4443 - Upgrade github.com/go-chi/chi/v5 from v5.2.1 to v5.2.2 - Upgrade github.com/go-jose/go-jose/v3 from v3.0.3 to v3.0.4 - Upgrade github.com/gofrs/uuid/v5 from v5.3.0 to v5.3.2 - Upgrade github.com/prometheus/client_golang from v1.22.0 to v1.23.0 - Upgrade github.com/prometheus/client_model from v0.6.1 to v0.6.2 - Upgrade github.com/prometheus/common from v0.62.0 to v0.65.0 - Upgrade github.com/prometheus/procfs from v0.15.1 to v0.16.1 - Upgrade go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from v0.60.0 to v0.62.0 - Upgrade go.opentelemetry.io/otel/exporters/otlp/otlptrace from v1.36.0 to v1.37.0 - Upgrade golang.org/x/crypto from v0.39.0 to v0.40.0 - Upgrade golang.org/x/sys from v0.33.0 to v0.34.0 - Upgrade golang.org/x/text from v0.26.0 to v0.27.0 - Upgrade golang.org/x/time from v0.11.0 to v0.12.0 - Upgrade google.golang.org/grpc from v1.73.0 to v1.74.2 Signed-off-by: Sammy Oina <sammyoina@gmail.com> --------- Signed-off-by: Sammy Oina <sammyoina@gmail.com>
274 lines
6.9 KiB
Go
274 lines
6.9 KiB
Go
// Copyright (c) Ultraviolet
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/absmach/supermq/pkg/errors"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/ultravioletrs/cocos/agent/cvms"
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/peer"
|
|
)
|
|
|
|
type mockServerStream struct {
|
|
mock.Mock
|
|
cvms.Service_ProcessServer
|
|
}
|
|
|
|
func (m *mockServerStream) Send(msg *cvms.ServerStreamMessage) error {
|
|
args := m.Called(msg)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *mockServerStream) Recv() (*cvms.ClientStreamMessage, error) {
|
|
args := m.Called()
|
|
return args.Get(0).(*cvms.ClientStreamMessage), args.Error(1)
|
|
}
|
|
|
|
func (m *mockServerStream) Context() context.Context {
|
|
args := m.Called()
|
|
return args.Get(0).(context.Context)
|
|
}
|
|
|
|
type mockService struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *mockService) Run(ctx context.Context, ipAddress string, sendMessage SendFunc, authInfo credentials.AuthInfo) {
|
|
m.Called(ctx, ipAddress, sendMessage, authInfo)
|
|
}
|
|
|
|
func TestNewServer(t *testing.T) {
|
|
incoming := make(chan *cvms.ClientStreamMessage)
|
|
mockSvc := new(mockService)
|
|
|
|
server := NewServer(incoming, mockSvc)
|
|
|
|
assert.NotNil(t, server)
|
|
assert.IsType(t, &grpcServer{}, server)
|
|
}
|
|
|
|
func TestGrpcServer_Process(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
recvReturn *cvms.ClientStreamMessage
|
|
recvError error
|
|
expectedError string
|
|
}{
|
|
{
|
|
name: "Process with context deadline exceeded",
|
|
recvReturn: &cvms.ClientStreamMessage{},
|
|
recvError: nil,
|
|
expectedError: "context deadline exceeded",
|
|
},
|
|
{
|
|
name: "Process with Recv error",
|
|
recvReturn: &cvms.ClientStreamMessage{},
|
|
recvError: errors.New("recv error"),
|
|
expectedError: "recv error",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
incoming := make(chan *cvms.ClientStreamMessage, 1)
|
|
mockSvc := new(mockService)
|
|
server := NewServer(incoming, mockSvc).(*grpcServer)
|
|
|
|
mockStream := new(mockServerStream)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
|
defer cancel()
|
|
|
|
mockStream.On("Context").Return(peer.NewContext(ctx, &peer.Peer{
|
|
Addr: mockAddr{},
|
|
AuthInfo: mockAuthInfo{},
|
|
}))
|
|
|
|
if tt.recvError == nil {
|
|
go func() {
|
|
for mes := range incoming {
|
|
assert.NotNil(t, mes)
|
|
}
|
|
}()
|
|
}
|
|
|
|
mockStream.On("Recv").Return(tt.recvReturn, tt.recvError)
|
|
mockSvc.On("Run", mock.Anything, "test", mock.Anything, mock.AnythingOfType("mockAuthInfo")).Return()
|
|
|
|
err := server.Process(mockStream)
|
|
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), tt.expectedError)
|
|
mockStream.AssertExpectations(t)
|
|
mockSvc.AssertExpectations(t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGrpcServer_sendRunReqInChunks(t *testing.T) {
|
|
incoming := make(chan *cvms.ClientStreamMessage)
|
|
mockSvc := new(mockService)
|
|
server := NewServer(incoming, mockSvc).(*grpcServer)
|
|
|
|
mockStream := new(mockServerStream)
|
|
|
|
runReq := &cvms.ComputationRunReq{
|
|
Id: "test-id",
|
|
}
|
|
|
|
largePayload := make([]byte, bufferSize*2)
|
|
for i := range largePayload {
|
|
largePayload[i] = byte(i % 256)
|
|
}
|
|
runReq.Algorithm = &cvms.Algorithm{}
|
|
runReq.Algorithm.UserKey = largePayload
|
|
|
|
mockStream.On("Send", mock.AnythingOfType("*cvms.ServerStreamMessage")).Return(nil).Times(4)
|
|
|
|
err := server.sendRunReqInChunks(mockStream, runReq)
|
|
|
|
assert.NoError(t, err)
|
|
mockStream.AssertExpectations(t)
|
|
|
|
calls := mockStream.Calls
|
|
assert.Equal(t, 4, len(calls))
|
|
|
|
for i, call := range calls {
|
|
msg := call.Arguments[0].(*cvms.ServerStreamMessage)
|
|
chunk := msg.GetRunReqChunks()
|
|
|
|
assert.NotNil(t, chunk)
|
|
assert.Equal(t, "test-id", chunk.Id)
|
|
|
|
if i < 3 {
|
|
assert.False(t, chunk.IsLast)
|
|
} else {
|
|
assert.Equal(t, 0, len(chunk.Data))
|
|
assert.True(t, chunk.IsLast)
|
|
}
|
|
}
|
|
}
|
|
|
|
type mockAddr struct{}
|
|
|
|
func (mockAddr) Network() string { return "test network" }
|
|
func (mockAddr) String() string { return "test" }
|
|
|
|
type mockAuthInfo struct{}
|
|
|
|
func (mockAuthInfo) AuthType() string { return "test auth" }
|
|
|
|
func TestGrpcServer_ProcessWithMockService(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
setupMockFn func(*mockService, *mockServerStream)
|
|
}{
|
|
{
|
|
name: "Run Request Test",
|
|
setupMockFn: func(mockSvc *mockService, mockStream *mockServerStream) {
|
|
mockSvc.On("Run", mock.Anything, "test", mock.Anything, mock.AnythingOfType("mockAuthInfo")).
|
|
Run(func(args mock.Arguments) {
|
|
sendFunc := args.Get(2).(SendFunc)
|
|
runReq := &cvms.ComputationRunReq{Id: "test-run-id"}
|
|
err := sendFunc(&cvms.ServerStreamMessage{
|
|
Message: &cvms.ServerStreamMessage_RunReq{
|
|
RunReq: runReq,
|
|
},
|
|
})
|
|
assert.NoError(t, err)
|
|
}).
|
|
Return()
|
|
|
|
mockStream.On("Send", mock.MatchedBy(func(msg *cvms.ServerStreamMessage) bool {
|
|
chunks := msg.GetRunReqChunks()
|
|
return chunks != nil && chunks.Id == "test-run-id"
|
|
})).Return(nil)
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
incoming := make(chan *cvms.ClientStreamMessage, 10)
|
|
mockSvc := new(mockService)
|
|
server := NewServer(incoming, mockSvc).(*grpcServer)
|
|
|
|
go func() {
|
|
for mes := range incoming {
|
|
assert.NotNil(t, mes)
|
|
}
|
|
}()
|
|
|
|
mockStream := new(mockServerStream)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
|
defer cancel()
|
|
|
|
peerCtx := peer.NewContext(ctx, &peer.Peer{
|
|
Addr: mockAddr{},
|
|
AuthInfo: mockAuthInfo{},
|
|
})
|
|
|
|
mockStream.On("Context").Return(peerCtx)
|
|
mockStream.On("Recv").Return(&cvms.ClientStreamMessage{}, nil).Maybe()
|
|
|
|
tt.setupMockFn(mockSvc, mockStream)
|
|
|
|
go func() {
|
|
time.Sleep(150 * time.Millisecond)
|
|
cancel()
|
|
}()
|
|
|
|
err := server.Process(mockStream)
|
|
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "context canceled")
|
|
mockStream.AssertExpectations(t)
|
|
mockSvc.AssertExpectations(t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGrpcServer_sendRunReqInChunksError(t *testing.T) {
|
|
incoming := make(chan *cvms.ClientStreamMessage)
|
|
mockSvc := new(mockService)
|
|
server := NewServer(incoming, mockSvc).(*grpcServer)
|
|
|
|
mockStream := new(mockServerStream)
|
|
|
|
runReq := &cvms.ComputationRunReq{
|
|
Id: "test-id",
|
|
}
|
|
|
|
// Simulate an error when sending
|
|
mockStream.On("Send", mock.AnythingOfType("*cvms.ServerStreamMessage")).Return(errors.New("send error")).Once()
|
|
|
|
err := server.sendRunReqInChunks(mockStream, runReq)
|
|
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "send error")
|
|
mockStream.AssertExpectations(t)
|
|
}
|
|
|
|
func TestGrpcServer_ProcessMissingPeerInfo(t *testing.T) {
|
|
incoming := make(chan *cvms.ClientStreamMessage)
|
|
mockSvc := new(mockService)
|
|
server := NewServer(incoming, mockSvc).(*grpcServer)
|
|
|
|
mockStream := new(mockServerStream)
|
|
ctx := context.Background()
|
|
|
|
// Return a context without peer info
|
|
mockStream.On("Context").Return(ctx)
|
|
|
|
err := server.Process(mockStream)
|
|
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "failed to get peer info")
|
|
mockStream.AssertExpectations(t)
|
|
}
|