mirror of
https://github.com/valitydev/salt.git
synced 2024-11-06 16:45:27 +00:00
Event assert (#33262)
* Initial POC * Allow the queue to fill by waiting for the lag in IPC * Add docs * Add run_tests * Add reactor to tests
This commit is contained in:
parent
8b3497b129
commit
d5a3e309bf
@ -362,6 +362,29 @@ Testing salt-ssh functionality can be done using the SSHCase test class:
|
|||||||
self.assertEqual(cmd, 'localhost')
|
self.assertEqual(cmd, 'localhost')
|
||||||
|
|
||||||
|
|
||||||
|
Testing Event System via SaltMinionEventAssertsMixin
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
The fundamentially asynchronous nature of Salt makes testing the event system a challenge.
|
||||||
|
The ``SaltMinionEventAssertsMixin`` provides a facility for testing that events were received
|
||||||
|
on a minion event bus.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import integration
|
||||||
|
|
||||||
|
class TestEvent(integration.SaltEventAssertsMixin):
|
||||||
|
'''
|
||||||
|
Example test of firing an event and receiving it
|
||||||
|
'''
|
||||||
|
|
||||||
|
def test_event(self):
|
||||||
|
e = salt.utils.event.get_event('minion', sock_dir=self.minion_opts['sock_dir'], opts=self.minion_opts)
|
||||||
|
|
||||||
|
e.fire_event({'a': 'b'}, '/test_event')
|
||||||
|
|
||||||
|
self.assertMinionEventReceived({'a': 'b'})
|
||||||
|
|
||||||
|
|
||||||
Syndic Example via SyndicCase
|
Syndic Example via SyndicCase
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
@ -1082,6 +1082,63 @@ class AdaptedConfigurationTestCaseMixIn(object):
|
|||||||
return self.get_config('master')
|
return self.get_config('master')
|
||||||
|
|
||||||
|
|
||||||
|
class SaltMinionEventAssertsMixIn(object):
|
||||||
|
'''
|
||||||
|
Asserts to verify that a given event was seen
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
# We have to cross-call to re-gen a config
|
||||||
|
cls.q = multiprocessing.Queue()
|
||||||
|
cls.fetch_proc = multiprocessing.Process(target=cls._fetch, args=(cls.q,))
|
||||||
|
cls.fetch_proc.start()
|
||||||
|
return object.__new__(cls)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _fetch(q):
|
||||||
|
'''
|
||||||
|
Collect events and store them
|
||||||
|
'''
|
||||||
|
def _clean_queue():
|
||||||
|
print('Cleaning queue!')
|
||||||
|
while not q.empty():
|
||||||
|
queue_item = q.get()
|
||||||
|
queue_item.task_done()
|
||||||
|
|
||||||
|
atexit.register(_clean_queue)
|
||||||
|
a_config = AdaptedConfigurationTestCaseMixIn()
|
||||||
|
event = salt.utils.event.get_event('minion', sock_dir=a_config.get_config('minion')['sock_dir'], opts=a_config.get_config('minion'))
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
events = event.get_event(full=False)
|
||||||
|
except Exception:
|
||||||
|
# This is broad but we'll see all kinds of issues right now
|
||||||
|
# if we drop the proc out from under the socket while we're reading
|
||||||
|
pass
|
||||||
|
q.put(events)
|
||||||
|
|
||||||
|
def assertMinionEventFired(self, tag):
|
||||||
|
#TODO
|
||||||
|
raise salt.exceptions.NotImplemented('assertMinionEventFired() not implemented')
|
||||||
|
|
||||||
|
def assertMinionEventReceived(self, desired_event):
|
||||||
|
queue_wait = 5 # 2.5s
|
||||||
|
while self.q.empty():
|
||||||
|
time.sleep(0.5) # Wait for events to be pushed into the queue
|
||||||
|
queue_wait -= 1
|
||||||
|
if queue_wait <= 0:
|
||||||
|
raise AssertionError('Queue wait timer expired')
|
||||||
|
while not self.q.empty(): # This is not thread-safe and may be inaccurate
|
||||||
|
event = self.q.get()
|
||||||
|
if isinstance(event, dict):
|
||||||
|
event.pop('_stamp')
|
||||||
|
if desired_event == event:
|
||||||
|
self.fetch_proc.terminate()
|
||||||
|
return True
|
||||||
|
self.fetch_proc.terminate()
|
||||||
|
raise AssertionError('Event {0} was not received by minion'.format(desired_event))
|
||||||
|
|
||||||
|
|
||||||
class SaltClientTestCaseMixIn(AdaptedConfigurationTestCaseMixIn):
|
class SaltClientTestCaseMixIn(AdaptedConfigurationTestCaseMixIn):
|
||||||
|
|
||||||
_salt_client_config_file_name_ = 'master'
|
_salt_client_config_file_name_ = 'master'
|
||||||
|
1
tests/integration/reactor/__init__.py
Normal file
1
tests/integration/reactor/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
43
tests/integration/reactor/reactor.py
Normal file
43
tests/integration/reactor/reactor.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
|
||||||
|
integration.reactor.reactor
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Test Salt's reactor system
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# Import Salt testing libs
|
||||||
|
from salttesting.helpers import ensure_in_syspath
|
||||||
|
|
||||||
|
ensure_in_syspath('../')
|
||||||
|
|
||||||
|
import integration
|
||||||
|
|
||||||
|
# Import Salt libs
|
||||||
|
import salt.utils.event
|
||||||
|
|
||||||
|
|
||||||
|
class ReactorTest(integration.ModuleCase, integration.SaltMinionEventAssertsMixIn):
|
||||||
|
'''
|
||||||
|
Test Salt's reactor system
|
||||||
|
'''
|
||||||
|
|
||||||
|
def test_ping_reaction(self):
|
||||||
|
'''
|
||||||
|
Fire an event on the master and ensure
|
||||||
|
that it pings the minion
|
||||||
|
'''
|
||||||
|
# Create event bus connection
|
||||||
|
e = salt.utils.event.get_event('minion', sock_dir=self.minion_opts['sock_dir'], opts=self.minion_opts)
|
||||||
|
|
||||||
|
e.fire_event({'a': 'b'}, '/test_event')
|
||||||
|
|
||||||
|
self.assertMinionEventReceived({'a': 'b'})
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests
|
||||||
|
run_tests(ReactorTest)
|
@ -99,7 +99,10 @@ TEST_SUITES = {
|
|||||||
'path': 'integration/cloud/providers'},
|
'path': 'integration/cloud/providers'},
|
||||||
'minion':
|
'minion':
|
||||||
{'display_name': 'Minion',
|
{'display_name': 'Minion',
|
||||||
'path': 'integration/minion'}
|
'path': 'integration/minion'},
|
||||||
|
'reactor':
|
||||||
|
{'display_name': 'Reactor',
|
||||||
|
'path': 'integration/reactor'},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -240,6 +243,13 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
|||||||
action='store_true',
|
action='store_true',
|
||||||
help='Run salt/renderers/*.py tests'
|
help='Run salt/renderers/*.py tests'
|
||||||
)
|
)
|
||||||
|
self.test_selection_group.add_option(
|
||||||
|
'--reactor',
|
||||||
|
dest='reactor',
|
||||||
|
default=False,
|
||||||
|
action='store_true',
|
||||||
|
help='Run salt/reactor/*.py tests'
|
||||||
|
)
|
||||||
self.test_selection_group.add_option(
|
self.test_selection_group.add_option(
|
||||||
'--minion',
|
'--minion',
|
||||||
'--minion-tests',
|
'--minion-tests',
|
||||||
|
Loading…
Reference in New Issue
Block a user