1# Copyright 2016 Huawei, Inc. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may 4# not use this file except in compliance with the License. You may obtain 5# a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations 13# under the License. 14# 15 16from unittest import mock 17from unittest.mock import call 18 19from osc_lib.cli import format_columns 20from osc_lib import exceptions 21from osc_lib import utils 22 23from openstackclient.compute.v2 import aggregate 24from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes 25 26 27class TestAggregate(compute_fakes.TestComputev2): 28 29 fake_ag = compute_fakes.FakeAggregate.create_one_aggregate() 30 31 columns = ( 32 'availability_zone', 33 'hosts', 34 'id', 35 'name', 36 'properties', 37 ) 38 39 data = ( 40 fake_ag.availability_zone, 41 format_columns.ListColumn(fake_ag.hosts), 42 fake_ag.id, 43 fake_ag.name, 44 format_columns.DictColumn(fake_ag.metadata), 45 ) 46 47 def setUp(self): 48 super(TestAggregate, self).setUp() 49 50 # Get a shortcut to the AggregateManager Mock 51 self.aggregate_mock = self.app.client_manager.compute.aggregates 52 self.aggregate_mock.reset_mock() 53 54 55class TestAggregateAddHost(TestAggregate): 56 57 def setUp(self): 58 super(TestAggregateAddHost, self).setUp() 59 60 self.aggregate_mock.get.return_value = self.fake_ag 61 self.aggregate_mock.add_host.return_value = self.fake_ag 62 self.cmd = aggregate.AddAggregateHost(self.app, None) 63 64 def test_aggregate_add_host(self): 65 arglist = [ 66 'ag1', 67 'host1', 68 ] 69 verifylist = [ 70 ('aggregate', 'ag1'), 71 ('host', 'host1'), 72 ] 73 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 74 columns, data = self.cmd.take_action(parsed_args) 75 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 76 self.aggregate_mock.add_host.assert_called_once_with(self.fake_ag, 77 parsed_args.host) 78 self.assertEqual(self.columns, columns) 79 self.assertItemEqual(self.data, data) 80 81 82class TestAggregateCreate(TestAggregate): 83 84 def setUp(self): 85 super(TestAggregateCreate, self).setUp() 86 87 self.aggregate_mock.create.return_value = self.fake_ag 88 self.aggregate_mock.set_metadata.return_value = self.fake_ag 89 self.cmd = aggregate.CreateAggregate(self.app, None) 90 91 def test_aggregate_create(self): 92 arglist = [ 93 'ag1', 94 ] 95 verifylist = [ 96 ('name', 'ag1'), 97 ] 98 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 99 columns, data = self.cmd.take_action(parsed_args) 100 self.aggregate_mock.create.assert_called_once_with(parsed_args.name, 101 None) 102 self.assertEqual(self.columns, columns) 103 self.assertItemEqual(self.data, data) 104 105 def test_aggregate_create_with_zone(self): 106 arglist = [ 107 '--zone', 'zone1', 108 'ag1', 109 ] 110 verifylist = [ 111 ('zone', 'zone1'), 112 ('name', 'ag1'), 113 ] 114 115 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 116 columns, data = self.cmd.take_action(parsed_args) 117 self.aggregate_mock.create.assert_called_once_with(parsed_args.name, 118 parsed_args.zone) 119 self.assertEqual(self.columns, columns) 120 self.assertItemEqual(self.data, data) 121 122 def test_aggregate_create_with_property(self): 123 arglist = [ 124 '--property', 'key1=value1', 125 '--property', 'key2=value2', 126 'ag1', 127 ] 128 verifylist = [ 129 ('property', {'key1': 'value1', 'key2': 'value2'}), 130 ('name', 'ag1'), 131 ] 132 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 133 columns, data = self.cmd.take_action(parsed_args) 134 self.aggregate_mock.create.assert_called_once_with(parsed_args.name, 135 None) 136 self.aggregate_mock.set_metadata.assert_called_once_with( 137 self.fake_ag, parsed_args.property) 138 self.assertEqual(self.columns, columns) 139 self.assertItemEqual(self.data, data) 140 141 142class TestAggregateDelete(TestAggregate): 143 144 fake_ags = compute_fakes.FakeAggregate.create_aggregates(count=2) 145 146 def setUp(self): 147 super(TestAggregateDelete, self).setUp() 148 149 self.aggregate_mock.get = ( 150 compute_fakes.FakeAggregate.get_aggregates(self.fake_ags)) 151 self.cmd = aggregate.DeleteAggregate(self.app, None) 152 153 def test_aggregate_delete(self): 154 arglist = [ 155 self.fake_ags[0].id 156 ] 157 verifylist = [ 158 ('aggregate', [self.fake_ags[0].id]), 159 ] 160 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 161 result = self.cmd.take_action(parsed_args) 162 self.aggregate_mock.get.assert_called_once_with(self.fake_ags[0].id) 163 self.aggregate_mock.delete.assert_called_once_with(self.fake_ags[0].id) 164 self.assertIsNone(result) 165 166 def test_delete_multiple_aggregates(self): 167 arglist = [] 168 for a in self.fake_ags: 169 arglist.append(a.id) 170 verifylist = [ 171 ('aggregate', arglist), 172 ] 173 174 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 175 result = self.cmd.take_action(parsed_args) 176 177 calls = [] 178 for a in self.fake_ags: 179 calls.append(call(a.id)) 180 self.aggregate_mock.delete.assert_has_calls(calls) 181 self.assertIsNone(result) 182 183 def test_delete_multiple_agggregates_with_exception(self): 184 arglist = [ 185 self.fake_ags[0].id, 186 'unexist_aggregate', 187 ] 188 verifylist = [ 189 ('aggregate', arglist), 190 ] 191 192 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 193 194 find_mock_result = [self.fake_ags[0], exceptions.CommandError] 195 with mock.patch.object(utils, 'find_resource', 196 side_effect=find_mock_result) as find_mock: 197 try: 198 self.cmd.take_action(parsed_args) 199 self.fail('CommandError should be raised.') 200 except exceptions.CommandError as e: 201 self.assertEqual('1 of 2 aggregates failed to delete.', 202 str(e)) 203 204 find_mock.assert_any_call(self.aggregate_mock, self.fake_ags[0].id) 205 find_mock.assert_any_call(self.aggregate_mock, 'unexist_aggregate') 206 207 self.assertEqual(2, find_mock.call_count) 208 self.aggregate_mock.delete.assert_called_once_with( 209 self.fake_ags[0].id 210 ) 211 212 213class TestAggregateList(TestAggregate): 214 215 list_columns = ( 216 "ID", 217 "Name", 218 "Availability Zone", 219 ) 220 221 list_columns_long = ( 222 "ID", 223 "Name", 224 "Availability Zone", 225 "Properties", 226 ) 227 228 list_data = (( 229 TestAggregate.fake_ag.id, 230 TestAggregate.fake_ag.name, 231 TestAggregate.fake_ag.availability_zone, 232 ), ) 233 234 list_data_long = (( 235 TestAggregate.fake_ag.id, 236 TestAggregate.fake_ag.name, 237 TestAggregate.fake_ag.availability_zone, 238 format_columns.DictColumn({ 239 key: value 240 for key, value in TestAggregate.fake_ag.metadata.items() 241 if key != 'availability_zone' 242 }), 243 ), ) 244 245 def setUp(self): 246 super(TestAggregateList, self).setUp() 247 248 self.aggregate_mock.list.return_value = [self.fake_ag] 249 self.cmd = aggregate.ListAggregate(self.app, None) 250 251 def test_aggregate_list(self): 252 253 parsed_args = self.check_parser(self.cmd, [], []) 254 columns, data = self.cmd.take_action(parsed_args) 255 256 self.assertEqual(self.list_columns, columns) 257 self.assertItemEqual(self.list_data, tuple(data)) 258 259 def test_aggregate_list_with_long(self): 260 arglist = [ 261 '--long', 262 ] 263 vertifylist = [ 264 ('long', True), 265 ] 266 parsed_args = self.check_parser(self.cmd, arglist, vertifylist) 267 columns, data = self.cmd.take_action(parsed_args) 268 269 self.assertEqual(self.list_columns_long, columns) 270 self.assertListItemEqual(self.list_data_long, tuple(data)) 271 272 273class TestAggregateRemoveHost(TestAggregate): 274 275 def setUp(self): 276 super(TestAggregateRemoveHost, self).setUp() 277 278 self.aggregate_mock.get.return_value = self.fake_ag 279 self.aggregate_mock.remove_host.return_value = self.fake_ag 280 self.cmd = aggregate.RemoveAggregateHost(self.app, None) 281 282 def test_aggregate_add_host(self): 283 arglist = [ 284 'ag1', 285 'host1', 286 ] 287 verifylist = [ 288 ('aggregate', 'ag1'), 289 ('host', 'host1'), 290 ] 291 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 292 columns, data = self.cmd.take_action(parsed_args) 293 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 294 self.aggregate_mock.remove_host.assert_called_once_with( 295 self.fake_ag, parsed_args.host) 296 self.assertEqual(self.columns, columns) 297 self.assertItemEqual(self.data, data) 298 299 300class TestAggregateSet(TestAggregate): 301 302 def setUp(self): 303 super(TestAggregateSet, self).setUp() 304 305 self.aggregate_mock.get.return_value = self.fake_ag 306 self.cmd = aggregate.SetAggregate(self.app, None) 307 308 def test_aggregate_set_no_option(self): 309 arglist = [ 310 'ag1', 311 ] 312 verifylist = [ 313 ('aggregate', 'ag1'), 314 ] 315 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 316 result = self.cmd.take_action(parsed_args) 317 318 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 319 self.assertNotCalled(self.aggregate_mock.update) 320 self.assertNotCalled(self.aggregate_mock.set_metadata) 321 self.assertIsNone(result) 322 323 def test_aggregate_set_with_name(self): 324 arglist = [ 325 '--name', 'new_name', 326 'ag1', 327 ] 328 verifylist = [ 329 ('name', 'new_name'), 330 ('aggregate', 'ag1'), 331 ] 332 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 333 result = self.cmd.take_action(parsed_args) 334 335 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 336 self.aggregate_mock.update.assert_called_once_with( 337 self.fake_ag, {'name': parsed_args.name}) 338 self.assertNotCalled(self.aggregate_mock.set_metadata) 339 self.assertIsNone(result) 340 341 def test_aggregate_set_with_zone(self): 342 arglist = [ 343 '--zone', 'new_zone', 344 'ag1', 345 ] 346 verifylist = [ 347 ('zone', 'new_zone'), 348 ('aggregate', 'ag1'), 349 ] 350 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 351 result = self.cmd.take_action(parsed_args) 352 353 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 354 self.aggregate_mock.update.assert_called_once_with( 355 self.fake_ag, {'availability_zone': parsed_args.zone}) 356 self.assertNotCalled(self.aggregate_mock.set_metadata) 357 self.assertIsNone(result) 358 359 def test_aggregate_set_with_property(self): 360 arglist = [ 361 '--property', 'key1=value1', 362 '--property', 'key2=value2', 363 'ag1', 364 ] 365 verifylist = [ 366 ('property', {'key1': 'value1', 'key2': 'value2'}), 367 ('aggregate', 'ag1'), 368 ] 369 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 370 result = self.cmd.take_action(parsed_args) 371 372 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 373 self.assertNotCalled(self.aggregate_mock.update) 374 self.aggregate_mock.set_metadata.assert_called_once_with( 375 self.fake_ag, parsed_args.property) 376 self.assertIsNone(result) 377 378 def test_aggregate_set_with_no_property_and_property(self): 379 arglist = [ 380 '--no-property', 381 '--property', 'key2=value2', 382 'ag1', 383 ] 384 verifylist = [ 385 ('no_property', True), 386 ('property', {'key2': 'value2'}), 387 ('aggregate', 'ag1'), 388 ] 389 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 390 result = self.cmd.take_action(parsed_args) 391 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 392 self.assertNotCalled(self.aggregate_mock.update) 393 self.aggregate_mock.set_metadata.assert_called_once_with( 394 self.fake_ag, {'key1': None, 'key2': 'value2'}) 395 self.assertIsNone(result) 396 397 def test_aggregate_set_with_no_property(self): 398 arglist = [ 399 '--no-property', 400 'ag1', 401 ] 402 verifylist = [ 403 ('no_property', True), 404 ('aggregate', 'ag1'), 405 ] 406 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 407 result = self.cmd.take_action(parsed_args) 408 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 409 self.assertNotCalled(self.aggregate_mock.update) 410 self.aggregate_mock.set_metadata.assert_called_once_with( 411 self.fake_ag, {'key1': None}) 412 self.assertIsNone(result) 413 414 def test_aggregate_set_with_zone_and_no_property(self): 415 arglist = [ 416 '--zone', 'new_zone', 417 '--no-property', 418 'ag1', 419 ] 420 verifylist = [ 421 ('zone', 'new_zone'), 422 ('no_property', True), 423 ('aggregate', 'ag1'), 424 ] 425 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 426 result = self.cmd.take_action(parsed_args) 427 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 428 self.aggregate_mock.update.assert_called_once_with( 429 self.fake_ag, {'availability_zone': parsed_args.zone}) 430 self.aggregate_mock.set_metadata.assert_called_once_with( 431 self.fake_ag, {'key1': None}) 432 self.assertIsNone(result) 433 434 435class TestAggregateShow(TestAggregate): 436 437 columns = ( 438 'availability_zone', 439 'hosts', 440 'id', 441 'name', 442 'properties', 443 ) 444 445 data = ( 446 TestAggregate.fake_ag.availability_zone, 447 format_columns.ListColumn(TestAggregate.fake_ag.hosts), 448 TestAggregate.fake_ag.id, 449 TestAggregate.fake_ag.name, 450 format_columns.DictColumn({ 451 key: value 452 for key, value in TestAggregate.fake_ag.metadata.items() 453 if key != 'availability_zone' 454 }), 455 ) 456 457 def setUp(self): 458 super(TestAggregateShow, self).setUp() 459 460 self.aggregate_mock.get.return_value = self.fake_ag 461 self.cmd = aggregate.ShowAggregate(self.app, None) 462 463 def test_aggregate_show(self): 464 arglist = [ 465 'ag1', 466 ] 467 verifylist = [ 468 ('aggregate', 'ag1'), 469 ] 470 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 471 columns, data = self.cmd.take_action(parsed_args) 472 self.aggregate_mock.get.assert_called_once_with(parsed_args.aggregate) 473 474 self.assertEqual(self.columns, columns) 475 self.assertItemEqual(self.data, tuple(data)) 476 477 478class TestAggregateUnset(TestAggregate): 479 480 def setUp(self): 481 super(TestAggregateUnset, self).setUp() 482 483 self.aggregate_mock.get.return_value = self.fake_ag 484 self.cmd = aggregate.UnsetAggregate(self.app, None) 485 486 def test_aggregate_unset(self): 487 arglist = [ 488 '--property', 'unset_key', 489 'ag1', 490 ] 491 verifylist = [ 492 ('property', ['unset_key']), 493 ('aggregate', 'ag1'), 494 ] 495 496 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 497 result = self.cmd.take_action(parsed_args) 498 self.aggregate_mock.set_metadata.assert_called_once_with( 499 self.fake_ag, {'unset_key': None}) 500 self.assertIsNone(result) 501 502 def test_aggregate_unset_multiple_properties(self): 503 arglist = [ 504 '--property', 'unset_key1', 505 '--property', 'unset_key2', 506 'ag1', 507 ] 508 verifylist = [ 509 ('property', ['unset_key1', 'unset_key2']), 510 ('aggregate', 'ag1'), 511 ] 512 513 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 514 result = self.cmd.take_action(parsed_args) 515 self.aggregate_mock.set_metadata.assert_called_once_with( 516 self.fake_ag, {'unset_key1': None, 'unset_key2': None}) 517 self.assertIsNone(result) 518 519 def test_aggregate_unset_no_option(self): 520 arglist = [ 521 'ag1', 522 ] 523 verifylist = [ 524 ('property', None), 525 ('aggregate', 'ag1'), 526 ] 527 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 528 result = self.cmd.take_action(parsed_args) 529 self.assertNotCalled(self.aggregate_mock.set_metadata) 530 self.assertIsNone(result) 531