github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/session/pingpong/hermes_promise_handler_test.go (about) 1 /* 2 * Copyright (C) 2019 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package pingpong 19 20 import ( 21 "errors" 22 "testing" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/mysteriumnetwork/node/core/node/event" 26 "github.com/mysteriumnetwork/node/eventbus" 27 "github.com/mysteriumnetwork/node/identity" 28 "github.com/mysteriumnetwork/node/identity/registry" 29 "github.com/mysteriumnetwork/payments/crypto" 30 "github.com/rs/zerolog/log" 31 "github.com/stretchr/testify/assert" 32 ) 33 34 func TestHermesPromiseHandler_RequestPromise(t *testing.T) { 35 bus := eventbus.New() 36 mockFactory := &mockHermesCallerFactory{} 37 aph := &HermesPromiseHandler{ 38 deps: HermesPromiseHandlerDeps{ 39 HermesURLGetter: &mockHermesURLGetter{}, 40 HermesCallerFactory: mockFactory.Get, 41 Encryption: &mockEncryptor{}, 42 EventBus: eventbus.New(), 43 HermesPromiseStorage: &mockHermesPromiseStorage{}, 44 FeeProvider: &mockFeeProvider{}, 45 }, 46 queue: make(chan enqueuedRequest), 47 stop: make(chan struct{}), 48 } 49 aph.transactorFees = make(map[int64]registry.FeesResponse) 50 err := aph.Subscribe(bus) 51 assert.NoError(t, err) 52 bus.Publish(event.AppTopicNode, event.Payload{ 53 Status: event.StatusStarted, 54 }) 55 56 defer bus.Publish(event.AppTopicNode, event.Payload{ 57 Status: event.StatusStopped, 58 }) 59 60 r := []byte{0x0, 0x1} 61 em := crypto.ExchangeMessage{ 62 Promise: crypto.Promise{}, 63 } 64 65 ch := aph.RequestPromise(r, em, identity.FromAddress("0x0000000000000000000000000000000000000001"), "session") 66 67 err, more := <-ch 68 assert.False(t, more) 69 assert.Nil(t, err) 70 } 71 72 func TestHermesPromiseHandler_RequestPromise_BubblesErrors(t *testing.T) { 73 bus := eventbus.New() 74 mockFactory := &mockHermesCallerFactory{ 75 errToReturn: ErrNeedsRRecovery, 76 } 77 78 aph := &HermesPromiseHandler{ 79 deps: HermesPromiseHandlerDeps{ 80 HermesURLGetter: &mockHermesURLGetter{}, 81 HermesCallerFactory: mockFactory.Get, 82 Encryption: &mockEncryptor{ 83 errToReturn: errors.New("beep beep boop boop"), 84 }, 85 EventBus: bus, 86 HermesPromiseStorage: &mockHermesPromiseStorage{}, 87 FeeProvider: &mockFeeProvider{}, 88 }, 89 queue: make(chan enqueuedRequest), 90 stop: make(chan struct{}), 91 } 92 aph.transactorFees = make(map[int64]registry.FeesResponse) 93 err := aph.Subscribe(bus) 94 assert.NoError(t, err) 95 bus.Publish(event.AppTopicNode, event.Payload{ 96 Status: event.StatusStarted, 97 }) 98 99 defer bus.Publish(event.AppTopicNode, event.Payload{ 100 Status: event.StatusStopped, 101 }) 102 103 r := []byte{0x0, 0x1} 104 em := crypto.ExchangeMessage{ 105 Promise: crypto.Promise{}, 106 } 107 108 ch := aph.RequestPromise(r, em, identity.FromAddress("0x0000000000000000000000000000000000000001"), "session") 109 110 err, more := <-ch 111 assert.True(t, more) 112 assert.Error(t, err) 113 114 err, more = <-ch 115 assert.False(t, more) 116 assert.Nil(t, err) 117 } 118 119 func TestHermesPromiseHandler_recoverR(t *testing.T) { 120 type fields struct { 121 deps HermesPromiseHandlerDeps 122 providerID identity.Identity 123 chainID int64 124 hermesID common.Address 125 } 126 mockFactory := &mockHermesCallerFactory{} 127 tests := []struct { 128 name string 129 fields fields 130 err hermesError 131 wantErr bool 132 before func() 133 }{ 134 { 135 name: "green path", 136 fields: fields{ 137 deps: HermesPromiseHandlerDeps{ 138 HermesCallerFactory: mockFactory.Get, 139 HermesURLGetter: &mockHermesURLGetter{}, 140 Encryption: &mockEncryptor{}, 141 }, 142 providerID: identity.FromAddress("0x0"), 143 }, 144 err: HermesErrorResponse{ 145 ErrorMessage: `Secret R for previous promise exchange (Encrypted recovery data: "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d"`, 146 CausedBy: ErrNeedsRRecovery.Error(), 147 c: ErrNeedsRRecovery, 148 ErrorData: "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d", 149 }, 150 wantErr: false, 151 before: func() { 152 mockFactory.errToReturn = nil 153 }, 154 }, 155 { 156 name: "bubbles hermes errors", 157 fields: fields{ 158 providerID: identity.FromAddress("0x0"), 159 deps: HermesPromiseHandlerDeps{ 160 HermesCallerFactory: mockFactory.Get, 161 HermesURLGetter: &mockHermesURLGetter{}, 162 Encryption: &mockEncryptor{}, 163 }, 164 }, 165 err: HermesErrorResponse{ 166 ErrorMessage: `Secret R for previous promise exchange (Encrypted recovery data: "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d"`, 167 CausedBy: ErrNeedsRRecovery.Error(), 168 c: ErrNeedsRRecovery, 169 ErrorData: "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d", 170 }, 171 wantErr: true, 172 before: func() { 173 mockFactory.errToReturn = errors.New("explosions") 174 }, 175 }, 176 { 177 name: "bubbles decryptor errors", 178 fields: fields{ 179 providerID: identity.FromAddress("0x0"), 180 deps: HermesPromiseHandlerDeps{ 181 HermesCallerFactory: mockFactory.Get, 182 HermesURLGetter: &mockHermesURLGetter{}, 183 Encryption: &mockEncryptor{ 184 errToReturn: errors.New("explosions"), 185 }, 186 }, 187 }, 188 err: HermesErrorResponse{ 189 ErrorMessage: `Secret R for previous promise exchange (Encrypted recovery data: "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d"`, 190 CausedBy: ErrNeedsRRecovery.Error(), 191 c: ErrNeedsRRecovery, 192 ErrorData: "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d", 193 }, 194 wantErr: true, 195 before: func() { 196 mockFactory.errToReturn = nil 197 }, 198 }, 199 } 200 for _, tt := range tests { 201 if tt.before != nil { 202 tt.before() 203 } 204 205 t.Run(tt.name, func(t *testing.T) { 206 it := &HermesPromiseHandler{ 207 deps: tt.fields.deps, 208 } 209 if err := it.recoverR(tt.err, tt.fields.providerID, tt.fields.chainID, tt.fields.hermesID); (err != nil) != tt.wantErr { 210 t.Errorf("HermesPromiseHandler.recoverR() error = %v, wantErr %v", err, tt.wantErr) 211 } 212 }) 213 } 214 } 215 216 func TestHermesPromiseHandler_handleHermesError(t *testing.T) { 217 merr := errors.New("this is a test") 218 mockFactory := &mockHermesCallerFactory{} 219 tests := []struct { 220 name string 221 err error 222 wantErr error 223 providerID identity.Identity 224 hermesID common.Address 225 chainID int64 226 deps HermesPromiseHandlerDeps 227 }{ 228 { 229 name: "ignores nil errors", 230 wantErr: nil, 231 err: nil, 232 }, 233 { 234 name: "returns nil on ErrHermesNoPreviousPromise", 235 wantErr: nil, 236 err: ErrHermesNoPreviousPromise, 237 }, 238 { 239 name: "returns error if something else happens", 240 wantErr: ErrTooManyRequests, 241 err: ErrTooManyRequests, 242 }, 243 { 244 name: "bubbles R recovery errors", 245 deps: HermesPromiseHandlerDeps{ 246 HermesCallerFactory: mockFactory.Get, 247 HermesURLGetter: &mockHermesURLGetter{}, 248 Encryption: &mockEncryptor{ 249 errToReturn: merr, 250 }, 251 }, 252 providerID: identity.FromAddress("0x0"), 253 wantErr: merr, 254 err: HermesErrorResponse{ 255 c: ErrNeedsRRecovery, 256 }, 257 }, 258 } 259 for _, tt := range tests { 260 t.Run(tt.name, func(t *testing.T) { 261 aph := &HermesPromiseHandler{ 262 deps: tt.deps, 263 } 264 err := aph.handleHermesError(tt.err, tt.providerID, tt.chainID, tt.hermesID) 265 if tt.wantErr == nil { 266 assert.NoError(t, err, tt.name) 267 } else { 268 log.Debug().Msgf("%v", err) 269 assert.True(t, errors.Is(err, tt.wantErr), tt.name) 270 } 271 }) 272 } 273 } 274 275 type mockFeeProvider struct { 276 toReturn registry.FeesResponse 277 errToReturn error 278 } 279 280 func (mfp *mockFeeProvider) FetchSettleFees(chainID int64) (registry.FeesResponse, error) { 281 return mfp.toReturn, mfp.errToReturn 282 } 283 284 type mockHermesCallerFactory struct { 285 errToReturn error 286 } 287 288 func (mhcf *mockHermesCallerFactory) Get(url string) HermesHTTPRequester { 289 return &mockHermesCaller{ 290 errToReturn: mhcf.errToReturn, 291 } 292 } 293 294 type mockHermesURLGetter struct { 295 errToReturn error 296 urlToReturn string 297 } 298 299 func (mhug *mockHermesURLGetter) GetHermesURL(chainID int64, address common.Address) (string, error) { 300 return mhug.urlToReturn, mhug.errToReturn 301 }