go.uber.org/yarpc@v1.72.1/yarpctest/fake_peer.go (about) 1 // Copyright (c) 2022 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package yarpctest 22 23 import ( 24 "sync" 25 26 "go.uber.org/yarpc/api/peer" 27 ) 28 29 // FakePeer is a fake peer with an identifier. 30 type FakePeer struct { 31 id peer.Identifier 32 33 // mutable 34 lock sync.RWMutex 35 // subscribers needs to be modified under lock in FakeTransport 36 subscribers []peer.Subscriber 37 status peer.Status 38 } 39 40 // Identifier returns the fake peer identifier. 41 func (p *FakePeer) Identifier() string { 42 return p.id.Identifier() 43 } 44 45 // String returns a humane representation of the peer and its status for debugging. 46 func (p *FakePeer) String() string { 47 p.lock.RLock() 48 defer p.lock.RUnlock() 49 50 return p.id.Identifier() + ":" + p.status.String() 51 } 52 53 // Status returns the fake peer status. 54 func (p *FakePeer) Status() peer.Status { 55 p.lock.RLock() 56 defer p.lock.RUnlock() 57 58 return p.status 59 } 60 61 // StartRequest increments pending request count. 62 func (p *FakePeer) StartRequest() { 63 p.lock.Lock() 64 defer p.lock.Unlock() 65 66 p.status.PendingRequestCount++ 67 } 68 69 // EndRequest decrements pending request count. 70 func (p *FakePeer) EndRequest() { 71 p.lock.Lock() 72 defer p.lock.Unlock() 73 74 p.status.PendingRequestCount-- 75 } 76 77 func (p *FakePeer) simulateConnect() { 78 p.simulateStatusChange(peer.Available) 79 } 80 81 func (p *FakePeer) simulateDisconnect() { 82 p.simulateStatusChange(peer.Unavailable) 83 } 84 85 func (p *FakePeer) simulateStatusChange(status peer.ConnectionStatus) { 86 for _, sub := range p.prepareStatusChange(status) { 87 sub.NotifyStatusChanged(p.id) 88 } 89 } 90 91 func (p *FakePeer) prepareStatusChange(status peer.ConnectionStatus) []peer.Subscriber { 92 p.lock.Lock() 93 defer p.lock.Unlock() 94 95 p.status.ConnectionStatus = status 96 subscribers := make([]peer.Subscriber, len(p.subscribers)) 97 copy(subscribers, p.subscribers) 98 return subscribers 99 } 100 101 func (p *FakePeer) subscribe(ps peer.Subscriber) { 102 p.lock.Lock() 103 defer p.lock.Unlock() 104 105 p.subscribers = append(p.subscribers, ps) 106 } 107 108 func (p *FakePeer) unsubscribe(ps peer.Subscriber) int { 109 p.lock.Lock() 110 defer p.lock.Unlock() 111 112 subscribers, count := filterSubscriber(p.subscribers, ps) 113 p.subscribers = subscribers 114 return count 115 } 116 117 func filterSubscriber(subs []peer.Subscriber, ps peer.Subscriber) ([]peer.Subscriber, int) { 118 res := make([]peer.Subscriber, 0, len(subs)) 119 count := 0 120 for _, sub := range subs { 121 if sub != ps { 122 res = append(res, sub) 123 } else { 124 count++ 125 } 126 } 127 return res, count 128 }