python-openstackclient 8.0.0__py3-none-any.whl → 8.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. openstackclient/api/compute_v2.py +2 -2
  2. openstackclient/api/volume_v2.py +60 -0
  3. openstackclient/api/volume_v3.py +60 -0
  4. openstackclient/compute/client.py +5 -0
  5. openstackclient/compute/v2/console.py +7 -0
  6. openstackclient/compute/v2/console_connection.py +48 -0
  7. openstackclient/compute/v2/flavor.py +14 -1
  8. openstackclient/compute/v2/keypair.py +10 -3
  9. openstackclient/compute/v2/server.py +76 -13
  10. openstackclient/compute/v2/server_event.py +1 -1
  11. openstackclient/identity/common.py +85 -11
  12. openstackclient/identity/v3/application_credential.py +88 -87
  13. openstackclient/identity/v3/domain.py +67 -49
  14. openstackclient/identity/v3/group.py +113 -68
  15. openstackclient/identity/v3/project.py +42 -20
  16. openstackclient/identity/v3/role.py +7 -2
  17. openstackclient/identity/v3/user.py +38 -5
  18. openstackclient/image/client.py +5 -0
  19. openstackclient/image/v1/image.py +16 -1
  20. openstackclient/image/v2/cache.py +10 -6
  21. openstackclient/image/v2/image.py +59 -12
  22. openstackclient/image/v2/metadef_objects.py +8 -2
  23. openstackclient/image/v2/metadef_properties.py +9 -2
  24. openstackclient/network/client.py +0 -6
  25. openstackclient/network/v2/floating_ip.py +58 -29
  26. openstackclient/network/v2/network_qos_rule.py +3 -11
  27. openstackclient/network/v2/port.py +16 -0
  28. openstackclient/network/v2/router.py +1 -1
  29. openstackclient/network/v2/security_group.py +49 -7
  30. openstackclient/network/v2/security_group_rule.py +18 -1
  31. openstackclient/shell.py +1 -1
  32. openstackclient/tests/functional/base.py +5 -1
  33. openstackclient/tests/functional/compute/v2/test_keypair.py +41 -5
  34. openstackclient/tests/functional/identity/v3/test_access_rule.py +1 -1
  35. openstackclient/tests/functional/identity/v3/test_application_credential.py +7 -7
  36. openstackclient/tests/functional/image/v2/test_image.py +36 -14
  37. openstackclient/tests/functional/volume/v2/test_volume.py +1 -1
  38. openstackclient/tests/functional/volume/v3/test_volume.py +2 -2
  39. openstackclient/tests/unit/api/test_volume_v2.py +124 -0
  40. openstackclient/tests/unit/api/test_volume_v3.py +124 -0
  41. openstackclient/tests/unit/compute/v2/fakes.py +81 -305
  42. openstackclient/tests/unit/compute/v2/test_console.py +18 -1
  43. openstackclient/tests/unit/compute/v2/test_console_connection.py +72 -0
  44. openstackclient/tests/unit/compute/v2/test_flavor.py +160 -175
  45. openstackclient/tests/unit/compute/v2/test_keypair.py +12 -5
  46. openstackclient/tests/unit/compute/v2/test_server.py +211 -97
  47. openstackclient/tests/unit/compute/v2/test_server_backup.py +32 -71
  48. openstackclient/tests/unit/compute/v2/test_server_event.py +2 -2
  49. openstackclient/tests/unit/compute/v2/test_server_image.py +33 -72
  50. openstackclient/tests/unit/compute/v2/test_server_migration.py +4 -4
  51. openstackclient/tests/unit/identity/v3/test_application_credential.py +93 -65
  52. openstackclient/tests/unit/identity/v3/test_domain.py +117 -107
  53. openstackclient/tests/unit/identity/v3/test_group.py +353 -202
  54. openstackclient/tests/unit/identity/v3/test_project.py +46 -53
  55. openstackclient/tests/unit/identity/v3/test_role.py +2 -8
  56. openstackclient/tests/unit/identity/v3/test_user.py +86 -6
  57. openstackclient/tests/unit/image/v1/test_image.py +55 -9
  58. openstackclient/tests/unit/image/v2/test_image.py +128 -58
  59. openstackclient/tests/unit/image/v2/test_metadef_objects.py +22 -0
  60. openstackclient/tests/unit/image/v2/test_metadef_properties.py +24 -10
  61. openstackclient/tests/unit/network/v2/fakes.py +406 -485
  62. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +13 -19
  63. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +2 -2
  64. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +3 -5
  65. openstackclient/tests/unit/network/v2/test_network.py +4 -4
  66. openstackclient/tests/unit/network/v2/test_network_agent.py +15 -29
  67. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +16 -19
  68. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +79 -152
  69. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +4 -6
  70. openstackclient/tests/unit/network/v2/test_network_rbac.py +2 -2
  71. openstackclient/tests/unit/network/v2/test_port.py +57 -17
  72. openstackclient/tests/unit/network/v2/test_router.py +73 -57
  73. openstackclient/tests/unit/network/v2/test_security_group_network.py +31 -27
  74. openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +1 -3
  75. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +82 -39
  76. openstackclient/tests/unit/volume/v2/fakes.py +1 -2
  77. openstackclient/tests/unit/volume/v2/test_service.py +57 -91
  78. openstackclient/tests/unit/volume/v2/test_volume.py +466 -410
  79. openstackclient/tests/unit/volume/v2/test_volume_backup.py +141 -148
  80. openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +293 -283
  81. openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +61 -71
  82. openstackclient/tests/unit/volume/v3/test_service.py +221 -141
  83. openstackclient/tests/unit/volume/v3/test_volume.py +569 -534
  84. openstackclient/tests/unit/volume/v3/test_volume_attachment.py +1 -1
  85. openstackclient/tests/unit/volume/v3/test_volume_backup.py +198 -203
  86. openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +682 -47
  87. openstackclient/volume/v2/service.py +41 -38
  88. openstackclient/volume/v2/volume.py +140 -88
  89. openstackclient/volume/v2/volume_backup.py +9 -3
  90. openstackclient/volume/v2/volume_snapshot.py +121 -84
  91. openstackclient/volume/v3/block_storage_log_level.py +22 -28
  92. openstackclient/volume/v3/service.py +105 -14
  93. openstackclient/volume/v3/volume.py +287 -99
  94. openstackclient/volume/v3/volume_backup.py +24 -19
  95. openstackclient/volume/v3/volume_group.py +1 -1
  96. openstackclient/volume/v3/volume_snapshot.py +485 -10
  97. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/AUTHORS +13 -0
  98. python_openstackclient-8.2.0.dist-info/METADATA +264 -0
  99. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/RECORD +104 -98
  100. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/entry_points.txt +7 -6
  101. python_openstackclient-8.2.0.dist-info/pbr.json +1 -0
  102. python_openstackclient-8.0.0.dist-info/METADATA +0 -166
  103. python_openstackclient-8.0.0.dist-info/pbr.json +0 -1
  104. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/LICENSE +0 -0
  105. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/WHEEL +0 -0
  106. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/top_level.txt +0 -0
@@ -77,8 +77,7 @@ class TestProjectCreate(TestProject):
77
77
  ]
78
78
  verifylist = [
79
79
  ('parent', None),
80
- ('enable', False),
81
- ('disable', False),
80
+ ('enabled', True),
82
81
  ('name', self.project.name),
83
82
  ('tags', []),
84
83
  ]
@@ -134,8 +133,7 @@ class TestProjectCreate(TestProject):
134
133
  ]
135
134
  verifylist = [
136
135
  ('description', 'new desc'),
137
- ('enable', False),
138
- ('disable', False),
136
+ ('enabled', True),
139
137
  ('name', self.project.name),
140
138
  ('parent', None),
141
139
  ('tags', []),
@@ -172,8 +170,7 @@ class TestProjectCreate(TestProject):
172
170
  ]
173
171
  verifylist = [
174
172
  ('domain', self.project.domain_id),
175
- ('enable', False),
176
- ('disable', False),
173
+ ('enabled', True),
177
174
  ('name', self.project.name),
178
175
  ('parent', None),
179
176
  ('tags', []),
@@ -210,8 +207,7 @@ class TestProjectCreate(TestProject):
210
207
  ]
211
208
  verifylist = [
212
209
  ('domain', self.project.domain_id),
213
- ('enable', False),
214
- ('disable', False),
210
+ ('enabled', True),
215
211
  ('name', self.project.name),
216
212
  ('parent', None),
217
213
  ('tags', []),
@@ -243,8 +239,7 @@ class TestProjectCreate(TestProject):
243
239
  self.project.name,
244
240
  ]
245
241
  verifylist = [
246
- ('enable', True),
247
- ('disable', False),
242
+ ('enabled', True),
248
243
  ('name', self.project.name),
249
244
  ('parent', None),
250
245
  ('tags', []),
@@ -279,8 +274,7 @@ class TestProjectCreate(TestProject):
279
274
  self.project.name,
280
275
  ]
281
276
  verifylist = [
282
- ('enable', False),
283
- ('disable', True),
277
+ ('enabled', False),
284
278
  ('name', self.project.name),
285
279
  ('parent', None),
286
280
  ]
@@ -317,7 +311,7 @@ class TestProjectCreate(TestProject):
317
311
  self.project.name,
318
312
  ]
319
313
  verifylist = [
320
- ('property', {'fee': 'fi', 'fo': 'fum'}),
314
+ ('properties', {'fee': 'fi', 'fo': 'fum'}),
321
315
  ('name', self.project.name),
322
316
  ]
323
317
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -354,11 +348,10 @@ class TestProjectCreate(TestProject):
354
348
  ]
355
349
  verifylist = [
356
350
  ('parent', None),
357
- ('enable', False),
358
- ('disable', False),
351
+ ('enabled', True),
359
352
  ('name', self.project.name),
360
353
  ('tags', []),
361
- ('property', {'is_domain': 'false'}),
354
+ ('properties', {'is_domain': 'false'}),
362
355
  ('name', self.project.name),
363
356
  ]
364
357
 
@@ -393,11 +386,10 @@ class TestProjectCreate(TestProject):
393
386
  ]
394
387
  verifylist = [
395
388
  ('parent', None),
396
- ('enable', False),
397
- ('disable', False),
389
+ ('enabled', True),
398
390
  ('name', self.project.name),
399
391
  ('tags', []),
400
- ('property', {'is_domain': 'true'}),
392
+ ('properties', {'is_domain': 'true'}),
401
393
  ('name', self.project.name),
402
394
  ]
403
395
 
@@ -432,11 +424,10 @@ class TestProjectCreate(TestProject):
432
424
  ]
433
425
  verifylist = [
434
426
  ('parent', None),
435
- ('enable', False),
436
- ('disable', False),
427
+ ('enabled', True),
437
428
  ('name', self.project.name),
438
429
  ('tags', []),
439
- ('property', {'is_domain': 'none'}),
430
+ ('properties', {'is_domain': 'none'}),
440
431
  ('name', self.project.name),
441
432
  ]
442
433
 
@@ -481,8 +472,7 @@ class TestProjectCreate(TestProject):
481
472
  verifylist = [
482
473
  ('domain', self.project.domain_id),
483
474
  ('parent', self.parent.name),
484
- ('enable', False),
485
- ('disable', False),
475
+ ('enabled', True),
486
476
  ('name', self.project.name),
487
477
  ('tags', []),
488
478
  ]
@@ -544,8 +534,7 @@ class TestProjectCreate(TestProject):
544
534
  verifylist = [
545
535
  ('domain', self.project.domain_id),
546
536
  ('parent', 'invalid'),
547
- ('enable', False),
548
- ('disable', False),
537
+ ('enabled', True),
549
538
  ('name', self.project.name),
550
539
  ]
551
540
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -566,8 +555,7 @@ class TestProjectCreate(TestProject):
566
555
  ]
567
556
  verifylist = [
568
557
  ('domain', self.project.domain_id),
569
- ('enable', False),
570
- ('disable', False),
558
+ ('enabled', True),
571
559
  ('name', self.project.name),
572
560
  ('parent', None),
573
561
  ('tags', ['foo']),
@@ -602,8 +590,7 @@ class TestProjectCreate(TestProject):
602
590
  verifylist = [
603
591
  ('immutable', True),
604
592
  ('description', None),
605
- ('enable', False),
606
- ('disable', False),
593
+ ('enabled', True),
607
594
  ('name', self.project.name),
608
595
  ('parent', None),
609
596
  ('tags', []),
@@ -638,10 +625,9 @@ class TestProjectCreate(TestProject):
638
625
  self.project.name,
639
626
  ]
640
627
  verifylist = [
641
- ('no_immutable', True),
628
+ ('immutable', False),
642
629
  ('description', None),
643
- ('enable', False),
644
- ('disable', False),
630
+ ('enabled', True),
645
631
  ('name', self.project.name),
646
632
  ('parent', None),
647
633
  ('tags', []),
@@ -941,6 +927,22 @@ class TestProjectList(TestProject):
941
927
  )
942
928
  self.assertEqual(datalist, tuple(data))
943
929
 
930
+ def test_project_list_with_option_enabled(self):
931
+ arglist = ['--enabled']
932
+ verifylist = [('is_enabled', True)]
933
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
934
+
935
+ # In base command class Lister in cliff, abstract method take_action()
936
+ # returns a tuple containing the column names and an iterable
937
+ # containing the data to be listed.
938
+ columns, data = self.cmd.take_action(parsed_args)
939
+
940
+ kwargs = {'is_enabled': True}
941
+ self.projects_mock.list.assert_called_with(**kwargs)
942
+
943
+ self.assertEqual(self.columns, columns)
944
+ self.assertEqual(self.datalist, tuple(data))
945
+
944
946
 
945
947
  class TestProjectSet(TestProject):
946
948
  domain = identity_fakes.FakeDomain.create_one_domain()
@@ -965,8 +967,7 @@ class TestProjectSet(TestProject):
965
967
  ]
966
968
  verifylist = [
967
969
  ('project', self.project.name),
968
- ('enable', False),
969
- ('disable', False),
970
+ ('enabled', None),
970
971
  ]
971
972
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
972
973
 
@@ -985,8 +986,7 @@ class TestProjectSet(TestProject):
985
986
  verifylist = [
986
987
  ('name', 'qwerty'),
987
988
  ('domain', self.project.domain_id),
988
- ('enable', False),
989
- ('disable', False),
989
+ ('enabled', None),
990
990
  ('project', self.project.name),
991
991
  ]
992
992
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1013,8 +1013,7 @@ class TestProjectSet(TestProject):
1013
1013
  verifylist = [
1014
1014
  ('domain', self.project.domain_id),
1015
1015
  ('description', 'new desc'),
1016
- ('enable', False),
1017
- ('disable', False),
1016
+ ('enabled', None),
1018
1017
  ('project', self.project.name),
1019
1018
  ]
1020
1019
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1037,8 +1036,7 @@ class TestProjectSet(TestProject):
1037
1036
  ]
1038
1037
  verifylist = [
1039
1038
  ('domain', self.project.domain_id),
1040
- ('enable', True),
1041
- ('disable', False),
1039
+ ('enabled', True),
1042
1040
  ('project', self.project.name),
1043
1041
  ]
1044
1042
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1061,8 +1059,7 @@ class TestProjectSet(TestProject):
1061
1059
  ]
1062
1060
  verifylist = [
1063
1061
  ('domain', self.project.domain_id),
1064
- ('enable', False),
1065
- ('disable', True),
1062
+ ('enabled', False),
1066
1063
  ('project', self.project.name),
1067
1064
  ]
1068
1065
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1088,7 +1085,7 @@ class TestProjectSet(TestProject):
1088
1085
  ]
1089
1086
  verifylist = [
1090
1087
  ('domain', self.project.domain_id),
1091
- ('property', {'fee': 'fi', 'fo': 'fum'}),
1088
+ ('properties', {'fee': 'fi', 'fo': 'fum'}),
1092
1089
  ('project', self.project.name),
1093
1090
  ]
1094
1091
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1116,8 +1113,7 @@ class TestProjectSet(TestProject):
1116
1113
  verifylist = [
1117
1114
  ('name', 'qwerty'),
1118
1115
  ('domain', self.project.domain_id),
1119
- ('enable', False),
1120
- ('disable', False),
1116
+ ('enabled', None),
1121
1117
  ('project', self.project.name),
1122
1118
  ('tags', ['foo']),
1123
1119
  ]
@@ -1144,8 +1140,7 @@ class TestProjectSet(TestProject):
1144
1140
  self.project.name,
1145
1141
  ]
1146
1142
  verifylist = [
1147
- ('enable', False),
1148
- ('disable', False),
1143
+ ('enabled', None),
1149
1144
  ('project', self.project.name),
1150
1145
  ('remove_tag', ['tag1', 'tag2']),
1151
1146
  ]
@@ -1167,8 +1162,7 @@ class TestProjectSet(TestProject):
1167
1162
  verifylist = [
1168
1163
  ('domain', self.project.domain_id),
1169
1164
  ('immutable', True),
1170
- ('enable', False),
1171
- ('disable', False),
1165
+ ('enabled', None),
1172
1166
  ('project', self.project.name),
1173
1167
  ]
1174
1168
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1191,9 +1185,8 @@ class TestProjectSet(TestProject):
1191
1185
  ]
1192
1186
  verifylist = [
1193
1187
  ('domain', self.project.domain_id),
1194
- ('no_immutable', True),
1195
- ('enable', False),
1196
- ('disable', False),
1188
+ ('immutable', False),
1189
+ ('enabled', None),
1197
1190
  ('project', self.project.name),
1198
1191
  ]
1199
1192
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -494,7 +494,6 @@ class TestRoleCreate(identity_fakes.TestIdentityv3):
494
494
  # Set expected values
495
495
  kwargs = {
496
496
  'name': self.role.name,
497
- 'options': {},
498
497
  }
499
498
 
500
499
  self.identity_sdk_client.create_role.assert_called_with(**kwargs)
@@ -533,7 +532,6 @@ class TestRoleCreate(identity_fakes.TestIdentityv3):
533
532
  kwargs = {
534
533
  'domain_id': self.domain.id,
535
534
  'name': self.role_with_domain.name,
536
- 'options': {},
537
535
  }
538
536
 
539
537
  self.identity_sdk_client.create_role.assert_called_with(**kwargs)
@@ -572,7 +570,6 @@ class TestRoleCreate(identity_fakes.TestIdentityv3):
572
570
  kwargs = {
573
571
  'name': self.role_with_description.name,
574
572
  'description': self.role_with_description.description,
575
- 'options': {},
576
573
  }
577
574
 
578
575
  self.identity_sdk_client.create_role.assert_called_with(**kwargs)
@@ -629,7 +626,7 @@ class TestRoleCreate(identity_fakes.TestIdentityv3):
629
626
  self.role.name,
630
627
  ]
631
628
  verifylist = [
632
- ('no_immutable', True),
629
+ ('immutable', False),
633
630
  ('name', self.role.name),
634
631
  ]
635
632
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1437,7 +1434,6 @@ class TestRoleSet(identity_fakes.TestIdentityv3):
1437
1434
  kwargs = {
1438
1435
  'name': 'over',
1439
1436
  'role': self.role.id,
1440
- 'options': {},
1441
1437
  }
1442
1438
  self.identity_sdk_client.update_role.assert_called_with(**kwargs)
1443
1439
  self.assertIsNone(result)
@@ -1472,7 +1468,6 @@ class TestRoleSet(identity_fakes.TestIdentityv3):
1472
1468
  'name': 'over',
1473
1469
  'role': self.role_with_domain.id,
1474
1470
  'domain_id': self.domain2.id,
1475
- 'options': {},
1476
1471
  }
1477
1472
  self.identity_sdk_client.update_role.assert_called_with(**kwargs)
1478
1473
  self.assertIsNone(result)
@@ -1501,7 +1496,6 @@ class TestRoleSet(identity_fakes.TestIdentityv3):
1501
1496
  'name': 'over',
1502
1497
  'description': 'role description',
1503
1498
  'role': self.role_with_domain.id,
1504
- 'options': {},
1505
1499
  }
1506
1500
  self.identity_sdk_client.update_role.assert_called_with(**kwargs)
1507
1501
  self.assertIsNone(result)
@@ -1544,7 +1538,7 @@ class TestRoleSet(identity_fakes.TestIdentityv3):
1544
1538
  ]
1545
1539
  verifylist = [
1546
1540
  ('name', 'over'),
1547
- ('no_immutable', True),
1541
+ ('immutable', False),
1548
1542
  ('role', self.role_with_domain.name),
1549
1543
  ]
1550
1544
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -44,6 +44,7 @@ class TestUserCreate(identity_fakes.TestIdentityv3):
44
44
  'name',
45
45
  'description',
46
46
  'password_expires_at',
47
+ 'options',
47
48
  )
48
49
 
49
50
  def setUp(self):
@@ -63,6 +64,7 @@ class TestUserCreate(identity_fakes.TestIdentityv3):
63
64
  self.user.name,
64
65
  self.user.description,
65
66
  self.user.password_expires_at,
67
+ getattr(self.user, 'options', {}),
66
68
  )
67
69
 
68
70
  self.identity_sdk_client.find_domain.return_value = self.domain
@@ -163,6 +165,53 @@ class TestUserCreate(identity_fakes.TestIdentityv3):
163
165
  self.assertEqual(self.columns, columns)
164
166
  self.assertEqual(self.datalist, data)
165
167
 
168
+ def test_user_create_password_prompt_no_warning(self):
169
+ arglist = [
170
+ '--password-prompt',
171
+ self.user.name,
172
+ ]
173
+ verifylist = [
174
+ ('password', None),
175
+ ('password_prompt', True),
176
+ ('enable', False),
177
+ ('disable', False),
178
+ ('name', self.user.name),
179
+ ]
180
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
181
+ import logging
182
+
183
+ # Mock the password prompt
184
+ mocker = mock.Mock()
185
+ mocker.return_value = 'abc123'
186
+
187
+ # Use assertLogs to verify no warnings are logged
188
+ logger = 'openstackclient.identity.v3.user'
189
+ with mock.patch("osc_lib.utils.get_password", mocker):
190
+ with self.assertLogs(logger, level='WARNING') as log_ctx:
191
+ logging.getLogger(logger).warning(
192
+ "Dummy warning for test setup"
193
+ )
194
+ columns, data = self.cmd.take_action(parsed_args)
195
+
196
+ self.assertEqual(1, len(log_ctx.records))
197
+ self.assertIn(
198
+ "Dummy warning for test setup", log_ctx.output[0]
199
+ )
200
+ self.assertNotIn(
201
+ "No password was supplied", ''.join(log_ctx.output)
202
+ )
203
+
204
+ # Set expected values
205
+ kwargs = {
206
+ 'name': self.user.name,
207
+ 'is_enabled': True,
208
+ 'password': 'abc123',
209
+ }
210
+ self.identity_sdk_client.create_user.assert_called_with(**kwargs)
211
+
212
+ self.assertEqual(self.columns, columns)
213
+ self.assertEqual(self.datalist, data)
214
+
166
215
  def test_user_create_email(self):
167
216
  arglist = [
168
217
  '--email',
@@ -232,6 +281,7 @@ class TestUserCreate(identity_fakes.TestIdentityv3):
232
281
  self.user.name,
233
282
  self.user.description,
234
283
  self.user.password_expires_at,
284
+ getattr(self.user, 'options', {}),
235
285
  )
236
286
  self.assertEqual(datalist, data)
237
287
 
@@ -279,6 +329,7 @@ class TestUserCreate(identity_fakes.TestIdentityv3):
279
329
  self.user.name,
280
330
  self.user.description,
281
331
  self.user.password_expires_at,
332
+ getattr(self.user, 'options', {}),
282
333
  )
283
334
  self.assertEqual(datalist, data)
284
335
 
@@ -988,6 +1039,24 @@ class TestUserList(identity_fakes.TestIdentityv3):
988
1039
  self.assertEqual(self.columns, columns)
989
1040
  self.assertEqual(self.datalist, tuple(data))
990
1041
 
1042
+ def test_user_list_with_option_enabled(self):
1043
+ arglist = ['--enabled']
1044
+ verifylist = [('is_enabled', True)]
1045
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1046
+
1047
+ # In base command class Lister in cliff, abstract method take_action()
1048
+ # returns a tuple containing the column names and an iterable
1049
+ # containing the data to be listed.
1050
+ columns, data = self.cmd.take_action(parsed_args)
1051
+
1052
+ kwargs = {'domain_id': None, 'is_enabled': True}
1053
+ self.identity_sdk_client.users.assert_called_with(**kwargs)
1054
+ self.identity_sdk_client.find_user.assert_not_called()
1055
+ self.identity_sdk_client.group_users.assert_not_called()
1056
+
1057
+ self.assertEqual(self.columns, columns)
1058
+ self.assertEqual(self.datalist, tuple(data))
1059
+
991
1060
 
992
1061
  class TestUserSet(identity_fakes.TestIdentityv3):
993
1062
  project = sdk_fakes.generate_fake_resource(_project.Project)
@@ -1686,11 +1755,14 @@ class TestUserSetPassword(identity_fakes.TestIdentityv3):
1686
1755
  # Mock getting user current password.
1687
1756
  with self._mock_get_password(current_pass):
1688
1757
  result = self.cmd.take_action(parsed_args)
1758
+ self.assertIsNone(result)
1759
+
1760
+ conn = self.app.client_manager.sdk_connection
1761
+ user_id = conn.config.get_auth().get_user_id(conn.identity)
1689
1762
 
1690
1763
  self.identity_sdk_client.update_user.assert_called_with(
1691
- current_password=current_pass, password=new_pass
1764
+ user=user_id, current_password=current_pass, password=new_pass
1692
1765
  )
1693
- self.assertIsNone(result)
1694
1766
 
1695
1767
  def test_user_create_password_prompt(self):
1696
1768
  current_pass = 'old_pass'
@@ -1700,11 +1772,14 @@ class TestUserSetPassword(identity_fakes.TestIdentityv3):
1700
1772
  # Mock getting user current and new password.
1701
1773
  with self._mock_get_password(current_pass, new_pass):
1702
1774
  result = self.cmd.take_action(parsed_args)
1775
+ self.assertIsNone(result)
1776
+
1777
+ conn = self.app.client_manager.sdk_connection
1778
+ user_id = conn.config.get_auth().get_user_id(conn.identity)
1703
1779
 
1704
1780
  self.identity_sdk_client.update_user.assert_called_with(
1705
- current_password=current_pass, password=new_pass
1781
+ user=user_id, current_password=current_pass, password=new_pass
1706
1782
  )
1707
- self.assertIsNone(result)
1708
1783
 
1709
1784
  def test_user_password_change_no_prompt(self):
1710
1785
  current_pass = 'old_pass'
@@ -1722,11 +1797,14 @@ class TestUserSetPassword(identity_fakes.TestIdentityv3):
1722
1797
  parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1723
1798
 
1724
1799
  result = self.cmd.take_action(parsed_args)
1800
+ self.assertIsNone(result)
1801
+
1802
+ conn = self.app.client_manager.sdk_connection
1803
+ user_id = conn.config.get_auth().get_user_id(conn.identity)
1725
1804
 
1726
1805
  self.identity_sdk_client.update_user.assert_called_with(
1727
- current_password=current_pass, password=new_pass
1806
+ user=user_id, current_password=current_pass, password=new_pass
1728
1807
  )
1729
- self.assertIsNone(result)
1730
1808
 
1731
1809
 
1732
1810
  class TestUserShow(identity_fakes.TestIdentityv3):
@@ -1779,6 +1857,7 @@ class TestUserShow(identity_fakes.TestIdentityv3):
1779
1857
  'name',
1780
1858
  'description',
1781
1859
  'password_expires_at',
1860
+ 'options',
1782
1861
  )
1783
1862
  self.assertEqual(collist, columns)
1784
1863
  datalist = (
@@ -1790,6 +1869,7 @@ class TestUserShow(identity_fakes.TestIdentityv3):
1790
1869
  self.user.name,
1791
1870
  self.user.description,
1792
1871
  self.user.password_expires_at,
1872
+ getattr(self.user, 'options', {}),
1793
1873
  )
1794
1874
  self.assertEqual(datalist, data)
1795
1875
 
@@ -54,9 +54,9 @@ class TestImageCreate(image_fakes.TestImagev1):
54
54
  def setUp(self):
55
55
  super().setUp()
56
56
 
57
- self.image_client.create_image = mock.Mock(return_value=self.new_image)
58
- self.image_client.find_image = mock.Mock(return_value=self.new_image)
59
- self.image_client.update_image = mock.Mock(return_image=self.new_image)
57
+ self.image_client.create_image.return_value = self.new_image
58
+ self.image_client.find_image.return_value = self.new_image
59
+ self.image_client.update_image.return_value = self.new_image
60
60
 
61
61
  # Get the command object to test
62
62
  self.cmd = image.CreateImage(self.app, None)
@@ -212,8 +212,8 @@ class TestImageDelete(image_fakes.TestImagev1):
212
212
  super().setUp()
213
213
 
214
214
  # This is the return value for utils.find_resource()
215
- self.image_client.find_image = mock.Mock(return_value=self._image)
216
- self.image_client.delete_image = mock.Mock(return_value=None)
215
+ self.image_client.find_image.return_value = self._image
216
+ self.image_client.delete_image.return_value = None
217
217
 
218
218
  # Get the command object to test
219
219
  self.cmd = image.DeleteImage(self.app, None)
@@ -261,7 +261,6 @@ class TestImageList(image_fakes.TestImagev1):
261
261
  def setUp(self):
262
262
  super().setUp()
263
263
 
264
- self.image_client.images = mock.Mock()
265
264
  self.image_client.images.side_effect = [
266
265
  [self._image],
267
266
  [],
@@ -441,8 +440,8 @@ class TestImageSet(image_fakes.TestImagev1):
441
440
  super().setUp()
442
441
 
443
442
  # This is the return value for utils.find_resource()
444
- self.image_client.find_image = mock.Mock(return_value=self._image)
445
- self.image_client.update_image = mock.Mock(return_value=self._image)
443
+ self.image_client.find_image.return_value = self._image
444
+ self.image_client.update_image.return_value = self._image
446
445
 
447
446
  # Get the command object to test
448
447
  self.cmd = image.SetImage(self.app, None)
@@ -712,7 +711,7 @@ class TestImageShow(image_fakes.TestImagev1):
712
711
  def setUp(self):
713
712
  super().setUp()
714
713
 
715
- self.image_client.find_image = mock.Mock(return_value=self._image)
714
+ self.image_client.find_image.return_value = self._image
716
715
 
717
716
  # Get the command object to test
718
717
  self.cmd = image.ShowImage(self.app, None)
@@ -758,3 +757,50 @@ class TestImageShow(image_fakes.TestImagev1):
758
757
 
759
758
  size_index = columns.index('size')
760
759
  self.assertEqual(data[size_index].human_readable(), '2K')
760
+
761
+
762
+ class TestImageSave(image_fakes.TestImagev1):
763
+ image = image_fakes.create_one_image({})
764
+
765
+ def setUp(self):
766
+ super().setUp()
767
+
768
+ self.image_client.find_image.return_value = self.image
769
+ self.image_client.download_image.return_value = self.image
770
+
771
+ # Get the command object to test
772
+ self.cmd = image.SaveImage(self.app, None)
773
+
774
+ def test_save_data(self):
775
+ arglist = ['--file', '/path/to/file', self.image.id]
776
+
777
+ verifylist = [('file', '/path/to/file'), ('image', self.image.id)]
778
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
779
+
780
+ self.cmd.take_action(parsed_args)
781
+
782
+ self.image_client.download_image.assert_called_once_with(
783
+ self.image.id, output='/path/to/file', stream=True, chunk_size=1024
784
+ )
785
+
786
+ def test_save_data_with_chunk_size(self):
787
+ arglist = [
788
+ '--file',
789
+ '/path/to/file',
790
+ '--chunk-size',
791
+ '2048',
792
+ self.image.id,
793
+ ]
794
+
795
+ verifylist = [
796
+ ('file', '/path/to/file'),
797
+ ('chunk_size', 2048),
798
+ ('image', self.image.id),
799
+ ]
800
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
801
+
802
+ self.cmd.take_action(parsed_args)
803
+
804
+ self.image_client.download_image.assert_called_once_with(
805
+ self.image.id, output='/path/to/file', stream=True, chunk_size=2048
806
+ )