2019-05-07 07:05:38 +00:00
|
|
|
package subscriptions
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2019-12-11 08:44:57 +00:00
|
|
|
"sync"
|
2019-05-07 07:05:38 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
2020-01-02 09:10:19 +00:00
|
|
|
|
|
|
|
"github.com/status-im/status-go/signal"
|
2019-05-07 07:05:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
filterID = "123"
|
|
|
|
filterNS = "tst"
|
|
|
|
)
|
|
|
|
|
|
|
|
type mockFilter struct {
|
2019-12-11 08:44:57 +00:00
|
|
|
sync.Mutex
|
2019-05-07 07:05:38 +00:00
|
|
|
filterID string
|
|
|
|
data []interface{}
|
|
|
|
filterError error
|
|
|
|
uninstalled bool
|
|
|
|
uninstallError error
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMockFilter(filterID string) *mockFilter {
|
|
|
|
return &mockFilter{
|
|
|
|
filterID: filterID,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mf *mockFilter) getID() string {
|
2019-12-11 08:44:57 +00:00
|
|
|
mf.Lock()
|
|
|
|
defer mf.Unlock()
|
2019-05-07 07:05:38 +00:00
|
|
|
return mf.filterID
|
|
|
|
}
|
|
|
|
func (mf *mockFilter) getChanges() ([]interface{}, error) {
|
2019-12-11 08:44:57 +00:00
|
|
|
mf.Lock()
|
|
|
|
defer mf.Unlock()
|
|
|
|
|
2019-05-07 07:05:38 +00:00
|
|
|
if mf.filterError != nil {
|
|
|
|
err := mf.filterError
|
|
|
|
mf.filterError = nil
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
data := mf.data
|
|
|
|
mf.data = nil
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mf *mockFilter) uninstall() error {
|
2019-12-11 08:44:57 +00:00
|
|
|
mf.Lock()
|
|
|
|
defer mf.Unlock()
|
2019-05-07 07:05:38 +00:00
|
|
|
mf.uninstalled = true
|
|
|
|
return mf.uninstallError
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mf *mockFilter) setData(data ...interface{}) {
|
2019-12-11 08:44:57 +00:00
|
|
|
mf.Lock()
|
|
|
|
defer mf.Unlock()
|
2019-05-07 07:05:38 +00:00
|
|
|
mf.data = data
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mf *mockFilter) setError(err error) {
|
2019-12-11 08:44:57 +00:00
|
|
|
mf.Lock()
|
|
|
|
defer mf.Unlock()
|
2019-05-07 07:05:38 +00:00
|
|
|
mf.data = nil
|
|
|
|
mf.filterError = err
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSubscriptionGetData(t *testing.T) {
|
|
|
|
filter := newMockFilter(filterID)
|
|
|
|
|
|
|
|
subs := NewSubscriptions(time.Microsecond)
|
|
|
|
|
|
|
|
subID, _ := subs.Create(filterNS, filter)
|
|
|
|
|
|
|
|
require.Equal(t, string(subID), fmt.Sprintf("%s-%s", filterNS, filterID))
|
|
|
|
|
|
|
|
proceed := make(chan struct{})
|
|
|
|
|
|
|
|
signal.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
|
|
|
defer close(proceed)
|
|
|
|
validateFilterData(t, jsonEvent, string(subID), "1", "2", "3", "4")
|
|
|
|
})
|
|
|
|
|
|
|
|
filter.setData("1", "2", "3", "4")
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-proceed:
|
|
|
|
return
|
|
|
|
case <-time.After(time.Second):
|
|
|
|
require.NoError(t, errors.New("timeout while waiting for filter results"))
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, subs.removeAll())
|
|
|
|
signal.ResetDefaultNodeNotificationHandler()
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSubscriptionGetError(t *testing.T) {
|
|
|
|
filter := newMockFilter(filterID)
|
|
|
|
|
|
|
|
subs := NewSubscriptions(time.Microsecond)
|
|
|
|
|
|
|
|
subID, _ := subs.Create(filterNS, filter)
|
|
|
|
|
|
|
|
require.Equal(t, string(subID), fmt.Sprintf("%s-%s", filterNS, filterID))
|
|
|
|
|
|
|
|
proceed := make(chan struct{})
|
|
|
|
|
|
|
|
expectedError := errors.New("test-error")
|
|
|
|
|
|
|
|
signal.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
|
|
|
|
defer close(proceed)
|
|
|
|
validateFilterError(t, jsonEvent, string(subID), expectedError.Error())
|
|
|
|
})
|
|
|
|
|
|
|
|
filter.setError(expectedError)
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-proceed:
|
|
|
|
return
|
|
|
|
case <-time.After(time.Second):
|
|
|
|
require.NoError(t, errors.New("timeout while waiting for filter results"))
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, subs.removeAll())
|
|
|
|
signal.ResetDefaultNodeNotificationHandler()
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSubscriptionRemove(t *testing.T) {
|
|
|
|
filter := newMockFilter(filterID)
|
|
|
|
subs := NewSubscriptions(time.Microsecond)
|
|
|
|
|
2019-12-11 08:44:57 +00:00
|
|
|
subID, err := subs.Create(filterNS, filter)
|
|
|
|
require.NoError(t, err)
|
|
|
|
time.Sleep(time.Millisecond * 100) // create starts in a goroutine
|
2019-05-07 07:05:38 +00:00
|
|
|
|
|
|
|
require.NoError(t, subs.Remove(subID))
|
|
|
|
require.True(t, filter.uninstalled)
|
|
|
|
require.Empty(t, subs.subs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSubscriptionRemoveError(t *testing.T) {
|
|
|
|
filter := newMockFilter(filterID)
|
|
|
|
filter.uninstallError = errors.New("uninstall-error-1")
|
|
|
|
|
|
|
|
subs := NewSubscriptions(time.Microsecond)
|
2019-12-11 08:44:57 +00:00
|
|
|
subID, err := subs.Create(filterNS, filter)
|
|
|
|
require.NoError(t, err)
|
|
|
|
time.Sleep(time.Millisecond * 100) // create starts in a goroutine
|
2019-05-07 07:05:38 +00:00
|
|
|
|
|
|
|
require.Equal(t, subs.Remove(subID), filter.uninstallError)
|
|
|
|
require.True(t, filter.uninstalled)
|
|
|
|
require.Equal(t, len(subs.subs), 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSubscriptionRemoveAll(t *testing.T) {
|
|
|
|
filter0 := newMockFilter(filterID)
|
|
|
|
filter1 := newMockFilter(filterID + "1")
|
|
|
|
|
|
|
|
subs := NewSubscriptions(time.Microsecond)
|
|
|
|
_, err := subs.Create(filterNS, filter0)
|
|
|
|
require.NoError(t, err)
|
|
|
|
_, err = subs.Create(filterNS, filter1)
|
|
|
|
require.NoError(t, err)
|
2019-12-11 08:44:57 +00:00
|
|
|
time.Sleep(time.Millisecond * 100) // create starts in a goroutine
|
2019-05-07 07:05:38 +00:00
|
|
|
|
|
|
|
require.Equal(t, len(subs.subs), 2)
|
2019-12-11 08:44:57 +00:00
|
|
|
err = subs.removeAll()
|
|
|
|
require.NoError(t, err)
|
2019-05-07 07:05:38 +00:00
|
|
|
require.False(t, filter0.uninstalled)
|
|
|
|
require.False(t, filter1.uninstalled)
|
|
|
|
require.Equal(t, len(subs.subs), 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateFilterError(t *testing.T, jsonEvent string, expectedSubID string, expectedErrorMessage string) {
|
|
|
|
result := struct {
|
|
|
|
Event signal.SubscriptionErrorEvent `json:"event"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
}{}
|
|
|
|
require.NoError(t, json.Unmarshal([]byte(jsonEvent), &result))
|
|
|
|
require.Equal(t, signal.EventSubscriptionsError, result.Type)
|
|
|
|
require.Equal(t, expectedErrorMessage, result.Event.ErrorMessage)
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateFilterData(t *testing.T, jsonEvent string, expectedSubID string, expectedData ...interface{}) {
|
|
|
|
result := struct {
|
|
|
|
Event signal.SubscriptionDataEvent `json:"event"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
}{}
|
|
|
|
require.NoError(t, json.Unmarshal([]byte(jsonEvent), &result))
|
|
|
|
require.Equal(t, signal.EventSubscriptionsData, result.Type)
|
|
|
|
require.Equal(t, expectedData, result.Event.Data)
|
|
|
|
require.Equal(t, expectedSubID, result.Event.FilterID)
|
|
|
|
}
|