test_terminals.py 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # coding: utf-8
  2. import time
  3. import os
  4. import pytest
  5. from synergine2.config import Config
  6. from synergine2.core import Core
  7. from synergine2.cycle import CycleManager
  8. from synergine2.log import SynergineLogger
  9. from synergine2.share import shared
  10. from synergine2.simulation import Event
  11. from synergine2.simulation import Simulation
  12. from synergine2.simulation import Subjects
  13. from synergine2.terminals import Terminal
  14. from synergine2.terminals import TerminalPackage
  15. from synergine2.terminals import TerminalManager
  16. from tests import BaseTest
  17. class ValueTerminalPackage(TerminalPackage):
  18. def __init__(self, value, *args, **kwargs):
  19. super().__init__(*args, **kwargs)
  20. self.value = value
  21. class MultiplyTerminal(Terminal):
  22. def receive(self, package: ValueTerminalPackage):
  23. self.send(ValueTerminalPackage(value=package.value * 2))
  24. self.send(ValueTerminalPackage(value=package.value * 4))
  25. class DivideTerminal(Terminal):
  26. def receive(self, package: ValueTerminalPackage):
  27. self.send(ValueTerminalPackage(value=package.value / 2))
  28. self.send(ValueTerminalPackage(value=package.value / 4))
  29. class AnEvent(Event):
  30. pass
  31. class AnOtherEvent(Event):
  32. pass
  33. class SendBackTerminal(Terminal):
  34. def receive(self, package: ValueTerminalPackage):
  35. self.send(package)
  36. class TestTerminals(BaseTest):
  37. def test_terminal_communications(self):
  38. terminals_manager = TerminalManager(
  39. Config(),
  40. SynergineLogger('test'),
  41. terminals=[
  42. MultiplyTerminal(Config(), SynergineLogger('test')),
  43. ]
  44. )
  45. terminals_manager.start()
  46. terminals_manager.send(ValueTerminalPackage(value=42))
  47. # We wait max 2s (see time.sleep) to consider
  48. # process have finished. If not, it will fail
  49. packages = []
  50. for i in range(200):
  51. packages.extend(terminals_manager.receive())
  52. if len(packages) == 2:
  53. break
  54. time.sleep(0.01)
  55. assert 2 == len(packages)
  56. values = [p.value for p in packages]
  57. assert 84 in values
  58. assert 168 in values
  59. terminals_manager.stop() # pytest must execute this if have fail
  60. def test_terminals_communications(self):
  61. terminals_manager = TerminalManager(
  62. Config(),
  63. SynergineLogger('test'),
  64. terminals=[
  65. MultiplyTerminal(Config(), SynergineLogger('test')),
  66. DivideTerminal(Config(), SynergineLogger('test')),
  67. ]
  68. )
  69. terminals_manager.start()
  70. terminals_manager.send(ValueTerminalPackage(value=42))
  71. # We wait max 2s (see time.sleep) to consider
  72. # process have finished. If not, it will fail
  73. packages = []
  74. for i in range(200):
  75. packages.extend(terminals_manager.receive())
  76. if len(packages) == 4:
  77. break
  78. time.sleep(0.01)
  79. assert 4 == len(packages)
  80. values = [p.value for p in packages]
  81. assert 84 in values
  82. assert 168 in values
  83. assert 21 in values
  84. assert 10.5 in values
  85. terminals_manager.stop() # TODO pytest must execute this if have fail
  86. def test_event_listen_everything(self):
  87. class ListenEverythingTerminal(SendBackTerminal):
  88. pass
  89. terminals_manager = TerminalManager(
  90. Config(),
  91. SynergineLogger('test'),
  92. terminals=[ListenEverythingTerminal(Config(), SynergineLogger('test'))]
  93. )
  94. terminals_manager.start()
  95. terminals_manager.send(ValueTerminalPackage(value=42))
  96. an_event = AnEvent()
  97. terminals_manager.send(TerminalPackage(events=[an_event]))
  98. # We wait max 2s (see time.sleep) to consider
  99. # process have finished. If not, it will fail
  100. packages = []
  101. for i in range(200):
  102. packages.extend(terminals_manager.receive())
  103. if len(packages) == 2:
  104. break
  105. time.sleep(0.01)
  106. assert 2 == len(packages)
  107. assert 42 == packages[0].value
  108. assert AnEvent == type(packages[1].events[0])
  109. terminals_manager.stop() # TODO pytest must execute this if have fail
  110. def test_event_listen_specified(self):
  111. class ListenAnEventTerminal(SendBackTerminal):
  112. subscribed_events = [AnOtherEvent]
  113. terminals_manager = TerminalManager(
  114. Config(),
  115. SynergineLogger('test'),
  116. terminals=[ListenAnEventTerminal(Config(), SynergineLogger('test'))]
  117. )
  118. terminals_manager.start()
  119. terminals_manager.send(ValueTerminalPackage(value=42))
  120. an_event = AnEvent()
  121. an_other_event = AnOtherEvent()
  122. terminals_manager.send(TerminalPackage(events=[an_event, an_other_event]))
  123. # We wait max 10s (see time.sleep) to consider
  124. # process have finished. If not, it will fail
  125. packages = []
  126. for i in range(1000):
  127. packages.extend(terminals_manager.receive())
  128. if len(packages) == 2:
  129. break
  130. time.sleep(0.01)
  131. assert 2 == len(packages)
  132. assert AnOtherEvent == type(packages[1].events[0])
  133. terminals_manager.stop() # TODO pytest must execute this if have fail
  134. @pytest.mark.skip(reason="Bug: globals fail in python 3.6 "
  135. "and still one process when not in debug ...")
  136. def test_terminal_as_main_process(self):
  137. shared.reset()
  138. config = Config()
  139. logger = SynergineLogger('test')
  140. simulation = Simulation(config)
  141. simulation.subjects = Subjects(simulation=simulation)
  142. cycle_manager = CycleManager(
  143. config=config,
  144. logger=logger,
  145. simulation=simulation,
  146. )
  147. global terminal_pid
  148. global core_pid
  149. terminal_pid = 0
  150. core_pid = 0
  151. class MyMainTerminal(Terminal):
  152. main_process = True
  153. def run(self):
  154. global terminal_pid
  155. terminal_pid = os.getpid()
  156. terminal = MyMainTerminal(config, logger)
  157. class MyCore(Core):
  158. def _end_cycle(self):
  159. self._continue = False
  160. global core_pid
  161. core_pid = os.getpid()
  162. core = MyCore(
  163. config=config,
  164. logger=logger,
  165. simulation=simulation,
  166. cycle_manager=cycle_manager,
  167. terminal_manager=TerminalManager(
  168. config=config,
  169. logger=logger,
  170. terminals=[terminal],
  171. ),
  172. )
  173. core.run()
  174. core.cycle_manager.process_manager.terminate()
  175. assert terminal_pid == os.getpid()
  176. assert core_pid == 0 # because changed in other process