Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 2 additions & 11 deletions pkg/lumera/modules/action_msg/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,10 @@ type FinalizeActionResult struct {
// Module defines the interface for action messages operations
type Module interface {
// FinalizeCascadeAction finalizes a CASCADE action with the given parameters
FinalizeCascadeAction(
ctx context.Context,
actionId string,
rqIdsIds []string,
) (*FinalizeActionResult, error)
FinalizeCascadeAction(ctx context.Context, actionId string, rqIdsIds []string) (*FinalizeActionResult, error)
}

// NewModule creates a new ActionMsg module client
func NewModule(
conn *grpc.ClientConn,
kr keyring.Keyring,
keyName string,
chainID string,
) (Module, error) {
func NewModule(conn *grpc.ClientConn, kr keyring.Keyring, keyName string, chainID string) (Module, error) {
return newModule(conn, kr, keyName, chainID)
}
2 changes: 1 addition & 1 deletion pkg/testutil/lumera.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ type MockActionMsgModule struct{}
// For now, this is a placeholder implementation

// FinalizeCascadeAction implements the required method from action_msg.Module interface
func (m *MockActionMsgModule) FinalizeCascadeAction(ctx context.Context, actionId string, rqIDs []string) (*action_msg.FinalizeActionResult, error) {
func (m *MockActionMsgModule) FinalizeCascadeAction(ctx context.Context, actionId string, signatures []string) (*action_msg.FinalizeActionResult, error) {
// Mock implementation returns success with empty result
return &action_msg.FinalizeActionResult{}, nil
}
Expand Down
8 changes: 3 additions & 5 deletions sdk/action/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
)

// Client defines the interface for action operations
//
//go:generate mockery --name=Client --output=testutil/mocks --outpkg=mocks --filename=client_mock.go
type Client interface {
StartCascade(ctx context.Context, data []byte, actionID string) (string, error)
DeleteTask(ctx context.Context, taskID string) error
Expand Down Expand Up @@ -52,11 +54,7 @@ func NewClient(ctx context.Context, config config.Config, logger log.Logger, key
}

// StartCascade initiates a cascade operation
func (c *ClientImpl) StartCascade(ctx context.Context,
data []byte,
actionID string,
) (string, error) {

func (c *ClientImpl) StartCascade(ctx context.Context, data []byte, actionID string) (string, error) {
if actionID == "" {
c.logger.Error(ctx, "Empty action ID provided")
return "", ErrEmptyActionID
Expand Down
194 changes: 194 additions & 0 deletions sdk/action/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package action

import (
"context"
"errors"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

"github.com/LumeraProtocol/supernode/sdk/config"
"github.com/LumeraProtocol/supernode/sdk/event"
"github.com/LumeraProtocol/supernode/sdk/log"
"github.com/LumeraProtocol/supernode/sdk/task"

mocktask "github.com/LumeraProtocol/supernode/sdk/task/testutil/mocks"
)

func newClientWithMock(mgr *mocktask.Manager) *ClientImpl {
return &ClientImpl{
config: config.Config{}, // empty fixture
taskManager: mgr, // injected mock
logger: log.NewNoopLogger(), // quiet logger
}
}

func TestClient_StartCascade(t *testing.T) {
ctx := context.Background()
payload := []byte("hello-world")
actionID := "act-123"
mockErr := errors.New("boom")

tests := map[string]struct {
data []byte
actionID string
setupMock func(*mocktask.Manager)
wantTaskID string
wantErrMatch func(error) bool
}{
"happy path": {
data: payload,
actionID: actionID,
setupMock: func(m *mocktask.Manager) {
m.On("CreateCascadeTask", ctx, payload, actionID).
Return("task-42", nil)
},
wantTaskID: "task-42",
wantErrMatch: func(err error) bool { return err == nil },
},
"empty action id": {
data: payload,
actionID: "",
setupMock: func(*mocktask.Manager) {},
wantErrMatch: func(err error) bool { return errors.Is(err, ErrEmptyActionID) },
},
"empty data": {
data: nil,
actionID: actionID,
setupMock: func(*mocktask.Manager) {},
wantErrMatch: func(err error) bool { return errors.Is(err, ErrEmptyData) },
},
"manager failure": {
data: payload,
actionID: actionID,
setupMock: func(m *mocktask.Manager) {
m.On("CreateCascadeTask", ctx, payload, actionID).
Return("", mockErr)
},
wantErrMatch: func(err error) bool {
return err != nil && errors.Is(err, mockErr)
},
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
mockMgr := mocktask.NewManager(t)
tc.setupMock(mockMgr)

client := newClientWithMock(mockMgr)

gotID, err := client.StartCascade(ctx, tc.data, tc.actionID)
assert.True(t, tc.wantErrMatch(err), "error assertion failed")
assert.Equal(t, tc.wantTaskID, gotID)
})
}
}

func TestClient_GetTask(t *testing.T) {
ctx := context.Background()
entry := &task.TaskEntry{TaskID: "tid-7"}

tests := map[string]struct {
taskID string
setupMock func(*mocktask.Manager)
wantEntry *task.TaskEntry
wantFound bool
}{
"found": {
taskID: "tid-7",
setupMock: func(m *mocktask.Manager) {
m.On("GetTask", ctx, "tid-7").Return(entry, true)
},
wantEntry: entry, wantFound: true,
},
"missing": {
taskID: "tid-404",
setupMock: func(m *mocktask.Manager) {
m.On("GetTask", ctx, "tid-404").Return((*task.TaskEntry)(nil), false)
},
wantEntry: nil, wantFound: false,
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
mockMgr := mocktask.NewManager(t)
tc.setupMock(mockMgr)

client := newClientWithMock(mockMgr)
got, ok := client.GetTask(ctx, tc.taskID)

assert.Equal(t, tc.wantFound, ok)
assert.Equal(t, tc.wantEntry, got)
})
}
}

func TestClient_DeleteTask(t *testing.T) {
ctx := context.Background()
mockErr := errors.New("delete fail")

tests := map[string]struct {
taskID string
setupMock func(*mocktask.Manager)
wantErrNil bool
}{
"happy path": {
taskID: "tid-1",
setupMock: func(m *mocktask.Manager) {
m.On("DeleteTask", ctx, "tid-1").Return(nil)
},
wantErrNil: true,
},
"empty id": {
taskID: "",
setupMock: func(*mocktask.Manager) {},
wantErrNil: false,
},
"manager error": {
taskID: "tid-2",
setupMock: func(m *mocktask.Manager) {
m.On("DeleteTask", ctx, "tid-2").Return(mockErr)
},
wantErrNil: false,
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
mockMgr := mocktask.NewManager(t)
tc.setupMock(mockMgr)

client := newClientWithMock(mockMgr)
err := client.DeleteTask(ctx, tc.taskID)

assert.Equal(t, tc.wantErrNil, err == nil)
})
}
}

func TestClient_Subscribe(t *testing.T) {
ctx := context.Background()
handler := func(context.Context, event.Event) {}

mockMgr := mocktask.NewManager(t)

mockMgr.
On("SubscribeToEvents", ctx, event.EventType("foo"), mock.AnythingOfType("event.Handler")).
Once()
mockMgr.
On("SubscribeToAllEvents", ctx, mock.AnythingOfType("event.Handler")).
Once()

client := newClientWithMock(mockMgr)

assert.NoError(t, client.SubscribeToEvents(ctx, "foo", handler))
assert.NoError(t, client.SubscribeToAllEvents(ctx, handler))

// nil Manager branch
nilClient := &ClientImpl{}
assert.Error(t, nilClient.SubscribeToEvents(ctx, "bar", handler))
assert.Error(t, nilClient.SubscribeToAllEvents(ctx, handler))
}
143 changes: 143 additions & 0 deletions sdk/action/testutil/mocks/client_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading