Merge lp:~jtv/gwacl/extract-roundtrippers into lp:gwacl
- extract-roundtrippers
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Jeroen T. Vermeulen |
Approved revision: | 94 |
Merged at revision: | 95 |
Proposed branch: | lp:~jtv/gwacl/extract-roundtrippers |
Merge into: | lp:gwacl |
Diff against target: |
700 lines (+335/-291) 7 files modified
storage_base_test.go (+0/-13) storage_test.go (+0/-38) testhelpers_apiobjects.go (+138/-0) testhelpers_factory.go (+49/-0) testhelpers_http.go (+58/-0) testhelpers_misc.go (+16/-240) testhelpers_x509dispatch.go (+74/-0) |
To merge this branch: | bzr merge lp:~jtv/gwacl/extract-roundtrippers |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Raphaël Badin (community) | Approve | ||
Review via email: mp+160590@code.launchpad.net |
Commit message
Extract a bunch of our test helpers into separate files.
Description of the change
The ad-hoc test helpers, and our tests in general, were really getting out of hand. Before I added more crud of my own I thought I'd rearrange what we have a bit first, to make it more maintainable.
Turned out the thing I'll be needing was already in there, under a cryptic name. So good thing I did the cleanup first. It may look as if I'm creating a whole bunch of shared internal API for the package, but actually the visibility of these items doesn't change just because I move them.
We'll have to remember that when working in Go: even an unexported little ad-hoc helper will be globally visible within the package, and may move out to a different file! We have to name and document it as such. In this case, I documented where I could.
There were a few problems with the random-string functions, which aren't really very good for general testing. I doubt we should be exporting these. Yes, it'll be a pain to change all the calls when we start importing them from some reusable test package, but that's probably better than inviting third parties to rely on our test helpers and be stuck with them as public API.
I also re-did the two bool/text conversion functions, which just duplicated existing fmt functionality.
Jeroen
Jeroen T. Vermeulen (jtv) wrote : | # |
> Looks good, a fairly mechanical change so if it compiles, ship it! ;)
Thanks. I tried moving this into a separate directory, but that seemed to require a separate package, which I wasn't prepared to create.
> [0]
>
> === added file 'testhelpers_
> === added file 'testhelpers_
> === renamed file 'test_helpers.go' => 'testhelpers_
> etc…
>
> I seem to remember that Go does not compile files named test_* when not
> running the tests. I cannot find the doc where this is documented though… but
> if it's true, then it would be worth keeping the 'test_' prefix for all these
> files so that they won't be used at all, except when running the tests.
I couldn't find any mention of it, either on golang.org or by searching the internet at large. And actually I'd expect unused, unexported code to be left out of the library anyway given the way dependencies work in Go. Basically, all the information is in the object file, and they went to great lengths to avoid pulling in unneeded dependencies.
In that model it would make perfect sense to strip dead code out of the object file very aggressively. Otherwise you could have an unused function (about which the compiler does not complain!) pulling in any number of unneeded packages. I'd try this out, except we're not currently working at a code scale where it matters. :)
Jeroen
Preview Diff
1 | === modified file 'storage_base_test.go' |
2 | --- storage_base_test.go 2013-04-22 16:00:31 +0000 |
3 | +++ storage_base_test.go 2013-04-24 10:18:32 +0000 |
4 | @@ -257,19 +257,6 @@ |
5 | c.Assert(context.getClient(), Equals, context.client) |
6 | } |
7 | |
8 | -// TestTransport is used as an http.Client.Transport for testing. The only |
9 | -// requirement is that it adhere to the http.RoundTripper interface. |
10 | -type TestTransport struct { |
11 | - Request *http.Request |
12 | - Response *http.Response |
13 | - Error error |
14 | -} |
15 | - |
16 | -func (t *TestTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { |
17 | - t.Request = req |
18 | - return t.Response, t.Error |
19 | -} |
20 | - |
21 | // Convenience factory to create a StorageContext with a random name and |
22 | // random base64-encoded key. |
23 | func makeStorageContext() *StorageContext { |
24 | |
25 | === modified file 'storage_test.go' |
26 | --- storage_test.go 2013-04-22 16:00:31 +0000 |
27 | +++ storage_test.go 2013-04-24 10:18:32 +0000 |
28 | @@ -5,7 +5,6 @@ |
29 | |
30 | import ( |
31 | "bytes" |
32 | - "encoding/base64" |
33 | "fmt" |
34 | "io/ioutil" |
35 | . "launchpad.net/gocheck" |
36 | @@ -13,35 +12,6 @@ |
37 | "net/url" |
38 | ) |
39 | |
40 | -func b64(s string) string { |
41 | - return base64.StdEncoding.EncodeToString([]byte(s)) |
42 | -} |
43 | - |
44 | -type TestTransport2Exchange struct { |
45 | - Request *http.Request |
46 | - Response *http.Response |
47 | - Error error |
48 | -} |
49 | - |
50 | -// TestTransport2 is used as an http.Client.Transport for testing. The only |
51 | -// requirement is that it adhere to the http.RoundTripper interface. |
52 | -type TestTransport2 struct { |
53 | - Exchanges []*TestTransport2Exchange |
54 | - ExchangeCount int |
55 | -} |
56 | - |
57 | -func (t *TestTransport2) AddExchange(response *http.Response, error error) { |
58 | - exchange := TestTransport2Exchange{Response: response, Error: error} |
59 | - t.Exchanges = append(t.Exchanges, &exchange) |
60 | -} |
61 | - |
62 | -func (t *TestTransport2) RoundTrip(req *http.Request) (resp *http.Response, err error) { |
63 | - exchange := t.Exchanges[t.ExchangeCount] |
64 | - t.ExchangeCount += 1 |
65 | - exchange.Request = req |
66 | - return exchange.Response, exchange.Error |
67 | -} |
68 | - |
69 | type testUploadBlockBlob struct{} |
70 | |
71 | var _ = Suite(&testUploadBlockBlob{}) |
72 | @@ -87,14 +57,6 @@ |
73 | assertBlockListSent(c, context, []string{b64("0"), b64("1")}, transport.Exchanges[2]) |
74 | } |
75 | |
76 | -func makeFakeCreatedResponse() *http.Response { |
77 | - return &http.Response{ |
78 | - Status: fmt.Sprintf("%d", http.StatusCreated), |
79 | - StatusCode: http.StatusCreated, |
80 | - Body: Empty, |
81 | - } |
82 | -} |
83 | - |
84 | func uploadRandomBlob(c *C, context *StorageContext, size int) []byte { |
85 | data := MakeRandomByteSlice(size) |
86 | err := context.UploadBlockBlob( |
87 | |
88 | === added file 'testhelpers_apiobjects.go' |
89 | --- testhelpers_apiobjects.go 1970-01-01 00:00:00 +0000 |
90 | +++ testhelpers_apiobjects.go 2013-04-24 10:18:32 +0000 |
91 | @@ -0,0 +1,138 @@ |
92 | +// Copyright 2013 Canonical Ltd. This software is licensed under the |
93 | +// GNU Lesser General Public License version 3 (see the file COPYING). |
94 | +// |
95 | +// Test helpers to fake objects that go into, or come out of, the Azure API. |
96 | + |
97 | +package gwacl |
98 | + |
99 | +import ( |
100 | + "math/rand" |
101 | +) |
102 | + |
103 | +type endpointParams struct { |
104 | + setname string |
105 | + localport int |
106 | + name string |
107 | + port int |
108 | + protocol string |
109 | +} |
110 | + |
111 | +func makeEndpoint(params endpointParams) *InputEndpoint { |
112 | + if params.setname == "" { |
113 | + params.setname = MakeRandomString(10) |
114 | + } |
115 | + if params.name == "" { |
116 | + params.name = MakeRandomString(10) |
117 | + } |
118 | + if params.protocol == "" { |
119 | + params.protocol = MakeRandomString(10) |
120 | + } |
121 | + if params.localport == 0 { |
122 | + params.localport = rand.Intn(65535) |
123 | + } |
124 | + if params.port == 0 { |
125 | + params.port = rand.Intn(65535) |
126 | + } |
127 | + |
128 | + return &InputEndpoint{ |
129 | + LoadBalancedEndpointSetName: params.setname, |
130 | + LocalPort: params.localport, |
131 | + Name: params.name, |
132 | + Port: params.port, |
133 | + Protocol: params.protocol} |
134 | +} |
135 | + |
136 | +func makeLinuxProvisioningConfiguration() *LinuxProvisioningConfiguration { |
137 | + hostname := MakeRandomString(10) |
138 | + username := MakeRandomString(10) |
139 | + password := MakeRandomString(10) |
140 | + disable_ssh := MakeRandomBool() |
141 | + |
142 | + return &LinuxProvisioningConfiguration{ |
143 | + ConfigurationSetType: "LinuxProvisioningConfiguration", |
144 | + Hostname: hostname, |
145 | + Username: username, |
146 | + Password: password, |
147 | + DisableSSHPasswordAuthentication: disable_ssh} |
148 | +} |
149 | + |
150 | +func makeOSVirtualHardDisk() *OSVirtualHardDisk { |
151 | + HostCaching := BoolToString(MakeRandomBool()) |
152 | + DiskLabel := MakeRandomString(10) |
153 | + DiskName := MakeRandomString(10) |
154 | + MediaLink := MakeRandomString(10) |
155 | + SourceImageName := MakeRandomString(10) |
156 | + |
157 | + return &OSVirtualHardDisk{ |
158 | + HostCaching: HostCaching, |
159 | + DiskLabel: DiskLabel, |
160 | + DiskName: DiskName, |
161 | + MediaLink: MediaLink, |
162 | + SourceImageName: SourceImageName} |
163 | +} |
164 | + |
165 | +func makeRole() *Role { |
166 | + RoleSize := "ExtraSmall" |
167 | + RoleName := MakeRandomString(10) |
168 | + RoleType := "PersistentVMRole" |
169 | + config := makeLinuxProvisioningConfiguration() |
170 | + configset := []LinuxProvisioningConfiguration{*config} |
171 | + |
172 | + return &Role{ |
173 | + RoleSize: RoleSize, |
174 | + RoleName: RoleName, |
175 | + RoleType: RoleType, |
176 | + ConfigurationSets: configset} |
177 | +} |
178 | + |
179 | +func makeDnsServer() *DnsServer { |
180 | + name := MakeRandomString(10) |
181 | + address := MakeRandomString(10) |
182 | + |
183 | + return &DnsServer{ |
184 | + Name: name, |
185 | + Address: address} |
186 | +} |
187 | + |
188 | +func makeDeployment() *Deployment { |
189 | + Name := MakeRandomString(10) |
190 | + DeploymentSlot := "Staging" |
191 | + Label := MakeRandomString(10) |
192 | + VirtualNetworkName := MakeRandomString(10) |
193 | + role := makeRole() |
194 | + RoleList := []Role{*role} |
195 | + Dns := []DnsServer{*makeDnsServer()} |
196 | + |
197 | + return &Deployment{ |
198 | + XMLNS: XMLNS, |
199 | + XMLNS_I: XMLNS_I, |
200 | + Name: Name, |
201 | + DeploymentSlot: DeploymentSlot, |
202 | + Label: Label, |
203 | + RoleList: RoleList, |
204 | + VirtualNetworkName: VirtualNetworkName, |
205 | + DNS: Dns, |
206 | + } |
207 | +} |
208 | + |
209 | +func makeCreateStorageServiceInput() *CreateStorageServiceInput { |
210 | + ServiceName := MakeRandomString(10) |
211 | + Description := MakeRandomString(10) |
212 | + Label := MakeRandomString(10) |
213 | + AffinityGroup := MakeRandomString(10) |
214 | + Location := MakeRandomString(10) |
215 | + GeoReplicationEnabled := BoolToString(MakeRandomBool()) |
216 | + ExtendedProperties := []ExtendedProperty{{ |
217 | + Name: MakeRandomString(10), |
218 | + Value: MakeRandomString(10)}} |
219 | + |
220 | + return &CreateStorageServiceInput{ |
221 | + XMLNS: XMLNS, |
222 | + ServiceName: ServiceName, |
223 | + Description: Description, |
224 | + Label: Label, |
225 | + AffinityGroup: AffinityGroup, |
226 | + Location: Location, |
227 | + GeoReplicationEnabled: GeoReplicationEnabled, |
228 | + ExtendedProperties: ExtendedProperties} |
229 | +} |
230 | |
231 | === added file 'testhelpers_factory.go' |
232 | --- testhelpers_factory.go 1970-01-01 00:00:00 +0000 |
233 | +++ testhelpers_factory.go 2013-04-24 10:18:32 +0000 |
234 | @@ -0,0 +1,49 @@ |
235 | +// Copyright 2013 Canonical Ltd. This software is licensed under the |
236 | +// GNU Lesser General Public License version 3 (see the file COPYING). |
237 | +// |
238 | +// Factories for various types of objects that tests need to create. |
239 | + |
240 | +package gwacl |
241 | + |
242 | +import ( |
243 | + "math/rand" |
244 | + "time" |
245 | +) |
246 | + |
247 | +// This should be refactored at some point, it does not belong in here. |
248 | +// Perhaps we can add it to gocheck, or start a testtools-like project. |
249 | +const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz" |
250 | + |
251 | +// MakeRandomString returns an arbitrary string of alphanumerical characters. |
252 | +// TODO: This isn't really a random string, more of a random identifier. |
253 | +func MakeRandomString(length int) string { |
254 | + return string(MakeRandomByteSlice(length)) |
255 | +} |
256 | + |
257 | +// MakeRandomString returns a slice of arbitrary bytes, all corresponding to |
258 | +// alphanumerical characters in ASCII. |
259 | +// TODO: This isn't really very random. Good tests need zero and "high" values. |
260 | +func MakeRandomByteSlice(length int) []byte { |
261 | + dest := make([]byte, length) |
262 | + for i := range dest { |
263 | + num := rand.Intn(len(chars)) |
264 | + rand_char := chars[num] |
265 | + dest[i] = rand_char |
266 | + } |
267 | + return dest |
268 | +} |
269 | + |
270 | +// MakeRandomBool returns an arbitrary bool value (true or false). |
271 | +func MakeRandomBool() bool { |
272 | + v := rand.Intn(2) |
273 | + if v == 0 { |
274 | + return false |
275 | + } |
276 | + return true |
277 | +} |
278 | + |
279 | +func init() { |
280 | + // Seed the pseudo-random number generator. Without this, each test run |
281 | + // will get the same sequence of results from the math/rand package. |
282 | + rand.Seed(int64(time.Now().Nanosecond())) |
283 | +} |
284 | |
285 | === added file 'testhelpers_http.go' |
286 | --- testhelpers_http.go 1970-01-01 00:00:00 +0000 |
287 | +++ testhelpers_http.go 2013-04-24 10:18:32 +0000 |
288 | @@ -0,0 +1,58 @@ |
289 | +// Copyright 2013 Canonical Ltd. This software is licensed under the |
290 | +// GNU Lesser General Public License version 3 (see the file COPYING). |
291 | +// |
292 | +// Test helpers for dealing with http requests through the http package. |
293 | + |
294 | +package gwacl |
295 | + |
296 | +import ( |
297 | + "fmt" |
298 | + "net/http" |
299 | +) |
300 | + |
301 | +// TestTransport is used as an http.Client.Transport for testing. The only |
302 | +// requirement is that it adhere to the http.RoundTripper interface. |
303 | +type TestTransport struct { |
304 | + Request *http.Request |
305 | + Response *http.Response |
306 | + Error error |
307 | +} |
308 | + |
309 | +func (t *TestTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { |
310 | + t.Request = req |
311 | + return t.Response, t.Error |
312 | +} |
313 | + |
314 | +type TestTransport2Exchange struct { |
315 | + Request *http.Request |
316 | + Response *http.Response |
317 | + Error error |
318 | +} |
319 | + |
320 | +// TestTransport2 is used as an http.Client.Transport for testing. The only |
321 | +// requirement is that it adhere to the http.RoundTripper interface. |
322 | +type TestTransport2 struct { |
323 | + Exchanges []*TestTransport2Exchange |
324 | + ExchangeCount int |
325 | +} |
326 | + |
327 | +func (t *TestTransport2) AddExchange(response *http.Response, error error) { |
328 | + exchange := TestTransport2Exchange{Response: response, Error: error} |
329 | + t.Exchanges = append(t.Exchanges, &exchange) |
330 | +} |
331 | + |
332 | +func (t *TestTransport2) RoundTrip(req *http.Request) (resp *http.Response, err error) { |
333 | + exchange := t.Exchanges[t.ExchangeCount] |
334 | + t.ExchangeCount += 1 |
335 | + exchange.Request = req |
336 | + return exchange.Response, exchange.Error |
337 | +} |
338 | + |
339 | +// makeFakeCreatedResponse returns an HTTP response with the Created status. |
340 | +func makeFakeCreatedResponse() *http.Response { |
341 | + return &http.Response{ |
342 | + Status: fmt.Sprintf("%d", http.StatusCreated), |
343 | + StatusCode: http.StatusCreated, |
344 | + Body: Empty, |
345 | + } |
346 | +} |
347 | |
348 | === renamed file 'test_helpers.go' => 'testhelpers_misc.go' |
349 | --- test_helpers.go 2013-04-19 14:44:13 +0000 |
350 | +++ testhelpers_misc.go 2013-04-24 10:18:32 +0000 |
351 | @@ -5,254 +5,30 @@ |
352 | |
353 | import ( |
354 | "bytes" |
355 | + "encoding/base64" |
356 | "fmt" |
357 | "io" |
358 | "io/ioutil" |
359 | - "math/rand" |
360 | - "net/http" |
361 | - "strings" |
362 | - "time" |
363 | ) |
364 | |
365 | -// This should be refactored at some point, it does not belong in here. |
366 | -// Perhaps we can add it to gocheck, or start a testtools-like project. |
367 | -const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz" |
368 | +// b64 is shorthand for base64-encoding a string. |
369 | +func b64(s string) string { |
370 | + return base64.StdEncoding.EncodeToString([]byte(s)) |
371 | +} |
372 | |
373 | // A Reader and ReadCloser that EOFs immediately. |
374 | var Empty io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil)) |
375 | |
376 | -func MakeRandomString(length int) string { |
377 | - return string(MakeRandomByteSlice(length)) |
378 | -} |
379 | - |
380 | -func MakeRandomByteSlice(length int) []byte { |
381 | - dest := make([]byte, length) |
382 | - for i := range dest { |
383 | - num := rand.Intn(len(chars)) |
384 | - rand_char := chars[num] |
385 | - dest[i] = rand_char |
386 | - } |
387 | - return dest |
388 | -} |
389 | - |
390 | -func MakeRandomBool() bool { |
391 | - v := rand.Intn(2) |
392 | - if v == 0 { |
393 | - return false |
394 | - } |
395 | - return true |
396 | -} |
397 | - |
398 | +// BoolToString represents a boolean value as a string ("true" or "false"). |
399 | func BoolToString(v bool) string { |
400 | - if v { |
401 | - return "true" |
402 | - } |
403 | - return "false" |
404 | -} |
405 | - |
406 | -func StringToBool(v string) bool { |
407 | - switch strings.ToLower(v) { |
408 | - case "true": |
409 | - return true |
410 | - case "false": |
411 | - return false |
412 | - } |
413 | - panic(fmt.Errorf("can't convert '%s' to a bool", v)) |
414 | -} |
415 | - |
416 | -type endpointParams struct { |
417 | - setname string |
418 | - localport int |
419 | - name string |
420 | - port int |
421 | - protocol string |
422 | -} |
423 | - |
424 | -func makeEndpoint(params endpointParams) *InputEndpoint { |
425 | - if params.setname == "" { |
426 | - params.setname = MakeRandomString(10) |
427 | - } |
428 | - if params.name == "" { |
429 | - params.name = MakeRandomString(10) |
430 | - } |
431 | - if params.protocol == "" { |
432 | - params.protocol = MakeRandomString(10) |
433 | - } |
434 | - if params.localport == 0 { |
435 | - params.localport = rand.Intn(65535) |
436 | - } |
437 | - if params.port == 0 { |
438 | - params.port = rand.Intn(65535) |
439 | - } |
440 | - |
441 | - return &InputEndpoint{ |
442 | - LoadBalancedEndpointSetName: params.setname, |
443 | - LocalPort: params.localport, |
444 | - Name: params.name, |
445 | - Port: params.port, |
446 | - Protocol: params.protocol} |
447 | -} |
448 | - |
449 | -func makeLinuxProvisioningConfiguration() *LinuxProvisioningConfiguration { |
450 | - hostname := MakeRandomString(10) |
451 | - username := MakeRandomString(10) |
452 | - password := MakeRandomString(10) |
453 | - disable_ssh := MakeRandomBool() |
454 | - |
455 | - return &LinuxProvisioningConfiguration{ |
456 | - ConfigurationSetType: "LinuxProvisioningConfiguration", |
457 | - Hostname: hostname, |
458 | - Username: username, |
459 | - Password: password, |
460 | - DisableSSHPasswordAuthentication: disable_ssh} |
461 | -} |
462 | - |
463 | -func makeOSVirtualHardDisk() *OSVirtualHardDisk { |
464 | - HostCaching := BoolToString(MakeRandomBool()) |
465 | - DiskLabel := MakeRandomString(10) |
466 | - DiskName := MakeRandomString(10) |
467 | - MediaLink := MakeRandomString(10) |
468 | - SourceImageName := MakeRandomString(10) |
469 | - |
470 | - return &OSVirtualHardDisk{ |
471 | - HostCaching: HostCaching, |
472 | - DiskLabel: DiskLabel, |
473 | - DiskName: DiskName, |
474 | - MediaLink: MediaLink, |
475 | - SourceImageName: SourceImageName} |
476 | -} |
477 | - |
478 | -func makeRole() *Role { |
479 | - RoleSize := "ExtraSmall" |
480 | - RoleName := MakeRandomString(10) |
481 | - RoleType := "PersistentVMRole" |
482 | - config := makeLinuxProvisioningConfiguration() |
483 | - configset := []LinuxProvisioningConfiguration{*config} |
484 | - |
485 | - return &Role{ |
486 | - RoleSize: RoleSize, |
487 | - RoleName: RoleName, |
488 | - RoleType: RoleType, |
489 | - ConfigurationSets: configset} |
490 | -} |
491 | - |
492 | -func makeDnsServer() *DnsServer { |
493 | - name := MakeRandomString(10) |
494 | - address := MakeRandomString(10) |
495 | - |
496 | - return &DnsServer{ |
497 | - Name: name, |
498 | - Address: address} |
499 | -} |
500 | - |
501 | -func makeDeployment() *Deployment { |
502 | - Name := MakeRandomString(10) |
503 | - DeploymentSlot := "Staging" |
504 | - Label := MakeRandomString(10) |
505 | - VirtualNetworkName := MakeRandomString(10) |
506 | - role := makeRole() |
507 | - RoleList := []Role{*role} |
508 | - Dns := []DnsServer{*makeDnsServer()} |
509 | - |
510 | - return &Deployment{ |
511 | - XMLNS: XMLNS, |
512 | - XMLNS_I: XMLNS_I, |
513 | - Name: Name, |
514 | - DeploymentSlot: DeploymentSlot, |
515 | - Label: Label, |
516 | - RoleList: RoleList, |
517 | - VirtualNetworkName: VirtualNetworkName, |
518 | - DNS: Dns, |
519 | - } |
520 | -} |
521 | - |
522 | -func makeCreateStorageServiceInput() *CreateStorageServiceInput { |
523 | - ServiceName := MakeRandomString(10) |
524 | - Description := MakeRandomString(10) |
525 | - Label := MakeRandomString(10) |
526 | - AffinityGroup := MakeRandomString(10) |
527 | - Location := MakeRandomString(10) |
528 | - GeoReplicationEnabled := BoolToString(MakeRandomBool()) |
529 | - ExtendedProperties := []ExtendedProperty{{ |
530 | - Name: MakeRandomString(10), |
531 | - Value: MakeRandomString(10)}} |
532 | - |
533 | - return &CreateStorageServiceInput{ |
534 | - XMLNS: XMLNS, |
535 | - ServiceName: ServiceName, |
536 | - Description: Description, |
537 | - Label: Label, |
538 | - AffinityGroup: AffinityGroup, |
539 | - Location: Location, |
540 | - GeoReplicationEnabled: GeoReplicationEnabled, |
541 | - ExtendedProperties: ExtendedProperties} |
542 | -} |
543 | - |
544 | -// rigRecordingDispatcher sets up a request dispatcher that records incoming |
545 | -// requests by appending them to *record. It returns the result of whatever |
546 | -// dispatcher was already active. |
547 | -// If you also want the dispatcher to return a particular result, rig it for |
548 | -// that result first (using one of the other rig...Dispatcher functions) and |
549 | -// then chain the recording dispatcher in front of it. |
550 | -func rigRecordingDispatcher(record *[]*x509Request) { |
551 | - previousDispatcher := _X509Dispatcher |
552 | - _X509Dispatcher = func(session *x509Session, request *x509Request) (*x509Response, error) { |
553 | - *record = append(*record, request) |
554 | - return previousDispatcher(session, request) |
555 | - } |
556 | -} |
557 | - |
558 | -// rigFixedResponseDispatcher sets up a request dispatcher that always returns |
559 | -// a prepared response. |
560 | -func rigFixedResponseDispatcher(response *x509Response) { |
561 | - _X509Dispatcher = func(*x509Session, *x509Request) (*x509Response, error) { |
562 | - return response, nil |
563 | - } |
564 | -} |
565 | - |
566 | -// rigFailingDispatcher sets up a request dispatcher that returns a given |
567 | -// error. |
568 | -func rigFailingDispatcher(failure error) { |
569 | - _X509Dispatcher = func(*x509Session, *x509Request) (*x509Response, error) { |
570 | - return nil, failure |
571 | - } |
572 | -} |
573 | - |
574 | -type DispatcherResponse struct { |
575 | - response *x509Response |
576 | - errorObject error |
577 | -} |
578 | - |
579 | -// rigPreparedResponseDispatcher sets up a request dispatcher that returns, |
580 | -// for each consecutive request, the next of a series of prepared responses. |
581 | -func rigPreparedResponseDispatcher(responses []DispatcherResponse) { |
582 | - index := 0 |
583 | - _X509Dispatcher = func(*x509Session, *x509Request) (*x509Response, error) { |
584 | - response := responses[index] |
585 | - index += 1 |
586 | - return response.response, response.errorObject |
587 | - } |
588 | -} |
589 | - |
590 | -// setUpDispatcher sets up a request dispatcher that: |
591 | -// - records requests |
592 | -// - returns empty responses |
593 | -func setUpDispatcher(operationID string) *[]*x509Request { |
594 | - header := http.Header{} |
595 | - header.Set("X-Ms-Request-Id", operationID) |
596 | - fixedResponse := x509Response{ |
597 | - StatusCode: http.StatusOK, |
598 | - Body: []byte{}, |
599 | - Header: header, |
600 | - } |
601 | - rigFixedResponseDispatcher(&fixedResponse) |
602 | - recordedRequests := make([]*x509Request, 0) |
603 | - rigRecordingDispatcher(&recordedRequests) |
604 | - return &recordedRequests |
605 | -} |
606 | - |
607 | -func init() { |
608 | - // Staggeringly, rand will produce the same numbers from the start of |
609 | - // program invocation unless you seed it ... |
610 | - rand.Seed(int64(time.Now().Nanosecond())) |
611 | + return fmt.Sprintf("%t", v) |
612 | +} |
613 | + |
614 | +// StringToBool parses a string containing a boolean (case-insensitive). |
615 | +func StringToBool(v string) (b bool) { |
616 | + items, err := fmt.Sscanf(v, "%t", &b) |
617 | + if err != nil || items != 1 { |
618 | + panic(fmt.Errorf("can't convert '%s' to a bool", v)) |
619 | + } |
620 | + return |
621 | } |
622 | |
623 | === added file 'testhelpers_x509dispatch.go' |
624 | --- testhelpers_x509dispatch.go 1970-01-01 00:00:00 +0000 |
625 | +++ testhelpers_x509dispatch.go 2013-04-24 10:18:32 +0000 |
626 | @@ -0,0 +1,74 @@ |
627 | +// Copyright 2013 Canonical Ltd. This software is licensed under the |
628 | +// GNU Lesser General Public License version 3 (see the file COPYING). |
629 | +// |
630 | +// Helpers for testing with x509 requests. These help inject fake responses |
631 | +// into the x509 request dispatcher. |
632 | + |
633 | +package gwacl |
634 | + |
635 | +import ( |
636 | + "net/http" |
637 | +) |
638 | + |
639 | +// rigRecordingDispatcher sets up a request dispatcher that records incoming |
640 | +// requests by appending them to *record. It returns the result of whatever |
641 | +// dispatcher was already active. |
642 | +// If you also want the dispatcher to return a particular result, rig it for |
643 | +// that result first (using one of the other rig...Dispatcher functions) and |
644 | +// then chain the recording dispatcher in front of it. |
645 | +func rigRecordingDispatcher(record *[]*x509Request) { |
646 | + previousDispatcher := _X509Dispatcher |
647 | + _X509Dispatcher = func(session *x509Session, request *x509Request) (*x509Response, error) { |
648 | + *record = append(*record, request) |
649 | + return previousDispatcher(session, request) |
650 | + } |
651 | +} |
652 | + |
653 | +// rigFixedResponseDispatcher sets up a request dispatcher that always returns |
654 | +// a prepared response. |
655 | +func rigFixedResponseDispatcher(response *x509Response) { |
656 | + _X509Dispatcher = func(*x509Session, *x509Request) (*x509Response, error) { |
657 | + return response, nil |
658 | + } |
659 | +} |
660 | + |
661 | +// rigFailingDispatcher sets up a request dispatcher that returns a given |
662 | +// error. |
663 | +func rigFailingDispatcher(failure error) { |
664 | + _X509Dispatcher = func(*x509Session, *x509Request) (*x509Response, error) { |
665 | + return nil, failure |
666 | + } |
667 | +} |
668 | + |
669 | +type DispatcherResponse struct { |
670 | + response *x509Response |
671 | + errorObject error |
672 | +} |
673 | + |
674 | +// rigPreparedResponseDispatcher sets up a request dispatcher that returns, |
675 | +// for each consecutive request, the next of a series of prepared responses. |
676 | +func rigPreparedResponseDispatcher(responses []DispatcherResponse) { |
677 | + index := 0 |
678 | + _X509Dispatcher = func(*x509Session, *x509Request) (*x509Response, error) { |
679 | + response := responses[index] |
680 | + index += 1 |
681 | + return response.response, response.errorObject |
682 | + } |
683 | +} |
684 | + |
685 | +// setUpDispatcher sets up a request dispatcher that: |
686 | +// - records requests |
687 | +// - returns empty responses |
688 | +func setUpDispatcher(operationID string) *[]*x509Request { |
689 | + header := http.Header{} |
690 | + header.Set("X-Ms-Request-Id", operationID) |
691 | + fixedResponse := x509Response{ |
692 | + StatusCode: http.StatusOK, |
693 | + Body: []byte{}, |
694 | + Header: header, |
695 | + } |
696 | + rigFixedResponseDispatcher(&fixedResponse) |
697 | + recordedRequests := make([]*x509Request, 0) |
698 | + rigRecordingDispatcher(&recordedRequests) |
699 | + return &recordedRequests |
700 | +} |
Looks good, a fairly mechanical change so if it compiles, ship it! ;)
[0]
=== added file 'testhelpers_ apiobjects. go' http.go' misc.go'
=== added file 'testhelpers_
=== renamed file 'test_helpers.go' => 'testhelpers_
etc…
I seem to remember that Go does not compile files named test_* when not running the tests. I cannot find the doc where this is documented though… but if it's true, then it would be worth keeping the 'test_' prefix for all these files so that they won't be used at all, except when running the tests.