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 time.Sleep(c.responses[0].d) 135 c.repeatResponse[0]-- 136 if c.repeatResponse[0] == 0 { 137 c.responses = c.responses[1:] 138 c.repeatResponse = c.repeatResponse[1:] 139 } 140 } else { 141 resp = NewResponse() 142 } 143 if resp != nil { 144 resp.Request = r 145 } 146 147 if c.emitErrorAfter > 0 { 148 c.emitErrorAfter-- 149 } else if c.err != nil { 150 err = c.err 151 c.repeatError-- 152 if c.repeatError == 0 { 153 c.err = nil 154 } 155 } 156 157 return 158} 159 160// AppendResponse adds the passed http.Response to the response stack. 161func (c *Sender) AppendResponse(resp *http.Response) { 162 c.AppendAndRepeatResponse(resp, 1) 163} 164 165// AppendResponseWithDelay adds the passed http.Response to the response stack with the specified delay. 166func (c *Sender) AppendResponseWithDelay(resp *http.Response, delay time.Duration) { 167 c.AppendAndRepeatResponseWithDelay(resp, delay, 1) 168} 169 170// AppendAndRepeatResponse adds the passed http.Response to the response stack along with a 171// repeat count. A negative repeat count will return the response for all remaining calls to Do. 172func (c *Sender) AppendAndRepeatResponse(resp *http.Response, repeat int) { 173 c.appendAndRepeat(response{r: resp}, repeat) 174} 175 176// AppendAndRepeatResponseWithDelay adds the passed http.Response to the response stack with the specified 177// delay along with a repeat count. A negative repeat count will return the response for all remaining calls to Do. 178func (c *Sender) AppendAndRepeatResponseWithDelay(resp *http.Response, delay time.Duration, repeat int) { 179 c.appendAndRepeat(response{r: resp, d: delay}, repeat) 180} 181 182// AppendError adds the passed error to the response stack. 183func (c *Sender) AppendError(err error) { 184 c.AppendAndRepeatError(err, 1) 185} 186 187// AppendAndRepeatError adds the passed error to the response stack along with a repeat 188// count. A negative repeat count will return the response for all remaining calls to Do. 189func (c *Sender) AppendAndRepeatError(err error, repeat int) { 190 c.appendAndRepeat(response{e: err}, repeat) 191} 192 193func (c *Sender) appendAndRepeat(resp response, repeat int) { 194 if c.responses == nil { 195 c.responses = []response{resp} 196 c.repeatResponse = []int{repeat} 197 } else { 198 c.responses = append(c.responses, resp) 199 c.repeatResponse = append(c.repeatResponse, repeat) 200 } 201 c.numResponses++ 202} 203 204// Attempts returns the number of times Do was called. 205func (c *Sender) Attempts() int { 206 return c.attempts 207} 208 209// SetError sets the error Do should return. 210func (c *Sender) SetError(err error) { 211 c.SetAndRepeatError(err, 1) 212} 213 214// SetAndRepeatError sets the error Do should return and how many calls to Do will return the error. 215// A negative repeat value will return the error for all remaining calls to Do. 216func (c *Sender) SetAndRepeatError(err error, repeat int) { 217 c.err = err 218 c.repeatError = repeat 219} 220 221// SetEmitErrorAfter sets the number of attempts to be made before errors are emitted. 222func (c *Sender) SetEmitErrorAfter(ea int) { 223 c.emitErrorAfter = ea 224} 225 226// NumResponses returns the number of responses that have been added to the sender. 227func (c *Sender) NumResponses() int { 228 return c.numResponses 229} 230 231// T is a simple testing struct. 232type T struct { 233 Name string `json:"name" xml:"Name"` 234 Age int `json:"age" xml:"Age"` 235} 236