1""" 2 :codeauthor: Rahul Handay <rahulha@saltstack.com> 3""" 4 5import datetime 6import logging 7import os 8 9import pytest 10import salt.config 11import salt.loader 12import salt.modules.config as config 13import salt.modules.state as state 14import salt.state 15import salt.utils.args 16import salt.utils.files 17import salt.utils.hashutils 18import salt.utils.json 19import salt.utils.odict 20import salt.utils.platform 21import salt.utils.state 22from salt.exceptions import CommandExecutionError, SaltInvocationError 23from salt.utils.event import SaltEvent 24from tests.support.mock import MagicMock, Mock, mock_open, patch 25 26log = logging.getLogger(__name__) 27 28 29class MockState: 30 """ 31 Mock class 32 """ 33 34 def __init__(self): 35 pass 36 37 class State: 38 """ 39 Mock state class 40 """ 41 42 flag = None 43 44 def __init__( 45 self, opts, pillar_override=False, pillar_enc=None, initial_pillar=None 46 ): 47 pass 48 49 def verify_data(self, data): 50 """ 51 Mock verify_data method 52 """ 53 if self.flag: 54 return True 55 else: 56 return False 57 58 @staticmethod 59 def call(data): 60 """ 61 Mock call method 62 """ 63 return list 64 65 @staticmethod 66 def call_high(data, orchestration_jid=None): 67 """ 68 Mock call_high method 69 """ 70 return True 71 72 @staticmethod 73 def call_template_str(data): 74 """ 75 Mock call_template_str method 76 """ 77 return True 78 79 @staticmethod 80 def _mod_init(data): 81 """ 82 Mock _mod_init method 83 """ 84 return True 85 86 def verify_high(self, data): 87 """ 88 Mock verify_high method 89 """ 90 if self.flag: 91 return True 92 else: 93 return -1 94 95 @staticmethod 96 def compile_high_data(data): 97 """ 98 Mock compile_high_data 99 """ 100 return [{"__id__": "ABC"}] 101 102 @staticmethod 103 def call_chunk(data, data1, data2): 104 """ 105 Mock call_chunk method 106 """ 107 return {"": "ABC"} 108 109 @staticmethod 110 def call_chunks(data): 111 """ 112 Mock call_chunks method 113 """ 114 return True 115 116 @staticmethod 117 def call_listen(data, ret): 118 """ 119 Mock call_listen method 120 """ 121 return True 122 123 def requisite_in(self, data): # pylint: disable=unused-argument 124 return data, [] 125 126 class HighState: 127 """ 128 Mock HighState class 129 """ 130 131 flag = False 132 opts = {"state_top": "", "pillar": {}} 133 134 def __init__(self, opts, pillar_override=None, *args, **kwargs): 135 self.building_highstate = salt.utils.odict.OrderedDict 136 self.state = MockState.State(opts, pillar_override=pillar_override) 137 138 def render_state(self, sls, saltenv, mods, matches, local=False): 139 """ 140 Mock render_state method 141 """ 142 if self.flag: 143 return {}, True 144 else: 145 return {}, False 146 147 @staticmethod 148 def get_top(): 149 """ 150 Mock get_top method 151 """ 152 return "_top" 153 154 def verify_tops(self, data): 155 """ 156 Mock verify_tops method 157 """ 158 if self.flag: 159 return ["a", "b"] 160 else: 161 return [] 162 163 @staticmethod 164 def top_matches(data): 165 """ 166 Mock top_matches method 167 """ 168 return ["a", "b", "c"] 169 170 @staticmethod 171 def push_active(): 172 """ 173 Mock push_active method 174 """ 175 return True 176 177 @staticmethod 178 def compile_highstate(): 179 """ 180 Mock compile_highstate method 181 """ 182 return "A" 183 184 @staticmethod 185 def compile_state_usage(): 186 """ 187 Mock compile_state_usage method 188 """ 189 return "A" 190 191 @staticmethod 192 def pop_active(): 193 """ 194 Mock pop_active method 195 """ 196 return True 197 198 @staticmethod 199 def compile_low_chunks(): 200 """ 201 Mock compile_low_chunks method 202 """ 203 return [{"__id__": "ABC", "__sls__": "abc"}] 204 205 def render_highstate(self, data): 206 """ 207 Mock render_highstate method 208 """ 209 if self.flag: 210 return ["a", "b"], True 211 else: 212 return ["a", "b"], False 213 214 @staticmethod 215 def call_highstate( 216 exclude, 217 cache, 218 cache_name, 219 force=None, 220 whitelist=None, 221 orchestration_jid=None, 222 ): 223 """ 224 Mock call_highstate method 225 """ 226 return True 227 228 def __enter__(self): 229 return self 230 231 def __exit__(self, *_): 232 pass 233 234 235class MockSerial: 236 """ 237 Mock Class 238 """ 239 240 @staticmethod 241 def load(data): 242 """ 243 Mock load method 244 """ 245 return {"A": "B"} 246 247 @staticmethod 248 def dump(data, data1): 249 """ 250 Mock dump method 251 """ 252 return True 253 254 255class MockTarFile: 256 """ 257 Mock tarfile class 258 """ 259 260 path = os.sep + "tmp" 261 262 def __init__(self): 263 pass 264 265 @staticmethod 266 def open(data, data1): 267 """ 268 Mock open method 269 """ 270 return MockTarFile 271 272 @staticmethod 273 def getmembers(): 274 """ 275 Mock getmembers method 276 """ 277 return [MockTarFile] 278 279 @staticmethod 280 def extractall(data): 281 """ 282 Mock extractall method 283 """ 284 return True 285 286 @staticmethod 287 def close(): 288 """ 289 Mock close method 290 """ 291 return True 292 293 294@pytest.fixture 295def configure_loader_modules(salt_minion_factory): 296 utils = salt.loader.utils( 297 salt_minion_factory.config.copy(), 298 whitelist=["state", "args", "systemd", "path", "platform"], 299 ) 300 with patch("salt.modules.state.salt.state", MockState()): 301 yield { 302 state: { 303 "__opts__": { 304 "cachedir": "/D", 305 "saltenv": None, 306 "sock_dir": "/var/run/salt/master", 307 "transport": "zeromq", 308 "__cli": "salt", 309 }, 310 "__utils__": utils, 311 "__salt__": { 312 "config.get": config.get, 313 "config.option": MagicMock(return_value=""), 314 }, 315 }, 316 config: {"__opts__": {}, "__pillar__": {}}, 317 } 318 319 320def test_running(): 321 """ 322 Test of checking i fthe state function is already running 323 """ 324 assert state.running(True) == [] 325 326 mock = MagicMock( 327 side_effect=[ 328 [{"fun": "state.running", "pid": "4126", "jid": "20150325123407204096"}], 329 [], 330 ] 331 ) 332 with patch.dict(state.__salt__, {"saltutil.is_running": mock}): 333 assert state.running() == [ 334 'The function "state.running"' 335 " is running as PID 4126 and " 336 "was started at 2015, Mar 25 12:34:07." 337 "204096 with jid 20150325123407204096" 338 ] 339 340 assert state.running() == [] 341 342 343def test_low(): 344 """ 345 Test of executing a single low data call 346 """ 347 with patch.object(state, "_check_queue", side_effect=[False, None, None]): 348 assert not state.low({"state": "pkg", "fun": "installed", "name": "vi"}) 349 350 MockState.State.flag = False 351 assert state.low({"state": "pkg", "fun": "installed", "name": "vi"}) == list 352 353 MockState.State.flag = True 354 assert state.low({"state": "pkg", "fun": "installed", "name": "vi"}) 355 356 357def test_high(): 358 """ 359 Test for checking the state system 360 """ 361 with patch.object(state, "_check_queue", side_effect=[False, None]): 362 assert not state.high({"vim": {"pkg": ["installed"]}}) 363 364 with patch.object( 365 salt.utils.state, "get_sls_opts", return_value={"test": True} 366 ): 367 assert state.high({"vim": {"pkg": ["installed"]}}) 368 369 370def test_template(): 371 """ 372 Test of executing the information 373 stored in a template file on the minion 374 """ 375 with patch.object(state, "_check_queue", side_effect=[False, None, None]): 376 assert not state.template("/home/salt/salt.sls") 377 378 MockState.HighState.flag = True 379 assert state.template("/home/salt/salt.sls") 380 381 MockState.HighState.flag = False 382 assert state.template("/home/salt/salt.sls") 383 384 385def test_template_str(): 386 """ 387 Test for Executing the information 388 stored in a string from an sls template 389 """ 390 with patch.object(state, "_check_queue", side_effect=[False, None]): 391 assert not state.template_str("Template String") 392 393 assert state.template_str("Template String") 394 395 396def test_apply_(): 397 """ 398 Test to apply states 399 """ 400 with patch.object(state, "sls", return_value=True): 401 assert state.apply_(True) 402 403 with patch.object(state, "highstate", return_value=True): 404 assert state.apply_(None) 405 406 407def test_test(): 408 """ 409 Test to apply states in test mode 410 """ 411 with patch.dict(state.__opts__, {"test": False}): 412 with patch.object(state, "sls", return_value=True) as mock: 413 assert state.test(True) 414 mock.assert_called_once_with(True, test=True) 415 assert state.__opts__["test"] is False 416 417 with patch.object(state, "highstate", return_value=True) as mock: 418 assert state.test(None) 419 mock.assert_called_once_with(test=True) 420 assert state.__opts__["test"] is False 421 422 423def test_list_disabled(): 424 """ 425 Test to list disabled states 426 """ 427 mock = MagicMock(return_value=["A", "B", "C"]) 428 with patch.dict(state.__salt__, {"grains.get": mock}): 429 assert state.list_disabled() == ["A", "B", "C"] 430 431 432def test_enable(): 433 """ 434 Test to Enable state function or sls run 435 """ 436 mock = MagicMock(return_value=["A", "B"]) 437 with patch.dict(state.__salt__, {"grains.get": mock}): 438 mock = MagicMock(return_value=[]) 439 with patch.dict(state.__salt__, {"grains.setval": mock}): 440 mock = MagicMock(return_value=[]) 441 with patch.dict(state.__salt__, {"saltutil.refresh_modules": mock}): 442 assert state.enable("A") == { 443 "msg": "Info: A state enabled.", 444 "res": True, 445 } 446 447 assert state.enable("Z") == { 448 "msg": "Info: Z state already " "enabled.", 449 "res": True, 450 } 451 452 453def test_disable(): 454 """ 455 Test to disable state run 456 """ 457 mock = MagicMock(return_value=["C", "D"]) 458 with patch.dict(state.__salt__, {"grains.get": mock}): 459 mock = MagicMock(return_value=[]) 460 with patch.dict(state.__salt__, {"grains.setval": mock}): 461 mock = MagicMock(return_value=[]) 462 with patch.dict(state.__salt__, {"saltutil.refresh_modules": mock}): 463 assert state.disable("C") == { 464 "msg": "Info: C state " "already disabled.", 465 "res": True, 466 } 467 468 assert state.disable("Z") == { 469 "msg": "Info: Z state " "disabled.", 470 "res": True, 471 } 472 473 474def test_clear_cache(): 475 """ 476 Test to clear out cached state file 477 """ 478 mock = MagicMock(return_value=["A.cache.p", "B.cache.p", "C"]) 479 with patch.object(os, "listdir", mock): 480 mock = MagicMock(return_value=True) 481 with patch.object(os.path, "isfile", mock): 482 mock = MagicMock(return_value=True) 483 with patch.object(os, "remove", mock): 484 assert state.clear_cache() == ["A.cache.p", "B.cache.p"] 485 486 487def test_single(): 488 """ 489 Test to execute single state function 490 """ 491 ret = {"pkg_|-name=vim_|-name=vim_|-installed": list} 492 mock = MagicMock(side_effect=["A", None, None, None, None]) 493 with patch.object(state, "_check_queue", mock): 494 assert state.single("pkg.installed", " name=vim") == "A" 495 496 assert state.single("pk", "name=vim") == "Invalid function passed" 497 498 with patch.dict(state.__opts__, {"test": "install"}): 499 mock = MagicMock(return_value={"test": ""}) 500 with patch.object(salt.utils.state, "get_sls_opts", mock): 501 mock = MagicMock(return_value=True) 502 with patch.object(salt.utils.args, "test_mode", mock): 503 pytest.raises( 504 SaltInvocationError, 505 state.single, 506 "pkg.installed", 507 "name=vim", 508 pillar="A", 509 ) 510 511 MockState.State.flag = True 512 assert state.single("pkg.installed", "name=vim") 513 514 MockState.State.flag = False 515 assert state.single("pkg.installed", "name=vim") == ret 516 517 518def test_show_top(): 519 """ 520 Test to return the top data that the minion will use for a highstate 521 """ 522 mock = MagicMock(side_effect=["A", None, None]) 523 with patch.object(state, "_check_queue", mock): 524 assert state.show_top() == "A" 525 526 MockState.HighState.flag = True 527 assert state.show_top() == ["a", "b"] 528 529 MockState.HighState.flag = False 530 assert state.show_top() == ["a", "b", "c"] 531 532 533def test_run_request(): 534 """ 535 Test to Execute the pending state request 536 """ 537 mock = MagicMock( 538 side_effect=[{}, {"name": "A"}, {"name": {"mods": "A", "kwargs": {}}}] 539 ) 540 with patch.object(state, "check_request", mock): 541 assert state.run_request("A") == {} 542 543 assert state.run_request("A") == {} 544 545 mock = MagicMock(return_value=["True"]) 546 with patch.object(state, "apply_", mock): 547 mock = MagicMock(return_value="") 548 with patch.object(os, "remove", mock): 549 assert state.run_request("name") == ["True"] 550 551 552def test_show_highstate(): 553 """ 554 Test to retrieve the highstate data from the salt master 555 """ 556 mock = MagicMock(side_effect=["A", None, None]) 557 with patch.object(state, "_check_queue", mock): 558 assert state.show_highstate() == "A" 559 560 pytest.raises(SaltInvocationError, state.show_highstate, pillar="A") 561 562 assert state.show_highstate() == "A" 563 564 565def test_show_lowstate(): 566 """ 567 Test to list out the low data that will be applied to this minion 568 """ 569 mock = MagicMock(side_effect=["A", None]) 570 with patch.object(state, "_check_queue", mock): 571 pytest.raises(AssertionError, state.show_lowstate) 572 573 assert state.show_lowstate() 574 575 576def test_show_state_usage(): 577 """ 578 Test to list out the state usage that will be applied to this minion 579 """ 580 581 mock = MagicMock(side_effect=["A", None, None]) 582 with patch.object(state, "_check_queue", mock): 583 assert state.show_state_usage() == "A" 584 585 pytest.raises(SaltInvocationError, state.show_state_usage, pillar="A") 586 587 assert state.show_state_usage() == "A" 588 589 590def test_show_states(): 591 """ 592 Test to display the low data from a specific sls 593 """ 594 mock = MagicMock(side_effect=["A", None]) 595 with patch.object(state, "_check_queue", mock): 596 597 assert state.show_low_sls("foo") == "A" 598 assert state.show_states("foo") == ["abc"] 599 600 601def test_show_states_missing_sls(): 602 """ 603 Test state.show_states when a sls file defined 604 in a top.sls file is missing 605 """ 606 msg = ["No matching sls found for 'cloud' in evn 'base'"] 607 chunks_mock = MagicMock(side_effect=[msg]) 608 mock = MagicMock(side_effect=["A", None]) 609 with patch.object(state, "_check_queue", mock), patch( 610 "salt.state.HighState.compile_low_chunks", chunks_mock 611 ): 612 assert state.show_low_sls("foo") == "A" 613 assert state.show_states("foo") == [msg[0]] 614 615 616def test_sls_id(): 617 """ 618 Test to call a single ID from the 619 named module(s) and handle all requisites 620 """ 621 mock = MagicMock(side_effect=["A", None, None, None]) 622 with patch.object(state, "_check_queue", mock): 623 assert state.sls_id("apache", "http") == "A" 624 625 with patch.dict(state.__opts__, {"test": "A"}): 626 mock = MagicMock(return_value={"test": True, "saltenv": None}) 627 with patch.object(salt.utils.state, "get_sls_opts", mock): 628 mock = MagicMock(return_value=True) 629 with patch.object(salt.utils.args, "test_mode", mock): 630 MockState.State.flag = True 631 MockState.HighState.flag = True 632 assert state.sls_id("apache", "http") == 2 633 634 MockState.State.flag = False 635 assert state.sls_id("ABC", "http") == {"": "ABC"} 636 pytest.raises(SaltInvocationError, state.sls_id, "DEF", "http") 637 638 639def test_show_low_sls(): 640 """ 641 Test to display the low data from a specific sls 642 """ 643 mock = MagicMock(side_effect=["A", None, None]) 644 with patch.object(state, "_check_queue", mock): 645 assert state.show_low_sls("foo") == "A" 646 647 with patch.dict(state.__opts__, {"test": "A"}): 648 mock = MagicMock(return_value={"test": True, "saltenv": None}) 649 with patch.object(salt.utils.state, "get_sls_opts", mock): 650 MockState.State.flag = True 651 MockState.HighState.flag = True 652 assert state.show_low_sls("foo") == 2 653 654 MockState.State.flag = False 655 assert state.show_low_sls("foo") == [{"__id__": "ABC"}] 656 657 658def test_show_sls(): 659 """ 660 Test to display the state data from a specific sls 661 """ 662 mock = MagicMock(side_effect=["A", None, None, None]) 663 with patch.object(state, "_check_queue", mock): 664 assert state.show_sls("foo") == "A" 665 666 with patch.dict(state.__opts__, {"test": "A"}): 667 mock = MagicMock(return_value={"test": True, "saltenv": None}) 668 with patch.object(salt.utils.state, "get_sls_opts", mock): 669 mock = MagicMock(return_value=True) 670 with patch.object(salt.utils.args, "test_mode", mock): 671 pytest.raises( 672 SaltInvocationError, state.show_sls, "foo", pillar="A" 673 ) 674 675 MockState.State.flag = True 676 assert state.show_sls("foo") == 2 677 678 MockState.State.flag = False 679 assert state.show_sls("foo") == ["a", "b"] 680 681 682def test_sls_exists(): 683 """ 684 Test of sls_exists 685 """ 686 test_state = {} 687 test_missing_state = [] 688 689 mock = MagicMock(return_value=test_state) 690 with patch.object(state, "show_sls", mock): 691 assert state.sls_exists("state_name") 692 mock = MagicMock(return_value=test_missing_state) 693 with patch.object(state, "show_sls", mock): 694 assert not state.sls_exists("missing_state") 695 696 697def test_id_exists(): 698 """ 699 Test of id_exists 700 """ 701 test_state = [ 702 { 703 "key1": "value1", 704 "name": "value1", 705 "state": "file", 706 "fun": "test", 707 "__env__": "base", 708 "__sls__": "test-sls", 709 "order": 10000, 710 "__id__": "state_id1", 711 }, 712 { 713 "key2": "value2", 714 "name": "value2", 715 "state": "file", 716 "fun": "directory", 717 "__env__": "base", 718 "__sls__": "test-sls", 719 "order": 10001, 720 "__id__": "state_id2", 721 }, 722 ] 723 mock = MagicMock(return_value=test_state) 724 with patch.object(state, "show_low_sls", mock): 725 assert state.id_exists("state_id1,state_id2", "test-sls") 726 assert not state.id_exists("invalid", "state_name") 727 728 729def test_top(): 730 """ 731 Test to execute a specific top file 732 """ 733 ret = ["Pillar failed to render with the following messages:", "E"] 734 mock = MagicMock(side_effect=["A", None, None, None]) 735 with patch.object(state, "_check_queue", mock): 736 assert state.top("reverse_top.sls") == "A" 737 738 mock = MagicMock(side_effect=[["E"], None, None]) 739 with patch.object(state, "_get_pillar_errors", mock): 740 with patch.dict(state.__pillar__, {"_errors": ["E"]}): 741 assert state.top("reverse_top.sls") == ret 742 743 with patch.dict(state.__opts__, {"test": "A"}): 744 mock = MagicMock(return_value={"test": True}) 745 with patch.object(salt.utils.state, "get_sls_opts", mock): 746 mock = MagicMock(return_value=True) 747 with patch.object(salt.utils.args, "test_mode", mock): 748 pytest.raises( 749 SaltInvocationError, 750 state.top, 751 "reverse_top.sls", 752 pillar="A", 753 ) 754 755 mock = MagicMock(return_value="salt://reverse_top.sls") 756 with patch.object(os.path, "join", mock): 757 mock = MagicMock(return_value=True) 758 with patch.object(state, "_set_retcode", mock): 759 assert state.top( 760 "reverse_top.sls " "exclude=exclude.sls" 761 ) 762 763 764def test_highstate(): 765 """ 766 Test to retrieve the state data from the 767 salt master for the minion and execute it 768 """ 769 arg = "whitelist=sls1.sls" 770 mock = MagicMock(side_effect=[True, False, False, False]) 771 with patch.object(state, "_disabled", mock): 772 assert state.highstate("whitelist=sls1.sls") == { 773 "comment": "Disabled", 774 "name": "Salt highstate run is disabled. " 775 "To re-enable, run state.enable highstate", 776 "result": "False", 777 } 778 779 mock = MagicMock(side_effect=["A", None, None]) 780 with patch.object(state, "_check_queue", mock): 781 assert state.highstate("whitelist=sls1.sls") == "A" 782 783 with patch.dict(state.__opts__, {"test": "A"}): 784 mock = MagicMock(return_value={"test": True}) 785 with patch.object(salt.utils.state, "get_sls_opts", mock): 786 pytest.raises( 787 SaltInvocationError, 788 state.highstate, 789 "whitelist=sls1.sls", 790 pillar="A", 791 ) 792 793 mock = MagicMock(return_value="A") 794 with patch.object(state, "_filter_running", mock): 795 mock = MagicMock(return_value=True) 796 with patch.object(state, "_filter_running", mock): 797 mock = MagicMock(return_value=True) 798 with patch.object(salt.payload, "Serial", mock): 799 with patch.object(os.path, "join", mock): 800 with patch.object(state, "_set" "_retcode", mock): 801 assert state.highstate(arg) 802 803 804def test_clear_request(): 805 """ 806 Test to clear out the state execution request without executing it 807 """ 808 mock = MagicMock(return_value=True) 809 with patch.object(salt.payload, "Serial", mock): 810 mock = MagicMock(side_effect=[False, True, True]) 811 with patch.object(os.path, "isfile", mock): 812 assert state.clear_request("A") 813 814 mock = MagicMock(return_value=True) 815 with patch.object(os, "remove", mock): 816 assert state.clear_request() 817 818 mock = MagicMock(return_value={}) 819 with patch.object(state, "check_request", mock): 820 assert not state.clear_request("A") 821 822 823def test_check_request(): 824 """ 825 Test to return the state request information 826 """ 827 with patch("salt.modules.state.salt.payload", MockSerial): 828 mock = MagicMock(side_effect=[True, True, False]) 829 with patch.object(os.path, "isfile", mock): 830 with patch("salt.utils.files.fopen", mock_open(b"")): 831 assert state.check_request() == {"A": "B"} 832 833 with patch("salt.utils.files.fopen", mock_open("")): 834 assert state.check_request("A") == "B" 835 836 assert state.check_request() == {} 837 838 839def test_request(): 840 """ 841 Test to request the local admin execute a state run 842 """ 843 mock = MagicMock(return_value=True) 844 with patch.object(state, "apply_", mock): 845 mock = MagicMock(return_value=True) 846 with patch.object(os.path, "join", mock): 847 mock = MagicMock(return_value={"test_run": "", "mods": "", "kwargs": ""}) 848 with patch.object(state, "check_request", mock): 849 mock = MagicMock(return_value=True) 850 with patch.object(os, "umask", mock): 851 with patch.object(salt.utils.platform, "is_windows", mock): 852 with patch.dict(state.__salt__, {"cmd.run": mock}): 853 with patch("salt.utils.files.fopen", mock_open()): 854 mock = MagicMock(return_value=True) 855 with patch.object(os, "umask", mock): 856 assert state.request("A") 857 858 859def test_sls(): 860 """ 861 Test to execute a set list of state files from an environment 862 """ 863 arg = "core,edit.vim dev" 864 ret = ["Pillar failed to render with the following messages:", "E", "1"] 865 with patch.object(state, "running", return_value=True): 866 with patch.dict(state.__context__, {"retcode": 1}): 867 assert state.sls("core,edit.vim dev") is True 868 869 with patch.object( 870 state, "_wait", side_effect=[True, True, True, True, True, True] 871 ), patch.object(state, "_disabled", side_effect=[["A"], [], [], [], [], []]): 872 with patch.dict(state.__context__, {"retcode": 1}): 873 assert state.sls("core,edit.vim dev", None, None, True) == ["A"] 874 875 with patch.object( 876 state, 877 "_get_pillar_errors", 878 side_effect=[["E", "1"], None, None, None, None], 879 ): 880 with patch.dict(state.__context__, {"retcode": 5}), patch.dict( 881 state.__pillar__, {"_errors": ["E", "1"]} 882 ): 883 assert state.sls("core,edit.vim dev", None, None, True) == ret 884 885 with patch.dict(state.__opts__, {"test": None}), patch.object( 886 salt.utils.state, 887 "get_sls_opts", 888 return_value={"test": "", "saltenv": None}, 889 ), patch.object(salt.utils.args, "test_mode", return_value=True): 890 pytest.raises( 891 SaltInvocationError, 892 state.sls, 893 "core,edit.vim dev", 894 None, 895 None, 896 True, 897 pillar="A", 898 ) 899 with patch.object(os.path, "join", return_value="/D/cache.cache.p"): 900 with patch.object(os.path, "isfile", return_value=True), patch( 901 "salt.utils.files.fopen", mock_open(b"") 902 ): 903 assert state.sls(arg, None, None, True, cache=True) 904 905 MockState.HighState.flag = True 906 assert state.sls("core,edit" ".vim dev", None, None, True) 907 908 MockState.HighState.flag = False 909 with patch.object( 910 state, "_filter_" "running", return_value=True 911 ), patch.object(os.path, "join", return_value=True), patch.object( 912 os, "umask", return_value=True 913 ), patch.object( 914 salt.utils.platform, "is_windows", return_value=False 915 ), patch.object( 916 state, "_set_retcode", return_value=True 917 ), patch.dict( 918 state.__opts__, {"test": True} 919 ), patch( 920 "salt.utils.files.fopen", mock_open() 921 ): 922 assert state.sls("core,edit" ".vim dev", None, None, True) 923 924 925def test_get_test_value(): 926 """ 927 Test _get_test_value when opts contains different values 928 """ 929 test_arg = "test" 930 with patch.dict(state.__opts__, {test_arg: True}): 931 assert state._get_test_value( 932 test=None 933 ), "Failure when {} is True in __opts__".format(test_arg) 934 935 with patch.dict(config.__pillar__, {test_arg: "blah"}): 936 assert not state._get_test_value( 937 test=None 938 ), "Failure when {} is blah in __opts__".format(test_arg) 939 940 with patch.dict(config.__pillar__, {test_arg: "true"}): 941 assert not state._get_test_value( 942 test=None 943 ), "Failure when {} is true in __opts__".format(test_arg) 944 945 with patch.dict(config.__opts__, {test_arg: False}): 946 assert not state._get_test_value( 947 test=None 948 ), "Failure when {} is False in __opts__".format(test_arg) 949 950 with patch.dict(config.__opts__, {}): 951 assert not state._get_test_value( 952 test=None 953 ), "Failure when {} does not exist in __opts__".format(test_arg) 954 955 with patch.dict(config.__pillar__, {test_arg: None}): 956 assert ( 957 state._get_test_value(test=None) is None 958 ), "Failure when {} is None in __opts__".format(test_arg) 959 960 with patch.dict(config.__pillar__, {test_arg: True}): 961 assert state._get_test_value( 962 test=None 963 ), "Failure when {} is True in __pillar__".format(test_arg) 964 965 with patch.dict(config.__pillar__, {"master": {test_arg: True}}): 966 assert state._get_test_value( 967 test=None 968 ), "Failure when {} is True in master __pillar__".format(test_arg) 969 970 with patch.dict(config.__pillar__, {"master": {test_arg: False}}): 971 with patch.dict(config.__pillar__, {test_arg: True}): 972 assert state._get_test_value( 973 test=None 974 ), "Failure when {} is False in master __pillar__ and True in pillar".format( 975 test_arg 976 ) 977 978 with patch.dict(config.__pillar__, {"master": {test_arg: True}}): 979 with patch.dict(config.__pillar__, {test_arg: False}): 980 assert not state._get_test_value( 981 test=None 982 ), "Failure when {} is True in master __pillar__ and False in pillar".format( 983 test_arg 984 ) 985 986 with patch.dict(state.__opts__, {"test": False}): 987 assert not state._get_test_value( 988 test=None 989 ), "Failure when {} is False in __opts__".format(test_arg) 990 991 with patch.dict(state.__opts__, {"test": False}): 992 with patch.dict(config.__pillar__, {"master": {test_arg: True}}): 993 assert state._get_test_value( 994 test=None 995 ), "Failure when {} is False in __opts__".format(test_arg) 996 997 with patch.dict(state.__opts__, {}): 998 assert state._get_test_value(test=True), "Failure when test is True as arg" 999 1000 1001def test_sls_sync(subtests): 1002 """ 1003 Test test.sls with the sync argument 1004 1005 We're only mocking the sync functions we expect to sync. If any other 1006 sync functions are run then they will raise a KeyError, which we want 1007 as it will tell us that we are syncing things we shouldn't. 1008 """ 1009 expected_err_msg = "{} called {} time(s) (expected: {})" 1010 mock_empty_list = MagicMock(return_value=[]) 1011 with patch.object(state, "running", mock_empty_list), patch.object( 1012 state, "_disabled", mock_empty_list 1013 ), patch.object(state, "_get_pillar_errors", mock_empty_list): 1014 1015 with subtests.test("sync_mods=modules,states"): 1016 sync_mocks = { 1017 "saltutil.sync_modules": Mock(), 1018 "saltutil.sync_states": Mock(), 1019 } 1020 if salt.utils.platform.is_windows(): 1021 sync_mocks["cmd.run"] = Mock() 1022 with patch.dict(state.__salt__, sync_mocks): 1023 state.sls("foo", sync_mods="modules,states") 1024 1025 for key in sync_mocks: 1026 call_count = sync_mocks[key].call_count 1027 expected = 1 1028 assert call_count == expected, expected_err_msg.format( 1029 key, call_count, expected 1030 ) 1031 1032 with subtests.test("sync_mods=all"): 1033 # Test syncing all 1034 sync_mocks = {"saltutil.sync_all": Mock()} 1035 if salt.utils.platform.is_windows(): 1036 sync_mocks["cmd.run"] = Mock() 1037 with patch.dict(state.__salt__, sync_mocks): 1038 state.sls("foo", sync_mods="all") 1039 1040 for key in sync_mocks: 1041 call_count = sync_mocks[key].call_count 1042 expected = 1 1043 assert call_count == expected, expected_err_msg.format( 1044 key, call_count, expected 1045 ) 1046 1047 with subtests.test("sync_mods=True"): 1048 # sync_mods=True should be interpreted as sync_mods=all 1049 sync_mocks = {"saltutil.sync_all": Mock()} 1050 if salt.utils.platform.is_windows(): 1051 sync_mocks["cmd.run"] = Mock() 1052 with patch.dict(state.__salt__, sync_mocks): 1053 state.sls("foo", sync_mods=True) 1054 1055 for key in sync_mocks: 1056 call_count = sync_mocks[key].call_count 1057 expected = 1 1058 assert call_count == expected, expected_err_msg.format( 1059 key, call_count, expected 1060 ) 1061 1062 with subtests.test("sync_mods=modules,all"): 1063 # Test syncing all when "all" is passed along with module types. 1064 # This tests that we *only* run a sync_all and avoid unnecessary 1065 # extra syncing. 1066 sync_mocks = {"saltutil.sync_all": Mock()} 1067 if salt.utils.platform.is_windows(): 1068 sync_mocks["cmd.run"] = Mock() 1069 with patch.dict(state.__salt__, sync_mocks): 1070 state.sls("foo", sync_mods="modules,all") 1071 1072 for key in sync_mocks: 1073 call_count = sync_mocks[key].call_count 1074 expected = 1 1075 assert call_count == expected, expected_err_msg.format( 1076 key, call_count, expected 1077 ) 1078 1079 1080def test_pkg(): 1081 """ 1082 Test to execute a packaged state run 1083 """ 1084 tar_file = os.sep + os.path.join("tmp", "state_pkg.tgz") 1085 mock = MagicMock( 1086 side_effect=[False, True, True, True, True, True, True, True, True, True, True] 1087 ) 1088 mock_json_loads_true = MagicMock(return_value=[True]) 1089 mock_json_loads_dictlist = MagicMock(return_value=[{"test": ""}]) 1090 with patch.object(os.path, "isfile", mock), patch( 1091 "salt.modules.state.tarfile", MockTarFile 1092 ), patch.object(salt.utils, "json", mock_json_loads_dictlist): 1093 assert state.pkg(tar_file, "", "md5") == {} 1094 1095 mock = MagicMock(side_effect=[False, 0, 0, 0, 0]) 1096 with patch.object(salt.utils.hashutils, "get_hash", mock): 1097 # Verify hash 1098 assert state.pkg(tar_file, "", "md5") == {} 1099 1100 # Verify file outside intended root 1101 assert state.pkg(tar_file, 0, "md5") == {} 1102 1103 MockTarFile.path = "" 1104 with patch("salt.utils.files.fopen", mock_open()), patch.object( 1105 salt.utils.json, "loads", mock_json_loads_true 1106 ), patch.object(state, "_format_cached_grains", MagicMock()): 1107 assert state.pkg(tar_file, 0, "md5") is True 1108 state._format_cached_grains.assert_called_once() 1109 1110 MockTarFile.path = "" 1111 with patch("salt.utils.files.fopen", mock_open()): 1112 assert state.pkg(tar_file, 0, "md5") 1113 1114 1115def test_lock_saltenv(): 1116 """ 1117 Tests lock_saltenv in each function which accepts saltenv on the CLI 1118 """ 1119 lock_msg = "lock_saltenv is enabled, saltenv cannot be changed" 1120 empty_list_mock = MagicMock(return_value=[]) 1121 with patch.dict(state.__opts__, {"lock_saltenv": True}), patch.dict( 1122 state.__salt__, {"grains.get": empty_list_mock} 1123 ), patch.object(state, "running", empty_list_mock): 1124 1125 # Test high 1126 with pytest.raises(CommandExecutionError, match=lock_msg): 1127 state.high([{"vim": {"pkg": ["installed"]}}], saltenv="base") 1128 1129 # Test template 1130 with pytest.raises(CommandExecutionError, match=lock_msg): 1131 state.template("foo", saltenv="base") 1132 1133 # Test template_str 1134 with pytest.raises(CommandExecutionError, match=lock_msg): 1135 state.template_str("foo", saltenv="base") 1136 1137 # Test apply_ with SLS 1138 with pytest.raises(CommandExecutionError, match=lock_msg): 1139 state.apply_("foo", saltenv="base") 1140 1141 # Test apply_ with Highstate 1142 with pytest.raises(CommandExecutionError, match=lock_msg): 1143 state.apply_(saltenv="base") 1144 1145 # Test "test" with SLS 1146 with pytest.raises(CommandExecutionError, match=lock_msg): 1147 state.test("foo", saltenv="base") 1148 1149 # Test "test" with Highstate 1150 with pytest.raises(CommandExecutionError, match=lock_msg): 1151 state.test(saltenv="base") 1152 1153 # Test highstate 1154 with pytest.raises(CommandExecutionError, match=lock_msg): 1155 state.highstate(saltenv="base") 1156 1157 # Test sls 1158 with pytest.raises(CommandExecutionError, match=lock_msg): 1159 state.sls("foo", saltenv="base") 1160 1161 # Test top 1162 with pytest.raises(CommandExecutionError, match=lock_msg): 1163 state.top("foo.sls", saltenv="base") 1164 1165 # Test show_highstate 1166 with pytest.raises(CommandExecutionError, match=lock_msg): 1167 state.show_highstate(saltenv="base") 1168 1169 # Test show_lowstate 1170 with pytest.raises(CommandExecutionError, match=lock_msg): 1171 state.show_lowstate(saltenv="base") 1172 1173 # Test sls_id 1174 with pytest.raises(CommandExecutionError, match=lock_msg): 1175 state.sls_id("foo", "bar", saltenv="base") 1176 1177 # Test show_low_sls 1178 with pytest.raises(CommandExecutionError, match=lock_msg): 1179 state.show_low_sls("foo", saltenv="base") 1180 1181 # Test show_sls 1182 with pytest.raises(CommandExecutionError, match=lock_msg): 1183 state.show_sls("foo", saltenv="base") 1184 1185 # Test show_top 1186 with pytest.raises(CommandExecutionError, match=lock_msg): 1187 state.show_top(saltenv="base") 1188 1189 # Test single 1190 with pytest.raises(CommandExecutionError, match=lock_msg): 1191 state.single("foo.bar", name="baz", saltenv="base") 1192 1193 # Test pkg 1194 with pytest.raises(CommandExecutionError, match=lock_msg): 1195 state.pkg( 1196 "/tmp/salt_state.tgz", 1197 "760a9353810e36f6d81416366fc426dc", 1198 "md5", 1199 saltenv="base", 1200 ) 1201 1202 1203def test_get_pillar_errors_CC(): 1204 """ 1205 Test _get_pillar_errors function. 1206 CC: External clean, Internal clean 1207 :return: 1208 """ 1209 for int_pillar, ext_pillar in [ 1210 ({"foo": "bar"}, {"fred": "baz"}), 1211 ({"foo": "bar"}, None), 1212 ({}, {"fred": "baz"}), 1213 ]: 1214 with patch("salt.modules.state.__pillar__", int_pillar): 1215 for opts, res in [ 1216 ({"force": True}, None), 1217 ({"force": False}, None), 1218 ({}, None), 1219 ]: 1220 assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar) 1221 1222 1223def test_get_pillar_errors_EC(): 1224 """ 1225 Test _get_pillar_errors function. 1226 EC: External erroneous, Internal clean 1227 :return: 1228 """ 1229 errors = ["failure", "everywhere"] 1230 for int_pillar, ext_pillar in [ 1231 ({"foo": "bar"}, {"fred": "baz", "_errors": errors}), 1232 ({}, {"fred": "baz", "_errors": errors}), 1233 ]: 1234 with patch("salt.modules.state.__pillar__", int_pillar): 1235 for opts, res in [ 1236 ({"force": True}, None), 1237 ({"force": False}, errors), 1238 ({}, errors), 1239 ]: 1240 assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar) 1241 1242 1243def test_get_pillar_errors_EE(): 1244 """ 1245 Test _get_pillar_errors function. 1246 CC: External erroneous, Internal erroneous 1247 :return: 1248 """ 1249 errors = ["failure", "everywhere"] 1250 for int_pillar, ext_pillar in [ 1251 ({"foo": "bar", "_errors": errors}, {"fred": "baz", "_errors": errors}) 1252 ]: 1253 with patch("salt.modules.state.__pillar__", int_pillar): 1254 for opts, res in [ 1255 ({"force": True}, None), 1256 ({"force": False}, errors), 1257 ({}, errors), 1258 ]: 1259 assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar) 1260 1261 1262def test_get_pillar_errors_CE(): 1263 """ 1264 Test _get_pillar_errors function. 1265 CC: External clean, Internal erroneous 1266 :return: 1267 """ 1268 errors = ["failure", "everywhere"] 1269 for int_pillar, ext_pillar in [ 1270 ({"foo": "bar", "_errors": errors}, {"fred": "baz"}), 1271 ({"foo": "bar", "_errors": errors}, None), 1272 ]: 1273 with patch("salt.modules.state.__pillar__", int_pillar): 1274 for opts, res in [ 1275 ({"force": True}, None), 1276 ({"force": False}, errors), 1277 ({}, errors), 1278 ]: 1279 assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar) 1280 1281 1282def test_event(): 1283 """ 1284 test state.event runner 1285 """ 1286 event_returns = { 1287 "data": { 1288 "body": b'{"text": "Hello World"}', 1289 "_stamp": "2021-01-08T00:12:32.320928", 1290 }, 1291 "tag": "salt/engines/hook/test", 1292 } 1293 1294 _expected = '"body": "{\\"text\\": \\"Hello World\\"}"' 1295 with patch.object(SaltEvent, "get_event", return_value=event_returns): 1296 print_cli_mock = MagicMock() 1297 with patch.object(salt.utils.stringutils, "print_cli", print_cli_mock): 1298 found = False 1299 state.event(count=1) 1300 for x in print_cli_mock.mock_calls: 1301 if _expected in x.args[0]: 1302 found = True 1303 assert found is True 1304 1305 now = datetime.datetime.now().isoformat() 1306 event_returns = { 1307 "data": {"date": now, "_stamp": "2021-01-08T00:12:32.320928"}, 1308 "tag": "a_event_tag", 1309 } 1310 1311 _expected = '"date": "{}"'.format(now) 1312 with patch.object(SaltEvent, "get_event", return_value=event_returns): 1313 print_cli_mock = MagicMock() 1314 with patch.object(salt.utils.stringutils, "print_cli", print_cli_mock): 1315 found = False 1316 state.event(count=1) 1317 for x in print_cli_mock.mock_calls: 1318 if _expected in x.args[0]: 1319 found = True 1320 assert found is True 1321