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>
258 lines
7.9 KiB
Go
258 lines
7.9 KiB
Go
// Copyright (c) Ultraviolet
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
mglog "github.com/absmach/supermq/logger"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/ultravioletrs/cocos/agent/cvms"
|
|
servermocks "github.com/ultravioletrs/cocos/agent/cvms/server/mocks"
|
|
"github.com/ultravioletrs/cocos/agent/mocks"
|
|
pkggrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
|
clientmocks "github.com/ultravioletrs/cocos/pkg/clients/grpc/mocks"
|
|
"golang.org/x/crypto/sha3"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
type mockStream struct {
|
|
mock.Mock
|
|
grpc.ClientStream
|
|
}
|
|
|
|
func (m *mockStream) Recv() (*cvms.ServerStreamMessage, error) {
|
|
args := m.Called()
|
|
return args.Get(0).(*cvms.ServerStreamMessage), args.Error(1)
|
|
}
|
|
|
|
func (m *mockStream) Send(msg *cvms.ClientStreamMessage) error {
|
|
args := m.Called(msg)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func TestManagerClient_Process(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
setupMocks func(mockStream *mockStream, mockSvc *mocks.Service, mockServerSvc *servermocks.AgentServer, grpcClient *clientmocks.Client)
|
|
expectError bool
|
|
errorMsg string
|
|
}{
|
|
{
|
|
name: "Stop computation",
|
|
setupMocks: func(mockStream *mockStream, mockSvc *mocks.Service, mockServerSvc *servermocks.AgentServer, grpcClient *clientmocks.Client) {
|
|
mockStream.On("Recv").Return(&cvms.ServerStreamMessage{
|
|
Message: &cvms.ServerStreamMessage_StopComputation{
|
|
StopComputation: &cvms.StopComputation{},
|
|
},
|
|
}, nil)
|
|
mockStream.On("Send", mock.Anything).Return(nil)
|
|
mockSvc.On("StopComputation", mock.Anything).Return(nil)
|
|
mockServerSvc.On("Stop").Return(nil)
|
|
},
|
|
expectError: true,
|
|
errorMsg: "context deadline exceeded",
|
|
},
|
|
{
|
|
name: "Run request chunks",
|
|
setupMocks: func(mockStream *mockStream, mockSvc *mocks.Service, mockServerSvc *servermocks.AgentServer, grpcClient *clientmocks.Client) {
|
|
mockStream.On("Recv").Return(&cvms.ServerStreamMessage{
|
|
Message: &cvms.ServerStreamMessage_RunReqChunks{
|
|
RunReqChunks: &cvms.RunReqChunks{},
|
|
},
|
|
}, nil)
|
|
mockStream.On("Send", mock.Anything).Return(nil).Once()
|
|
mockSvc.On("Run", mock.Anything, mock.Anything).Return("", assert.AnError).Once()
|
|
},
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "Agent state request",
|
|
setupMocks: func(mockStream *mockStream, mockSvc *mocks.Service, mockServerSvc *servermocks.AgentServer, grpcClient *clientmocks.Client) {
|
|
mockStream.On("Recv").Return(&cvms.ServerStreamMessage{
|
|
Message: &cvms.ServerStreamMessage_AgentStateReq{
|
|
AgentStateReq: &cvms.AgentStateReq{
|
|
Id: "test-agent",
|
|
},
|
|
},
|
|
}, nil)
|
|
mockStream.On("Send", mock.Anything).Return(nil)
|
|
mockSvc.On("State").Return("test-state")
|
|
},
|
|
expectError: true,
|
|
errorMsg: "context deadline exceeded",
|
|
},
|
|
{
|
|
name: "Disconnect request",
|
|
setupMocks: func(mockStream *mockStream, mockSvc *mocks.Service, mockServerSvc *servermocks.AgentServer, grpcClient *clientmocks.Client) {
|
|
mockStream.On("Recv").Return(&cvms.ServerStreamMessage{
|
|
Message: &cvms.ServerStreamMessage_DisconnectReq{},
|
|
}, nil)
|
|
mockStream.On("Send", mock.Anything).Return(nil)
|
|
grpcClient.On("Close").Return(nil)
|
|
},
|
|
expectError: true,
|
|
errorMsg: "context deadline exceeded",
|
|
},
|
|
{
|
|
name: "Receive error",
|
|
setupMocks: func(mockStream *mockStream, mockSvc *mocks.Service, mockServerSvc *servermocks.AgentServer, grpcClient *clientmocks.Client) {
|
|
mockStream.On("Recv").Return(&cvms.ServerStreamMessage{}, assert.AnError)
|
|
},
|
|
expectError: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
mockStream := new(mockStream)
|
|
mockSvc := new(mocks.Service)
|
|
mockServerSvc := new(servermocks.AgentServer)
|
|
messageQueue := make(chan *cvms.ClientStreamMessage)
|
|
logger := mglog.NewMock()
|
|
|
|
go func() {
|
|
<-messageQueue
|
|
}()
|
|
|
|
grpcClient := new(clientmocks.Client)
|
|
|
|
client, err := NewClient(mockStream, mockSvc, messageQueue, logger, mockServerSvc, t.TempDir(), func(ctx context.Context) (pkggrpc.Client, cvms.Service_ProcessClient, error) { return nil, nil, nil }, grpcClient)
|
|
assert.NoError(t, err)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
|
defer cancel()
|
|
|
|
tc.setupMocks(mockStream, mockSvc, mockServerSvc, grpcClient)
|
|
|
|
err = client.Process(ctx, cancel)
|
|
|
|
if tc.expectError {
|
|
assert.Error(t, err)
|
|
if tc.errorMsg != "" {
|
|
assert.Contains(t, err.Error(), tc.errorMsg)
|
|
}
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestManagerClient_handleRunReqChunks(t *testing.T) {
|
|
mockStream := new(mockStream)
|
|
mockSvc := new(mocks.Service)
|
|
mockServerSvc := new(servermocks.AgentServer)
|
|
messageQueue := make(chan *cvms.ClientStreamMessage, 10)
|
|
logger := mglog.NewMock()
|
|
grpcClient := new(clientmocks.Client)
|
|
|
|
client, err := NewClient(mockStream, mockSvc, messageQueue, logger, mockServerSvc, t.TempDir(), func(ctx context.Context) (pkggrpc.Client, cvms.Service_ProcessClient, error) { return nil, nil, nil }, grpcClient)
|
|
assert.NoError(t, err)
|
|
|
|
runReq := &cvms.ComputationRunReq{
|
|
Id: "test-id",
|
|
Datasets: []*cvms.Dataset{
|
|
{
|
|
Hash: sha3.New256().Sum([]byte("test-dataset")),
|
|
},
|
|
},
|
|
Algorithm: &cvms.Algorithm{
|
|
Hash: sha3.New256().Sum([]byte("test-algorithm")),
|
|
},
|
|
ResultConsumers: []*cvms.ResultConsumer{
|
|
{
|
|
UserKey: []byte("test-consumer"),
|
|
},
|
|
},
|
|
}
|
|
runReqBytes, _ := proto.Marshal(runReq)
|
|
|
|
chunk1 := &cvms.ServerStreamMessage_RunReqChunks{
|
|
RunReqChunks: &cvms.RunReqChunks{
|
|
Id: "chunk-1",
|
|
Data: runReqBytes[:len(runReqBytes)/2],
|
|
IsLast: false,
|
|
},
|
|
}
|
|
chunk2 := &cvms.ServerStreamMessage_RunReqChunks{
|
|
RunReqChunks: &cvms.RunReqChunks{
|
|
Id: "chunk-1",
|
|
Data: runReqBytes[len(runReqBytes)/2:],
|
|
IsLast: true,
|
|
},
|
|
}
|
|
|
|
mockSvc.On("InitComputation", mock.Anything, mock.Anything).Return(nil)
|
|
mockServerSvc.On("Start", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
|
|
|
err = client.handleRunReqChunks(context.Background(), chunk1)
|
|
assert.NoError(t, err)
|
|
|
|
err = client.handleRunReqChunks(context.Background(), chunk2)
|
|
assert.NoError(t, err)
|
|
|
|
// Wait for the goroutine to finish
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
mockSvc.AssertExpectations(t)
|
|
assert.Len(t, messageQueue, 1)
|
|
|
|
msg := <-messageQueue
|
|
runRes, ok := msg.Message.(*cvms.ClientStreamMessage_RunRes)
|
|
assert.True(t, ok)
|
|
assert.Equal(t, "test-id", runRes.RunRes.ComputationId)
|
|
}
|
|
|
|
func TestManagerClient_handleStopComputation(t *testing.T) {
|
|
mockStream := new(mockStream)
|
|
mockSvc := new(mocks.Service)
|
|
mockServerSvc := new(servermocks.AgentServer)
|
|
messageQueue := make(chan *cvms.ClientStreamMessage, 10)
|
|
logger := mglog.NewMock()
|
|
grpcClient := new(clientmocks.Client)
|
|
|
|
client, err := NewClient(mockStream, mockSvc, messageQueue, logger, mockServerSvc, t.TempDir(), func(ctx context.Context) (pkggrpc.Client, cvms.Service_ProcessClient, error) { return nil, nil, nil }, grpcClient)
|
|
assert.NoError(t, err)
|
|
|
|
stopReq := &cvms.ServerStreamMessage_StopComputation{
|
|
StopComputation: &cvms.StopComputation{
|
|
ComputationId: "test-comp-id",
|
|
},
|
|
}
|
|
|
|
mockSvc.On("StopComputation", mock.Anything).Return(nil)
|
|
mockServerSvc.On("Stop").Return(nil)
|
|
|
|
client.handleStopComputation(context.Background(), stopReq)
|
|
|
|
// Wait for the goroutine to finish
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
mockSvc.AssertExpectations(t)
|
|
assert.Len(t, messageQueue, 1)
|
|
|
|
msg := <-messageQueue
|
|
stopRes, ok := msg.Message.(*cvms.ClientStreamMessage_StopComputationRes)
|
|
assert.True(t, ok)
|
|
assert.Equal(t, "test-comp-id", stopRes.StopComputationRes.ComputationId)
|
|
assert.Empty(t, stopRes.StopComputationRes.Message)
|
|
}
|
|
|
|
func TestManagerClient_timeoutRequest(t *testing.T) {
|
|
rm := newRunRequestManager()
|
|
rm.requests["test-id"] = &runRequest{
|
|
timer: time.NewTimer(100 * time.Millisecond),
|
|
buffer: []byte("test-data"),
|
|
lastChunk: time.Now(),
|
|
}
|
|
|
|
rm.timeoutRequest("test-id")
|
|
|
|
assert.Len(t, rm.requests, 0)
|
|
}
|