1/* 2Package mocks provides mocks and helpers used in testing. 3*/ 4package mocks 5 6// Copyright 2017 Microsoft Corporation 7// 8// Licensed under the Apache License, Version 2.0 (the "License"); 9// you may not use this file except in compliance with the License. 10// You may obtain a copy of the License at 11// 12// http://www.apache.org/licenses/LICENSE-2.0 13// 14// Unless required by applicable law or agreed to in writing, software 15// distributed under the License is distributed on an "AS IS" BASIS, 16// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17// See the License for the specific language governing permissions and 18// limitations under the License. 19 20import ( 21 "fmt" 22 "io" 23 "net/http" 24 "time" 25) 26 27// Body implements acceptable body over a string. 28type Body struct { 29 s string 30 b []byte 31 isOpen bool 32 closeAttempts int 33} 34 35// NewBody creates a new instance of Body. 36func NewBody(s string) *Body { 37 return (&Body{s: s}).reset() 38} 39 40// NewBodyWithBytes creates a new instance of Body. 41func NewBodyWithBytes(b []byte) *Body { 42 return &Body{ 43 b: b, 44 isOpen: true, 45 } 46} 47 48// NewBodyClose creates a new instance of Body. 49func NewBodyClose(s string) *Body { 50 return &Body{s: s} 51} 52 53// Read reads into the passed byte slice and returns the bytes read. 54func (body *Body) Read(b []byte) (n int, err error) { 55 if !body.IsOpen() { 56 return 0, fmt.Errorf("ERROR: Body has been closed") 57 } 58 if len(body.b) == 0 { 59 return 0, io.EOF 60 } 61 n = copy(b, body.b) 62 body.b = body.b[n:] 63 return n, nil 64} 65 66// Close closes the body. 67func (body *Body) Close() error { 68 if body.isOpen { 69 body.isOpen = false 70 body.closeAttempts++ 71 } 72 return nil 73} 74 75// CloseAttempts returns the number of times Close was called. 76func (body *Body) CloseAttempts() int { 77 return body.closeAttempts 78} 79 80// IsOpen returns true if the Body has not been closed, false otherwise. 81func (body *Body) IsOpen() bool { 82 return body.isOpen 83} 84 85func (body *Body) reset() *Body { 86 body.isOpen = true 87 body.b = []byte(body.s) 88 return body 89} 90 91// Length returns the number of bytes in the body. 92func (body *Body) Length() int64 { 93 if body == nil { 94 return 0 95 } 96 return int64(len(body.b)) 97} 98 99type response struct { 100 r *http.Response 101 e error 102 d time.Duration 103} 104 105// Sender implements a simple null sender. 106type Sender struct { 107 attempts int 108 responses []response 109 numResponses int 110 repeatResponse []int 111 err error 112 repeatError int 113 emitErrorAfter int 114} 115 116// NewSender creates a new instance of Sender. 117func NewSender() *Sender { 118 return &Sender{} 119} 120 121// Do accepts the passed request and, based on settings, emits a response and possible error. 122func (c *Sender) Do(r *http.Request) (resp *http.Response, err error) { 123 c.attempts++ 124 125 if len(c.responses) > 0 { 126 resp = c.responses[0].r 127 if resp != nil { 128 if b, ok := resp.Body.(*Body); ok { 129 b.reset() 130 } 131 } else { 132 err = c.responses[0].e 133 } 134 select { 135 case <-time.After(c.responses[0].d): 136 // do nothing 137 case <-r.Context().Done(): 138 err = r.Context().Err() 139 return 140 } 141 c.repeatResponse[0]-- 142 if c.repeatResponse[0] == 0 { 143 c.responses = c.responses[1:] 144 c.repeatResponse = c.repeatResponse[1:] 145 } 146 } else { 147 resp = NewResponse() 148 } 149 if resp != nil { 150 resp.Request = r 151 } 152 153 if c.emitErrorAfter > 0 { 154 c.emitErrorAfter-- 155 } else if c.err != nil { 156 err = c.err 157 c.repeatError-- 158 if c.repeatError == 0 { 159 c.err = nil 160 } 161 } 162 163 return 164} 165 166// AppendResponse adds the passed http.Response to the response stack. 167func (c *Sender) AppendResponse(resp *http.Response) { 168 c.AppendAndRepeatResponse(resp, 1) 169} 170 171// AppendResponseWithDelay adds the passed http.Response to the response stack with the specified delay. 172func (c *Sender) AppendResponseWithDelay(resp *http.Response, delay time.Duration) { 173 c.AppendAndRepeatResponseWithDelay(resp, delay, 1) 174} 175 176// AppendAndRepeatResponse adds the passed http.Response to the response stack along with a 177// repeat count. A negative repeat count will return the response for all remaining calls to Do. 178func (c *Sender) AppendAndRepeatResponse(resp *http.Response, repeat int) { 179 c.appendAndRepeat(response{r: resp}, repeat) 180} 181 182// AppendAndRepeatResponseWithDelay adds the passed http.Response to the response stack with the specified 183// delay along with a repeat count. A negative repeat count will return the response for all remaining calls to Do. 184func (c *Sender) AppendAndRepeatResponseWithDelay(resp *http.Response, delay time.Duration, repeat int) { 185 c.appendAndRepeat(response{r: resp, d: delay}, repeat) 186} 187 188// AppendError adds the passed error to the response stack. 189func (c *Sender) AppendError(err error) { 190 c.AppendAndRepeatError(err, 1) 191} 192 193// AppendAndRepeatError adds the passed error to the response stack along with a repeat 194// count. A negative repeat count will return the response for all remaining calls to Do. 195func (c *Sender) AppendAndRepeatError(err error, repeat int) { 196 c.appendAndRepeat(response{e: err}, repeat) 197} 198 199func (c *Sender) appendAndRepeat(resp response, repeat int) { 200 if c.responses == nil { 201 c.responses = []response{resp} 202 c.repeatResponse = []int{repeat} 203 } else { 204 c.responses = append(c.responses, resp) 205 c.repeatResponse = append(c.repeatResponse, repeat) 206 } 207 c.numResponses++ 208} 209 210// Attempts returns the number of times Do was called. 211func (c *Sender) Attempts() int { 212 return c.attempts 213} 214 215// SetError sets the error Do should return. 216func (c *Sender) SetError(err error) { 217 c.SetAndRepeatError(err, 1) 218} 219 220// SetAndRepeatError sets the error Do should return and how many calls to Do will return the error. 221// A negative repeat value will return the error for all remaining calls to Do. 222func (c *Sender) SetAndRepeatError(err error, repeat int) { 223 c.err = err 224 c.repeatError = repeat 225} 226 227// SetEmitErrorAfter sets the number of attempts to be made before errors are emitted. 228func (c *Sender) SetEmitErrorAfter(ea int) { 229 c.emitErrorAfter = ea 230} 231 232// NumResponses returns the number of responses that have been added to the sender. 233func (c *Sender) NumResponses() int { 234 return c.numResponses 235} 236 237// T is a simple testing struct. 238type T struct { 239 Name string `json:"name" xml:"Name"` 240 Age int `json:"age" xml:"Age"` 241} 242