github.com/status-im/status-go@v1.1.0/services/subscriptions/subscriptions_test.go (about) 1 package subscriptions 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/stretchr/testify/require" 12 13 "github.com/status-im/status-go/signal" 14 ) 15 16 const ( 17 filterID = "123" 18 filterNS = "tst" 19 ) 20 21 type mockFilter struct { 22 sync.Mutex 23 filterID string 24 data []interface{} 25 filterError error 26 uninstalled bool 27 uninstallError error 28 } 29 30 func newMockFilter(filterID string) *mockFilter { 31 return &mockFilter{ 32 filterID: filterID, 33 } 34 } 35 36 func (mf *mockFilter) getID() string { 37 mf.Lock() 38 defer mf.Unlock() 39 return mf.filterID 40 } 41 func (mf *mockFilter) getChanges() ([]interface{}, error) { 42 mf.Lock() 43 defer mf.Unlock() 44 45 if mf.filterError != nil { 46 err := mf.filterError 47 mf.filterError = nil 48 return nil, err 49 } 50 51 data := mf.data 52 mf.data = nil 53 return data, nil 54 } 55 56 func (mf *mockFilter) uninstall() error { 57 mf.Lock() 58 defer mf.Unlock() 59 mf.uninstalled = true 60 return mf.uninstallError 61 } 62 63 func (mf *mockFilter) setData(data ...interface{}) { 64 mf.Lock() 65 defer mf.Unlock() 66 mf.data = data 67 } 68 69 func (mf *mockFilter) setError(err error) { 70 mf.Lock() 71 defer mf.Unlock() 72 mf.data = nil 73 mf.filterError = err 74 } 75 76 func TestSubscriptionGetData(t *testing.T) { 77 filter := newMockFilter(filterID) 78 79 subs := NewSubscriptions(time.Microsecond) 80 81 subID, _ := subs.Create(filterNS, filter) 82 83 require.Equal(t, string(subID), fmt.Sprintf("%s-%s", filterNS, filterID)) 84 85 proceed := make(chan struct{}) 86 87 signal.SetDefaultNodeNotificationHandler(func(jsonEvent string) { 88 defer close(proceed) 89 validateFilterData(t, jsonEvent, string(subID), "1", "2", "3", "4") 90 }) 91 92 filter.setData("1", "2", "3", "4") 93 94 select { 95 case <-proceed: 96 return 97 case <-time.After(time.Second): 98 require.NoError(t, errors.New("timeout while waiting for filter results")) 99 } 100 101 require.NoError(t, subs.removeAll()) 102 signal.ResetDefaultNodeNotificationHandler() 103 } 104 105 func TestSubscriptionGetError(t *testing.T) { 106 filter := newMockFilter(filterID) 107 108 subs := NewSubscriptions(time.Microsecond) 109 110 subID, _ := subs.Create(filterNS, filter) 111 112 require.Equal(t, string(subID), fmt.Sprintf("%s-%s", filterNS, filterID)) 113 114 proceed := make(chan struct{}) 115 116 expectedError := errors.New("test-error") 117 118 signal.SetDefaultNodeNotificationHandler(func(jsonEvent string) { 119 defer close(proceed) 120 validateFilterError(t, jsonEvent, string(subID), expectedError.Error()) 121 }) 122 123 filter.setError(expectedError) 124 125 select { 126 case <-proceed: 127 return 128 case <-time.After(time.Second): 129 require.NoError(t, errors.New("timeout while waiting for filter results")) 130 } 131 132 require.NoError(t, subs.removeAll()) 133 signal.ResetDefaultNodeNotificationHandler() 134 } 135 136 func TestSubscriptionRemove(t *testing.T) { 137 filter := newMockFilter(filterID) 138 subs := NewSubscriptions(time.Microsecond) 139 140 subID, err := subs.Create(filterNS, filter) 141 require.NoError(t, err) 142 time.Sleep(time.Millisecond * 100) // create starts in a goroutine 143 144 require.NoError(t, subs.Remove(subID)) 145 require.True(t, filter.uninstalled) 146 require.Empty(t, subs.subs) 147 } 148 149 func TestSubscriptionRemoveError(t *testing.T) { 150 filter := newMockFilter(filterID) 151 filter.uninstallError = errors.New("uninstall-error-1") 152 153 subs := NewSubscriptions(time.Microsecond) 154 subID, err := subs.Create(filterNS, filter) 155 require.NoError(t, err) 156 time.Sleep(time.Millisecond * 100) // create starts in a goroutine 157 158 require.Equal(t, subs.Remove(subID), filter.uninstallError) 159 require.True(t, filter.uninstalled) 160 require.Equal(t, len(subs.subs), 0) 161 } 162 163 func TestSubscriptionRemoveAll(t *testing.T) { 164 filter0 := newMockFilter(filterID) 165 filter1 := newMockFilter(filterID + "1") 166 167 subs := NewSubscriptions(time.Microsecond) 168 _, err := subs.Create(filterNS, filter0) 169 require.NoError(t, err) 170 _, err = subs.Create(filterNS, filter1) 171 require.NoError(t, err) 172 time.Sleep(time.Millisecond * 100) // create starts in a goroutine 173 174 require.Equal(t, len(subs.subs), 2) 175 err = subs.removeAll() 176 require.NoError(t, err) 177 require.False(t, filter0.uninstalled) 178 require.False(t, filter1.uninstalled) 179 require.Equal(t, len(subs.subs), 0) 180 } 181 182 func validateFilterError(t *testing.T, jsonEvent string, expectedSubID string, expectedErrorMessage string) { 183 result := struct { 184 Event signal.SubscriptionErrorEvent `json:"event"` 185 Type string `json:"type"` 186 }{} 187 require.NoError(t, json.Unmarshal([]byte(jsonEvent), &result)) 188 require.Equal(t, signal.EventSubscriptionsError, result.Type) 189 require.Equal(t, expectedErrorMessage, result.Event.ErrorMessage) 190 } 191 192 func validateFilterData(t *testing.T, jsonEvent string, expectedSubID string, expectedData ...interface{}) { 193 result := struct { 194 Event signal.SubscriptionDataEvent `json:"event"` 195 Type string `json:"type"` 196 }{} 197 require.NoError(t, json.Unmarshal([]byte(jsonEvent), &result)) 198 require.Equal(t, signal.EventSubscriptionsData, result.Type) 199 require.Equal(t, expectedData, result.Event.Data) 200 require.Equal(t, expectedSubID, result.Event.FilterID) 201 }