blob: 8ce36a22133e772a166b7b539ca8da74f9c4d0ac [file] [log] [blame]
Ash Wilson64d67b22014-09-05 13:04:12 -04001package gophercloud
2
3import (
Ash Wilson4bf4fac2014-09-15 09:16:13 -04004 "fmt"
Ash Wilson64d67b22014-09-05 13:04:12 -04005 "net/http"
6 "reflect"
Ash Wilson993cf322014-09-15 14:34:12 -04007 "strings"
Ash Wilson64d67b22014-09-05 13:04:12 -04008 "testing"
9
Ash Wilson5bf6f662014-09-12 12:31:17 -040010 "github.com/mitchellh/mapstructure"
Ash Wilson4bf4fac2014-09-15 09:16:13 -040011 "github.com/rackspace/gophercloud/testhelper"
Ash Wilson64d67b22014-09-05 13:04:12 -040012)
13
Ash Wilson4bf4fac2014-09-15 09:16:13 -040014func createClient() *ServiceClient {
15 return &ServiceClient{
16 Provider: &ProviderClient{TokenID: "abc123"},
17 Endpoint: testhelper.Endpoint(),
18 }
Ash Wilson5bf6f662014-09-12 12:31:17 -040019}
20
Ash Wilson64d67b22014-09-05 13:04:12 -040021// SinglePage sample and test cases.
22
Ash Wilsonc93fde72014-09-16 10:06:22 -040023type SinglePageResult struct {
24 SinglePageBase
25}
26
27func (r SinglePageResult) IsEmpty() (bool, error) {
28 is, err := ExtractSingleInts(r)
29 if err != nil {
30 return true, err
31 }
32 return len(is) == 0, nil
33}
34
Ash Wilson5bf6f662014-09-12 12:31:17 -040035func ExtractSingleInts(page Page) ([]int, error) {
36 var response struct {
37 Ints []int `mapstructure:"ints"`
38 }
Ash Wilson64d67b22014-09-05 13:04:12 -040039
Ash Wilsonc93fde72014-09-16 10:06:22 -040040 err := mapstructure.Decode(page.(SinglePageResult).Body, &response)
Ash Wilson5bf6f662014-09-12 12:31:17 -040041 if err != nil {
42 return nil, err
43 }
Ash Wilsonb110fc92014-09-08 13:54:59 -040044
Ash Wilson5bf6f662014-09-12 12:31:17 -040045 return response.Ints, nil
Ash Wilson64d67b22014-09-05 13:04:12 -040046}
47
Ash Wilsone30b76b2014-09-12 08:36:17 -040048func setupSinglePaged() Pager {
Ash Wilson4bf4fac2014-09-15 09:16:13 -040049 testhelper.SetupHTTP()
50 client := createClient()
51
52 testhelper.Mux.HandleFunc("/only", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson993cf322014-09-15 14:34:12 -040053 w.Header().Add("Content-Type", "application/json")
Ash Wilson4bf4fac2014-09-15 09:16:13 -040054 fmt.Fprintf(w, `{ "ints": [1, 2, 3] }`)
Ash Wilsone30b76b2014-09-12 08:36:17 -040055 })
Ash Wilson4bf4fac2014-09-15 09:16:13 -040056
Ash Wilsonc93fde72014-09-16 10:06:22 -040057 createPage := func(r LastHTTPResponse) Page {
58 return SinglePageResult{SinglePageBase(r)}
Ash Wilson5a25f542014-09-15 15:43:20 -040059 }
60
Ash Wilsonc93fde72014-09-16 10:06:22 -040061 return NewSinglePager(client, testhelper.Server.URL+"/only", createPage)
Ash Wilson64d67b22014-09-05 13:04:12 -040062}
63
64func TestEnumerateSinglePaged(t *testing.T) {
65 callCount := 0
Ash Wilson4bf4fac2014-09-15 09:16:13 -040066 pager := setupSinglePaged()
67 defer testhelper.TeardownHTTP()
68
69 err := pager.EachPage(func(page Page) (bool, error) {
Ash Wilson64d67b22014-09-05 13:04:12 -040070 callCount++
71
72 expected := []int{1, 2, 3}
Ash Wilson5bf6f662014-09-12 12:31:17 -040073 actual, err := ExtractSingleInts(page)
Ash Wilsonc93fde72014-09-16 10:06:22 -040074 testhelper.AssertNoErr(t, err)
75 testhelper.CheckDeepEquals(t, expected, actual)
Ash Wilson6b35e502014-09-12 15:15:23 -040076 return true, nil
Ash Wilson64d67b22014-09-05 13:04:12 -040077 })
Ash Wilsonc93fde72014-09-16 10:06:22 -040078 testhelper.CheckNoErr(t, err)
79 testhelper.CheckEquals(t, 1, callCount)
Ash Wilson64d67b22014-09-05 13:04:12 -040080}
81
Ash Wilson64d67b22014-09-05 13:04:12 -040082// LinkedPager sample and test cases.
83
Ash Wilsonc93fde72014-09-16 10:06:22 -040084type LinkedPageResult struct {
85 LinkedPageBase
86}
87
88func (r LinkedPageResult) IsEmpty() (bool, error) {
89 is, err := ExtractLinkedInts(r)
90 if err != nil {
91 return true, nil
92 }
93 return len(is) == 0, nil
94}
95
Ash Wilson5bf6f662014-09-12 12:31:17 -040096func ExtractLinkedInts(page Page) ([]int, error) {
97 var response struct {
98 Ints []int `mapstructure:"ints"`
Ash Wilsone30b76b2014-09-12 08:36:17 -040099 }
Ash Wilsonb110fc92014-09-08 13:54:59 -0400100
Ash Wilsonc93fde72014-09-16 10:06:22 -0400101 err := mapstructure.Decode(page.(LinkedPageResult).Body, &response)
Ash Wilson5bf6f662014-09-12 12:31:17 -0400102 if err != nil {
103 return nil, err
Ash Wilsonb110fc92014-09-08 13:54:59 -0400104 }
Ash Wilson5bf6f662014-09-12 12:31:17 -0400105
106 return response.Ints, nil
Ash Wilsonb110fc92014-09-08 13:54:59 -0400107}
108
Ash Wilson5bf6f662014-09-12 12:31:17 -0400109func createLinked(t *testing.T) Pager {
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400110 testhelper.SetupHTTP()
111
112 testhelper.Mux.HandleFunc("/page1", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson993cf322014-09-15 14:34:12 -0400113 w.Header().Add("Content-Type", "application/json")
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400114 fmt.Fprintf(w, `{ "ints": [1, 2, 3], "links": { "next": "%s/page2" } }`, testhelper.Server.URL)
Ash Wilson64d67b22014-09-05 13:04:12 -0400115 })
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400116
117 testhelper.Mux.HandleFunc("/page2", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson993cf322014-09-15 14:34:12 -0400118 w.Header().Add("Content-Type", "application/json")
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400119 fmt.Fprintf(w, `{ "ints": [4, 5, 6], "links": { "next": "%s/page3" } }`, testhelper.Server.URL)
120 })
121
122 testhelper.Mux.HandleFunc("/page3", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson993cf322014-09-15 14:34:12 -0400123 w.Header().Add("Content-Type", "application/json")
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400124 fmt.Fprintf(w, `{ "ints": [7, 8, 9], "links": { "next": null } }`)
125 })
126
127 client := createClient()
128
Ash Wilsonc93fde72014-09-16 10:06:22 -0400129 createPage := func(r LastHTTPResponse) Page {
130 return LinkedPageResult{LinkedPageBase(r)}
Ash Wilson5a25f542014-09-15 15:43:20 -0400131 }
132
Ash Wilsonc93fde72014-09-16 10:06:22 -0400133 return NewLinkedPager(client, testhelper.Server.URL+"/page1", createPage)
Ash Wilson64d67b22014-09-05 13:04:12 -0400134}
135
136func TestEnumerateLinked(t *testing.T) {
Ash Wilson5bf6f662014-09-12 12:31:17 -0400137 pager := createLinked(t)
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400138 defer testhelper.TeardownHTTP()
Ash Wilson64d67b22014-09-05 13:04:12 -0400139
140 callCount := 0
Ash Wilson6b35e502014-09-12 15:15:23 -0400141 err := pager.EachPage(func(page Page) (bool, error) {
Ash Wilson5bf6f662014-09-12 12:31:17 -0400142 actual, err := ExtractLinkedInts(page)
143 if err != nil {
Ash Wilson6b35e502014-09-12 15:15:23 -0400144 return false, err
Ash Wilson5bf6f662014-09-12 12:31:17 -0400145 }
146
Ash Wilson64d67b22014-09-05 13:04:12 -0400147 t.Logf("Handler invoked with %v", actual)
148
149 var expected []int
150 switch callCount {
151 case 0:
152 expected = []int{1, 2, 3}
153 case 1:
154 expected = []int{4, 5, 6}
155 case 2:
156 expected = []int{7, 8, 9}
157 default:
158 t.Fatalf("Unexpected call count: %d", callCount)
Ash Wilson6b35e502014-09-12 15:15:23 -0400159 return false, nil
Ash Wilson64d67b22014-09-05 13:04:12 -0400160 }
161
162 if !reflect.DeepEqual(expected, actual) {
163 t.Errorf("Call %d: Expected %#v, but was %#v", callCount, expected, actual)
164 }
165
166 callCount++
Ash Wilson6b35e502014-09-12 15:15:23 -0400167 return true, nil
Ash Wilson64d67b22014-09-05 13:04:12 -0400168 })
169 if err != nil {
170 t.Errorf("Unexpected error for page iteration: %v", err)
171 }
172
173 if callCount != 3 {
174 t.Errorf("Expected 3 calls, but was %d", callCount)
175 }
176}
Ash Wilson993cf322014-09-15 14:34:12 -0400177
Ash Wilsonc93fde72014-09-16 10:06:22 -0400178// MarkerPager sample and test cases.
179
180type MarkerPageResult struct {
181 MarkerPageBase
182}
183
184func (r MarkerPageResult) IsEmpty() (bool, error) {
185 results, err := ExtractMarkerStrings(r)
186 if err != nil {
187 return true, err
188 }
189 return len(results) == 0, err
190}
191
192func (r MarkerPageResult) LastMark() (string, error) {
193 results, err := ExtractMarkerStrings(r)
194 if err != nil {
195 return "", err
196 }
197 if len(results) == 0 {
198 return "", nil
199 }
200 return results[len(results)-1], nil
201}
202
Ash Wilson993cf322014-09-15 14:34:12 -0400203func createMarkerPaged(t *testing.T) Pager {
204 testhelper.SetupHTTP()
205
206 testhelper.Mux.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
207 r.ParseForm()
208 ms := r.Form["marker"]
209 switch {
210 case len(ms) == 0:
211 fmt.Fprintf(w, "aaa\nbbb\nccc")
212 case len(ms) == 1 && ms[0] == "ccc":
213 fmt.Fprintf(w, "ddd\neee\nfff")
214 case len(ms) == 1 && ms[0] == "fff":
215 fmt.Fprintf(w, "ggg\nhhh\niii")
216 case len(ms) == 1 && ms[0] == "iii":
217 w.WriteHeader(http.StatusNoContent)
218 default:
219 t.Errorf("Request with unexpected marker: [%v]", ms)
220 }
221 })
222
223 client := createClient()
224
Ash Wilsonc93fde72014-09-16 10:06:22 -0400225 createPage := func(r LastHTTPResponse) MarkerPage {
226 p := MarkerPageResult{MarkerPageBase{LastHTTPResponse: r}}
227 p.MarkerPageBase.Self = p
228 return p
Ash Wilson5a25f542014-09-15 15:43:20 -0400229 }
230
Ash Wilsonc93fde72014-09-16 10:06:22 -0400231 return NewMarkerPager(client, testhelper.Server.URL+"/page", createPage)
Ash Wilson993cf322014-09-15 14:34:12 -0400232}
233
234func ExtractMarkerStrings(page Page) ([]string, error) {
Ash Wilsonc93fde72014-09-16 10:06:22 -0400235 content := page.(MarkerPageResult).Body.([]uint8)
Ash Wilson5a25f542014-09-15 15:43:20 -0400236 parts := strings.Split(string(content), "\n")
237 results := make([]string, 0, len(parts))
238 for _, part := range parts {
239 if len(part) > 0 {
240 results = append(results, part)
241 }
242 }
243 return results, nil
Ash Wilson993cf322014-09-15 14:34:12 -0400244}
245
246func TestEnumerateMarker(t *testing.T) {
247 pager := createMarkerPaged(t)
248 defer testhelper.TeardownHTTP()
249
250 callCount := 0
251 err := pager.EachPage(func(page Page) (bool, error) {
252 actual, err := ExtractMarkerStrings(page)
253 if err != nil {
254 return false, err
255 }
256
257 t.Logf("Handler invoked with %v", actual)
258
259 var expected []string
260 switch callCount {
261 case 0:
262 expected = []string{"aaa", "bbb", "ccc"}
263 case 1:
264 expected = []string{"ddd", "eee", "fff"}
265 case 2:
266 expected = []string{"ggg", "hhh", "iii"}
267 default:
268 t.Fatalf("Unexpected call count: %d", callCount)
269 return false, nil
270 }
271
272 testhelper.CheckDeepEquals(t, expected, actual)
273
274 callCount++
275 return true, nil
276 })
277 testhelper.AssertNoErr(t, err)
278 testhelper.AssertEquals(t, callCount, 3)
279}