Merge lp:~allenap/gwacl/destroy-hosted-service into lp:gwacl
- destroy-hosted-service
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Raphaël Badin |
Approved revision: | 175 |
Merged at revision: | 164 |
Proposed branch: | lp:~allenap/gwacl/destroy-hosted-service |
Merge into: | lp:gwacl |
Diff against target: |
394 lines (+252/-33) 4 files modified
example/management/run.go (+4/-10) management.go (+34/-0) management_base_test.go (+24/-9) management_test.go (+190/-14) |
To merge this branch: | bzr merge lp:~allenap/gwacl/destroy-hosted-service |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Raphaël Badin (community) | Approve | ||
Review via email: mp+173057@code.launchpad.net |
Commit message
New method to destroy a hosted service.
Description of the change
Raphaël Badin (rvb) wrote : | # |
Raphaël Badin (rvb) wrote : | # |
I think we should fix DestroyDeployment by doing this first: https:/
Since the deployment used in the tests does not contain VMs, this branch will probably work as is, even with that change.
Raphaël Badin (rvb) wrote : | # |
Confirmed, this can be reviewed (and landed) independently from my "fix-destroydep
Raphaël Badin (rvb) wrote : | # |
Looks good but please consider my suggestions below:
[0]
We've had trouble lately with using these DestroyDeployment() so I'd advice to do this: now that my "fix-destroydep
[1]
126 +var exampleHostedSe
127 + Deployments: []Deployment{
128 + {Name: "one"}, {Name: "two"},
129 + },
130 +}
Having that as a global variable is, I think, an anti-pattern. This saves a bit of duplicate to have that as a global variable and not repeat it in each and every test. But a side effect is that the tests are not "self-contained" anymore and it makes it them much more difficult to understand and reason with.
For instance, the reasoning behind these checks:
159 + assertGetDeploy
160 + request.
161 + assertDeleteDep
162 + record[2])
163 + // The fourth and fifth requests are a repaat of the previous two, but for
164 + // deployment "two".
165 + assertGetDeploy
166 + request.
167 + assertDeleteDep
168 + record[4])
is inherently linked to the structure of the tested object… and one has to navigate in the file to find the exampleHostedSe
I'd suggest:
- creating a tiny makeHostedService method that would take a slice of Deployment objects and return a *HostedService
- calling that method from every test so that the initialization of the tested object is not far from the checks.
Even better, maybe use variables instead of duplicating the strings/objects on which the checks are performed:
deployName1 := "one"
deployName2 := "two"
exampleHostedSe
then the checks can be along the lines of:
assertDeleteDep
Gavin Panella (allenap) wrote : | # |
Thanks for the review.
> [0]
>
> We've had trouble lately with using these DestroyDeployment() so I'd advice to
> do this: now that my "fix-destroydep
> then update the example/
> (instead of DestroyDeployment() and the defered which cleans up the hosted
> service) from there and make sure this works fine when talking to the Azure
> server.
Done.
>
> [1]
>
> 126 +var exampleHostedSe
> 127 + Deployments: []Deployment{
> 128 + {Name: "one"}, {Name: "two"},
> 129 + },
> 130 +}
>
> Having that as a global variable is, I think, an anti-pattern. This saves a
> bit of duplicate to have that as a global variable and not repeat it in each
> and every test. But a side effect is that the tests are not "self-contained"
> anymore and it makes it them much more difficult to understand and reason
> with.
...
I've changed some of these example bits to be functions instead, and
I'm not sure it makes it easier to reason about. I've noticed with
some of the test refactoring going on - extracting things into
functions and whatnot - that:
- The loss of locality of what I'm looking at is more harmful than
having a few extra lines of code in my test.
- The indirection of having all test data constructed at runtime from
parameters is more harmful than having static test data.
- Using strings like "disk1" is easier to read and grok than either
deployments[
the names of everything in lots of local variables.
- Using functions for creating things in Go is painful because of the
very limited calling conventions available. We are going to end up
with 100s of factory functions for creating objects when it would
simpler and more expressive to create them near the point of use.
Even so, I'll land the few changes that I did make.
Julian Edwards (julian-edwards) wrote : | # |
There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.
Preview Diff
1 | === modified file 'example/management/run.go' |
2 | --- example/management/run.go 2013-07-04 17:25:26 +0000 |
3 | +++ example/management/run.go 2013-07-05 10:51:26 +0000 |
4 | @@ -108,9 +108,10 @@ |
5 | fmt.Println("Done creating a hosted service\n") |
6 | |
7 | defer func() { |
8 | - fmt.Println("Deleting hosted service...") |
9 | - api.DeleteHostedService(hostServiceName) |
10 | - fmt.Println("Done deleting hosted service\n") |
11 | + fmt.Println("Destroying hosted service...") |
12 | + api.DestroyHostedService(&gwacl.DestroyHostedServiceRequest{ |
13 | + ServiceName: hostServiceName}) |
14 | + fmt.Println("Done destroying hosted service\n") |
15 | }() |
16 | |
17 | fmt.Println("Listing hosted services...") |
18 | @@ -171,13 +172,6 @@ |
19 | checkError(err) |
20 | fmt.Println("Done adding VM deployment\n") |
21 | |
22 | - defer func() { |
23 | - fmt.Printf("Destroying deployment %s...\n", machineName) |
24 | - requestDestroyDeployment := &gwacl.DestroyDeploymentRequest{ServiceName: hostServiceName, DeploymentName: machineName} |
25 | - api.DestroyDeployment(requestDestroyDeployment) |
26 | - fmt.Println("Done destroying deployment\n") |
27 | - }() |
28 | - |
29 | fmt.Println("Starting VM...") |
30 | err = api.StartRole(&gwacl.StartRoleRequest{hostServiceName, deployment.Name, role.RoleName}) |
31 | checkError(err) |
32 | |
33 | === modified file 'management.go' |
34 | --- management.go 2013-07-04 20:23:56 +0000 |
35 | +++ management.go 2013-07-05 10:51:26 +0000 |
36 | @@ -143,3 +143,37 @@ |
37 | // Done. |
38 | return nil |
39 | } |
40 | + |
41 | +type DestroyHostedServiceRequest struct { |
42 | + ServiceName string |
43 | +} |
44 | + |
45 | +// DestroyHostedService destroys all of the hosted service's contained |
46 | +// deployments then deletes the hosted service itself. |
47 | +func (api *ManagementAPI) DestroyHostedService(request *DestroyHostedServiceRequest) error { |
48 | + // 1. Get properties. |
49 | + properties, err := api.GetHostedServiceProperties(request.ServiceName, true) |
50 | + if err != nil { |
51 | + if IsNotFoundError(err) { |
52 | + return nil |
53 | + } |
54 | + return err |
55 | + } |
56 | + // 2. Delete deployments. |
57 | + for _, deployment := range properties.Deployments { |
58 | + err := api.DestroyDeployment(&DestroyDeploymentRequest{ |
59 | + ServiceName: request.ServiceName, |
60 | + DeploymentName: deployment.Name, |
61 | + }) |
62 | + if err != nil { |
63 | + return err |
64 | + } |
65 | + } |
66 | + // 3. Delete service. |
67 | + err = api.DeleteHostedService(request.ServiceName) |
68 | + if err != nil && !IsNotFoundError(err) { |
69 | + return err |
70 | + } |
71 | + // Done. |
72 | + return nil |
73 | +} |
74 | |
75 | === modified file 'management_base_test.go' |
76 | --- management_base_test.go 2013-07-04 07:11:22 +0000 |
77 | +++ management_base_test.go 2013-07-05 10:51:26 +0000 |
78 | @@ -399,6 +399,18 @@ |
79 | checkOneRequest(c, &recordedRequests, expectedURL, requestPayload, "PUT") |
80 | } |
81 | |
82 | +func assertGetHostedServicePropertiesRequest(c *C, api *ManagementAPI, serviceName string, embedDetail bool, httpRequest *X509Request) { |
83 | + var query string |
84 | + if embedDetail { |
85 | + query = "embed-detail=true" |
86 | + } else { |
87 | + query = "embed-detail=false" |
88 | + } |
89 | + expectedURL := fmt.Sprintf("%s%s/services/hostedservices/%s?%s", AZURE_URL, |
90 | + api.session.subscriptionId, serviceName, query) |
91 | + checkRequest(c, httpRequest, expectedURL, nil, "GET") |
92 | +} |
93 | + |
94 | func (suite *managementBaseAPISuite) TestGetHostedServiceProperties_withoutDetails(c *C) { |
95 | api := makeAPI(c) |
96 | body := ` |
97 | @@ -435,9 +447,8 @@ |
98 | |
99 | properties, err := api.GetHostedServiceProperties(serviceName, false) |
100 | c.Assert(err, IsNil) |
101 | - |
102 | - expectedURL := AZURE_URL + api.session.subscriptionId + "/services/hostedservices/" + serviceName + "?embed-detail=false" |
103 | - checkOneRequest(c, &recordedRequests, expectedURL, []byte{}, "GET") |
104 | + c.Check(recordedRequests, HasLen, 1) |
105 | + assertGetHostedServicePropertiesRequest(c, api, serviceName, false, recordedRequests[0]) |
106 | |
107 | c.Check(properties.URL, Equals, "hosted-service-url") |
108 | c.Check(properties.ServiceName, Equals, "hosted-service-name") |
109 | @@ -487,9 +498,8 @@ |
110 | |
111 | properties, err := api.GetHostedServiceProperties(serviceName, true) |
112 | c.Assert(err, IsNil) |
113 | - |
114 | - expectedURL := AZURE_URL + api.session.subscriptionId + "/services/hostedservices/" + serviceName + "?embed-detail=true" |
115 | - checkOneRequest(c, &recordedRequests, expectedURL, []byte{}, "GET") |
116 | + c.Check(recordedRequests, HasLen, 1) |
117 | + assertGetHostedServicePropertiesRequest(c, api, serviceName, true, recordedRequests[0]) |
118 | |
119 | c.Check(properties.URL, Equals, "hosted-service-url") |
120 | c.Check(properties.ServiceName, Equals, "hosted-service-name") |
121 | @@ -510,15 +520,20 @@ |
122 | checkOneRequest(c, recordedRequests, expectedURL, expectedPayload, "POST") |
123 | } |
124 | |
125 | +func assertDeleteHostedServiceRequest(c *C, api *ManagementAPI, serviceName string, httpRequest *X509Request) { |
126 | + expectedURL := fmt.Sprintf("%s%s/services/hostedservices/%s", AZURE_URL, |
127 | + api.session.subscriptionId, serviceName) |
128 | + checkRequest(c, httpRequest, expectedURL, nil, "DELETE") |
129 | +} |
130 | + |
131 | func (suite *managementBaseAPISuite) TestDeleteHostedService(c *C) { |
132 | api := makeAPI(c) |
133 | recordedRequests := setUpDispatcher("operationID") |
134 | hostedServiceName := "testName" |
135 | err := api.DeleteHostedService(hostedServiceName) |
136 | - |
137 | c.Assert(err, IsNil) |
138 | - expectedURL := AZURE_URL + api.session.subscriptionId + "/services/hostedservices/" + hostedServiceName |
139 | - checkOneRequest(c, recordedRequests, expectedURL, []byte{}, "DELETE") |
140 | + c.Check(*recordedRequests, HasLen, 1) |
141 | + assertDeleteHostedServiceRequest(c, api, hostedServiceName, (*recordedRequests)[0]) |
142 | } |
143 | |
144 | func (suite *managementBaseAPISuite) TestAddDeployment(c *C) { |
145 | |
146 | === modified file 'management_test.go' |
147 | --- management_test.go 2013-07-04 20:23:56 +0000 |
148 | +++ management_test.go 2013-07-05 10:51:26 +0000 |
149 | @@ -220,20 +220,6 @@ |
150 | c.Assert(recordedRequests, HasLen, 1) |
151 | } |
152 | |
153 | -type suiteDestroyDeployment struct{} |
154 | - |
155 | -var _ = Suite(&suiteDestroyDeployment{}) |
156 | - |
157 | -var exampleDeployment = &Deployment{ |
158 | - RoleInstanceList: makeNamedRoleInstances("one", "two"), |
159 | - RoleList: []Role{ |
160 | - {OSVirtualHardDisk: []OSVirtualHardDisk{ |
161 | - {DiskName: "disk1"}, {DiskName: "disk2"}}}, |
162 | - {OSVirtualHardDisk: []OSVirtualHardDisk{ |
163 | - {DiskName: "disk1"}, {DiskName: "disk3"}}}, |
164 | - }, |
165 | -} |
166 | - |
167 | var exampleOkayResponse = DispatcherResponse{ |
168 | response: &x509Response{StatusCode: http.StatusOK}, |
169 | } |
170 | @@ -246,9 +232,26 @@ |
171 | response: &x509Response{StatusCode: http.StatusNotFound}, |
172 | } |
173 | |
174 | +type suiteDestroyDeployment struct{} |
175 | + |
176 | +var _ = Suite(&suiteDestroyDeployment{}) |
177 | + |
178 | +func (suite *suiteDestroyDeployment) makeExampleDeployment() *Deployment { |
179 | + return &Deployment{ |
180 | + RoleInstanceList: makeNamedRoleInstances("one", "two"), |
181 | + RoleList: []Role{ |
182 | + {OSVirtualHardDisk: []OSVirtualHardDisk{ |
183 | + {DiskName: "disk1"}, {DiskName: "disk2"}}}, |
184 | + {OSVirtualHardDisk: []OSVirtualHardDisk{ |
185 | + {DiskName: "disk1"}, {DiskName: "disk3"}}}, |
186 | + }, |
187 | + } |
188 | +} |
189 | + |
190 | func (suite *suiteDestroyDeployment) TestHappyPath(c *C) { |
191 | var responses []DispatcherResponse |
192 | // Prepare. |
193 | + exampleDeployment := suite.makeExampleDeployment() |
194 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) |
195 | // For deleting the deployment. |
196 | responses = append(responses, exampleOkayResponse) |
197 | @@ -294,6 +297,7 @@ |
198 | func (suite *suiteDestroyDeployment) TestOkayWhenAssetsNotFound(c *C) { |
199 | var responses []DispatcherResponse |
200 | // Prepare. |
201 | + exampleDeployment := suite.makeExampleDeployment() |
202 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) |
203 | // For deleting the deployment. |
204 | responses = append(responses, exampleNotFoundResponse) |
205 | @@ -340,6 +344,7 @@ |
206 | func (suite *suiteDestroyDeployment) TestFailsDeletingDisk(c *C) { |
207 | var responses []DispatcherResponse |
208 | // Prepare. |
209 | + exampleDeployment := suite.makeExampleDeployment() |
210 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) |
211 | // For deleting disks. |
212 | responses = append(responses, exampleFailResponse) |
213 | @@ -360,6 +365,7 @@ |
214 | func (suite *suiteDestroyDeployment) TestFailsDeletingDeployment(c *C) { |
215 | var responses []DispatcherResponse |
216 | // Prepare. |
217 | + exampleDeployment := suite.makeExampleDeployment() |
218 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) |
219 | // For deleting disks. |
220 | responses = append(responses, exampleOkayResponse, exampleOkayResponse, exampleOkayResponse) |
221 | @@ -378,3 +384,173 @@ |
222 | c.Check(err, ErrorMatches, "DELETE request failed [(]500: Internal Server Error[)]") |
223 | c.Check(record, HasLen, 5) |
224 | } |
225 | + |
226 | +type suiteDestroyHostedService struct{} |
227 | + |
228 | +var _ = Suite(&suiteDestroyHostedService{}) |
229 | + |
230 | +func (suite *suiteDestroyHostedService) makeExampleHostedService(deploymentNames ...string) *HostedService { |
231 | + var exampleHostedService = &HostedService{} |
232 | + for _, deploymentName := range deploymentNames { |
233 | + exampleHostedService.Deployments = append( |
234 | + exampleHostedService.Deployments, |
235 | + Deployment{Name: deploymentName}) |
236 | + } |
237 | + return exampleHostedService |
238 | +} |
239 | + |
240 | +func (suite *suiteDestroyHostedService) TestHappyPath(c *C) { |
241 | + var responses []DispatcherResponse |
242 | + // DestroyHostedService first gets the hosted service proerties. |
243 | + exampleHostedService := suite.makeExampleHostedService("one", "two") |
244 | + responses = append(responses, makeOKXMLResponse(c, exampleHostedService)...) |
245 | + // It calls DestroyDeployment, which first gets the deployment's |
246 | + // properties, deletes any assets contained therein (none in this case) |
247 | + // then deletes the deployment. |
248 | + for _, deployment := range exampleHostedService.Deployments { |
249 | + responses = append(responses, makeOKXMLResponse(c, &deployment)...) |
250 | + responses = append(responses, exampleOkayResponse) |
251 | + } |
252 | + // For deleting the service itself. |
253 | + responses = append(responses, exampleOkayResponse) |
254 | + record := []*X509Request{} |
255 | + rigRecordingPreparedResponseDispatcher(&record, responses) |
256 | + // Exercise DestroyHostedService. |
257 | + api := makeAPI(c) |
258 | + request := &DestroyHostedServiceRequest{ |
259 | + ServiceName: "service-name", |
260 | + } |
261 | + err := api.DestroyHostedService(request) |
262 | + c.Assert(err, IsNil) |
263 | + c.Check(record, HasLen, 6) |
264 | + // The first request is for the hosted service. |
265 | + assertGetHostedServicePropertiesRequest(c, api, request.ServiceName, true, record[0]) |
266 | + // The second and third requests fetch then delete deployment "one"; see |
267 | + // DestroyDeployment for an explanation of this behaviour. |
268 | + assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ |
269 | + request.ServiceName, "one"}, record[1]) |
270 | + assertDeleteDeploymentRequest(c, api, request.ServiceName, "one", |
271 | + record[2]) |
272 | + // The fourth and fifth requests are a repaat of the previous two, but for |
273 | + // deployment "two". |
274 | + assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ |
275 | + request.ServiceName, "two"}, record[3]) |
276 | + assertDeleteDeploymentRequest(c, api, request.ServiceName, "two", |
277 | + record[4]) |
278 | + // The last request deletes the hosted service. |
279 | + assertDeleteHostedServiceRequest(c, api, request.ServiceName, record[5]) |
280 | +} |
281 | + |
282 | +func (suite *suiteDestroyHostedService) TestOkayWhenHostedServiceNotFound(c *C) { |
283 | + var responses []DispatcherResponse |
284 | + // Prepare. |
285 | + responses = []DispatcherResponse{exampleNotFoundResponse} |
286 | + record := []*X509Request{} |
287 | + rigRecordingPreparedResponseDispatcher(&record, responses) |
288 | + // Exercise DestroyHostedService. |
289 | + api := makeAPI(c) |
290 | + request := &DestroyHostedServiceRequest{ServiceName: "service-name"} |
291 | + err := api.DestroyHostedService(request) |
292 | + c.Assert(err, IsNil) |
293 | + c.Check(record, HasLen, 1) |
294 | +} |
295 | + |
296 | +func (suite *suiteDestroyHostedService) TestOkayWhenDeploymentsNotFound(c *C) { |
297 | + var responses []DispatcherResponse |
298 | + // Prepare. |
299 | + exampleHostedService := suite.makeExampleHostedService("one", "two") |
300 | + responses = append(responses, makeOKXMLResponse(c, exampleHostedService)...) |
301 | + // Someone else has destroyed the deployments in the meantime. |
302 | + responses = append(responses, exampleNotFoundResponse, exampleNotFoundResponse) |
303 | + // Success deleting the hosted service. |
304 | + responses = append(responses, exampleOkayResponse) |
305 | + record := []*X509Request{} |
306 | + rigRecordingPreparedResponseDispatcher(&record, responses) |
307 | + // Exercise DestroyHostedService. |
308 | + api := makeAPI(c) |
309 | + request := &DestroyHostedServiceRequest{ServiceName: "service-name"} |
310 | + err := api.DestroyHostedService(request) |
311 | + c.Assert(err, IsNil) |
312 | + c.Check(record, HasLen, 4) |
313 | + assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ |
314 | + request.ServiceName, "one"}, record[1]) |
315 | + assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ |
316 | + request.ServiceName, "two"}, record[2]) |
317 | + assertDeleteHostedServiceRequest(c, api, request.ServiceName, record[3]) |
318 | +} |
319 | + |
320 | +func (suite *suiteDestroyHostedService) TestOkayWhenHostedServiceNotFoundWhenDeleting(c *C) { |
321 | + var responses []DispatcherResponse |
322 | + // Prepare. |
323 | + exampleHostedService := suite.makeExampleHostedService("one", "two") |
324 | + responses = append(responses, makeOKXMLResponse(c, exampleHostedService)...) |
325 | + // Someone else has destroyed the deployments in the meantime. |
326 | + responses = append(responses, exampleNotFoundResponse, exampleNotFoundResponse) |
327 | + // Someone else has destroyed the hosted service in the meantime. |
328 | + responses = append(responses, exampleNotFoundResponse) |
329 | + record := []*X509Request{} |
330 | + rigRecordingPreparedResponseDispatcher(&record, responses) |
331 | + // Exercise DestroyHostedService. |
332 | + api := makeAPI(c) |
333 | + request := &DestroyHostedServiceRequest{ServiceName: "service-name"} |
334 | + err := api.DestroyHostedService(request) |
335 | + c.Assert(err, IsNil) |
336 | + c.Check(record, HasLen, 4) |
337 | + assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ |
338 | + request.ServiceName, "one"}, record[1]) |
339 | + assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ |
340 | + request.ServiceName, "two"}, record[2]) |
341 | + assertDeleteHostedServiceRequest(c, api, request.ServiceName, record[3]) |
342 | +} |
343 | + |
344 | +func (suite *suiteDestroyHostedService) TestFailsGettingHostedService(c *C) { |
345 | + var responses []DispatcherResponse |
346 | + // Prepare. |
347 | + responses = []DispatcherResponse{exampleFailResponse} |
348 | + record := []*X509Request{} |
349 | + rigRecordingPreparedResponseDispatcher(&record, responses) |
350 | + // Exercise DestroyHostedService. |
351 | + api := makeAPI(c) |
352 | + request := &DestroyHostedServiceRequest{ServiceName: "service-name"} |
353 | + err := api.DestroyHostedService(request) |
354 | + c.Assert(err, NotNil) |
355 | + c.Check(err, ErrorMatches, "GET request failed [(]500: Internal Server Error[)]") |
356 | + c.Check(record, HasLen, 1) |
357 | +} |
358 | + |
359 | +func (suite *suiteDestroyHostedService) TestFailsDestroyingDeployment(c *C) { |
360 | + var responses []DispatcherResponse |
361 | + // Prepare. |
362 | + exampleHostedService := suite.makeExampleHostedService("one", "two") |
363 | + responses = append(responses, makeOKXMLResponse(c, exampleHostedService)...) |
364 | + responses = append(responses, exampleFailResponse) |
365 | + record := []*X509Request{} |
366 | + rigRecordingPreparedResponseDispatcher(&record, responses) |
367 | + // Exercise DestroyHostedService. |
368 | + api := makeAPI(c) |
369 | + request := &DestroyHostedServiceRequest{ServiceName: "service-name"} |
370 | + err := api.DestroyHostedService(request) |
371 | + c.Assert(err, NotNil) |
372 | + c.Check(err, ErrorMatches, "GET request failed [(]500: Internal Server Error[)]") |
373 | + c.Check(record, HasLen, 2) |
374 | +} |
375 | + |
376 | +func (suite *suiteDestroyHostedService) TestFailsDeletingHostedService(c *C) { |
377 | + var responses []DispatcherResponse |
378 | + // Prepare. |
379 | + exampleHostedService := suite.makeExampleHostedService("one", "two") |
380 | + responses = append(responses, makeOKXMLResponse(c, exampleHostedService)...) |
381 | + // Deployments not found, but that's okay. |
382 | + responses = append(responses, exampleNotFoundResponse, exampleNotFoundResponse) |
383 | + // When deleting hosted service. |
384 | + responses = append(responses, exampleFailResponse) |
385 | + record := []*X509Request{} |
386 | + rigRecordingPreparedResponseDispatcher(&record, responses) |
387 | + // Exercise DestroyHostedService. |
388 | + api := makeAPI(c) |
389 | + request := &DestroyHostedServiceRequest{ServiceName: "service-name"} |
390 | + err := api.DestroyHostedService(request) |
391 | + c.Assert(err, NotNil) |
392 | + c.Check(err, ErrorMatches, "DELETE request failed [(]500: Internal Server Error[)]") |
393 | + c.Check(record, HasLen, 4) |
394 | +} |
Please wait a bit to review and land this… we've got a problem with the underlying DestroyDeployment() method (I've tested it using example/ management/ run.go and it does not work [blows up trying to stop the VMs]… I thought the only problem is that we should ignore the error we get when stopping the VMs but it turns out it's a bit more involved).