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// NewBodyClose creates a new instance of Body. 41func NewBodyClose(s string) *Body { 42 return &Body{s: s} 43} 44 45// Read reads into the passed byte slice and returns the bytes read. 46func (body *Body) Read(b []byte) (n int, err error) { 47 if !body.IsOpen() { 48 return 0, fmt.Errorf("ERROR: Body has been closed") 49 } 50 if len(body.b) == 0 { 51 return 0, io.EOF 52 } 53 n = copy(b, body.b) 54 body.b = body.b[n:] 55 return n, nil 56} 57 58// Close closes the body. 59func (body *Body) Close() error { 60 if body.isOpen { 61 body.isOpen = false 62 body.closeAttempts++ 63 } 64 return nil 65} 66 67// CloseAttempts returns the number of times Close was called. 68func (body *Body) CloseAttempts() int { 69 return body.closeAttempts 70} 71 72// IsOpen returns true if the Body has not been closed, false otherwise. 73func (body *Body) IsOpen() bool { 74 return body.isOpen 75} 76 77func (body *Body) reset() *Body { 78 body.isOpen = true 79 body.b = []byte(body.s) 80 return body 81} 82 83// Length returns the number of bytes in the body. 84func (body *Body) Length() int64 { 85 if body == nil { 86 return 0 87 } 88 return int64(len(body.b)) 89} 90 91type response struct { 92 r *http.Response 93 e error 94 d time.Duration 95} 96 97// Sender implements a simple null sender. 98type Sender struct { 99 attempts int 100 responses []response 101 numResponses int 102 repeatResponse []int 103 err error 104 repeatError int 105 emitErrorAfter int 106} 107 108// NewSender creates a new instance of Sender. 109func NewSender() *Sender { 110 return &Sender{} 111} 112 113// Do accepts the passed request and, based on settings, emits a response and possible error. 114func (c *Sender) Do(r *http.Request) (resp *http.Response, err error) { 115 c.attempts++ 116 117 if len(c.responses) > 0 { 118 resp = c.responses[0].r 119 if resp != nil { 120 if b, ok := resp.Body.(*Body); ok { 121 b.reset() 122 } 123 } else { 124 err = c.responses[0].e 125 } 126 time.Sleep(c.responses[0].d) 127 c.repeatResponse[0]-- 128 if c.repeatResponse[0] == 0 { 129 c.responses = c.responses[1:] 130 c.repeatResponse = c.repeatResponse[1:] 131 } 132 } else { 133 resp = NewResponse() 134 } 135 if resp != nil { 136 resp.Request = r 137 } 138 139 if c.emitErrorAfter > 0 { 140 c.emitErrorAfter-- 141 } else if c.err != nil { 142 err = c.err 143 c.repeatError-- 144 if c.repeatError == 0 { 145 c.err = nil 146 } 147 } 148 149 return 150} 151 152// AppendResponse adds the passed http.Response to the response stack. 153func (c *Sender) AppendResponse(resp *http.Response) { 154 c.AppendAndRepeatResponse(resp, 1) 155} 156 157// AppendResponseWithDelay adds the passed http.Response to the response stack with the specified delay. 158func (c *Sender) AppendResponseWithDelay(resp *http.Response, delay time.Duration) { 159 c.AppendAndRepeatResponseWithDelay(resp, delay, 1) 160} 161 162// AppendAndRepeatResponse adds the passed http.Response to the response stack along with a 163// repeat count. A negative repeat count will return the response for all remaining calls to Do. 164func (c *Sender) AppendAndRepeatResponse(resp *http.Response, repeat int) { 165 c.appendAndRepeat(response{r: resp}, repeat) 166} 167 168// AppendAndRepeatResponseWithDelay adds the passed http.Response to the response stack with the specified 169// delay along with a repeat count. A negative repeat count will return the response for all remaining calls to Do. 170func (c *Sender) AppendAndRepeatResponseWithDelay(resp *http.Response, delay time.Duration, repeat int) { 171 c.appendAndRepeat(response{r: resp, d: delay}, repeat) 172} 173 174// AppendError adds the passed error to the response stack. 175func (c *Sender) AppendError(err error) { 176 c.AppendAndRepeatError(err, 1) 177} 178 179// AppendAndRepeatError adds the passed error to the response stack along with a repeat 180// count. A negative repeat count will return the response for all remaining calls to Do. 181func (c *Sender) AppendAndRepeatError(err error, repeat int) { 182 c.appendAndRepeat(response{e: err}, repeat) 183} 184 185func (c *Sender) appendAndRepeat(resp response, repeat int) { 186 if c.responses == nil { 187 c.responses = []response{resp} 188 c.repeatResponse = []int{repeat} 189 } else { 190 c.responses = append(c.responses, resp) 191 c.repeatResponse = append(c.repeatResponse, repeat) 192 } 193 c.numResponses++ 194} 195 196// Attempts returns the number of times Do was called. 197func (c *Sender) Attempts() int { 198 return c.attempts 199} 200 201// SetError sets the error Do should return. 202func (c *Sender) SetError(err error) { 203 c.SetAndRepeatError(err, 1) 204} 205 206// SetAndRepeatError sets the error Do should return and how many calls to Do will return the error. 207// A negative repeat value will return the error for all remaining calls to Do. 208func (c *Sender) SetAndRepeatError(err error, repeat int) { 209 c.err = err 210 c.repeatError = repeat 211} 212 213// SetEmitErrorAfter sets the number of attempts to be made before errors are emitted. 214func (c *Sender) SetEmitErrorAfter(ea int) { 215 c.emitErrorAfter = ea 216} 217 218// NumResponses returns the number of responses that have been added to the sender. 219func (c *Sender) NumResponses() int { 220 return c.numResponses 221} 222 223// T is a simple testing struct. 224type T struct { 225 Name string `json:"name" xml:"Name"` 226 Age int `json:"age" xml:"Age"` 227} 228