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