blob: eb773bddb9a4dcf7f2cc02602f7afd83653c86f6 [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 Wilson5bf6f662014-09-12 12:31:17 -040023func ExtractSingleInts(page Page) ([]int, error) {
24 var response struct {
25 Ints []int `mapstructure:"ints"`
26 }
Ash Wilson64d67b22014-09-05 13:04:12 -040027
Ash Wilson75eae572014-09-12 12:34:21 -040028 err := mapstructure.Decode(page.(SinglePage).Body, &response)
Ash Wilson5bf6f662014-09-12 12:31:17 -040029 if err != nil {
30 return nil, err
31 }
Ash Wilsonb110fc92014-09-08 13:54:59 -040032
Ash Wilson5bf6f662014-09-12 12:31:17 -040033 return response.Ints, nil
Ash Wilson64d67b22014-09-05 13:04:12 -040034}
35
Ash Wilsone30b76b2014-09-12 08:36:17 -040036func setupSinglePaged() Pager {
Ash Wilson4bf4fac2014-09-15 09:16:13 -040037 testhelper.SetupHTTP()
38 client := createClient()
39
40 testhelper.Mux.HandleFunc("/only", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson993cf322014-09-15 14:34:12 -040041 w.Header().Add("Content-Type", "application/json")
Ash Wilson4bf4fac2014-09-15 09:16:13 -040042 fmt.Fprintf(w, `{ "ints": [1, 2, 3] }`)
Ash Wilsone30b76b2014-09-12 08:36:17 -040043 })
Ash Wilson4bf4fac2014-09-15 09:16:13 -040044
Ash Wilson5a25f542014-09-15 15:43:20 -040045 countPage := func(p Page) (int, error) {
46 is, err := ExtractSingleInts(p)
47 if err != nil {
48 return 0, err
49 }
50 return len(is), nil
51 }
52
53 return NewSinglePager(client, testhelper.Server.URL+"/only", countPage)
Ash Wilson64d67b22014-09-05 13:04:12 -040054}
55
56func TestEnumerateSinglePaged(t *testing.T) {
57 callCount := 0
Ash Wilson4bf4fac2014-09-15 09:16:13 -040058 pager := setupSinglePaged()
59 defer testhelper.TeardownHTTP()
60
61 err := pager.EachPage(func(page Page) (bool, error) {
Ash Wilson64d67b22014-09-05 13:04:12 -040062 callCount++
63
64 expected := []int{1, 2, 3}
Ash Wilson5bf6f662014-09-12 12:31:17 -040065 actual, err := ExtractSingleInts(page)
66 if err != nil {
Ash Wilson6b35e502014-09-12 15:15:23 -040067 return false, err
Ash Wilson5bf6f662014-09-12 12:31:17 -040068 }
Ash Wilson64d67b22014-09-05 13:04:12 -040069 if !reflect.DeepEqual(expected, actual) {
70 t.Errorf("Expected %v, but was %v", expected, actual)
71 }
Ash Wilson6b35e502014-09-12 15:15:23 -040072 return true, nil
Ash Wilson64d67b22014-09-05 13:04:12 -040073 })
Ash Wilsone30b76b2014-09-12 08:36:17 -040074 if err != nil {
75 t.Fatalf("Unexpected error calling EachPage: %v", err)
76 }
Ash Wilson64d67b22014-09-05 13:04:12 -040077
78 if callCount != 1 {
79 t.Errorf("Callback was invoked %d times", callCount)
80 }
81}
82
Ash Wilson64d67b22014-09-05 13:04:12 -040083// LinkedPager sample and test cases.
84
Ash Wilson5bf6f662014-09-12 12:31:17 -040085func ExtractLinkedInts(page Page) ([]int, error) {
86 var response struct {
87 Ints []int `mapstructure:"ints"`
Ash Wilsone30b76b2014-09-12 08:36:17 -040088 }
Ash Wilsonb110fc92014-09-08 13:54:59 -040089
Ash Wilson583dc732014-09-12 13:30:05 -040090 err := mapstructure.Decode(page.(LinkedPage).Body, &response)
Ash Wilson5bf6f662014-09-12 12:31:17 -040091 if err != nil {
92 return nil, err
Ash Wilsonb110fc92014-09-08 13:54:59 -040093 }
Ash Wilson5bf6f662014-09-12 12:31:17 -040094
95 return response.Ints, nil
Ash Wilsonb110fc92014-09-08 13:54:59 -040096}
97
Ash Wilson5bf6f662014-09-12 12:31:17 -040098func createLinked(t *testing.T) Pager {
Ash Wilson4bf4fac2014-09-15 09:16:13 -040099 testhelper.SetupHTTP()
100
101 testhelper.Mux.HandleFunc("/page1", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson993cf322014-09-15 14:34:12 -0400102 w.Header().Add("Content-Type", "application/json")
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400103 fmt.Fprintf(w, `{ "ints": [1, 2, 3], "links": { "next": "%s/page2" } }`, testhelper.Server.URL)
Ash Wilson64d67b22014-09-05 13:04:12 -0400104 })
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400105
106 testhelper.Mux.HandleFunc("/page2", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson993cf322014-09-15 14:34:12 -0400107 w.Header().Add("Content-Type", "application/json")
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400108 fmt.Fprintf(w, `{ "ints": [4, 5, 6], "links": { "next": "%s/page3" } }`, testhelper.Server.URL)
109 })
110
111 testhelper.Mux.HandleFunc("/page3", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson993cf322014-09-15 14:34:12 -0400112 w.Header().Add("Content-Type", "application/json")
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400113 fmt.Fprintf(w, `{ "ints": [7, 8, 9], "links": { "next": null } }`)
114 })
115
116 client := createClient()
117
Ash Wilson5a25f542014-09-15 15:43:20 -0400118 countPage := func(p Page) (int, error) {
119 is, err := ExtractLinkedInts(p)
120 if err != nil {
121 return 0, err
122 }
123 return len(is), nil
124 }
125
126 return NewLinkedPager(client, testhelper.Server.URL+"/page1", countPage)
Ash Wilson64d67b22014-09-05 13:04:12 -0400127}
128
129func TestEnumerateLinked(t *testing.T) {
Ash Wilson5bf6f662014-09-12 12:31:17 -0400130 pager := createLinked(t)
Ash Wilson4bf4fac2014-09-15 09:16:13 -0400131 defer testhelper.TeardownHTTP()
Ash Wilson64d67b22014-09-05 13:04:12 -0400132
133 callCount := 0
Ash Wilson6b35e502014-09-12 15:15:23 -0400134 err := pager.EachPage(func(page Page) (bool, error) {
Ash Wilson5bf6f662014-09-12 12:31:17 -0400135 actual, err := ExtractLinkedInts(page)
136 if err != nil {
Ash Wilson6b35e502014-09-12 15:15:23 -0400137 return false, err
Ash Wilson5bf6f662014-09-12 12:31:17 -0400138 }
139
Ash Wilson64d67b22014-09-05 13:04:12 -0400140 t.Logf("Handler invoked with %v", actual)
141
142 var expected []int
143 switch callCount {
144 case 0:
145 expected = []int{1, 2, 3}
146 case 1:
147 expected = []int{4, 5, 6}
148 case 2:
149 expected = []int{7, 8, 9}
150 default:
151 t.Fatalf("Unexpected call count: %d", callCount)
Ash Wilson6b35e502014-09-12 15:15:23 -0400152 return false, nil
Ash Wilson64d67b22014-09-05 13:04:12 -0400153 }
154
155 if !reflect.DeepEqual(expected, actual) {
156 t.Errorf("Call %d: Expected %#v, but was %#v", callCount, expected, actual)
157 }
158
159 callCount++
Ash Wilson6b35e502014-09-12 15:15:23 -0400160 return true, nil
Ash Wilson64d67b22014-09-05 13:04:12 -0400161 })
162 if err != nil {
163 t.Errorf("Unexpected error for page iteration: %v", err)
164 }
165
166 if callCount != 3 {
167 t.Errorf("Expected 3 calls, but was %d", callCount)
168 }
169}
Ash Wilson993cf322014-09-15 14:34:12 -0400170
171func createMarkerPaged(t *testing.T) Pager {
172 testhelper.SetupHTTP()
173
174 testhelper.Mux.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
175 r.ParseForm()
176 ms := r.Form["marker"]
177 switch {
178 case len(ms) == 0:
179 fmt.Fprintf(w, "aaa\nbbb\nccc")
180 case len(ms) == 1 && ms[0] == "ccc":
181 fmt.Fprintf(w, "ddd\neee\nfff")
182 case len(ms) == 1 && ms[0] == "fff":
183 fmt.Fprintf(w, "ggg\nhhh\niii")
184 case len(ms) == 1 && ms[0] == "iii":
185 w.WriteHeader(http.StatusNoContent)
186 default:
187 t.Errorf("Request with unexpected marker: [%v]", ms)
188 }
189 })
190
191 client := createClient()
192
Ash Wilson5a25f542014-09-15 15:43:20 -0400193 lastMark := func(p Page) (string, error) {
Ash Wilson993cf322014-09-15 14:34:12 -0400194 items, err := ExtractMarkerStrings(p)
195 if err != nil {
196 return "", err
197 }
198 return items[len(items)-1], nil
Ash Wilson5a25f542014-09-15 15:43:20 -0400199 }
200
201 countPage := func(p Page) (int, error) {
202 items, err := ExtractMarkerStrings(p)
203 if err != nil {
204 return 0, err
205 }
206 fmt.Printf("Counting items [%#v] = [%d]\n", items, len(items))
207 return len(items), nil
208 }
209
210 return NewMarkerPager(client, testhelper.Server.URL+"/page", lastMark, countPage)
Ash Wilson993cf322014-09-15 14:34:12 -0400211}
212
213func ExtractMarkerStrings(page Page) ([]string, error) {
214 content := page.(MarkerPage).Body.([]uint8)
Ash Wilson5a25f542014-09-15 15:43:20 -0400215 parts := strings.Split(string(content), "\n")
216 results := make([]string, 0, len(parts))
217 for _, part := range parts {
218 if len(part) > 0 {
219 results = append(results, part)
220 }
221 }
222 return results, nil
Ash Wilson993cf322014-09-15 14:34:12 -0400223}
224
225func TestEnumerateMarker(t *testing.T) {
226 pager := createMarkerPaged(t)
227 defer testhelper.TeardownHTTP()
228
229 callCount := 0
230 err := pager.EachPage(func(page Page) (bool, error) {
231 actual, err := ExtractMarkerStrings(page)
232 if err != nil {
233 return false, err
234 }
235
236 t.Logf("Handler invoked with %v", actual)
237
238 var expected []string
239 switch callCount {
240 case 0:
241 expected = []string{"aaa", "bbb", "ccc"}
242 case 1:
243 expected = []string{"ddd", "eee", "fff"}
244 case 2:
245 expected = []string{"ggg", "hhh", "iii"}
246 default:
247 t.Fatalf("Unexpected call count: %d", callCount)
248 return false, nil
249 }
250
251 testhelper.CheckDeepEquals(t, expected, actual)
252
253 callCount++
254 return true, nil
255 })
256 testhelper.AssertNoErr(t, err)
257 testhelper.AssertEquals(t, callCount, 3)
258}