go.uber.org/yarpc@v1.72.1/peer/abstractpeer/peeraction_test.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 abstractpeer 22 23 import ( 24 "fmt" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/stretchr/testify/assert" 30 "go.uber.org/yarpc/api/peer" 31 "go.uber.org/yarpc/internal/testtime" 32 ) 33 34 // There are no actual tests in this file, it contains a series of helper methods 35 // for testing abstractpeer.Peers 36 37 // Dependences are passed through all the PeerActions in order to pass certain 38 // state in between Actions 39 type Dependencies struct { 40 Subscribers map[string]peer.Subscriber 41 } 42 43 // PeerAction defines actions that can be applied on a abstractpeer.Peer 44 type PeerAction interface { 45 Apply(*testing.T, *Peer, *Dependencies) 46 } 47 48 // StartStopReqAction will run a StartRequest and (optionally) EndRequest 49 type StartStopReqAction struct { 50 Stop bool 51 } 52 53 // Apply will run StartRequest and (optionally) EndRequest 54 func (sa StartStopReqAction) Apply(t *testing.T, p *Peer, d *Dependencies) { 55 p.StartRequest() 56 p.NotifyStatusChanged() 57 if sa.Stop { 58 p.EndRequest() 59 p.NotifyStatusChanged() 60 } 61 } 62 63 // SetStatusAction will run a SetStatus on a Peer 64 type SetStatusAction struct { 65 InputStatus peer.ConnectionStatus 66 } 67 68 // Apply will run SetStatus on the Peer 69 func (sa SetStatusAction) Apply(t *testing.T, p *Peer, d *Dependencies) { 70 p.SetStatus(sa.InputStatus) 71 p.NotifyStatusChanged() 72 73 assert.Equal(t, sa.InputStatus, p.Status().ConnectionStatus) 74 } 75 76 // SubscribeAction will run an Subscribe on a Peer 77 type SubscribeAction struct { 78 // SubscriberID is a unique identifier for a subscriber that is 79 // contained in the Dependencies object passed in Apply 80 SubscriberID string 81 82 // ExpectedSubCount is the number of subscribers on the Peer after 83 // the subscription 84 ExpectedSubCount int 85 } 86 87 // Apply will run Subscribe on a Peer 88 func (sa SubscribeAction) Apply(t *testing.T, p *Peer, d *Dependencies) { 89 sub, ok := d.Subscribers[sa.SubscriberID] 90 assert.True(t, ok, "referenced a subscriberID that does not exist %s", sa.SubscriberID) 91 92 p.Subscribe(sub) 93 94 assert.Equal(t, sa.ExpectedSubCount, p.NumSubscribers()) 95 } 96 97 // UnsubscribeAction will run Unsubscribe on a Peer 98 type UnsubscribeAction struct { 99 // SubscriberID is a unique identifier for a subscriber that is 100 // contained in the Dependencies object passed in Apply 101 SubscriberID string 102 103 // ExpectedErrType is the type of error that is expected to be returned 104 // from Unsubscribe 105 ExpectedErrType error 106 107 // ExpectedSubCount is the number of subscribers on the Peer after 108 // the subscription 109 ExpectedSubCount int 110 } 111 112 // Apply will run Unsubscribe from the Peer and assert on the result 113 func (ua UnsubscribeAction) Apply(t *testing.T, p *Peer, d *Dependencies) { 114 sub, ok := d.Subscribers[ua.SubscriberID] 115 assert.True(t, ok, "referenced a subscriberID that does not exist %s", ua.SubscriberID) 116 117 err := p.Unsubscribe(sub) 118 119 assert.Equal(t, ua.ExpectedSubCount, p.NumSubscribers()) 120 if err != nil { 121 assert.IsType(t, ua.ExpectedErrType, err) 122 } else { 123 assert.Nil(t, ua.ExpectedErrType) 124 } 125 } 126 127 // PeerConcurrentAction will run a series of actions in parallel 128 type PeerConcurrentAction struct { 129 Actions []PeerAction 130 Wait time.Duration 131 } 132 133 // Apply runs all the ConcurrentAction's actions in goroutines with a delay of `Wait` 134 // between each action. Returns when all actions have finished executing 135 func (a PeerConcurrentAction) Apply(t *testing.T, p *Peer, d *Dependencies) { 136 var wg sync.WaitGroup 137 138 wg.Add(len(a.Actions)) 139 for _, action := range a.Actions { 140 go func(ac PeerAction) { 141 defer wg.Done() 142 ac.Apply(t, p, d) 143 }(action) 144 145 if a.Wait > 0 { 146 testtime.Sleep(a.Wait) 147 } 148 } 149 150 wg.Wait() 151 } 152 153 // ApplyPeerActions runs all the PeerActions on the Peer 154 func ApplyPeerActions(t *testing.T, p *Peer, actions []PeerAction, d *Dependencies) { 155 for i, action := range actions { 156 t.Run(fmt.Sprintf("action #%d: %T", i, action), func(t *testing.T) { 157 action.Apply(t, p, d) 158 }) 159 } 160 }