1# Copyright 2013 Nebula Inc. 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 17 18from keystoneauth1 import exceptions as ks_exc 19from osc_lib import exceptions 20from osc_lib import utils 21 22from openstackclient.identity.v2_0 import user 23from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes 24 25 26class TestUser(identity_fakes.TestIdentityv2): 27 28 fake_project = identity_fakes.FakeProject.create_one_project() 29 attr = { 30 'tenantId': fake_project.id, 31 } 32 fake_user = identity_fakes.FakeUser.create_one_user(attr) 33 34 def setUp(self): 35 super(TestUser, self).setUp() 36 37 # Get a shortcut to the TenantManager Mock 38 self.projects_mock = self.app.client_manager.identity.tenants 39 self.projects_mock.reset_mock() 40 41 # Get a shortcut to the UserManager Mock 42 self.users_mock = self.app.client_manager.identity.users 43 self.users_mock.reset_mock() 44 45 46class TestUserCreate(TestUser): 47 48 fake_project_c = identity_fakes.FakeProject.create_one_project() 49 attr = { 50 'tenantId': fake_project_c.id, 51 } 52 fake_user_c = identity_fakes.FakeUser.create_one_user(attr) 53 54 columns = ( 55 'email', 56 'enabled', 57 'id', 58 'name', 59 'project_id', 60 ) 61 datalist = ( 62 fake_user_c.email, 63 True, 64 fake_user_c.id, 65 fake_user_c.name, 66 fake_project_c.id, 67 ) 68 69 def setUp(self): 70 super(TestUserCreate, self).setUp() 71 72 self.projects_mock.get.return_value = self.fake_project_c 73 74 self.users_mock.create.return_value = self.fake_user_c 75 76 # Get the command object to test 77 self.cmd = user.CreateUser(self.app, None) 78 79 def test_user_create_no_options(self): 80 arglist = [ 81 self.fake_user_c.name, 82 ] 83 verifylist = [ 84 ('enable', False), 85 ('disable', False), 86 ('name', self.fake_user_c.name), 87 ] 88 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 89 90 # In base command class ShowOne in cliff, abstract method take_action() 91 # returns a two-part tuple with a tuple of column names and a tuple of 92 # data to be shown. 93 columns, data = self.cmd.take_action(parsed_args) 94 95 # Set expected values 96 kwargs = { 97 'enabled': True, 98 'tenant_id': None, 99 } 100 # UserManager.create(name, password, email, tenant_id=, enabled=) 101 self.users_mock.create.assert_called_with( 102 self.fake_user_c.name, 103 None, 104 None, 105 **kwargs 106 ) 107 108 self.assertEqual(self.columns, columns) 109 self.assertEqual(self.datalist, data) 110 111 def test_user_create_password(self): 112 arglist = [ 113 '--password', 'secret', 114 self.fake_user_c.name, 115 ] 116 verifylist = [ 117 ('name', self.fake_user_c.name), 118 ('password_prompt', False), 119 ('password', 'secret') 120 ] 121 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 122 123 # In base command class ShowOne in cliff, abstract method take_action() 124 # returns a two-part tuple with a tuple of column names and a tuple of 125 # data to be shown. 126 columns, data = self.cmd.take_action(parsed_args) 127 128 # Set expected values 129 kwargs = { 130 'enabled': True, 131 'tenant_id': None, 132 } 133 # UserManager.create(name, password, email, tenant_id=, enabled=) 134 self.users_mock.create.assert_called_with( 135 self.fake_user_c.name, 136 'secret', 137 None, 138 **kwargs 139 ) 140 self.assertEqual(self.columns, columns) 141 self.assertEqual(self.datalist, data) 142 143 def test_user_create_password_prompt(self): 144 arglist = [ 145 '--password-prompt', 146 self.fake_user_c.name, 147 ] 148 verifylist = [ 149 ('name', self.fake_user_c.name), 150 ('password_prompt', True) 151 ] 152 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 153 154 # In base command class ShowOne in cliff, abstract method take_action() 155 # returns a two-part tuple with a tuple of column names and a tuple of 156 # data to be shown. 157 mocker = mock.Mock() 158 mocker.return_value = 'abc123' 159 with mock.patch("osc_lib.utils.get_password", mocker): 160 columns, data = self.cmd.take_action(parsed_args) 161 162 # Set expected values 163 kwargs = { 164 'enabled': True, 165 'tenant_id': None, 166 } 167 # UserManager.create(name, password, email, tenant_id=, enabled=) 168 self.users_mock.create.assert_called_with( 169 self.fake_user_c.name, 170 'abc123', 171 None, 172 **kwargs 173 ) 174 175 self.assertEqual(self.columns, columns) 176 self.assertEqual(self.datalist, data) 177 178 def test_user_create_email(self): 179 arglist = [ 180 '--email', 'barney@example.com', 181 self.fake_user_c.name, 182 ] 183 verifylist = [ 184 ('name', self.fake_user_c.name), 185 ('email', 'barney@example.com'), 186 ] 187 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 188 189 # In base command class ShowOne in cliff, abstract method take_action() 190 # returns a two-part tuple with a tuple of column names and a tuple of 191 # data to be shown. 192 columns, data = self.cmd.take_action(parsed_args) 193 194 # Set expected values 195 kwargs = { 196 'enabled': True, 197 'tenant_id': None, 198 } 199 # UserManager.create(name, password, email, tenant_id=, enabled=) 200 self.users_mock.create.assert_called_with( 201 self.fake_user_c.name, 202 None, 203 'barney@example.com', 204 **kwargs 205 ) 206 207 self.assertEqual(self.columns, columns) 208 self.assertEqual(self.datalist, data) 209 210 def test_user_create_project(self): 211 # Return the new project 212 self.projects_mock.get.return_value = self.fake_project_c 213 214 # Set up to return an updated user 215 attr = { 216 'tenantId': self.fake_project_c.id, 217 } 218 user_2 = identity_fakes.FakeUser.create_one_user(attr) 219 self.users_mock.create.return_value = user_2 220 221 arglist = [ 222 '--project', self.fake_project_c.name, 223 user_2.name, 224 ] 225 verifylist = [ 226 ('name', user_2.name), 227 ('project', self.fake_project_c.name), 228 ] 229 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 230 231 # In base command class ShowOne in cliff, abstract method take_action() 232 # returns a two-part tuple with a tuple of column names and a tuple of 233 # data to be shown. 234 columns, data = self.cmd.take_action(parsed_args) 235 236 # Set expected values 237 kwargs = { 238 'enabled': True, 239 'tenant_id': self.fake_project_c.id, 240 } 241 # UserManager.create(name, password, email, tenant_id=, enabled=) 242 self.users_mock.create.assert_called_with( 243 user_2.name, 244 None, 245 None, 246 **kwargs 247 ) 248 249 self.assertEqual(self.columns, columns) 250 datalist = ( 251 user_2.email, 252 True, 253 user_2.id, 254 user_2.name, 255 self.fake_project_c.id, 256 ) 257 self.assertEqual(datalist, data) 258 259 def test_user_create_enable(self): 260 arglist = [ 261 '--enable', 262 self.fake_user_c.name, 263 ] 264 verifylist = [ 265 ('name', self.fake_user_c.name), 266 ('enable', True), 267 ('disable', False), 268 ] 269 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 270 271 # In base command class ShowOne in cliff, abstract method take_action() 272 # returns a two-part tuple with a tuple of column names and a tuple of 273 # data to be shown. 274 columns, data = self.cmd.take_action(parsed_args) 275 276 # Set expected values 277 kwargs = { 278 'enabled': True, 279 'tenant_id': None, 280 } 281 # UserManager.create(name, password, email, tenant_id=, enabled=) 282 self.users_mock.create.assert_called_with( 283 self.fake_user_c.name, 284 None, 285 None, 286 **kwargs 287 ) 288 289 self.assertEqual(self.columns, columns) 290 self.assertEqual(self.datalist, data) 291 292 def test_user_create_disable(self): 293 arglist = [ 294 '--disable', 295 self.fake_user_c.name, 296 ] 297 verifylist = [ 298 ('name', self.fake_user_c.name), 299 ('enable', False), 300 ('disable', True), 301 ] 302 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 303 304 # In base command class ShowOne in cliff, abstract method take_action() 305 # returns a two-part tuple with a tuple of column names and a tuple of 306 # data to be shown. 307 columns, data = self.cmd.take_action(parsed_args) 308 309 # Set expected values 310 kwargs = { 311 'enabled': False, 312 'tenant_id': None, 313 } 314 # UserManager.create(name, password, email, tenant_id=, enabled=) 315 self.users_mock.create.assert_called_with( 316 self.fake_user_c.name, 317 None, 318 None, 319 **kwargs 320 ) 321 322 self.assertEqual(self.columns, columns) 323 self.assertEqual(self.datalist, data) 324 325 def test_user_create_or_show_exists(self): 326 def _raise_conflict(*args, **kwargs): 327 raise ks_exc.Conflict(None) 328 329 # need to make this throw an exception... 330 self.users_mock.create.side_effect = _raise_conflict 331 332 self.users_mock.get.return_value = self.fake_user_c 333 334 arglist = [ 335 '--or-show', 336 self.fake_user_c.name, 337 ] 338 verifylist = [ 339 ('name', self.fake_user_c.name), 340 ('or_show', True), 341 ] 342 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 343 344 # In base command class ShowOne in cliff, abstract method take_action() 345 # returns a two-part tuple with a tuple of column names and a tuple of 346 # data to be shown. 347 columns, data = self.cmd.take_action(parsed_args) 348 349 # UserManager.create(name, password, email, tenant_id=, enabled=) 350 self.users_mock.get.assert_called_with(self.fake_user_c.name) 351 352 self.assertEqual(self.columns, columns) 353 self.assertEqual(self.datalist, data) 354 355 def test_user_create_or_show_not_exists(self): 356 arglist = [ 357 '--or-show', 358 self.fake_user_c.name, 359 ] 360 verifylist = [ 361 ('name', self.fake_user_c.name), 362 ('or_show', True), 363 ] 364 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 365 366 # In base command class ShowOne in cliff, abstract method take_action() 367 # returns a two-part tuple with a tuple of column names and a tuple of 368 # data to be shown. 369 columns, data = self.cmd.take_action(parsed_args) 370 371 # Set expected values 372 kwargs = { 373 'enabled': True, 374 'tenant_id': None, 375 } 376 # UserManager.create(name, password, email, tenant_id=, enabled=) 377 self.users_mock.create.assert_called_with( 378 self.fake_user_c.name, 379 None, 380 None, 381 **kwargs 382 ) 383 self.assertEqual(self.columns, columns) 384 self.assertEqual(self.datalist, data) 385 386 387class TestUserDelete(TestUser): 388 389 def setUp(self): 390 super(TestUserDelete, self).setUp() 391 392 # This is the return value for utils.find_resource() 393 self.users_mock.get.return_value = self.fake_user 394 self.users_mock.delete.return_value = None 395 396 # Get the command object to test 397 self.cmd = user.DeleteUser(self.app, None) 398 399 def test_user_delete_no_options(self): 400 arglist = [ 401 self.fake_user.id, 402 ] 403 verifylist = [ 404 ('users', [self.fake_user.id]), 405 ] 406 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 407 408 result = self.cmd.take_action(parsed_args) 409 410 self.users_mock.delete.assert_called_with( 411 self.fake_user.id, 412 ) 413 self.assertIsNone(result) 414 415 @mock.patch.object(utils, 'find_resource') 416 def test_delete_multi_users_with_exception(self, find_mock): 417 find_mock.side_effect = [self.fake_user, 418 exceptions.CommandError] 419 arglist = [ 420 self.fake_user.id, 421 'unexist_user', 422 ] 423 verifylist = [ 424 ('users', arglist), 425 ] 426 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 427 428 try: 429 self.cmd.take_action(parsed_args) 430 self.fail('CommandError should be raised.') 431 except exceptions.CommandError as e: 432 self.assertEqual('1 of 2 users failed to delete.', 433 str(e)) 434 435 find_mock.assert_any_call(self.users_mock, self.fake_user.id) 436 find_mock.assert_any_call(self.users_mock, 'unexist_user') 437 438 self.assertEqual(2, find_mock.call_count) 439 self.users_mock.delete.assert_called_once_with(self.fake_user.id) 440 441 442class TestUserList(TestUser): 443 444 fake_project_l = identity_fakes.FakeProject.create_one_project() 445 attr = { 446 'tenantId': fake_project_l.id, 447 } 448 fake_user_l = identity_fakes.FakeUser.create_one_user(attr) 449 450 columns = ( 451 'ID', 452 'Name', 453 ) 454 datalist = ( 455 ( 456 fake_user_l.id, 457 fake_user_l.name, 458 ), 459 ) 460 461 def setUp(self): 462 super(TestUserList, self).setUp() 463 464 self.projects_mock.get.return_value = self.fake_project_l 465 self.projects_mock.list.return_value = [self.fake_project_l] 466 467 self.users_mock.list.return_value = [self.fake_user_l] 468 469 # Get the command object to test 470 self.cmd = user.ListUser(self.app, None) 471 472 def test_user_list_no_options(self): 473 arglist = [] 474 verifylist = [] 475 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 476 477 # In base command class Lister in cliff, abstract method take_action() 478 # returns a tuple containing the column names and an iterable 479 # containing the data to be listed. 480 columns, data = self.cmd.take_action(parsed_args) 481 482 self.users_mock.list.assert_called_with(tenant_id=None) 483 484 self.assertEqual(self.columns, columns) 485 self.assertListItemEqual(self.datalist, tuple(data)) 486 487 def test_user_list_project(self): 488 arglist = [ 489 '--project', self.fake_project_l.id, 490 ] 491 verifylist = [ 492 ('project', self.fake_project_l.id), 493 ] 494 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 495 project_id = self.fake_project_l.id 496 497 # In base command class Lister in cliff, abstract method take_action() 498 # returns a tuple containing the column names and an iterable 499 # containing the data to be listed. 500 columns, data = self.cmd.take_action(parsed_args) 501 502 self.users_mock.list.assert_called_with(tenant_id=project_id) 503 504 self.assertEqual(self.columns, columns) 505 self.assertListItemEqual(self.datalist, tuple(data)) 506 507 def test_user_list_long(self): 508 arglist = [ 509 '--long', 510 ] 511 verifylist = [ 512 ('long', True), 513 ] 514 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 515 516 # In base command class Lister in cliff, abstract method take_action() 517 # returns a tuple containing the column names and an iterable 518 # containing the data to be listed. 519 columns, data = self.cmd.take_action(parsed_args) 520 521 self.users_mock.list.assert_called_with(tenant_id=None) 522 523 collist = ('ID', 'Name', 'Project', 'Email', 'Enabled') 524 self.assertEqual(collist, columns) 525 datalist = (( 526 self.fake_user_l.id, 527 self.fake_user_l.name, 528 user.ProjectColumn( 529 self.fake_project_l.id, 530 {self.fake_project_l.id: self.fake_project_l}), 531 self.fake_user_l.email, 532 True, 533 ), ) 534 self.assertListItemEqual(datalist, tuple(data)) 535 536 537class TestUserSet(TestUser): 538 539 def setUp(self): 540 super(TestUserSet, self).setUp() 541 542 self.projects_mock.get.return_value = self.fake_project 543 self.users_mock.get.return_value = self.fake_user 544 545 # Get the command object to test 546 self.cmd = user.SetUser(self.app, None) 547 548 def test_user_set_no_options(self): 549 arglist = [ 550 self.fake_user.name, 551 ] 552 verifylist = [ 553 ('name', None), 554 ('password', None), 555 ('email', None), 556 ('project', None), 557 ('enable', False), 558 ('disable', False), 559 ('user', self.fake_user.name), 560 ] 561 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 562 563 result = self.cmd.take_action(parsed_args) 564 565 self.assertIsNone(result) 566 567 def test_user_set_unexist_user(self): 568 arglist = [ 569 "unexist-user", 570 ] 571 verifylist = [ 572 ('name', None), 573 ('password', None), 574 ('email', None), 575 ('project', None), 576 ('enable', False), 577 ('disable', False), 578 ('user', "unexist-user"), 579 ] 580 self.users_mock.get.side_effect = exceptions.NotFound(None) 581 self.users_mock.find.side_effect = exceptions.NotFound(None) 582 583 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 584 585 self.assertRaises( 586 exceptions.CommandError, self.cmd.take_action, parsed_args) 587 588 def test_user_set_name(self): 589 arglist = [ 590 '--name', 'qwerty', 591 self.fake_user.name, 592 ] 593 verifylist = [ 594 ('name', 'qwerty'), 595 ('password', None), 596 ('email', None), 597 ('project', None), 598 ('enable', False), 599 ('disable', False), 600 ('user', self.fake_user.name), 601 ] 602 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 603 604 result = self.cmd.take_action(parsed_args) 605 606 # Set expected values 607 kwargs = { 608 'enabled': True, 609 'name': 'qwerty', 610 } 611 # UserManager.update(user, **kwargs) 612 self.users_mock.update.assert_called_with( 613 self.fake_user.id, 614 **kwargs 615 ) 616 self.assertIsNone(result) 617 618 def test_user_set_password(self): 619 arglist = [ 620 '--password', 'secret', 621 self.fake_user.name, 622 ] 623 verifylist = [ 624 ('name', None), 625 ('password', 'secret'), 626 ('password_prompt', False), 627 ('email', None), 628 ('project', None), 629 ('enable', False), 630 ('disable', False), 631 ('user', self.fake_user.name), 632 ] 633 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 634 635 result = self.cmd.take_action(parsed_args) 636 637 # UserManager.update_password(user, password) 638 self.users_mock.update_password.assert_called_with( 639 self.fake_user.id, 640 'secret', 641 ) 642 self.assertIsNone(result) 643 644 def test_user_set_password_prompt(self): 645 arglist = [ 646 '--password-prompt', 647 self.fake_user.name, 648 ] 649 verifylist = [ 650 ('name', None), 651 ('password', None), 652 ('password_prompt', True), 653 ('email', None), 654 ('project', None), 655 ('enable', False), 656 ('disable', False), 657 ('user', self.fake_user.name), 658 ] 659 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 660 661 mocker = mock.Mock() 662 mocker.return_value = 'abc123' 663 with mock.patch("osc_lib.utils.get_password", mocker): 664 result = self.cmd.take_action(parsed_args) 665 666 # UserManager.update_password(user, password) 667 self.users_mock.update_password.assert_called_with( 668 self.fake_user.id, 669 'abc123', 670 ) 671 self.assertIsNone(result) 672 673 def test_user_set_email(self): 674 arglist = [ 675 '--email', 'barney@example.com', 676 self.fake_user.name, 677 ] 678 verifylist = [ 679 ('name', None), 680 ('password', None), 681 ('email', 'barney@example.com'), 682 ('project', None), 683 ('enable', False), 684 ('disable', False), 685 ('user', self.fake_user.name), 686 ] 687 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 688 689 result = self.cmd.take_action(parsed_args) 690 691 # Set expected values 692 kwargs = { 693 'email': 'barney@example.com', 694 'enabled': True, 695 } 696 # UserManager.update(user, **kwargs) 697 self.users_mock.update.assert_called_with( 698 self.fake_user.id, 699 **kwargs 700 ) 701 self.assertIsNone(result) 702 703 def test_user_set_project(self): 704 arglist = [ 705 '--project', self.fake_project.id, 706 self.fake_user.name, 707 ] 708 verifylist = [ 709 ('name', None), 710 ('password', None), 711 ('email', None), 712 ('project', self.fake_project.id), 713 ('enable', False), 714 ('disable', False), 715 ('user', self.fake_user.name), 716 ] 717 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 718 719 result = self.cmd.take_action(parsed_args) 720 721 # UserManager.update_tenant(user, tenant) 722 self.users_mock.update_tenant.assert_called_with( 723 self.fake_user.id, 724 self.fake_project.id, 725 ) 726 self.assertIsNone(result) 727 728 def test_user_set_enable(self): 729 arglist = [ 730 '--enable', 731 self.fake_user.name, 732 ] 733 verifylist = [ 734 ('name', None), 735 ('password', None), 736 ('email', None), 737 ('project', None), 738 ('enable', True), 739 ('disable', False), 740 ('user', self.fake_user.name), 741 ] 742 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 743 744 result = self.cmd.take_action(parsed_args) 745 746 # Set expected values 747 kwargs = { 748 'enabled': True, 749 } 750 # UserManager.update(user, **kwargs) 751 self.users_mock.update.assert_called_with( 752 self.fake_user.id, 753 **kwargs 754 ) 755 self.assertIsNone(result) 756 757 def test_user_set_disable(self): 758 arglist = [ 759 '--disable', 760 self.fake_user.name, 761 ] 762 verifylist = [ 763 ('name', None), 764 ('password', None), 765 ('email', None), 766 ('project', None), 767 ('enable', False), 768 ('disable', True), 769 ('user', self.fake_user.name), 770 ] 771 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 772 773 result = self.cmd.take_action(parsed_args) 774 775 # Set expected values 776 kwargs = { 777 'enabled': False, 778 } 779 # UserManager.update(user, **kwargs) 780 self.users_mock.update.assert_called_with( 781 self.fake_user.id, 782 **kwargs 783 ) 784 self.assertIsNone(result) 785 786 787class TestUserShow(TestUser): 788 789 def setUp(self): 790 super(TestUserShow, self).setUp() 791 792 self.users_mock.get.return_value = self.fake_user 793 794 # Get the command object to test 795 self.cmd = user.ShowUser(self.app, None) 796 797 def test_user_show(self): 798 arglist = [ 799 self.fake_user.id, 800 ] 801 verifylist = [ 802 ('user', self.fake_user.id), 803 ] 804 parsed_args = self.check_parser(self.cmd, arglist, verifylist) 805 806 # In base command class ShowOne in cliff, abstract method take_action() 807 # returns a two-part tuple with a tuple of column names and a tuple of 808 # data to be shown. 809 columns, data = self.cmd.take_action(parsed_args) 810 811 self.users_mock.get.assert_called_with(self.fake_user.id) 812 813 collist = ('email', 'enabled', 'id', 'name', 'project_id') 814 self.assertEqual(collist, columns) 815 datalist = ( 816 self.fake_user.email, 817 True, 818 self.fake_user.id, 819 self.fake_user.name, 820 self.fake_project.id, 821 ) 822 self.assertItemEqual(datalist, data) 823