1package testing
2
3import (
4	"strings"
5	"testing"
6
7	"github.com/gophercloud/gophercloud/openstack/clustering/v1/clusters"
8	"github.com/gophercloud/gophercloud/pagination"
9	th "github.com/gophercloud/gophercloud/testhelper"
10	fake "github.com/gophercloud/gophercloud/testhelper/client"
11)
12
13func TestCreateCluster(t *testing.T) {
14	th.SetupHTTP()
15	defer th.TeardownHTTP()
16
17	HandleCreateClusterSuccessfully(t)
18
19	minSize := 1
20	opts := clusters.CreateOpts{
21		Name:            "cluster1",
22		DesiredCapacity: 3,
23		ProfileID:       "d8a48377-f6a3-4af4-bbbb-6e8bcaa0cbc0",
24		MinSize:         &minSize,
25		MaxSize:         20,
26		Timeout:         3600,
27		Metadata:        map[string]interface{}{},
28		Config:          map[string]interface{}{},
29	}
30
31	res := clusters.Create(fake.ServiceClient(), opts)
32	th.AssertNoErr(t, res.Err)
33
34	location := res.Header.Get("Location")
35	th.AssertEquals(t, "http://senlin.cloud.blizzard.net:8778/v1/actions/625628cd-f877-44be-bde0-fec79f84e13d", location)
36
37	locationFields := strings.Split(location, "actions/")
38	actionID := locationFields[1]
39	th.AssertEquals(t, "625628cd-f877-44be-bde0-fec79f84e13d", actionID)
40
41	actual, err := res.Extract()
42	th.AssertNoErr(t, err)
43	th.AssertDeepEquals(t, ExpectedCluster, *actual)
44}
45
46func TestCreateClusterEmptyTime(t *testing.T) {
47	th.SetupHTTP()
48	defer th.TeardownHTTP()
49
50	HandleCreateClusterEmptyTimeSuccessfully(t)
51
52	minSize := 1
53	opts := clusters.CreateOpts{
54		Name:            "cluster1",
55		DesiredCapacity: 3,
56		ProfileID:       "d8a48377-f6a3-4af4-bbbb-6e8bcaa0cbc0",
57		MinSize:         &minSize,
58		MaxSize:         20,
59		Timeout:         3600,
60		Metadata:        map[string]interface{}{},
61		Config:          map[string]interface{}{},
62	}
63
64	actual, err := clusters.Create(fake.ServiceClient(), opts).Extract()
65	th.AssertNoErr(t, err)
66	th.AssertDeepEquals(t, ExpectedCluster_EmptyTime, *actual)
67}
68
69func TestCreateClusterMetadata(t *testing.T) {
70	th.SetupHTTP()
71	defer th.TeardownHTTP()
72
73	HandleCreateClusterMetadataSuccessfully(t)
74
75	minSize := 1
76	opts := clusters.CreateOpts{
77		Name:            "cluster1",
78		DesiredCapacity: 3,
79		ProfileID:       "d8a48377-f6a3-4af4-bbbb-6e8bcaa0cbc0",
80		MinSize:         &minSize,
81		MaxSize:         20,
82		Timeout:         3600,
83		Metadata: map[string]interface{}{
84			"foo": "bar",
85			"test": map[string]interface{}{
86				"nil_interface": interface{}(nil),
87				"float_value":   float64(123.3),
88				"string_value":  "test_string",
89				"bool_value":    false,
90			},
91		},
92		Config: map[string]interface{}{},
93	}
94
95	actual, err := clusters.Create(fake.ServiceClient(), opts).Extract()
96	th.AssertNoErr(t, err)
97	th.AssertDeepEquals(t, ExpectedCluster_Metadata, *actual)
98}
99
100func TestGetCluster(t *testing.T) {
101	th.SetupHTTP()
102	defer th.TeardownHTTP()
103
104	HandleGetClusterSuccessfully(t)
105
106	actual, err := clusters.Get(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15").Extract()
107	th.AssertNoErr(t, err)
108	th.AssertDeepEquals(t, ExpectedCluster, *actual)
109}
110
111func TestGetClusterEmptyTime(t *testing.T) {
112	th.SetupHTTP()
113	defer th.TeardownHTTP()
114
115	HandleGetClusterEmptyTimeSuccessfully(t)
116
117	actual, err := clusters.Get(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15").Extract()
118	th.AssertNoErr(t, err)
119	th.AssertDeepEquals(t, ExpectedCluster_EmptyTime, *actual)
120}
121
122func TestListClusters(t *testing.T) {
123	th.SetupHTTP()
124	defer th.TeardownHTTP()
125
126	HandleListClusterSuccessfully(t)
127
128	count := 0
129
130	clusters.List(fake.ServiceClient(), clusters.ListOpts{GlobalProject: new(bool)}).EachPage(func(page pagination.Page) (bool, error) {
131		count++
132		actual, err := clusters.ExtractClusters(page)
133		th.AssertNoErr(t, err)
134		th.AssertDeepEquals(t, ExpectedClusters, actual)
135
136		return true, nil
137	})
138
139	if count != 1 {
140		t.Errorf("Expected 1 page, got %d", count)
141	}
142}
143
144func TestUpdateCluster(t *testing.T) {
145	th.SetupHTTP()
146	defer th.TeardownHTTP()
147
148	HandleUpdateClusterSuccessfully(t)
149
150	updateOpts := clusters.UpdateOpts{
151		Name:      "cluster1",
152		ProfileID: "edc63d0a-2ca4-48fa-9854-27926da76a4a",
153	}
154
155	actual, err := clusters.Update(fake.ServiceClient(), ExpectedCluster.ID, updateOpts).Extract()
156	th.AssertNoErr(t, err)
157	th.AssertDeepEquals(t, ExpectedCluster, *actual)
158}
159
160func TestUpdateClusterEmptyTime(t *testing.T) {
161	th.SetupHTTP()
162	defer th.TeardownHTTP()
163
164	HandleUpdateClusterEmptyTimeSuccessfully(t)
165
166	updateOpts := clusters.UpdateOpts{
167		Name:      "cluster1",
168		ProfileID: "edc63d0a-2ca4-48fa-9854-27926da76a4a",
169	}
170
171	actual, err := clusters.Update(fake.ServiceClient(), ExpectedCluster_EmptyTime.ID, updateOpts).Extract()
172	th.AssertNoErr(t, err)
173	th.AssertDeepEquals(t, ExpectedCluster_EmptyTime, *actual)
174}
175
176func TestDeleteCluster(t *testing.T) {
177	th.SetupHTTP()
178	defer th.TeardownHTTP()
179
180	HandleDeleteClusterSuccessfully(t)
181
182	err := clusters.Delete(fake.ServiceClient(), "6dc6d336e3fc4c0a951b5698cd1236ee").ExtractErr()
183	th.AssertNoErr(t, err)
184}
185
186func TestResizeCluster(t *testing.T) {
187	th.SetupHTTP()
188	defer th.TeardownHTTP()
189
190	HandleResizeSuccessfully(t)
191
192	maxSize := 5
193	minSize := 1
194	number := -2
195	strict := true
196	opts := clusters.ResizeOpts{
197		AdjustmentType: "CHANGE_IN_CAPACITY",
198		MaxSize:        &maxSize,
199		MinSize:        &minSize,
200		Number:         number,
201		Strict:         &strict,
202	}
203
204	actionID, err := clusters.Resize(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", opts).Extract()
205	th.AssertNoErr(t, err)
206	th.AssertEquals(t, ExpectedActionID, actionID)
207}
208
209// Test case for Number field having a float value
210func TestResizeClusterNumberFloat(t *testing.T) {
211	maxSize := 5
212	minSize := 1
213	number := 100.0
214	strict := true
215	opts := clusters.ResizeOpts{
216		AdjustmentType: "CHANGE_IN_PERCENTAGE",
217		MaxSize:        &maxSize,
218		MinSize:        &minSize,
219		Number:         number,
220		Strict:         &strict,
221	}
222
223	_, err := opts.ToClusterResizeMap()
224	th.AssertNoErr(t, err)
225}
226
227// Test case for missing Number field.
228func TestResizeClusterMissingNumber(t *testing.T) {
229	maxSize := 5
230	minSize := 1
231	strict := true
232	opts := clusters.ResizeOpts{
233		MaxSize: &maxSize,
234		MinSize: &minSize,
235		Strict:  &strict,
236	}
237
238	_, err := opts.ToClusterResizeMap()
239	th.AssertNoErr(t, err)
240}
241
242// Test case for missing Number field which is required when AdjustmentType is specified
243func TestResizeClusterInvalidParamsMissingNumber(t *testing.T) {
244	maxSize := 5
245	minSize := 1
246	strict := true
247	opts := clusters.ResizeOpts{
248		AdjustmentType: "CHANGE_IN_CAPACITY",
249		MaxSize:        &maxSize,
250		MinSize:        &minSize,
251		Strict:         &strict,
252	}
253
254	_, err := opts.ToClusterResizeMap()
255	isValid := err == nil
256	th.AssertEquals(t, false, isValid)
257}
258
259// Test case for float Number field which is only valid for CHANGE_IN_PERCENTAGE.
260func TestResizeClusterInvalidParamsNumberFloat(t *testing.T) {
261	maxSize := 5
262	minSize := 1
263	number := 100.0
264	strict := true
265	opts := clusters.ResizeOpts{
266		AdjustmentType: "CHANGE_IN_CAPACITY",
267		MaxSize:        &maxSize,
268		MinSize:        &minSize,
269		Number:         number,
270		Strict:         &strict,
271	}
272
273	_, err := opts.ToClusterResizeMap()
274	isValid := err == nil
275	th.AssertEquals(t, false, isValid)
276}
277
278func TestClusterScaleIn(t *testing.T) {
279	th.SetupHTTP()
280	defer th.TeardownHTTP()
281
282	HandleScaleInSuccessfully(t)
283
284	count := 5
285	scaleOpts := clusters.ScaleInOpts{
286		Count: &count,
287	}
288	actionID, err := clusters.ScaleIn(fake.ServiceClient(), "edce3528-864f-41fb-8759-f4707925cc09", scaleOpts).Extract()
289	th.AssertNoErr(t, err)
290	th.AssertEquals(t, ExpectedActionID, actionID)
291}
292
293func TestListClusterPolicies(t *testing.T) {
294	th.SetupHTTP()
295	defer th.TeardownHTTP()
296
297	HandleListPoliciesSuccessfully(t)
298
299	pageCount := 0
300	err := clusters.ListPolicies(fake.ServiceClient(), ExpectedClusterPolicy.ClusterID, clusters.ListPoliciesOpts{Name: "Test"}).EachPage(func(page pagination.Page) (bool, error) {
301		pageCount++
302		actual, err := clusters.ExtractClusterPolicies(page)
303		th.AssertNoErr(t, err)
304		th.AssertDeepEquals(t, ExpectedListPolicies, actual)
305
306		return true, nil
307	})
308
309	th.AssertNoErr(t, err)
310	th.AssertEquals(t, pageCount, 1)
311}
312
313func TestGetClusterPolicies(t *testing.T) {
314	th.SetupHTTP()
315	defer th.TeardownHTTP()
316
317	HandleGetPolicySuccessfully(t)
318
319	actual, err := clusters.GetPolicy(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", "714fe676-a08f-4196-b7af-61d52eeded15").Extract()
320	th.AssertNoErr(t, err)
321	th.AssertDeepEquals(t, ExpectedClusterPolicy, *actual)
322}
323
324func TestClusterRecover(t *testing.T) {
325	th.SetupHTTP()
326	defer th.TeardownHTTP()
327
328	HandleRecoverSuccessfully(t)
329
330	recoverOpts := clusters.RecoverOpts{
331		Operation:     clusters.RebuildRecovery,
332		Check:         new(bool),
333		CheckCapacity: new(bool),
334	}
335	actionID, err := clusters.Recover(fake.ServiceClient(), "edce3528-864f-41fb-8759-f4707925cc09", recoverOpts).Extract()
336	th.AssertNoErr(t, err)
337	th.AssertEquals(t, ExpectedActionID, actionID)
338}
339
340func TestAttachPolicy(t *testing.T) {
341	th.SetupHTTP()
342	defer th.TeardownHTTP()
343
344	HandleAttachPolicySuccessfully(t)
345
346	enabled := true
347	opts := clusters.AttachPolicyOpts{
348		PolicyID: "policy1",
349		Enabled:  &enabled,
350	}
351	actionID, err := clusters.AttachPolicy(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", opts).Extract()
352	th.AssertNoErr(t, err)
353	th.AssertEquals(t, ExpectedActionID, actionID)
354}
355
356func TestDetachPolicy(t *testing.T) {
357	th.SetupHTTP()
358	defer th.TeardownHTTP()
359
360	HandleDetachPolicySuccessfully(t)
361
362	opts := clusters.DetachPolicyOpts{
363		PolicyID: "policy1",
364	}
365	actionID, err := clusters.DetachPolicy(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", opts).Extract()
366	th.AssertNoErr(t, err)
367	th.AssertEquals(t, ExpectedActionID, actionID)
368}
369
370func TestUpdatePolicy(t *testing.T) {
371	th.SetupHTTP()
372	defer th.TeardownHTTP()
373
374	HandleUpdatePolicySuccessfully(t)
375
376	enabled := true
377	opts := clusters.UpdatePolicyOpts{
378		PolicyID: "policy1",
379		Enabled:  &enabled,
380	}
381	actionID, err := clusters.UpdatePolicy(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", opts).Extract()
382	th.AssertNoErr(t, err)
383	th.AssertEquals(t, ExpectedActionID, actionID)
384}
385
386func TestClusterScaleOut(t *testing.T) {
387	th.SetupHTTP()
388	defer th.TeardownHTTP()
389
390	HandleScaleOutSuccessfully(t)
391
392	scaleOutOpts := clusters.ScaleOutOpts{
393		Count: 5,
394	}
395	actionID, err := clusters.ScaleOut(fake.ServiceClient(), "edce3528-864f-41fb-8759-f4707925cc09", scaleOutOpts).Extract()
396	th.AssertNoErr(t, err)
397	th.AssertEquals(t, ExpectedActionID, actionID)
398}
399
400func TestClusterCheck(t *testing.T) {
401	th.SetupHTTP()
402	defer th.TeardownHTTP()
403
404	HandleCheckSuccessfully(t)
405
406	actionID, err := clusters.Check(fake.ServiceClient(), "edce3528-864f-41fb-8759-f4707925cc09").Extract()
407	th.AssertNoErr(t, err)
408	th.AssertEquals(t, ExpectedActionID, actionID)
409}
410
411func TestLifecycle(t *testing.T) {
412	th.SetupHTTP()
413	defer th.TeardownHTTP()
414
415	HandleLifecycleSuccessfully(t)
416
417	opts := clusters.CompleteLifecycleOpts{
418		LifecycleActionTokenID: "976528c6-dcf6-4d8d-9f4c-588f4e675f29",
419	}
420
421	res := clusters.CompleteLifecycle(fake.ServiceClient(), "edce3528-864f-41fb-8759-f4707925cc09", opts)
422	location := res.Header.Get("Location")
423	th.AssertEquals(t, "http://senlin.cloud.blizzard.net:8778/v1/actions/2a0ff107-e789-4660-a122-3816c43af703", location)
424
425	actionID, err := res.Extract()
426	th.AssertNoErr(t, err)
427	th.AssertEquals(t, "2a0ff107-e789-4660-a122-3816c43af703", actionID)
428}
429
430func TestAddNodes(t *testing.T) {
431	th.SetupHTTP()
432	defer th.TeardownHTTP()
433
434	HandleAddNodesSuccessfully(t)
435
436	opts := clusters.AddNodesOpts{
437		Nodes: []string{"node1", "node2", "node3"},
438	}
439	result, err := clusters.AddNodes(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", opts).Extract()
440	th.AssertNoErr(t, err)
441	th.AssertEquals(t, result, "2a0ff107-e789-4660-a122-3816c43af703")
442}
443
444func TestRemoveNodes(t *testing.T) {
445	th.SetupHTTP()
446	defer th.TeardownHTTP()
447
448	HandleRemoveNodesSuccessfully(t)
449
450	opts := clusters.RemoveNodesOpts{
451		Nodes: []string{"node1", "node2", "node3"},
452	}
453	result, err := clusters.RemoveNodes(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", opts).Extract()
454	th.AssertNoErr(t, err)
455	th.AssertEquals(t, result, "2a0ff107-e789-4660-a122-3816c43af703")
456}
457
458func TestReplaceNodes(t *testing.T) {
459	th.SetupHTTP()
460	defer th.TeardownHTTP()
461	HandleReplaceNodeSuccessfully(t)
462	opts := clusters.ReplaceNodesOpts{
463		Nodes: map[string]string{"node-1234": "node-5678"},
464	}
465	actionID, err := clusters.ReplaceNodes(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", opts).Extract()
466	th.AssertNoErr(t, err)
467	th.AssertEquals(t, actionID, "2a0ff107-e789-4660-a122-3816c43af703")
468}
469
470func TestClusterCollect(t *testing.T) {
471	th.SetupHTTP()
472	defer th.TeardownHTTP()
473	HandleClusterCollectSuccessfully(t)
474	opts := clusters.CollectOpts{
475		Path: "foo.bar",
476	}
477	attributes, err := clusters.Collect(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", opts).Extract()
478	th.AssertNoErr(t, err)
479	th.AssertDeepEquals(t, ExpectedCollectAttributes, attributes)
480}
481
482func TestOperation(t *testing.T) {
483	th.SetupHTTP()
484	defer th.TeardownHTTP()
485
486	HandleOpsSuccessfully(t)
487
488	clusterOpts := clusters.OperationOpts{
489		Operation: clusters.PauseOperation,
490		Filters:   clusters.OperationFilters{"role": "slave"},
491		Params:    clusters.OperationParams{"type": "soft"},
492	}
493	actual, err := clusters.Ops(fake.ServiceClient(), "7d85f602-a948-4a30-afd4-e84f47471c15", clusterOpts).Extract()
494	th.AssertNoErr(t, err)
495	th.AssertDeepEquals(t, OperationExpectedActionID, actual)
496}
497