Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added monitor #8

Merged
merged 3 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
22 changes: 22 additions & 0 deletions mock/executorStub.go
Original file line number Diff line number Diff line change
@@ -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
}
65 changes: 65 additions & 0 deletions monitor/blsKeysMonitor.go
Original file line number Diff line number Diff line change
@@ -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
}
78 changes: 78 additions & 0 deletions monitor/blsKeysMonitor_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package monitor

import (
"context"
"sync/atomic"
"testing"
"time"

"github.com/multiversx/mx-chain-keys-monitor-go/mock"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove empty line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"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))
}
7 changes: 7 additions & 0 deletions monitor/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package monitor

import "errors"

var (
errInvalidInterval = errors.New("invalid interval")
)
8 changes: 8 additions & 0 deletions monitor/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package monitor

type pollingHandler interface {
StartProcessingLoop() error
IsRunning() bool
Close() error
IsInterfaceNil() bool
}
Loading