2015-04-14 09:00:58 +00:00
# -*- coding: utf-8 -*-
'''
2018-05-28 21:13:12 +00:00
: codeauthor : Jayesh Kariya < jayeshk @saltstack.com >
2015-04-14 09:00:58 +00:00
'''
# Import Python libs
2018-01-24 20:47:14 +00:00
from __future__ import absolute_import , unicode_literals , print_function
2017-03-30 22:10:28 +00:00
import os
2017-02-27 15:59:04 +00:00
import time
2017-02-19 15:35:30 +00:00
import tempfile
2015-04-14 09:00:58 +00:00
# Import Salt Testing Libs
2017-02-19 15:35:30 +00:00
from tests . support . mixins import LoaderModuleMockMixin
from tests . support . paths import TMP
2017-02-27 13:58:07 +00:00
from tests . support . unit import skipIf , TestCase
from tests . support . mock import (
2015-04-14 09:00:58 +00:00
NO_MOCK ,
NO_MOCK_REASON ,
MagicMock ,
patch
)
# Import Salt Libs
2017-09-01 20:03:11 +00:00
import salt . config
import salt . loader
2017-02-19 15:35:30 +00:00
import salt . utils . jid
2017-02-27 15:59:04 +00:00
import salt . utils . event
2017-03-21 17:15:36 +00:00
import salt . states . saltmod as saltmod
2015-04-14 09:00:58 +00:00
@skipIf ( NO_MOCK , NO_MOCK_REASON )
2017-02-19 15:35:30 +00:00
class SaltmodTestCase ( TestCase , LoaderModuleMockMixin ) :
2015-04-14 09:00:58 +00:00
'''
Test cases for salt . states . saltmod
'''
2017-03-22 12:12:36 +00:00
def setup_loader_modules ( self ) :
2017-09-01 20:03:11 +00:00
utils = salt . loader . utils (
salt . config . DEFAULT_MINION_OPTS ,
whitelist = [ ' state ' ]
)
2017-02-19 15:35:30 +00:00
return {
2017-03-22 12:12:36 +00:00
saltmod : {
' __env__ ' : ' base ' ,
' __opts__ ' : {
' __role ' : ' master ' ,
' file_client ' : ' remote ' ,
' sock_dir ' : tempfile . mkdtemp ( dir = TMP ) ,
' transport ' : ' tcp '
} ,
' __salt__ ' : { ' saltutil.cmd ' : MagicMock ( ) } ,
2017-08-04 16:51:21 +00:00
' __orchestration_jid__ ' : salt . utils . jid . gen_jid ( { } ) ,
2017-09-01 20:03:11 +00:00
' __utils__ ' : utils ,
2017-03-22 12:12:36 +00:00
}
2017-02-19 15:35:30 +00:00
}
2017-03-22 12:12:36 +00:00
2015-04-14 09:00:58 +00:00
# 'state' function tests: 1
def test_state ( self ) :
'''
Test to invoke a state run on a given target
'''
name = ' state '
tgt = ' minion1 '
comt = ( ' Passed invalid value for \' allow_fail \' , must be an int ' )
ret = { ' name ' : name ,
' changes ' : { } ,
' result ' : False ,
' comment ' : comt }
2015-07-22 17:43:19 +00:00
test_ret = { ' name ' : name ,
' changes ' : { } ,
' result ' : True ,
' comment ' : ' States ran successfully. '
}
2017-05-23 13:56:40 +00:00
test_batch_return = {
' minion1 ' : {
' ret ' : {
' test_|-notify_me_|-this is a name_|-show_notification ' : {
' comment ' : ' Notify me ' ,
' name ' : ' this is a name ' ,
' start_time ' : ' 10:43:41.487565 ' ,
' result ' : True ,
' duration ' : 0.35 ,
' __run_num__ ' : 0 ,
' __sls__ ' : ' demo ' ,
' changes ' : { } ,
' __id__ ' : ' notify_me '
} ,
' retcode ' : 0
} ,
' out ' : ' highstate '
} ,
' minion2 ' : {
' ret ' : {
' test_|-notify_me_|-this is a name_|-show_notification ' : {
' comment ' : ' Notify me ' ,
' name ' : ' this is a name ' ,
' start_time ' : ' 10:43:41.487565 ' ,
' result ' : True ,
' duration ' : 0.35 ,
' __run_num__ ' : 0 ,
' __sls__ ' : ' demo ' ,
' changes ' : { } ,
' __id__ ' : ' notify_me '
} ,
' retcode ' : 0
} ,
' out ' : ' highstate '
} ,
' minion3 ' : {
' ret ' : {
' test_|-notify_me_|-this is a name_|-show_notification ' : {
' comment ' : ' Notify me ' ,
' name ' : ' this is a name ' ,
' start_time ' : ' 10:43:41.487565 ' ,
' result ' : True ,
' duration ' : 0.35 ,
' __run_num__ ' : 0 ,
' __sls__ ' : ' demo ' ,
' changes ' : { } ,
' __id__ ' : ' notify_me '
} ,
' retcode ' : 0
} ,
' out ' : ' highstate '
}
}
2015-04-14 09:00:58 +00:00
self . assertDictEqual ( saltmod . state ( name , tgt , allow_fail = ' a ' ) , ret )
comt = ( ' No highstate or sls specified, no execution made ' )
ret . update ( { ' comment ' : comt } )
self . assertDictEqual ( saltmod . state ( name , tgt ) , ret )
comt = ( " Must pass in boolean for value of ' concurrent ' " )
ret . update ( { ' comment ' : comt } )
self . assertDictEqual ( saltmod . state ( name , tgt , highstate = True ,
concurrent = ' a ' ) , ret )
ret . update ( { ' comment ' : comt , ' result ' : None } )
with patch . dict ( saltmod . __opts__ , { ' test ' : True } ) :
2015-07-22 17:43:19 +00:00
self . assertDictEqual ( saltmod . state ( name , tgt , highstate = True ) , test_ret )
2015-04-14 09:00:58 +00:00
2017-04-06 16:48:27 +00:00
ret . update ( { ' comment ' : ' States ran successfully. No changes made to silver. ' , ' result ' : True , ' __jid__ ' : ' 20170406104341210934 ' } )
2015-04-14 09:00:58 +00:00
with patch . dict ( saltmod . __opts__ , { ' test ' : False } ) :
2017-04-06 16:48:27 +00:00
mock = MagicMock ( return_value = { ' silver ' : { ' jid ' : ' 20170406104341210934 ' , ' retcode ' : 0 , ' ret ' : { ' test_|-notify_me_|-this is a name_|-show_notification ' : { ' comment ' : ' Notify me ' , ' name ' : ' this is a name ' , ' start_time ' : ' 10:43:41.487565 ' , ' result ' : True , ' duration ' : 0.35 , ' __run_num__ ' : 0 , ' __sls__ ' : ' demo ' , ' changes ' : { } , ' __id__ ' : ' notify_me ' } } , ' out ' : ' highstate ' } } )
2015-04-14 09:00:58 +00:00
with patch . dict ( saltmod . __salt__ , { ' saltutil.cmd ' : mock } ) :
2017-05-23 13:56:40 +00:00
self . assertDictEqual ( saltmod . state ( name , tgt , highstate = True ) , ret )
ret . update ( { ' comment ' : ' States ran successfully. No changes made to minion1, minion3, minion2. ' } )
del ret [ ' __jid__ ' ]
with patch . dict ( saltmod . __opts__ , { ' test ' : False } ) :
with patch . dict ( saltmod . __salt__ , { ' saltutil.cmd ' : MagicMock ( return_value = test_batch_return ) } ) :
2017-07-05 18:56:03 +00:00
state_run = saltmod . state ( name , tgt , highstate = True )
# Test return without checking the comment contents. Comments are tested later.
comment = state_run . pop ( ' comment ' )
ret . pop ( ' comment ' )
self . assertDictEqual ( state_run , ret )
# Check the comment contents in a non-order specific way (ordering fails sometimes on PY3)
self . assertIn ( ' States ran successfully. No changes made to ' , comment )
for minion in [ ' minion1 ' , ' minion2 ' , ' minion3 ' ] :
self . assertIn ( minion , comment )
2015-04-14 09:00:58 +00:00
# 'function' function tests: 1
def test_function ( self ) :
'''
Test to execute a single module function on a remote
minion via salt or salt - ssh
'''
name = ' state '
2015-04-16 20:41:46 +00:00
tgt = ' larry '
2015-04-14 09:00:58 +00:00
comt = ( ' Function state will be executed '
2015-04-16 20:41:46 +00:00
' on target {0} as test=False ' . format ( tgt ) )
2015-04-14 09:00:58 +00:00
ret = { ' name ' : name ,
' changes ' : { } ,
' result ' : None ,
' comment ' : comt }
with patch . dict ( saltmod . __opts__ , { ' test ' : True } ) :
self . assertDictEqual ( saltmod . function ( name , tgt ) , ret )
2015-04-16 20:41:46 +00:00
ret . update ( { ' result ' : True ,
' changes ' : { ' out ' : ' highstate ' , ' ret ' : { tgt : ' ' } } ,
' comment ' : ' Function ran successfully. '
' Function state ran on {0} . ' . format ( tgt ) } )
2015-04-14 09:00:58 +00:00
with patch . dict ( saltmod . __opts__ , { ' test ' : False } ) :
2015-04-16 20:41:46 +00:00
mock_ret = { ' larry ' : { ' ret ' : ' ' , ' retcode ' : 0 , ' failed ' : False } }
mock_cmd = MagicMock ( return_value = mock_ret )
with patch . dict ( saltmod . __salt__ , { ' saltutil.cmd ' : mock_cmd } ) :
2015-04-14 09:00:58 +00:00
self . assertDictEqual ( saltmod . function ( name , tgt ) , ret )
# 'wait_for_event' function tests: 1
def test_wait_for_event ( self ) :
'''
Test to watch Salt ' s event bus and block until a condition is met
'''
name = ' state '
tgt = ' minion1 '
comt = ( ' Timeout value reached. ' )
ret = { ' name ' : name ,
' changes ' : { } ,
' result ' : False ,
' comment ' : comt }
class Mockevent ( object ) :
'''
Mock event class
'''
flag = None
def __init__ ( self ) :
self . full = None
def get_event ( self , full ) :
'''
Mock get_event method
'''
self . full = full
if self . flag :
return { ' tag ' : name , ' data ' : { } }
return None
with patch . object ( salt . utils . event , ' get_event ' ,
MagicMock ( return_value = Mockevent ( ) ) ) :
with patch . dict ( saltmod . __opts__ , { ' sock_dir ' : True ,
' transport ' : True } ) :
with patch . object ( time , ' time ' , MagicMock ( return_value = 1.0 ) ) :
self . assertDictEqual ( saltmod . wait_for_event ( name , ' salt ' ,
timeout = - 1.0 ) ,
ret )
Mockevent . flag = True
ret . update ( { ' comment ' : ' All events seen in 0.0 seconds. ' ,
' result ' : True } )
self . assertDictEqual ( saltmod . wait_for_event ( name , ' ' ) , ret )
ret . update ( { ' comment ' : ' Timeout value reached. ' ,
' result ' : False } )
self . assertDictEqual ( saltmod . wait_for_event ( name , tgt ,
timeout = - 1.0 ) ,
ret )
# 'runner' function tests: 1
def test_runner ( self ) :
'''
Test to execute a runner module on the master
'''
name = ' state '
2017-11-29 21:51:53 +00:00
ret = { ' changes ' : { ' return ' : True } , ' name ' : ' state ' , ' result ' : True ,
' comment ' : ' Runner function \' state \' executed. ' ,
2016-08-09 13:48:59 +00:00
' __orchestration__ ' : True }
2016-07-27 18:01:24 +00:00
runner_mock = MagicMock ( return_value = { ' return ' : True } )
2015-04-14 09:00:58 +00:00
2016-07-27 18:01:24 +00:00
with patch . dict ( saltmod . __salt__ , { ' saltutil.runner ' : runner_mock } ) :
2015-04-14 09:00:58 +00:00
self . assertDictEqual ( saltmod . runner ( name ) , ret )
# 'wheel' function tests: 1
def test_wheel ( self ) :
'''
Test to execute a wheel module on the master
'''
name = ' state '
2017-11-29 21:51:53 +00:00
ret = { ' changes ' : { ' return ' : True } , ' name ' : ' state ' , ' result ' : True ,
' comment ' : ' Wheel function \' state \' executed. ' ,
2016-08-09 13:48:59 +00:00
' __orchestration__ ' : True }
2016-07-27 18:01:24 +00:00
wheel_mock = MagicMock ( return_value = { ' return ' : True } )
2015-04-14 09:00:58 +00:00
2016-07-27 18:01:24 +00:00
with patch . dict ( saltmod . __salt__ , { ' saltutil.wheel ' : wheel_mock } ) :
2015-04-14 09:00:58 +00:00
self . assertDictEqual ( saltmod . wheel ( name ) , ret )
2017-03-30 22:10:28 +00:00
@skipIf ( NO_MOCK , NO_MOCK_REASON )
class StatemodTests ( TestCase , LoaderModuleMockMixin ) :
def setup_loader_modules ( self ) :
self . tmp_cachedir = tempfile . mkdtemp ( dir = TMP )
return {
saltmod : {
' __env__ ' : ' base ' ,
' __opts__ ' : {
' id ' : ' webserver2 ' ,
' argv ' : [ ] ,
' __role ' : ' master ' ,
' cachedir ' : self . tmp_cachedir ,
' extension_modules ' : os . path . join ( self . tmp_cachedir , ' extmods ' ) ,
} ,
' __salt__ ' : { ' saltutil.cmd ' : MagicMock ( ) } ,
2017-08-04 16:51:21 +00:00
' __orchestration_jid__ ' : salt . utils . jid . gen_jid ( { } )
2017-03-30 22:10:28 +00:00
}
}
def test_statemod_state ( self ) :
''' Smoke test for for salt.states.statemod.state(). Ensures that we
don ' t take an exception if optional parameters are not specified in
__opts__ or __env__ .
'''
args = ( ' webserver_setup ' , ' webserver2 ' )
kwargs = {
' tgt_type ' : ' glob ' ,
' fail_minions ' : None ,
' pillar ' : None ,
' top ' : None ,
' batch ' : None ,
' orchestration_jid ' : None ,
' sls ' : ' vroom ' ,
' queue ' : False ,
' concurrent ' : False ,
' highstate ' : None ,
' expr_form ' : None ,
' ret ' : ' ' ,
' ssh ' : False ,
' timeout ' : None , ' test ' : False ,
' allow_fail ' : 0 ,
' saltenv ' : None ,
' expect_minions ' : False
}
ret = saltmod . state ( * args , * * kwargs )
expected = {
' comment ' : ' States ran successfully. ' ,
' changes ' : { } ,
' name ' : ' webserver_setup ' ,
' result ' : True
}
self . assertEqual ( ret , expected )