Merge "Adding more doc strings to event simulator"
This commit is contained in:
commit
b6459ac348
@ -24,6 +24,84 @@ race conditions that would normally be present from testing multi-threaded
|
|||||||
scenarios. It also means that the simulated time.sleep does not actually have
|
scenarios. It also means that the simulated time.sleep does not actually have
|
||||||
to sit around for the designated time, which greatly speeds up the time it
|
to sit around for the designated time, which greatly speeds up the time it
|
||||||
takes to run the tests.
|
takes to run the tests.
|
||||||
|
|
||||||
|
Event Simulator Overview
|
||||||
|
========================
|
||||||
|
|
||||||
|
We use this to simulate all the threads of Trove running.
|
||||||
|
i.e (api,taskmanager,probocsis tests) All the services end
|
||||||
|
up sleeping and having to wait for something to happen at times.
|
||||||
|
|
||||||
|
Monkey Patching Methods
|
||||||
|
-----------------------
|
||||||
|
We monkey patch a few method to make this happen.
|
||||||
|
|
||||||
|
A few sleep methods with a fake_sleep.
|
||||||
|
* time.sleep
|
||||||
|
* eventlet.sleep
|
||||||
|
* greenthread.sleep
|
||||||
|
|
||||||
|
A few spawn methods with a fake_spawn
|
||||||
|
* eventlet.spawn_after
|
||||||
|
* eventlet.spawn_n
|
||||||
|
|
||||||
|
Raise an error if you try this one.
|
||||||
|
* eventlet.spawn
|
||||||
|
|
||||||
|
Replace the poll_until with a fake_poll_until.
|
||||||
|
|
||||||
|
Coroutine Object
|
||||||
|
----------------
|
||||||
|
|
||||||
|
There is a Coroutine object here that mimics the behavior of a thread.
|
||||||
|
It takes in a function with args and kwargs and executes it. If at any
|
||||||
|
point that method calls time.sleep(seconds) then the event simulator will
|
||||||
|
put that method on the stack of threads and run the fake_sleep method
|
||||||
|
that will then iterate over all the threads in the stack updating the time
|
||||||
|
they still need to sleep. Then as the threads hit the end of their sleep
|
||||||
|
time period they will continue to execute.
|
||||||
|
|
||||||
|
fake_threads
|
||||||
|
------------
|
||||||
|
|
||||||
|
One thing to note here is the idea of a stack of threads being kept in
|
||||||
|
fake_threads list. Any new thread created is added to this stack.
|
||||||
|
|
||||||
|
A fake_thread attributes:
|
||||||
|
|
||||||
|
fake_thread = {
|
||||||
|
'sleep': time_from_now_in_seconds,
|
||||||
|
'greenlet': Coroutine(method_to_execute),
|
||||||
|
'name': str(func)
|
||||||
|
}
|
||||||
|
|
||||||
|
'sleep' is the time it should wait to execute this method.
|
||||||
|
'greenlet' is the thread object
|
||||||
|
'name' is the unique name of the thread to track
|
||||||
|
|
||||||
|
main_loop Method
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The main_loop method is a loop that runs forever waiting on all the
|
||||||
|
threads to complete while running pulse every 0.1 seconds. This is the
|
||||||
|
key to simulated the threads quickly. We are pulsing every 0.1
|
||||||
|
seconds looking to make sure there are no threads just waiting around for
|
||||||
|
no reason rather than waiting a full second to respond.
|
||||||
|
|
||||||
|
pulse Method
|
||||||
|
------------
|
||||||
|
|
||||||
|
The pulse method is going through the stack(list) of threads looking for
|
||||||
|
the the next thread to execute while updating the 'sleep' time and the if
|
||||||
|
the 'sleep' time is <=0 then it will run this thread until it calls for
|
||||||
|
another time.sleep.
|
||||||
|
|
||||||
|
If the method/thread running calls time.sleep for what ever reason then
|
||||||
|
the thread's 'sleep' parameter is updated to the new 'next_sleep_time'.
|
||||||
|
|
||||||
|
If the method/thread running completes without calling time.sleep because it
|
||||||
|
finished all work needed to be done then there the 'next_sleep_time' is set
|
||||||
|
to None and the method/thread is deleted from the stack(list) of threads.
|
||||||
"""
|
"""
|
||||||
import eventlet
|
import eventlet
|
||||||
from eventlet.event import Event
|
from eventlet.event import Event
|
||||||
@ -103,15 +181,14 @@ class Coroutine(object):
|
|||||||
self.my_sem.release()
|
self.my_sem.release()
|
||||||
self.caller_sem.acquire() # Wait for it to finish.
|
self.caller_sem.acquire() # Wait for it to finish.
|
||||||
|
|
||||||
|
# Main global thread to run.
|
||||||
sleep_entrance_count = 0
|
|
||||||
|
|
||||||
main_greenlet = None
|
main_greenlet = None
|
||||||
|
|
||||||
|
# Stack of threads currently running or sleeping
|
||||||
fake_threads = []
|
fake_threads = []
|
||||||
|
|
||||||
|
# Allow a sleep method to be called at least this number of times before
|
||||||
|
# raising an error that there are not other active threads waiting to run.
|
||||||
allowable_empty_sleeps = 1
|
allowable_empty_sleeps = 1
|
||||||
sleep_allowance = allowable_empty_sleeps
|
sleep_allowance = allowable_empty_sleeps
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user