From dcfa0e734084b293167c78a8a2a6a1889b1c4057 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Thu, 18 Apr 2024 15:28:43 +0300 Subject: [PATCH 1/2] - added monitor --- mock/executorStub.go | 22 ++++++++++ monitor/blsKeysMonitor.go | 65 ++++++++++++++++++++++++++++ monitor/blsKeysMonitor_test.go | 78 ++++++++++++++++++++++++++++++++++ monitor/errors.go | 7 +++ monitor/interface.go | 8 ++++ 5 files changed, 180 insertions(+) create mode 100644 mock/executorStub.go create mode 100644 monitor/blsKeysMonitor.go create mode 100644 monitor/blsKeysMonitor_test.go create mode 100644 monitor/errors.go create mode 100644 monitor/interface.go diff --git a/mock/executorStub.go b/mock/executorStub.go new file mode 100644 index 0000000..3a44498 --- /dev/null +++ b/mock/executorStub.go @@ -0,0 +1,22 @@ +package mock + +import "context" + +// ExecutorStub - +type ExecutorStub struct { + ExecuteHandler func(ctx context.Context) error +} + +// Execute - +func (stub *ExecutorStub) Execute(ctx context.Context) error { + if stub.ExecuteHandler != nil { + return stub.ExecuteHandler(ctx) + } + + return nil +} + +// IsInterfaceNil - +func (stub *ExecutorStub) IsInterfaceNil() bool { + return stub == nil +} diff --git a/monitor/blsKeysMonitor.go b/monitor/blsKeysMonitor.go new file mode 100644 index 0000000..de28d0f --- /dev/null +++ b/monitor/blsKeysMonitor.go @@ -0,0 +1,65 @@ +package monitor + +import ( + "fmt" + "time" + + logger "github.com/multiversx/mx-chain-logger-go" + "github.com/multiversx/mx-sdk-go/core/polling" +) + +const minInterval = time.Second +const intervalWhenError = time.Second * 10 + +var log = logger.GetOrCreate("monitor") + +type blsKeysMonitor struct { + pollingHandler pollingHandler + name string +} + +// NewBLSKeysMonitor creates a new BLS keys monitor instance +func NewBLSKeysMonitor( + executor polling.Executor, + interval time.Duration, + name string, +) (*blsKeysMonitor, error) { + if interval < minInterval { + return nil, fmt.Errorf("%w, got %v, minimum %v", errInvalidInterval, interval, minInterval) + } + + args := polling.ArgsPollingHandler{ + Log: log, + Name: name, + PollingInterval: interval, + PollingWhenError: intervalWhenError, + Executor: executor, + } + + pollingHandlerInstance, err := polling.NewPollingHandler(args) + if err != nil { + return nil, err + } + + err = pollingHandlerInstance.StartProcessingLoop() + if err != nil { + return nil, err + } + log.Debug("started new BLS keys monitor", "monitor name", name) + + return &blsKeysMonitor{ + pollingHandler: pollingHandlerInstance, + name: name, + }, nil +} + +// Close closes the polling handler +func (monitor *blsKeysMonitor) Close() error { + log.Debug("closed the BLS keys monitor", "monitor name", monitor.name) + return monitor.pollingHandler.Close() +} + +// IsInterfaceNil returns true if there is no value under the interface +func (monitor *blsKeysMonitor) IsInterfaceNil() bool { + return monitor == nil +} diff --git a/monitor/blsKeysMonitor_test.go b/monitor/blsKeysMonitor_test.go new file mode 100644 index 0000000..daa0d81 --- /dev/null +++ b/monitor/blsKeysMonitor_test.go @@ -0,0 +1,78 @@ +package monitor + +import ( + "context" + "sync/atomic" + "testing" + "time" + + "github.com/multiversx/mx-chain-keys-monitor-go/mock" + + "github.com/stretchr/testify/assert" +) + +func TestNewBLSKeysMonitor(t *testing.T) { + t.Parallel() + + t.Run("invalid interval should error", func(t *testing.T) { + t.Parallel() + + monitor, err := NewBLSKeysMonitor(&mock.ExecutorStub{}, time.Second-time.Nanosecond, "test") + assert.Nil(t, monitor) + assert.ErrorIs(t, err, errInvalidInterval) + assert.Contains(t, err.Error(), "got 999.999999ms, minimum 1s") + }) + t.Run("nil executor should error", func(t *testing.T) { + t.Parallel() + + monitor, err := NewBLSKeysMonitor(nil, time.Second, "test") + assert.Nil(t, monitor) + assert.NotNil(t, err) + assert.Equal(t, "nil executor", err.Error()) + }) + t.Run("should work", func(t *testing.T) { + t.Parallel() + + monitor, err := NewBLSKeysMonitor(&mock.ExecutorStub{}, time.Second, "test") + assert.NotNil(t, monitor) + assert.Nil(t, err) + + _ = monitor.Close() + }) +} + +func TestBlsKeysMonitor_IsInterfaceNil(t *testing.T) { + t.Parallel() + + var instance *blsKeysMonitor + assert.True(t, instance.IsInterfaceNil()) + + instance = &blsKeysMonitor{} + assert.False(t, instance.IsInterfaceNil()) +} + +func TestBlsKeysMonitor_Close(t *testing.T) { + t.Parallel() + + numExecution := uint32(0) + monitor, _ := NewBLSKeysMonitor(&mock.ExecutorStub{ + ExecuteHandler: func(ctx context.Context) error { + atomic.AddUint32(&numExecution, 1) + return nil + }, + }, time.Second, "test") + assert.NotNil(t, monitor) + + time.Sleep(time.Second + time.Millisecond*300) + assert.Equal(t, uint32(2), atomic.LoadUint32(&numExecution)) + + time.Sleep(time.Second) + assert.Equal(t, uint32(3), atomic.LoadUint32(&numExecution)) + + err := monitor.Close() + assert.Nil(t, err) + + // no more increment calls + time.Sleep(time.Second * 2) + assert.Equal(t, uint32(3), atomic.LoadUint32(&numExecution)) +} diff --git a/monitor/errors.go b/monitor/errors.go new file mode 100644 index 0000000..bdaaaff --- /dev/null +++ b/monitor/errors.go @@ -0,0 +1,7 @@ +package monitor + +import "errors" + +var ( + errInvalidInterval = errors.New("invalid interval") +) diff --git a/monitor/interface.go b/monitor/interface.go new file mode 100644 index 0000000..75b2a27 --- /dev/null +++ b/monitor/interface.go @@ -0,0 +1,8 @@ +package monitor + +type pollingHandler interface { + StartProcessingLoop() error + IsRunning() bool + Close() error + IsInterfaceNil() bool +} From 7f302b0a2b69a9abdb14f378cb8064c5440fee75 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Tue, 7 May 2024 11:18:12 +0300 Subject: [PATCH 2/2] - removed empty line --- monitor/blsKeysMonitor_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/monitor/blsKeysMonitor_test.go b/monitor/blsKeysMonitor_test.go index daa0d81..66f91c7 100644 --- a/monitor/blsKeysMonitor_test.go +++ b/monitor/blsKeysMonitor_test.go @@ -7,7 +7,6 @@ import ( "time" "github.com/multiversx/mx-chain-keys-monitor-go/mock" - "github.com/stretchr/testify/assert" )