Skip to content

Commit d514b0b

Browse files
author
Joe LeVeque
committed
[test_process.py] Add unit tests for clock rollback scenario
1 parent c5136b9 commit d514b0b

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed

supervisor/tests/test_process.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,40 @@ def test_stop_report_logs_throttled_by_laststopreport(self):
738738
instance.stop_report()
739739
self.assertEqual(len(options.logger.data), 1) # throttled
740740

741+
def test_stop_report_laststopreport_in_future(self):
742+
future_time = time.time() + 3600 # 1 hour into the future
743+
options = DummyOptions()
744+
config = DummyPConfig(options, 'test', '/test')
745+
instance = self._makeOne(config)
746+
instance.pid = 11
747+
dispatcher = DummyDispatcher(writable=True)
748+
instance.dispatchers = {'foo':dispatcher}
749+
from supervisor.states import ProcessStates
750+
instance.state = ProcessStates.STOPPING
751+
instance.laststopreport = future_time
752+
753+
# This iteration of stop_report() should reset instance.laststopreport
754+
# to the current time
755+
instance.stop_report()
756+
757+
# No logging should have taken place
758+
self.assertEqual(len(options.logger.data), 0)
759+
760+
# Ensure instance.laststopreport has rolled backward
761+
self.assertTrue(instance.laststopreport < future_time)
762+
763+
# Sleep for 2 seconds
764+
time.sleep(2)
765+
766+
# This iteration of stop_report() should actaully trigger the report
767+
instance.stop_report()
768+
769+
self.assertEqual(len(options.logger.data), 1)
770+
self.assertEqual(options.logger.data[0], 'waiting for test to stop')
771+
self.assertNotEqual(instance.laststopreport, 0)
772+
instance.stop_report()
773+
self.assertEqual(len(options.logger.data), 1) # throttled
774+
741775
def test_give_up(self):
742776
options = DummyOptions()
743777
config = DummyPConfig(options, 'test', '/test')
@@ -1403,6 +1437,92 @@ def test_transition_starting_to_running(self):
14031437
event = L[0]
14041438
self.assertEqual(event.__class__, events.ProcessStateRunningEvent)
14051439

1440+
def test_transition_starting_to_running_laststart_in_future(self):
1441+
from supervisor import events
1442+
L = []
1443+
events.subscribe(events.ProcessStateEvent, lambda x: L.append(x))
1444+
from supervisor.states import ProcessStates
1445+
1446+
future_time = time.time() + 3600 # 1 hour into the future
1447+
options = DummyOptions()
1448+
test_startsecs = 2
1449+
1450+
# this should go from STARTING to RUNNING via transition()
1451+
pconfig = DummyPConfig(options, 'process', 'process','/bin/process',
1452+
startsecs=test_startsecs)
1453+
process = self._makeOne(pconfig)
1454+
process.backoff = 1
1455+
process.delay = 1
1456+
process.system_stop = False
1457+
process.laststart = future_time
1458+
process.pid = 1
1459+
process.stdout_buffer = 'abc'
1460+
process.stderr_buffer = 'def'
1461+
process.state = ProcessStates.STARTING
1462+
1463+
# This iteration of transition() should reset process.laststart
1464+
# to the current time
1465+
process.transition()
1466+
1467+
# Process state should still be STARTING
1468+
self.assertEqual(process.state, ProcessStates.STARTING)
1469+
1470+
# Ensure process.laststart has rolled backward
1471+
self.assertTrue(process.laststart < future_time)
1472+
1473+
# Sleep for (startsecs + 1)
1474+
time.sleep(test_startsecs + 1)
1475+
1476+
# This iteration of transition() should actaully trigger the state
1477+
# transition to RUNNING
1478+
process.transition()
1479+
1480+
# this implies RUNNING
1481+
self.assertEqual(process.backoff, 0)
1482+
self.assertEqual(process.delay, 0)
1483+
self.assertFalse(process.system_stop)
1484+
self.assertEqual(process.state, ProcessStates.RUNNING)
1485+
self.assertEqual(options.logger.data[0],
1486+
'success: process entered RUNNING state, process has '
1487+
'stayed up for > than {} seconds (startsecs)'.format(test_startsecs))
1488+
self.assertEqual(len(L), 1)
1489+
event = L[0]
1490+
self.assertEqual(event.__class__, events.ProcessStateRunningEvent)
1491+
1492+
def test_transition_backoff_to_starting_delay_in_future(self):
1493+
from supervisor import events
1494+
L = []
1495+
events.subscribe(events.ProcessStateEvent, lambda x: L.append(x))
1496+
from supervisor.states import ProcessStates, SupervisorStates
1497+
1498+
future_time = time.time() + 3600 # 1 hour into the future
1499+
options = DummyOptions()
1500+
1501+
pconfig = DummyPConfig(options, 'process', 'process','/bin/process')
1502+
process = self._makeOne(pconfig)
1503+
process.laststart = 1
1504+
process.delay = future_time
1505+
process.backoff = 0
1506+
process.state = ProcessStates.BACKOFF
1507+
1508+
# This iteration of transition() should reset process.delay
1509+
# to the current time
1510+
process.transition()
1511+
1512+
# Process state should still be BACKOFF
1513+
self.assertEqual(process.state, ProcessStates.BACKOFF)
1514+
1515+
# Ensure process.delay has rolled backward
1516+
self.assertTrue(process.delay < future_time)
1517+
1518+
# This iteration of transition() should actaully trigger the state
1519+
# transition to STARTING
1520+
process.transition()
1521+
1522+
self.assertEqual(process.state, ProcessStates.STARTING)
1523+
self.assertEqual(len(L), 1)
1524+
self.assertEqual(L[0].__class__, events.ProcessStateStartingEvent)
1525+
14061526
def test_transition_backoff_to_fatal(self):
14071527
from supervisor import events
14081528
L = []
@@ -2034,6 +2154,32 @@ class DummyGroup:
20342154
self.assertEqual(process1.listener_state, EventListenerStates.BUSY)
20352155
self.assertEqual(process1.event, event)
20362156

2157+
def test_transition_event_proc_running_with_dispatch_throttle_last_dispatch_in_future(self):
2158+
future_time = time.time() + 3600 # 1 hour into the future
2159+
options = DummyOptions()
2160+
from supervisor.states import ProcessStates
2161+
pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1')
2162+
process1 = DummyProcess(pconfig1, state=ProcessStates.RUNNING)
2163+
gconfig = DummyPGroupConfig(options, pconfigs=[pconfig1])
2164+
pool = self._makeOne(gconfig)
2165+
pool.dispatch_throttle = 5
2166+
pool.last_dispatch = future_time
2167+
pool.processes = {'process1': process1}
2168+
event = DummyEvent()
2169+
from supervisor.states import EventListenerStates
2170+
process1.listener_state = EventListenerStates.READY
2171+
class DummyGroup:
2172+
config = gconfig
2173+
process1.group = DummyGroup
2174+
pool._acceptEvent(event)
2175+
pool.transition()
2176+
2177+
self.assertEqual(process1.transitioned, True)
2178+
self.assertEqual(pool.event_buffer, [event]) # not popped
2179+
2180+
# Ensure pool.last_dispatch has been rolled backward
2181+
self.assertTrue(pool.last_dispatch < future_time)
2182+
20372183
def test__dispatchEvent_notready(self):
20382184
options = DummyOptions()
20392185
from supervisor.states import ProcessStates

0 commit comments

Comments
 (0)