test__xxsubinterpreters.py 79 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327
  1. from collections import namedtuple
  2. import contextlib
  3. import itertools
  4. import os
  5. import pickle
  6. import sys
  7. from textwrap import dedent
  8. import threading
  9. import time
  10. import unittest
  11. from test import support
  12. from test.support import import_helper
  13. from test.support import script_helper
  14. interpreters = import_helper.import_module('_xxsubinterpreters')
  15. ##################################
  16. # helpers
  17. def _captured_script(script):
  18. r, w = os.pipe()
  19. indented = script.replace('\n', '\n ')
  20. wrapped = dedent(f"""
  21. import contextlib
  22. with open({w}, 'w', encoding="utf-8") as spipe:
  23. with contextlib.redirect_stdout(spipe):
  24. {indented}
  25. """)
  26. return wrapped, open(r, encoding="utf-8")
  27. def _run_output(interp, request, shared=None):
  28. script, rpipe = _captured_script(request)
  29. with rpipe:
  30. interpreters.run_string(interp, script, shared)
  31. return rpipe.read()
  32. def _wait_for_interp_to_run(interp, timeout=None):
  33. # bpo-37224: Running this test file in multiprocesses will fail randomly.
  34. # The failure reason is that the thread can't acquire the cpu to
  35. # run subinterpreter eariler than the main thread in multiprocess.
  36. if timeout is None:
  37. timeout = support.SHORT_TIMEOUT
  38. start_time = time.monotonic()
  39. deadline = start_time + timeout
  40. while not interpreters.is_running(interp):
  41. if time.monotonic() > deadline:
  42. raise RuntimeError('interp is not running')
  43. time.sleep(0.010)
  44. @contextlib.contextmanager
  45. def _running(interp):
  46. r, w = os.pipe()
  47. def run():
  48. interpreters.run_string(interp, dedent(f"""
  49. # wait for "signal"
  50. with open({r}, encoding="utf-8") as rpipe:
  51. rpipe.read()
  52. """))
  53. t = threading.Thread(target=run)
  54. t.start()
  55. _wait_for_interp_to_run(interp)
  56. yield
  57. with open(w, 'w', encoding="utf-8") as spipe:
  58. spipe.write('done')
  59. t.join()
  60. #@contextmanager
  61. #def run_threaded(id, source, **shared):
  62. # def run():
  63. # run_interp(id, source, **shared)
  64. # t = threading.Thread(target=run)
  65. # t.start()
  66. # yield
  67. # t.join()
  68. def run_interp(id, source, **shared):
  69. _run_interp(id, source, shared)
  70. def _run_interp(id, source, shared, _mainns={}):
  71. source = dedent(source)
  72. main = interpreters.get_main()
  73. if main == id:
  74. if interpreters.get_current() != main:
  75. raise RuntimeError
  76. # XXX Run a func?
  77. exec(source, _mainns)
  78. else:
  79. interpreters.run_string(id, source, shared)
  80. class Interpreter(namedtuple('Interpreter', 'name id')):
  81. @classmethod
  82. def from_raw(cls, raw):
  83. if isinstance(raw, cls):
  84. return raw
  85. elif isinstance(raw, str):
  86. return cls(raw)
  87. else:
  88. raise NotImplementedError
  89. def __new__(cls, name=None, id=None):
  90. main = interpreters.get_main()
  91. if id == main:
  92. if not name:
  93. name = 'main'
  94. elif name != 'main':
  95. raise ValueError(
  96. 'name mismatch (expected "main", got "{}")'.format(name))
  97. id = main
  98. elif id is not None:
  99. if not name:
  100. name = 'interp'
  101. elif name == 'main':
  102. raise ValueError('name mismatch (unexpected "main")')
  103. if not isinstance(id, interpreters.InterpreterID):
  104. id = interpreters.InterpreterID(id)
  105. elif not name or name == 'main':
  106. name = 'main'
  107. id = main
  108. else:
  109. id = interpreters.create()
  110. self = super().__new__(cls, name, id)
  111. return self
  112. # XXX expect_channel_closed() is unnecessary once we improve exc propagation.
  113. @contextlib.contextmanager
  114. def expect_channel_closed():
  115. try:
  116. yield
  117. except interpreters.ChannelClosedError:
  118. pass
  119. else:
  120. assert False, 'channel not closed'
  121. class ChannelAction(namedtuple('ChannelAction', 'action end interp')):
  122. def __new__(cls, action, end=None, interp=None):
  123. if not end:
  124. end = 'both'
  125. if not interp:
  126. interp = 'main'
  127. self = super().__new__(cls, action, end, interp)
  128. return self
  129. def __init__(self, *args, **kwargs):
  130. if self.action == 'use':
  131. if self.end not in ('same', 'opposite', 'send', 'recv'):
  132. raise ValueError(self.end)
  133. elif self.action in ('close', 'force-close'):
  134. if self.end not in ('both', 'same', 'opposite', 'send', 'recv'):
  135. raise ValueError(self.end)
  136. else:
  137. raise ValueError(self.action)
  138. if self.interp not in ('main', 'same', 'other', 'extra'):
  139. raise ValueError(self.interp)
  140. def resolve_end(self, end):
  141. if self.end == 'same':
  142. return end
  143. elif self.end == 'opposite':
  144. return 'recv' if end == 'send' else 'send'
  145. else:
  146. return self.end
  147. def resolve_interp(self, interp, other, extra):
  148. if self.interp == 'same':
  149. return interp
  150. elif self.interp == 'other':
  151. if other is None:
  152. raise RuntimeError
  153. return other
  154. elif self.interp == 'extra':
  155. if extra is None:
  156. raise RuntimeError
  157. return extra
  158. elif self.interp == 'main':
  159. if interp.name == 'main':
  160. return interp
  161. elif other and other.name == 'main':
  162. return other
  163. else:
  164. raise RuntimeError
  165. # Per __init__(), there aren't any others.
  166. class ChannelState(namedtuple('ChannelState', 'pending closed')):
  167. def __new__(cls, pending=0, *, closed=False):
  168. self = super().__new__(cls, pending, closed)
  169. return self
  170. def incr(self):
  171. return type(self)(self.pending + 1, closed=self.closed)
  172. def decr(self):
  173. return type(self)(self.pending - 1, closed=self.closed)
  174. def close(self, *, force=True):
  175. if self.closed:
  176. if not force or self.pending == 0:
  177. return self
  178. return type(self)(0 if force else self.pending, closed=True)
  179. def run_action(cid, action, end, state, *, hideclosed=True):
  180. if state.closed:
  181. if action == 'use' and end == 'recv' and state.pending:
  182. expectfail = False
  183. else:
  184. expectfail = True
  185. else:
  186. expectfail = False
  187. try:
  188. result = _run_action(cid, action, end, state)
  189. except interpreters.ChannelClosedError:
  190. if not hideclosed and not expectfail:
  191. raise
  192. result = state.close()
  193. else:
  194. if expectfail:
  195. raise ... # XXX
  196. return result
  197. def _run_action(cid, action, end, state):
  198. if action == 'use':
  199. if end == 'send':
  200. interpreters.channel_send(cid, b'spam')
  201. return state.incr()
  202. elif end == 'recv':
  203. if not state.pending:
  204. try:
  205. interpreters.channel_recv(cid)
  206. except interpreters.ChannelEmptyError:
  207. return state
  208. else:
  209. raise Exception('expected ChannelEmptyError')
  210. else:
  211. interpreters.channel_recv(cid)
  212. return state.decr()
  213. else:
  214. raise ValueError(end)
  215. elif action == 'close':
  216. kwargs = {}
  217. if end in ('recv', 'send'):
  218. kwargs[end] = True
  219. interpreters.channel_close(cid, **kwargs)
  220. return state.close()
  221. elif action == 'force-close':
  222. kwargs = {
  223. 'force': True,
  224. }
  225. if end in ('recv', 'send'):
  226. kwargs[end] = True
  227. interpreters.channel_close(cid, **kwargs)
  228. return state.close(force=True)
  229. else:
  230. raise ValueError(action)
  231. def clean_up_interpreters():
  232. for id in interpreters.list_all():
  233. if id == 0: # main
  234. continue
  235. try:
  236. interpreters.destroy(id)
  237. except RuntimeError:
  238. pass # already destroyed
  239. def clean_up_channels():
  240. for cid in interpreters.channel_list_all():
  241. try:
  242. interpreters.channel_destroy(cid)
  243. except interpreters.ChannelNotFoundError:
  244. pass # already destroyed
  245. class TestBase(unittest.TestCase):
  246. def tearDown(self):
  247. clean_up_interpreters()
  248. clean_up_channels()
  249. ##################################
  250. # misc. tests
  251. class IsShareableTests(unittest.TestCase):
  252. def test_default_shareables(self):
  253. shareables = [
  254. # singletons
  255. None,
  256. # builtin objects
  257. b'spam',
  258. 'spam',
  259. 10,
  260. -10,
  261. ]
  262. for obj in shareables:
  263. with self.subTest(obj):
  264. self.assertTrue(
  265. interpreters.is_shareable(obj))
  266. def test_not_shareable(self):
  267. class Cheese:
  268. def __init__(self, name):
  269. self.name = name
  270. def __str__(self):
  271. return self.name
  272. class SubBytes(bytes):
  273. """A subclass of a shareable type."""
  274. not_shareables = [
  275. # singletons
  276. True,
  277. False,
  278. NotImplemented,
  279. ...,
  280. # builtin types and objects
  281. type,
  282. object,
  283. object(),
  284. Exception(),
  285. 100.0,
  286. # user-defined types and objects
  287. Cheese,
  288. Cheese('Wensleydale'),
  289. SubBytes(b'spam'),
  290. ]
  291. for obj in not_shareables:
  292. with self.subTest(repr(obj)):
  293. self.assertFalse(
  294. interpreters.is_shareable(obj))
  295. class ShareableTypeTests(unittest.TestCase):
  296. def setUp(self):
  297. super().setUp()
  298. self.cid = interpreters.channel_create()
  299. def tearDown(self):
  300. interpreters.channel_destroy(self.cid)
  301. super().tearDown()
  302. def _assert_values(self, values):
  303. for obj in values:
  304. with self.subTest(obj):
  305. interpreters.channel_send(self.cid, obj)
  306. got = interpreters.channel_recv(self.cid)
  307. self.assertEqual(got, obj)
  308. self.assertIs(type(got), type(obj))
  309. # XXX Check the following in the channel tests?
  310. #self.assertIsNot(got, obj)
  311. def test_singletons(self):
  312. for obj in [None]:
  313. with self.subTest(obj):
  314. interpreters.channel_send(self.cid, obj)
  315. got = interpreters.channel_recv(self.cid)
  316. # XXX What about between interpreters?
  317. self.assertIs(got, obj)
  318. def test_types(self):
  319. self._assert_values([
  320. b'spam',
  321. 9999,
  322. self.cid,
  323. ])
  324. def test_bytes(self):
  325. self._assert_values(i.to_bytes(2, 'little', signed=True)
  326. for i in range(-1, 258))
  327. def test_strs(self):
  328. self._assert_values(['hello world', '你好世界', ''])
  329. def test_int(self):
  330. self._assert_values(itertools.chain(range(-1, 258),
  331. [sys.maxsize, -sys.maxsize - 1]))
  332. def test_non_shareable_int(self):
  333. ints = [
  334. sys.maxsize + 1,
  335. -sys.maxsize - 2,
  336. 2**1000,
  337. ]
  338. for i in ints:
  339. with self.subTest(i):
  340. with self.assertRaises(OverflowError):
  341. interpreters.channel_send(self.cid, i)
  342. ##################################
  343. # interpreter tests
  344. class ListAllTests(TestBase):
  345. def test_initial(self):
  346. main = interpreters.get_main()
  347. ids = interpreters.list_all()
  348. self.assertEqual(ids, [main])
  349. def test_after_creating(self):
  350. main = interpreters.get_main()
  351. first = interpreters.create()
  352. second = interpreters.create()
  353. ids = interpreters.list_all()
  354. self.assertEqual(ids, [main, first, second])
  355. def test_after_destroying(self):
  356. main = interpreters.get_main()
  357. first = interpreters.create()
  358. second = interpreters.create()
  359. interpreters.destroy(first)
  360. ids = interpreters.list_all()
  361. self.assertEqual(ids, [main, second])
  362. class GetCurrentTests(TestBase):
  363. def test_main(self):
  364. main = interpreters.get_main()
  365. cur = interpreters.get_current()
  366. self.assertEqual(cur, main)
  367. self.assertIsInstance(cur, interpreters.InterpreterID)
  368. def test_subinterpreter(self):
  369. main = interpreters.get_main()
  370. interp = interpreters.create()
  371. out = _run_output(interp, dedent("""
  372. import _xxsubinterpreters as _interpreters
  373. cur = _interpreters.get_current()
  374. print(cur)
  375. assert isinstance(cur, _interpreters.InterpreterID)
  376. """))
  377. cur = int(out.strip())
  378. _, expected = interpreters.list_all()
  379. self.assertEqual(cur, expected)
  380. self.assertNotEqual(cur, main)
  381. class GetMainTests(TestBase):
  382. def test_from_main(self):
  383. [expected] = interpreters.list_all()
  384. main = interpreters.get_main()
  385. self.assertEqual(main, expected)
  386. self.assertIsInstance(main, interpreters.InterpreterID)
  387. def test_from_subinterpreter(self):
  388. [expected] = interpreters.list_all()
  389. interp = interpreters.create()
  390. out = _run_output(interp, dedent("""
  391. import _xxsubinterpreters as _interpreters
  392. main = _interpreters.get_main()
  393. print(main)
  394. assert isinstance(main, _interpreters.InterpreterID)
  395. """))
  396. main = int(out.strip())
  397. self.assertEqual(main, expected)
  398. class IsRunningTests(TestBase):
  399. def test_main(self):
  400. main = interpreters.get_main()
  401. self.assertTrue(interpreters.is_running(main))
  402. @unittest.skip('Fails on FreeBSD')
  403. def test_subinterpreter(self):
  404. interp = interpreters.create()
  405. self.assertFalse(interpreters.is_running(interp))
  406. with _running(interp):
  407. self.assertTrue(interpreters.is_running(interp))
  408. self.assertFalse(interpreters.is_running(interp))
  409. def test_from_subinterpreter(self):
  410. interp = interpreters.create()
  411. out = _run_output(interp, dedent(f"""
  412. import _xxsubinterpreters as _interpreters
  413. if _interpreters.is_running({interp}):
  414. print(True)
  415. else:
  416. print(False)
  417. """))
  418. self.assertEqual(out.strip(), 'True')
  419. def test_already_destroyed(self):
  420. interp = interpreters.create()
  421. interpreters.destroy(interp)
  422. with self.assertRaises(RuntimeError):
  423. interpreters.is_running(interp)
  424. def test_does_not_exist(self):
  425. with self.assertRaises(RuntimeError):
  426. interpreters.is_running(1_000_000)
  427. def test_bad_id(self):
  428. with self.assertRaises(ValueError):
  429. interpreters.is_running(-1)
  430. class InterpreterIDTests(TestBase):
  431. def test_with_int(self):
  432. id = interpreters.InterpreterID(10, force=True)
  433. self.assertEqual(int(id), 10)
  434. def test_coerce_id(self):
  435. class Int(str):
  436. def __index__(self):
  437. return 10
  438. id = interpreters.InterpreterID(Int(), force=True)
  439. self.assertEqual(int(id), 10)
  440. def test_bad_id(self):
  441. self.assertRaises(TypeError, interpreters.InterpreterID, object())
  442. self.assertRaises(TypeError, interpreters.InterpreterID, 10.0)
  443. self.assertRaises(TypeError, interpreters.InterpreterID, '10')
  444. self.assertRaises(TypeError, interpreters.InterpreterID, b'10')
  445. self.assertRaises(ValueError, interpreters.InterpreterID, -1)
  446. self.assertRaises(OverflowError, interpreters.InterpreterID, 2**64)
  447. def test_does_not_exist(self):
  448. id = interpreters.channel_create()
  449. with self.assertRaises(RuntimeError):
  450. interpreters.InterpreterID(int(id) + 1) # unforced
  451. def test_str(self):
  452. id = interpreters.InterpreterID(10, force=True)
  453. self.assertEqual(str(id), '10')
  454. def test_repr(self):
  455. id = interpreters.InterpreterID(10, force=True)
  456. self.assertEqual(repr(id), 'InterpreterID(10)')
  457. def test_equality(self):
  458. id1 = interpreters.create()
  459. id2 = interpreters.InterpreterID(int(id1))
  460. id3 = interpreters.create()
  461. self.assertTrue(id1 == id1)
  462. self.assertTrue(id1 == id2)
  463. self.assertTrue(id1 == int(id1))
  464. self.assertTrue(int(id1) == id1)
  465. self.assertTrue(id1 == float(int(id1)))
  466. self.assertTrue(float(int(id1)) == id1)
  467. self.assertFalse(id1 == float(int(id1)) + 0.1)
  468. self.assertFalse(id1 == str(int(id1)))
  469. self.assertFalse(id1 == 2**1000)
  470. self.assertFalse(id1 == float('inf'))
  471. self.assertFalse(id1 == 'spam')
  472. self.assertFalse(id1 == id3)
  473. self.assertFalse(id1 != id1)
  474. self.assertFalse(id1 != id2)
  475. self.assertTrue(id1 != id3)
  476. class CreateTests(TestBase):
  477. def test_in_main(self):
  478. id = interpreters.create()
  479. self.assertIsInstance(id, interpreters.InterpreterID)
  480. self.assertIn(id, interpreters.list_all())
  481. @unittest.skip('enable this test when working on pystate.c')
  482. def test_unique_id(self):
  483. seen = set()
  484. for _ in range(100):
  485. id = interpreters.create()
  486. interpreters.destroy(id)
  487. seen.add(id)
  488. self.assertEqual(len(seen), 100)
  489. def test_in_thread(self):
  490. lock = threading.Lock()
  491. id = None
  492. def f():
  493. nonlocal id
  494. id = interpreters.create()
  495. lock.acquire()
  496. lock.release()
  497. t = threading.Thread(target=f)
  498. with lock:
  499. t.start()
  500. t.join()
  501. self.assertIn(id, interpreters.list_all())
  502. def test_in_subinterpreter(self):
  503. main, = interpreters.list_all()
  504. id1 = interpreters.create()
  505. out = _run_output(id1, dedent("""
  506. import _xxsubinterpreters as _interpreters
  507. id = _interpreters.create()
  508. print(id)
  509. assert isinstance(id, _interpreters.InterpreterID)
  510. """))
  511. id2 = int(out.strip())
  512. self.assertEqual(set(interpreters.list_all()), {main, id1, id2})
  513. def test_in_threaded_subinterpreter(self):
  514. main, = interpreters.list_all()
  515. id1 = interpreters.create()
  516. id2 = None
  517. def f():
  518. nonlocal id2
  519. out = _run_output(id1, dedent("""
  520. import _xxsubinterpreters as _interpreters
  521. id = _interpreters.create()
  522. print(id)
  523. """))
  524. id2 = int(out.strip())
  525. t = threading.Thread(target=f)
  526. t.start()
  527. t.join()
  528. self.assertEqual(set(interpreters.list_all()), {main, id1, id2})
  529. def test_after_destroy_all(self):
  530. before = set(interpreters.list_all())
  531. # Create 3 subinterpreters.
  532. ids = []
  533. for _ in range(3):
  534. id = interpreters.create()
  535. ids.append(id)
  536. # Now destroy them.
  537. for id in ids:
  538. interpreters.destroy(id)
  539. # Finally, create another.
  540. id = interpreters.create()
  541. self.assertEqual(set(interpreters.list_all()), before | {id})
  542. def test_after_destroy_some(self):
  543. before = set(interpreters.list_all())
  544. # Create 3 subinterpreters.
  545. id1 = interpreters.create()
  546. id2 = interpreters.create()
  547. id3 = interpreters.create()
  548. # Now destroy 2 of them.
  549. interpreters.destroy(id1)
  550. interpreters.destroy(id3)
  551. # Finally, create another.
  552. id = interpreters.create()
  553. self.assertEqual(set(interpreters.list_all()), before | {id, id2})
  554. class DestroyTests(TestBase):
  555. def test_one(self):
  556. id1 = interpreters.create()
  557. id2 = interpreters.create()
  558. id3 = interpreters.create()
  559. self.assertIn(id2, interpreters.list_all())
  560. interpreters.destroy(id2)
  561. self.assertNotIn(id2, interpreters.list_all())
  562. self.assertIn(id1, interpreters.list_all())
  563. self.assertIn(id3, interpreters.list_all())
  564. def test_all(self):
  565. before = set(interpreters.list_all())
  566. ids = set()
  567. for _ in range(3):
  568. id = interpreters.create()
  569. ids.add(id)
  570. self.assertEqual(set(interpreters.list_all()), before | ids)
  571. for id in ids:
  572. interpreters.destroy(id)
  573. self.assertEqual(set(interpreters.list_all()), before)
  574. def test_main(self):
  575. main, = interpreters.list_all()
  576. with self.assertRaises(RuntimeError):
  577. interpreters.destroy(main)
  578. def f():
  579. with self.assertRaises(RuntimeError):
  580. interpreters.destroy(main)
  581. t = threading.Thread(target=f)
  582. t.start()
  583. t.join()
  584. def test_already_destroyed(self):
  585. id = interpreters.create()
  586. interpreters.destroy(id)
  587. with self.assertRaises(RuntimeError):
  588. interpreters.destroy(id)
  589. def test_does_not_exist(self):
  590. with self.assertRaises(RuntimeError):
  591. interpreters.destroy(1_000_000)
  592. def test_bad_id(self):
  593. with self.assertRaises(ValueError):
  594. interpreters.destroy(-1)
  595. def test_from_current(self):
  596. main, = interpreters.list_all()
  597. id = interpreters.create()
  598. script = dedent(f"""
  599. import _xxsubinterpreters as _interpreters
  600. try:
  601. _interpreters.destroy({id})
  602. except RuntimeError:
  603. pass
  604. """)
  605. interpreters.run_string(id, script)
  606. self.assertEqual(set(interpreters.list_all()), {main, id})
  607. def test_from_sibling(self):
  608. main, = interpreters.list_all()
  609. id1 = interpreters.create()
  610. id2 = interpreters.create()
  611. script = dedent(f"""
  612. import _xxsubinterpreters as _interpreters
  613. _interpreters.destroy({id2})
  614. """)
  615. interpreters.run_string(id1, script)
  616. self.assertEqual(set(interpreters.list_all()), {main, id1})
  617. def test_from_other_thread(self):
  618. id = interpreters.create()
  619. def f():
  620. interpreters.destroy(id)
  621. t = threading.Thread(target=f)
  622. t.start()
  623. t.join()
  624. def test_still_running(self):
  625. main, = interpreters.list_all()
  626. interp = interpreters.create()
  627. with _running(interp):
  628. self.assertTrue(interpreters.is_running(interp),
  629. msg=f"Interp {interp} should be running before destruction.")
  630. with self.assertRaises(RuntimeError,
  631. msg=f"Should not be able to destroy interp {interp} while it's still running."):
  632. interpreters.destroy(interp)
  633. self.assertTrue(interpreters.is_running(interp))
  634. class RunStringTests(TestBase):
  635. def setUp(self):
  636. super().setUp()
  637. self.id = interpreters.create()
  638. def test_success(self):
  639. script, file = _captured_script('print("it worked!", end="")')
  640. with file:
  641. interpreters.run_string(self.id, script)
  642. out = file.read()
  643. self.assertEqual(out, 'it worked!')
  644. def test_in_thread(self):
  645. script, file = _captured_script('print("it worked!", end="")')
  646. with file:
  647. def f():
  648. interpreters.run_string(self.id, script)
  649. t = threading.Thread(target=f)
  650. t.start()
  651. t.join()
  652. out = file.read()
  653. self.assertEqual(out, 'it worked!')
  654. def test_create_thread(self):
  655. subinterp = interpreters.create(isolated=False)
  656. script, file = _captured_script("""
  657. import threading
  658. def f():
  659. print('it worked!', end='')
  660. t = threading.Thread(target=f)
  661. t.start()
  662. t.join()
  663. """)
  664. with file:
  665. interpreters.run_string(subinterp, script)
  666. out = file.read()
  667. self.assertEqual(out, 'it worked!')
  668. @support.requires_fork()
  669. def test_fork(self):
  670. import tempfile
  671. with tempfile.NamedTemporaryFile('w+', encoding="utf-8") as file:
  672. file.write('')
  673. file.flush()
  674. expected = 'spam spam spam spam spam'
  675. script = dedent(f"""
  676. import os
  677. try:
  678. os.fork()
  679. except RuntimeError:
  680. with open('{file.name}', 'w', encoding='utf-8') as out:
  681. out.write('{expected}')
  682. """)
  683. interpreters.run_string(self.id, script)
  684. file.seek(0)
  685. content = file.read()
  686. self.assertEqual(content, expected)
  687. def test_already_running(self):
  688. with _running(self.id):
  689. with self.assertRaises(RuntimeError):
  690. interpreters.run_string(self.id, 'print("spam")')
  691. def test_does_not_exist(self):
  692. id = 0
  693. while id in interpreters.list_all():
  694. id += 1
  695. with self.assertRaises(RuntimeError):
  696. interpreters.run_string(id, 'print("spam")')
  697. def test_error_id(self):
  698. with self.assertRaises(ValueError):
  699. interpreters.run_string(-1, 'print("spam")')
  700. def test_bad_id(self):
  701. with self.assertRaises(TypeError):
  702. interpreters.run_string('spam', 'print("spam")')
  703. def test_bad_script(self):
  704. with self.assertRaises(TypeError):
  705. interpreters.run_string(self.id, 10)
  706. def test_bytes_for_script(self):
  707. with self.assertRaises(TypeError):
  708. interpreters.run_string(self.id, b'print("spam")')
  709. @contextlib.contextmanager
  710. def assert_run_failed(self, exctype, msg=None):
  711. with self.assertRaises(interpreters.RunFailedError) as caught:
  712. yield
  713. if msg is None:
  714. self.assertEqual(str(caught.exception).split(':')[0],
  715. str(exctype))
  716. else:
  717. self.assertEqual(str(caught.exception),
  718. "{}: {}".format(exctype, msg))
  719. def test_invalid_syntax(self):
  720. with self.assert_run_failed(SyntaxError):
  721. # missing close paren
  722. interpreters.run_string(self.id, 'print("spam"')
  723. def test_failure(self):
  724. with self.assert_run_failed(Exception, 'spam'):
  725. interpreters.run_string(self.id, 'raise Exception("spam")')
  726. def test_SystemExit(self):
  727. with self.assert_run_failed(SystemExit, '42'):
  728. interpreters.run_string(self.id, 'raise SystemExit(42)')
  729. def test_sys_exit(self):
  730. with self.assert_run_failed(SystemExit):
  731. interpreters.run_string(self.id, dedent("""
  732. import sys
  733. sys.exit()
  734. """))
  735. with self.assert_run_failed(SystemExit, '42'):
  736. interpreters.run_string(self.id, dedent("""
  737. import sys
  738. sys.exit(42)
  739. """))
  740. def test_with_shared(self):
  741. r, w = os.pipe()
  742. shared = {
  743. 'spam': b'ham',
  744. 'eggs': b'-1',
  745. 'cheddar': None,
  746. }
  747. script = dedent(f"""
  748. eggs = int(eggs)
  749. spam = 42
  750. result = spam + eggs
  751. ns = dict(vars())
  752. del ns['__builtins__']
  753. import pickle
  754. with open({w}, 'wb') as chan:
  755. pickle.dump(ns, chan)
  756. """)
  757. interpreters.run_string(self.id, script, shared)
  758. with open(r, 'rb') as chan:
  759. ns = pickle.load(chan)
  760. self.assertEqual(ns['spam'], 42)
  761. self.assertEqual(ns['eggs'], -1)
  762. self.assertEqual(ns['result'], 41)
  763. self.assertIsNone(ns['cheddar'])
  764. def test_shared_overwrites(self):
  765. interpreters.run_string(self.id, dedent("""
  766. spam = 'eggs'
  767. ns1 = dict(vars())
  768. del ns1['__builtins__']
  769. """))
  770. shared = {'spam': b'ham'}
  771. script = dedent(f"""
  772. ns2 = dict(vars())
  773. del ns2['__builtins__']
  774. """)
  775. interpreters.run_string(self.id, script, shared)
  776. r, w = os.pipe()
  777. script = dedent(f"""
  778. ns = dict(vars())
  779. del ns['__builtins__']
  780. import pickle
  781. with open({w}, 'wb') as chan:
  782. pickle.dump(ns, chan)
  783. """)
  784. interpreters.run_string(self.id, script)
  785. with open(r, 'rb') as chan:
  786. ns = pickle.load(chan)
  787. self.assertEqual(ns['ns1']['spam'], 'eggs')
  788. self.assertEqual(ns['ns2']['spam'], b'ham')
  789. self.assertEqual(ns['spam'], b'ham')
  790. def test_shared_overwrites_default_vars(self):
  791. r, w = os.pipe()
  792. shared = {'__name__': b'not __main__'}
  793. script = dedent(f"""
  794. spam = 42
  795. ns = dict(vars())
  796. del ns['__builtins__']
  797. import pickle
  798. with open({w}, 'wb') as chan:
  799. pickle.dump(ns, chan)
  800. """)
  801. interpreters.run_string(self.id, script, shared)
  802. with open(r, 'rb') as chan:
  803. ns = pickle.load(chan)
  804. self.assertEqual(ns['__name__'], b'not __main__')
  805. def test_main_reused(self):
  806. r, w = os.pipe()
  807. interpreters.run_string(self.id, dedent(f"""
  808. spam = True
  809. ns = dict(vars())
  810. del ns['__builtins__']
  811. import pickle
  812. with open({w}, 'wb') as chan:
  813. pickle.dump(ns, chan)
  814. del ns, pickle, chan
  815. """))
  816. with open(r, 'rb') as chan:
  817. ns1 = pickle.load(chan)
  818. r, w = os.pipe()
  819. interpreters.run_string(self.id, dedent(f"""
  820. eggs = False
  821. ns = dict(vars())
  822. del ns['__builtins__']
  823. import pickle
  824. with open({w}, 'wb') as chan:
  825. pickle.dump(ns, chan)
  826. """))
  827. with open(r, 'rb') as chan:
  828. ns2 = pickle.load(chan)
  829. self.assertIn('spam', ns1)
  830. self.assertNotIn('eggs', ns1)
  831. self.assertIn('eggs', ns2)
  832. self.assertIn('spam', ns2)
  833. def test_execution_namespace_is_main(self):
  834. r, w = os.pipe()
  835. script = dedent(f"""
  836. spam = 42
  837. ns = dict(vars())
  838. ns['__builtins__'] = str(ns['__builtins__'])
  839. import pickle
  840. with open({w}, 'wb') as chan:
  841. pickle.dump(ns, chan)
  842. """)
  843. interpreters.run_string(self.id, script)
  844. with open(r, 'rb') as chan:
  845. ns = pickle.load(chan)
  846. ns.pop('__builtins__')
  847. ns.pop('__loader__')
  848. self.assertEqual(ns, {
  849. '__name__': '__main__',
  850. '__annotations__': {},
  851. '__doc__': None,
  852. '__package__': None,
  853. '__spec__': None,
  854. 'spam': 42,
  855. })
  856. # XXX Fix this test!
  857. @unittest.skip('blocking forever')
  858. def test_still_running_at_exit(self):
  859. script = dedent(f"""
  860. from textwrap import dedent
  861. import threading
  862. import _xxsubinterpreters as _interpreters
  863. id = _interpreters.create()
  864. def f():
  865. _interpreters.run_string(id, dedent('''
  866. import time
  867. # Give plenty of time for the main interpreter to finish.
  868. time.sleep(1_000_000)
  869. '''))
  870. t = threading.Thread(target=f)
  871. t.start()
  872. """)
  873. with support.temp_dir() as dirname:
  874. filename = script_helper.make_script(dirname, 'interp', script)
  875. with script_helper.spawn_python(filename) as proc:
  876. retcode = proc.wait()
  877. self.assertEqual(retcode, 0)
  878. ##################################
  879. # channel tests
  880. class ChannelIDTests(TestBase):
  881. def test_default_kwargs(self):
  882. cid = interpreters._channel_id(10, force=True)
  883. self.assertEqual(int(cid), 10)
  884. self.assertEqual(cid.end, 'both')
  885. def test_with_kwargs(self):
  886. cid = interpreters._channel_id(10, send=True, force=True)
  887. self.assertEqual(cid.end, 'send')
  888. cid = interpreters._channel_id(10, send=True, recv=False, force=True)
  889. self.assertEqual(cid.end, 'send')
  890. cid = interpreters._channel_id(10, recv=True, force=True)
  891. self.assertEqual(cid.end, 'recv')
  892. cid = interpreters._channel_id(10, recv=True, send=False, force=True)
  893. self.assertEqual(cid.end, 'recv')
  894. cid = interpreters._channel_id(10, send=True, recv=True, force=True)
  895. self.assertEqual(cid.end, 'both')
  896. def test_coerce_id(self):
  897. class Int(str):
  898. def __index__(self):
  899. return 10
  900. cid = interpreters._channel_id(Int(), force=True)
  901. self.assertEqual(int(cid), 10)
  902. def test_bad_id(self):
  903. self.assertRaises(TypeError, interpreters._channel_id, object())
  904. self.assertRaises(TypeError, interpreters._channel_id, 10.0)
  905. self.assertRaises(TypeError, interpreters._channel_id, '10')
  906. self.assertRaises(TypeError, interpreters._channel_id, b'10')
  907. self.assertRaises(ValueError, interpreters._channel_id, -1)
  908. self.assertRaises(OverflowError, interpreters._channel_id, 2**64)
  909. def test_bad_kwargs(self):
  910. with self.assertRaises(ValueError):
  911. interpreters._channel_id(10, send=False, recv=False)
  912. def test_does_not_exist(self):
  913. cid = interpreters.channel_create()
  914. with self.assertRaises(interpreters.ChannelNotFoundError):
  915. interpreters._channel_id(int(cid) + 1) # unforced
  916. def test_str(self):
  917. cid = interpreters._channel_id(10, force=True)
  918. self.assertEqual(str(cid), '10')
  919. def test_repr(self):
  920. cid = interpreters._channel_id(10, force=True)
  921. self.assertEqual(repr(cid), 'ChannelID(10)')
  922. cid = interpreters._channel_id(10, send=True, force=True)
  923. self.assertEqual(repr(cid), 'ChannelID(10, send=True)')
  924. cid = interpreters._channel_id(10, recv=True, force=True)
  925. self.assertEqual(repr(cid), 'ChannelID(10, recv=True)')
  926. cid = interpreters._channel_id(10, send=True, recv=True, force=True)
  927. self.assertEqual(repr(cid), 'ChannelID(10)')
  928. def test_equality(self):
  929. cid1 = interpreters.channel_create()
  930. cid2 = interpreters._channel_id(int(cid1))
  931. cid3 = interpreters.channel_create()
  932. self.assertTrue(cid1 == cid1)
  933. self.assertTrue(cid1 == cid2)
  934. self.assertTrue(cid1 == int(cid1))
  935. self.assertTrue(int(cid1) == cid1)
  936. self.assertTrue(cid1 == float(int(cid1)))
  937. self.assertTrue(float(int(cid1)) == cid1)
  938. self.assertFalse(cid1 == float(int(cid1)) + 0.1)
  939. self.assertFalse(cid1 == str(int(cid1)))
  940. self.assertFalse(cid1 == 2**1000)
  941. self.assertFalse(cid1 == float('inf'))
  942. self.assertFalse(cid1 == 'spam')
  943. self.assertFalse(cid1 == cid3)
  944. self.assertFalse(cid1 != cid1)
  945. self.assertFalse(cid1 != cid2)
  946. self.assertTrue(cid1 != cid3)
  947. class ChannelTests(TestBase):
  948. def test_create_cid(self):
  949. cid = interpreters.channel_create()
  950. self.assertIsInstance(cid, interpreters.ChannelID)
  951. def test_sequential_ids(self):
  952. before = interpreters.channel_list_all()
  953. id1 = interpreters.channel_create()
  954. id2 = interpreters.channel_create()
  955. id3 = interpreters.channel_create()
  956. after = interpreters.channel_list_all()
  957. self.assertEqual(id2, int(id1) + 1)
  958. self.assertEqual(id3, int(id2) + 1)
  959. self.assertEqual(set(after) - set(before), {id1, id2, id3})
  960. def test_ids_global(self):
  961. id1 = interpreters.create()
  962. out = _run_output(id1, dedent("""
  963. import _xxsubinterpreters as _interpreters
  964. cid = _interpreters.channel_create()
  965. print(cid)
  966. """))
  967. cid1 = int(out.strip())
  968. id2 = interpreters.create()
  969. out = _run_output(id2, dedent("""
  970. import _xxsubinterpreters as _interpreters
  971. cid = _interpreters.channel_create()
  972. print(cid)
  973. """))
  974. cid2 = int(out.strip())
  975. self.assertEqual(cid2, int(cid1) + 1)
  976. def test_channel_list_interpreters_none(self):
  977. """Test listing interpreters for a channel with no associations."""
  978. # Test for channel with no associated interpreters.
  979. cid = interpreters.channel_create()
  980. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  981. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  982. self.assertEqual(send_interps, [])
  983. self.assertEqual(recv_interps, [])
  984. def test_channel_list_interpreters_basic(self):
  985. """Test basic listing channel interpreters."""
  986. interp0 = interpreters.get_main()
  987. cid = interpreters.channel_create()
  988. interpreters.channel_send(cid, "send")
  989. # Test for a channel that has one end associated to an interpreter.
  990. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  991. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  992. self.assertEqual(send_interps, [interp0])
  993. self.assertEqual(recv_interps, [])
  994. interp1 = interpreters.create()
  995. _run_output(interp1, dedent(f"""
  996. import _xxsubinterpreters as _interpreters
  997. obj = _interpreters.channel_recv({cid})
  998. """))
  999. # Test for channel that has both ends associated to an interpreter.
  1000. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  1001. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1002. self.assertEqual(send_interps, [interp0])
  1003. self.assertEqual(recv_interps, [interp1])
  1004. def test_channel_list_interpreters_multiple(self):
  1005. """Test listing interpreters for a channel with many associations."""
  1006. interp0 = interpreters.get_main()
  1007. interp1 = interpreters.create()
  1008. interp2 = interpreters.create()
  1009. interp3 = interpreters.create()
  1010. cid = interpreters.channel_create()
  1011. interpreters.channel_send(cid, "send")
  1012. _run_output(interp1, dedent(f"""
  1013. import _xxsubinterpreters as _interpreters
  1014. _interpreters.channel_send({cid}, "send")
  1015. """))
  1016. _run_output(interp2, dedent(f"""
  1017. import _xxsubinterpreters as _interpreters
  1018. obj = _interpreters.channel_recv({cid})
  1019. """))
  1020. _run_output(interp3, dedent(f"""
  1021. import _xxsubinterpreters as _interpreters
  1022. obj = _interpreters.channel_recv({cid})
  1023. """))
  1024. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  1025. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1026. self.assertEqual(set(send_interps), {interp0, interp1})
  1027. self.assertEqual(set(recv_interps), {interp2, interp3})
  1028. def test_channel_list_interpreters_destroyed(self):
  1029. """Test listing channel interpreters with a destroyed interpreter."""
  1030. interp0 = interpreters.get_main()
  1031. interp1 = interpreters.create()
  1032. cid = interpreters.channel_create()
  1033. interpreters.channel_send(cid, "send")
  1034. _run_output(interp1, dedent(f"""
  1035. import _xxsubinterpreters as _interpreters
  1036. obj = _interpreters.channel_recv({cid})
  1037. """))
  1038. # Should be one interpreter associated with each end.
  1039. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  1040. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1041. self.assertEqual(send_interps, [interp0])
  1042. self.assertEqual(recv_interps, [interp1])
  1043. interpreters.destroy(interp1)
  1044. # Destroyed interpreter should not be listed.
  1045. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  1046. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1047. self.assertEqual(send_interps, [interp0])
  1048. self.assertEqual(recv_interps, [])
  1049. def test_channel_list_interpreters_released(self):
  1050. """Test listing channel interpreters with a released channel."""
  1051. # Set up one channel with main interpreter on the send end and two
  1052. # subinterpreters on the receive end.
  1053. interp0 = interpreters.get_main()
  1054. interp1 = interpreters.create()
  1055. interp2 = interpreters.create()
  1056. cid = interpreters.channel_create()
  1057. interpreters.channel_send(cid, "data")
  1058. _run_output(interp1, dedent(f"""
  1059. import _xxsubinterpreters as _interpreters
  1060. obj = _interpreters.channel_recv({cid})
  1061. """))
  1062. interpreters.channel_send(cid, "data")
  1063. _run_output(interp2, dedent(f"""
  1064. import _xxsubinterpreters as _interpreters
  1065. obj = _interpreters.channel_recv({cid})
  1066. """))
  1067. # Check the setup.
  1068. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  1069. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1070. self.assertEqual(len(send_interps), 1)
  1071. self.assertEqual(len(recv_interps), 2)
  1072. # Release the main interpreter from the send end.
  1073. interpreters.channel_release(cid, send=True)
  1074. # Send end should have no associated interpreters.
  1075. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  1076. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1077. self.assertEqual(len(send_interps), 0)
  1078. self.assertEqual(len(recv_interps), 2)
  1079. # Release one of the subinterpreters from the receive end.
  1080. _run_output(interp2, dedent(f"""
  1081. import _xxsubinterpreters as _interpreters
  1082. _interpreters.channel_release({cid})
  1083. """))
  1084. # Receive end should have the released interpreter removed.
  1085. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  1086. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1087. self.assertEqual(len(send_interps), 0)
  1088. self.assertEqual(recv_interps, [interp1])
  1089. def test_channel_list_interpreters_closed(self):
  1090. """Test listing channel interpreters with a closed channel."""
  1091. interp0 = interpreters.get_main()
  1092. interp1 = interpreters.create()
  1093. cid = interpreters.channel_create()
  1094. # Put something in the channel so that it's not empty.
  1095. interpreters.channel_send(cid, "send")
  1096. # Check initial state.
  1097. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  1098. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1099. self.assertEqual(len(send_interps), 1)
  1100. self.assertEqual(len(recv_interps), 0)
  1101. # Force close the channel.
  1102. interpreters.channel_close(cid, force=True)
  1103. # Both ends should raise an error.
  1104. with self.assertRaises(interpreters.ChannelClosedError):
  1105. interpreters.channel_list_interpreters(cid, send=True)
  1106. with self.assertRaises(interpreters.ChannelClosedError):
  1107. interpreters.channel_list_interpreters(cid, send=False)
  1108. def test_channel_list_interpreters_closed_send_end(self):
  1109. """Test listing channel interpreters with a channel's send end closed."""
  1110. interp0 = interpreters.get_main()
  1111. interp1 = interpreters.create()
  1112. cid = interpreters.channel_create()
  1113. # Put something in the channel so that it's not empty.
  1114. interpreters.channel_send(cid, "send")
  1115. # Check initial state.
  1116. send_interps = interpreters.channel_list_interpreters(cid, send=True)
  1117. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1118. self.assertEqual(len(send_interps), 1)
  1119. self.assertEqual(len(recv_interps), 0)
  1120. # Close the send end of the channel.
  1121. interpreters.channel_close(cid, send=True)
  1122. # Send end should raise an error.
  1123. with self.assertRaises(interpreters.ChannelClosedError):
  1124. interpreters.channel_list_interpreters(cid, send=True)
  1125. # Receive end should not be closed (since channel is not empty).
  1126. recv_interps = interpreters.channel_list_interpreters(cid, send=False)
  1127. self.assertEqual(len(recv_interps), 0)
  1128. # Close the receive end of the channel from a subinterpreter.
  1129. _run_output(interp1, dedent(f"""
  1130. import _xxsubinterpreters as _interpreters
  1131. _interpreters.channel_close({cid}, force=True)
  1132. """))
  1133. # Both ends should raise an error.
  1134. with self.assertRaises(interpreters.ChannelClosedError):
  1135. interpreters.channel_list_interpreters(cid, send=True)
  1136. with self.assertRaises(interpreters.ChannelClosedError):
  1137. interpreters.channel_list_interpreters(cid, send=False)
  1138. ####################
  1139. def test_send_recv_main(self):
  1140. cid = interpreters.channel_create()
  1141. orig = b'spam'
  1142. interpreters.channel_send(cid, orig)
  1143. obj = interpreters.channel_recv(cid)
  1144. self.assertEqual(obj, orig)
  1145. self.assertIsNot(obj, orig)
  1146. def test_send_recv_same_interpreter(self):
  1147. id1 = interpreters.create()
  1148. out = _run_output(id1, dedent("""
  1149. import _xxsubinterpreters as _interpreters
  1150. cid = _interpreters.channel_create()
  1151. orig = b'spam'
  1152. _interpreters.channel_send(cid, orig)
  1153. obj = _interpreters.channel_recv(cid)
  1154. assert obj is not orig
  1155. assert obj == orig
  1156. """))
  1157. def test_send_recv_different_interpreters(self):
  1158. cid = interpreters.channel_create()
  1159. id1 = interpreters.create()
  1160. out = _run_output(id1, dedent(f"""
  1161. import _xxsubinterpreters as _interpreters
  1162. _interpreters.channel_send({cid}, b'spam')
  1163. """))
  1164. obj = interpreters.channel_recv(cid)
  1165. self.assertEqual(obj, b'spam')
  1166. def test_send_recv_different_threads(self):
  1167. cid = interpreters.channel_create()
  1168. def f():
  1169. while True:
  1170. try:
  1171. obj = interpreters.channel_recv(cid)
  1172. break
  1173. except interpreters.ChannelEmptyError:
  1174. time.sleep(0.1)
  1175. interpreters.channel_send(cid, obj)
  1176. t = threading.Thread(target=f)
  1177. t.start()
  1178. interpreters.channel_send(cid, b'spam')
  1179. t.join()
  1180. obj = interpreters.channel_recv(cid)
  1181. self.assertEqual(obj, b'spam')
  1182. def test_send_recv_different_interpreters_and_threads(self):
  1183. cid = interpreters.channel_create()
  1184. id1 = interpreters.create()
  1185. out = None
  1186. def f():
  1187. nonlocal out
  1188. out = _run_output(id1, dedent(f"""
  1189. import time
  1190. import _xxsubinterpreters as _interpreters
  1191. while True:
  1192. try:
  1193. obj = _interpreters.channel_recv({cid})
  1194. break
  1195. except _interpreters.ChannelEmptyError:
  1196. time.sleep(0.1)
  1197. assert(obj == b'spam')
  1198. _interpreters.channel_send({cid}, b'eggs')
  1199. """))
  1200. t = threading.Thread(target=f)
  1201. t.start()
  1202. interpreters.channel_send(cid, b'spam')
  1203. t.join()
  1204. obj = interpreters.channel_recv(cid)
  1205. self.assertEqual(obj, b'eggs')
  1206. def test_send_not_found(self):
  1207. with self.assertRaises(interpreters.ChannelNotFoundError):
  1208. interpreters.channel_send(10, b'spam')
  1209. def test_recv_not_found(self):
  1210. with self.assertRaises(interpreters.ChannelNotFoundError):
  1211. interpreters.channel_recv(10)
  1212. def test_recv_empty(self):
  1213. cid = interpreters.channel_create()
  1214. with self.assertRaises(interpreters.ChannelEmptyError):
  1215. interpreters.channel_recv(cid)
  1216. def test_recv_default(self):
  1217. default = object()
  1218. cid = interpreters.channel_create()
  1219. obj1 = interpreters.channel_recv(cid, default)
  1220. interpreters.channel_send(cid, None)
  1221. interpreters.channel_send(cid, 1)
  1222. interpreters.channel_send(cid, b'spam')
  1223. interpreters.channel_send(cid, b'eggs')
  1224. obj2 = interpreters.channel_recv(cid, default)
  1225. obj3 = interpreters.channel_recv(cid, default)
  1226. obj4 = interpreters.channel_recv(cid)
  1227. obj5 = interpreters.channel_recv(cid, default)
  1228. obj6 = interpreters.channel_recv(cid, default)
  1229. self.assertIs(obj1, default)
  1230. self.assertIs(obj2, None)
  1231. self.assertEqual(obj3, 1)
  1232. self.assertEqual(obj4, b'spam')
  1233. self.assertEqual(obj5, b'eggs')
  1234. self.assertIs(obj6, default)
  1235. def test_run_string_arg_unresolved(self):
  1236. cid = interpreters.channel_create()
  1237. interp = interpreters.create()
  1238. out = _run_output(interp, dedent("""
  1239. import _xxsubinterpreters as _interpreters
  1240. print(cid.end)
  1241. _interpreters.channel_send(cid, b'spam')
  1242. """),
  1243. dict(cid=cid.send))
  1244. obj = interpreters.channel_recv(cid)
  1245. self.assertEqual(obj, b'spam')
  1246. self.assertEqual(out.strip(), 'send')
  1247. # XXX For now there is no high-level channel into which the
  1248. # sent channel ID can be converted...
  1249. # Note: this test caused crashes on some buildbots (bpo-33615).
  1250. @unittest.skip('disabled until high-level channels exist')
  1251. def test_run_string_arg_resolved(self):
  1252. cid = interpreters.channel_create()
  1253. cid = interpreters._channel_id(cid, _resolve=True)
  1254. interp = interpreters.create()
  1255. out = _run_output(interp, dedent("""
  1256. import _xxsubinterpreters as _interpreters
  1257. print(chan.id.end)
  1258. _interpreters.channel_send(chan.id, b'spam')
  1259. """),
  1260. dict(chan=cid.send))
  1261. obj = interpreters.channel_recv(cid)
  1262. self.assertEqual(obj, b'spam')
  1263. self.assertEqual(out.strip(), 'send')
  1264. # close
  1265. def test_close_single_user(self):
  1266. cid = interpreters.channel_create()
  1267. interpreters.channel_send(cid, b'spam')
  1268. interpreters.channel_recv(cid)
  1269. interpreters.channel_close(cid)
  1270. with self.assertRaises(interpreters.ChannelClosedError):
  1271. interpreters.channel_send(cid, b'eggs')
  1272. with self.assertRaises(interpreters.ChannelClosedError):
  1273. interpreters.channel_recv(cid)
  1274. def test_close_multiple_users(self):
  1275. cid = interpreters.channel_create()
  1276. id1 = interpreters.create()
  1277. id2 = interpreters.create()
  1278. interpreters.run_string(id1, dedent(f"""
  1279. import _xxsubinterpreters as _interpreters
  1280. _interpreters.channel_send({cid}, b'spam')
  1281. """))
  1282. interpreters.run_string(id2, dedent(f"""
  1283. import _xxsubinterpreters as _interpreters
  1284. _interpreters.channel_recv({cid})
  1285. """))
  1286. interpreters.channel_close(cid)
  1287. with self.assertRaises(interpreters.RunFailedError) as cm:
  1288. interpreters.run_string(id1, dedent(f"""
  1289. _interpreters.channel_send({cid}, b'spam')
  1290. """))
  1291. self.assertIn('ChannelClosedError', str(cm.exception))
  1292. with self.assertRaises(interpreters.RunFailedError) as cm:
  1293. interpreters.run_string(id2, dedent(f"""
  1294. _interpreters.channel_send({cid}, b'spam')
  1295. """))
  1296. self.assertIn('ChannelClosedError', str(cm.exception))
  1297. def test_close_multiple_times(self):
  1298. cid = interpreters.channel_create()
  1299. interpreters.channel_send(cid, b'spam')
  1300. interpreters.channel_recv(cid)
  1301. interpreters.channel_close(cid)
  1302. with self.assertRaises(interpreters.ChannelClosedError):
  1303. interpreters.channel_close(cid)
  1304. def test_close_empty(self):
  1305. tests = [
  1306. (False, False),
  1307. (True, False),
  1308. (False, True),
  1309. (True, True),
  1310. ]
  1311. for send, recv in tests:
  1312. with self.subTest((send, recv)):
  1313. cid = interpreters.channel_create()
  1314. interpreters.channel_send(cid, b'spam')
  1315. interpreters.channel_recv(cid)
  1316. interpreters.channel_close(cid, send=send, recv=recv)
  1317. with self.assertRaises(interpreters.ChannelClosedError):
  1318. interpreters.channel_send(cid, b'eggs')
  1319. with self.assertRaises(interpreters.ChannelClosedError):
  1320. interpreters.channel_recv(cid)
  1321. def test_close_defaults_with_unused_items(self):
  1322. cid = interpreters.channel_create()
  1323. interpreters.channel_send(cid, b'spam')
  1324. interpreters.channel_send(cid, b'ham')
  1325. with self.assertRaises(interpreters.ChannelNotEmptyError):
  1326. interpreters.channel_close(cid)
  1327. interpreters.channel_recv(cid)
  1328. interpreters.channel_send(cid, b'eggs')
  1329. def test_close_recv_with_unused_items_unforced(self):
  1330. cid = interpreters.channel_create()
  1331. interpreters.channel_send(cid, b'spam')
  1332. interpreters.channel_send(cid, b'ham')
  1333. with self.assertRaises(interpreters.ChannelNotEmptyError):
  1334. interpreters.channel_close(cid, recv=True)
  1335. interpreters.channel_recv(cid)
  1336. interpreters.channel_send(cid, b'eggs')
  1337. interpreters.channel_recv(cid)
  1338. interpreters.channel_recv(cid)
  1339. interpreters.channel_close(cid, recv=True)
  1340. def test_close_send_with_unused_items_unforced(self):
  1341. cid = interpreters.channel_create()
  1342. interpreters.channel_send(cid, b'spam')
  1343. interpreters.channel_send(cid, b'ham')
  1344. interpreters.channel_close(cid, send=True)
  1345. with self.assertRaises(interpreters.ChannelClosedError):
  1346. interpreters.channel_send(cid, b'eggs')
  1347. interpreters.channel_recv(cid)
  1348. interpreters.channel_recv(cid)
  1349. with self.assertRaises(interpreters.ChannelClosedError):
  1350. interpreters.channel_recv(cid)
  1351. def test_close_both_with_unused_items_unforced(self):
  1352. cid = interpreters.channel_create()
  1353. interpreters.channel_send(cid, b'spam')
  1354. interpreters.channel_send(cid, b'ham')
  1355. with self.assertRaises(interpreters.ChannelNotEmptyError):
  1356. interpreters.channel_close(cid, recv=True, send=True)
  1357. interpreters.channel_recv(cid)
  1358. interpreters.channel_send(cid, b'eggs')
  1359. interpreters.channel_recv(cid)
  1360. interpreters.channel_recv(cid)
  1361. interpreters.channel_close(cid, recv=True)
  1362. def test_close_recv_with_unused_items_forced(self):
  1363. cid = interpreters.channel_create()
  1364. interpreters.channel_send(cid, b'spam')
  1365. interpreters.channel_send(cid, b'ham')
  1366. interpreters.channel_close(cid, recv=True, force=True)
  1367. with self.assertRaises(interpreters.ChannelClosedError):
  1368. interpreters.channel_send(cid, b'eggs')
  1369. with self.assertRaises(interpreters.ChannelClosedError):
  1370. interpreters.channel_recv(cid)
  1371. def test_close_send_with_unused_items_forced(self):
  1372. cid = interpreters.channel_create()
  1373. interpreters.channel_send(cid, b'spam')
  1374. interpreters.channel_send(cid, b'ham')
  1375. interpreters.channel_close(cid, send=True, force=True)
  1376. with self.assertRaises(interpreters.ChannelClosedError):
  1377. interpreters.channel_send(cid, b'eggs')
  1378. with self.assertRaises(interpreters.ChannelClosedError):
  1379. interpreters.channel_recv(cid)
  1380. def test_close_both_with_unused_items_forced(self):
  1381. cid = interpreters.channel_create()
  1382. interpreters.channel_send(cid, b'spam')
  1383. interpreters.channel_send(cid, b'ham')
  1384. interpreters.channel_close(cid, send=True, recv=True, force=True)
  1385. with self.assertRaises(interpreters.ChannelClosedError):
  1386. interpreters.channel_send(cid, b'eggs')
  1387. with self.assertRaises(interpreters.ChannelClosedError):
  1388. interpreters.channel_recv(cid)
  1389. def test_close_never_used(self):
  1390. cid = interpreters.channel_create()
  1391. interpreters.channel_close(cid)
  1392. with self.assertRaises(interpreters.ChannelClosedError):
  1393. interpreters.channel_send(cid, b'spam')
  1394. with self.assertRaises(interpreters.ChannelClosedError):
  1395. interpreters.channel_recv(cid)
  1396. def test_close_by_unassociated_interp(self):
  1397. cid = interpreters.channel_create()
  1398. interpreters.channel_send(cid, b'spam')
  1399. interp = interpreters.create()
  1400. interpreters.run_string(interp, dedent(f"""
  1401. import _xxsubinterpreters as _interpreters
  1402. _interpreters.channel_close({cid}, force=True)
  1403. """))
  1404. with self.assertRaises(interpreters.ChannelClosedError):
  1405. interpreters.channel_recv(cid)
  1406. with self.assertRaises(interpreters.ChannelClosedError):
  1407. interpreters.channel_close(cid)
  1408. def test_close_used_multiple_times_by_single_user(self):
  1409. cid = interpreters.channel_create()
  1410. interpreters.channel_send(cid, b'spam')
  1411. interpreters.channel_send(cid, b'spam')
  1412. interpreters.channel_send(cid, b'spam')
  1413. interpreters.channel_recv(cid)
  1414. interpreters.channel_close(cid, force=True)
  1415. with self.assertRaises(interpreters.ChannelClosedError):
  1416. interpreters.channel_send(cid, b'eggs')
  1417. with self.assertRaises(interpreters.ChannelClosedError):
  1418. interpreters.channel_recv(cid)
  1419. def test_channel_list_interpreters_invalid_channel(self):
  1420. cid = interpreters.channel_create()
  1421. # Test for invalid channel ID.
  1422. with self.assertRaises(interpreters.ChannelNotFoundError):
  1423. interpreters.channel_list_interpreters(1000, send=True)
  1424. interpreters.channel_close(cid)
  1425. # Test for a channel that has been closed.
  1426. with self.assertRaises(interpreters.ChannelClosedError):
  1427. interpreters.channel_list_interpreters(cid, send=True)
  1428. def test_channel_list_interpreters_invalid_args(self):
  1429. # Tests for invalid arguments passed to the API.
  1430. cid = interpreters.channel_create()
  1431. with self.assertRaises(TypeError):
  1432. interpreters.channel_list_interpreters(cid)
  1433. class ChannelReleaseTests(TestBase):
  1434. # XXX Add more test coverage a la the tests for close().
  1435. """
  1436. - main / interp / other
  1437. - run in: current thread / new thread / other thread / different threads
  1438. - end / opposite
  1439. - force / no force
  1440. - used / not used (associated / not associated)
  1441. - empty / emptied / never emptied / partly emptied
  1442. - closed / not closed
  1443. - released / not released
  1444. - creator (interp) / other
  1445. - associated interpreter not running
  1446. - associated interpreter destroyed
  1447. """
  1448. """
  1449. use
  1450. pre-release
  1451. release
  1452. after
  1453. check
  1454. """
  1455. """
  1456. release in: main, interp1
  1457. creator: same, other (incl. interp2)
  1458. use: None,send,recv,send/recv in None,same,other(incl. interp2),same+other(incl. interp2),all
  1459. pre-release: None,send,recv,both in None,same,other(incl. interp2),same+other(incl. interp2),all
  1460. pre-release forced: None,send,recv,both in None,same,other(incl. interp2),same+other(incl. interp2),all
  1461. release: same
  1462. release forced: same
  1463. use after: None,send,recv,send/recv in None,same,other(incl. interp2),same+other(incl. interp2),all
  1464. release after: None,send,recv,send/recv in None,same,other(incl. interp2),same+other(incl. interp2),all
  1465. check released: send/recv for same/other(incl. interp2)
  1466. check closed: send/recv for same/other(incl. interp2)
  1467. """
  1468. def test_single_user(self):
  1469. cid = interpreters.channel_create()
  1470. interpreters.channel_send(cid, b'spam')
  1471. interpreters.channel_recv(cid)
  1472. interpreters.channel_release(cid, send=True, recv=True)
  1473. with self.assertRaises(interpreters.ChannelClosedError):
  1474. interpreters.channel_send(cid, b'eggs')
  1475. with self.assertRaises(interpreters.ChannelClosedError):
  1476. interpreters.channel_recv(cid)
  1477. def test_multiple_users(self):
  1478. cid = interpreters.channel_create()
  1479. id1 = interpreters.create()
  1480. id2 = interpreters.create()
  1481. interpreters.run_string(id1, dedent(f"""
  1482. import _xxsubinterpreters as _interpreters
  1483. _interpreters.channel_send({cid}, b'spam')
  1484. """))
  1485. out = _run_output(id2, dedent(f"""
  1486. import _xxsubinterpreters as _interpreters
  1487. obj = _interpreters.channel_recv({cid})
  1488. _interpreters.channel_release({cid})
  1489. print(repr(obj))
  1490. """))
  1491. interpreters.run_string(id1, dedent(f"""
  1492. _interpreters.channel_release({cid})
  1493. """))
  1494. self.assertEqual(out.strip(), "b'spam'")
  1495. def test_no_kwargs(self):
  1496. cid = interpreters.channel_create()
  1497. interpreters.channel_send(cid, b'spam')
  1498. interpreters.channel_recv(cid)
  1499. interpreters.channel_release(cid)
  1500. with self.assertRaises(interpreters.ChannelClosedError):
  1501. interpreters.channel_send(cid, b'eggs')
  1502. with self.assertRaises(interpreters.ChannelClosedError):
  1503. interpreters.channel_recv(cid)
  1504. def test_multiple_times(self):
  1505. cid = interpreters.channel_create()
  1506. interpreters.channel_send(cid, b'spam')
  1507. interpreters.channel_recv(cid)
  1508. interpreters.channel_release(cid, send=True, recv=True)
  1509. with self.assertRaises(interpreters.ChannelClosedError):
  1510. interpreters.channel_release(cid, send=True, recv=True)
  1511. def test_with_unused_items(self):
  1512. cid = interpreters.channel_create()
  1513. interpreters.channel_send(cid, b'spam')
  1514. interpreters.channel_send(cid, b'ham')
  1515. interpreters.channel_release(cid, send=True, recv=True)
  1516. with self.assertRaises(interpreters.ChannelClosedError):
  1517. interpreters.channel_recv(cid)
  1518. def test_never_used(self):
  1519. cid = interpreters.channel_create()
  1520. interpreters.channel_release(cid)
  1521. with self.assertRaises(interpreters.ChannelClosedError):
  1522. interpreters.channel_send(cid, b'spam')
  1523. with self.assertRaises(interpreters.ChannelClosedError):
  1524. interpreters.channel_recv(cid)
  1525. def test_by_unassociated_interp(self):
  1526. cid = interpreters.channel_create()
  1527. interpreters.channel_send(cid, b'spam')
  1528. interp = interpreters.create()
  1529. interpreters.run_string(interp, dedent(f"""
  1530. import _xxsubinterpreters as _interpreters
  1531. _interpreters.channel_release({cid})
  1532. """))
  1533. obj = interpreters.channel_recv(cid)
  1534. interpreters.channel_release(cid)
  1535. with self.assertRaises(interpreters.ChannelClosedError):
  1536. interpreters.channel_send(cid, b'eggs')
  1537. self.assertEqual(obj, b'spam')
  1538. def test_close_if_unassociated(self):
  1539. # XXX Something's not right with this test...
  1540. cid = interpreters.channel_create()
  1541. interp = interpreters.create()
  1542. interpreters.run_string(interp, dedent(f"""
  1543. import _xxsubinterpreters as _interpreters
  1544. obj = _interpreters.channel_send({cid}, b'spam')
  1545. _interpreters.channel_release({cid})
  1546. """))
  1547. with self.assertRaises(interpreters.ChannelClosedError):
  1548. interpreters.channel_recv(cid)
  1549. def test_partially(self):
  1550. # XXX Is partial close too weird/confusing?
  1551. cid = interpreters.channel_create()
  1552. interpreters.channel_send(cid, None)
  1553. interpreters.channel_recv(cid)
  1554. interpreters.channel_send(cid, b'spam')
  1555. interpreters.channel_release(cid, send=True)
  1556. obj = interpreters.channel_recv(cid)
  1557. self.assertEqual(obj, b'spam')
  1558. def test_used_multiple_times_by_single_user(self):
  1559. cid = interpreters.channel_create()
  1560. interpreters.channel_send(cid, b'spam')
  1561. interpreters.channel_send(cid, b'spam')
  1562. interpreters.channel_send(cid, b'spam')
  1563. interpreters.channel_recv(cid)
  1564. interpreters.channel_release(cid, send=True, recv=True)
  1565. with self.assertRaises(interpreters.ChannelClosedError):
  1566. interpreters.channel_send(cid, b'eggs')
  1567. with self.assertRaises(interpreters.ChannelClosedError):
  1568. interpreters.channel_recv(cid)
  1569. class ChannelCloseFixture(namedtuple('ChannelCloseFixture',
  1570. 'end interp other extra creator')):
  1571. # Set this to True to avoid creating interpreters, e.g. when
  1572. # scanning through test permutations without running them.
  1573. QUICK = False
  1574. def __new__(cls, end, interp, other, extra, creator):
  1575. assert end in ('send', 'recv')
  1576. if cls.QUICK:
  1577. known = {}
  1578. else:
  1579. interp = Interpreter.from_raw(interp)
  1580. other = Interpreter.from_raw(other)
  1581. extra = Interpreter.from_raw(extra)
  1582. known = {
  1583. interp.name: interp,
  1584. other.name: other,
  1585. extra.name: extra,
  1586. }
  1587. if not creator:
  1588. creator = 'same'
  1589. self = super().__new__(cls, end, interp, other, extra, creator)
  1590. self._prepped = set()
  1591. self._state = ChannelState()
  1592. self._known = known
  1593. return self
  1594. @property
  1595. def state(self):
  1596. return self._state
  1597. @property
  1598. def cid(self):
  1599. try:
  1600. return self._cid
  1601. except AttributeError:
  1602. creator = self._get_interpreter(self.creator)
  1603. self._cid = self._new_channel(creator)
  1604. return self._cid
  1605. def get_interpreter(self, interp):
  1606. interp = self._get_interpreter(interp)
  1607. self._prep_interpreter(interp)
  1608. return interp
  1609. def expect_closed_error(self, end=None):
  1610. if end is None:
  1611. end = self.end
  1612. if end == 'recv' and self.state.closed == 'send':
  1613. return False
  1614. return bool(self.state.closed)
  1615. def prep_interpreter(self, interp):
  1616. self._prep_interpreter(interp)
  1617. def record_action(self, action, result):
  1618. self._state = result
  1619. def clean_up(self):
  1620. clean_up_interpreters()
  1621. clean_up_channels()
  1622. # internal methods
  1623. def _new_channel(self, creator):
  1624. if creator.name == 'main':
  1625. return interpreters.channel_create()
  1626. else:
  1627. ch = interpreters.channel_create()
  1628. run_interp(creator.id, f"""
  1629. import _xxsubinterpreters
  1630. cid = _xxsubinterpreters.channel_create()
  1631. # We purposefully send back an int to avoid tying the
  1632. # channel to the other interpreter.
  1633. _xxsubinterpreters.channel_send({ch}, int(cid))
  1634. del _xxsubinterpreters
  1635. """)
  1636. self._cid = interpreters.channel_recv(ch)
  1637. return self._cid
  1638. def _get_interpreter(self, interp):
  1639. if interp in ('same', 'interp'):
  1640. return self.interp
  1641. elif interp == 'other':
  1642. return self.other
  1643. elif interp == 'extra':
  1644. return self.extra
  1645. else:
  1646. name = interp
  1647. try:
  1648. interp = self._known[name]
  1649. except KeyError:
  1650. interp = self._known[name] = Interpreter(name)
  1651. return interp
  1652. def _prep_interpreter(self, interp):
  1653. if interp.id in self._prepped:
  1654. return
  1655. self._prepped.add(interp.id)
  1656. if interp.name == 'main':
  1657. return
  1658. run_interp(interp.id, f"""
  1659. import _xxsubinterpreters as interpreters
  1660. import test.test__xxsubinterpreters as helpers
  1661. ChannelState = helpers.ChannelState
  1662. try:
  1663. cid
  1664. except NameError:
  1665. cid = interpreters._channel_id({self.cid})
  1666. """)
  1667. @unittest.skip('these tests take several hours to run')
  1668. class ExhaustiveChannelTests(TestBase):
  1669. """
  1670. - main / interp / other
  1671. - run in: current thread / new thread / other thread / different threads
  1672. - end / opposite
  1673. - force / no force
  1674. - used / not used (associated / not associated)
  1675. - empty / emptied / never emptied / partly emptied
  1676. - closed / not closed
  1677. - released / not released
  1678. - creator (interp) / other
  1679. - associated interpreter not running
  1680. - associated interpreter destroyed
  1681. - close after unbound
  1682. """
  1683. """
  1684. use
  1685. pre-close
  1686. close
  1687. after
  1688. check
  1689. """
  1690. """
  1691. close in: main, interp1
  1692. creator: same, other, extra
  1693. use: None,send,recv,send/recv in None,same,other,same+other,all
  1694. pre-close: None,send,recv in None,same,other,same+other,all
  1695. pre-close forced: None,send,recv in None,same,other,same+other,all
  1696. close: same
  1697. close forced: same
  1698. use after: None,send,recv,send/recv in None,same,other,extra,same+other,all
  1699. close after: None,send,recv,send/recv in None,same,other,extra,same+other,all
  1700. check closed: send/recv for same/other(incl. interp2)
  1701. """
  1702. def iter_action_sets(self):
  1703. # - used / not used (associated / not associated)
  1704. # - empty / emptied / never emptied / partly emptied
  1705. # - closed / not closed
  1706. # - released / not released
  1707. # never used
  1708. yield []
  1709. # only pre-closed (and possible used after)
  1710. for closeactions in self._iter_close_action_sets('same', 'other'):
  1711. yield closeactions
  1712. for postactions in self._iter_post_close_action_sets():
  1713. yield closeactions + postactions
  1714. for closeactions in self._iter_close_action_sets('other', 'extra'):
  1715. yield closeactions
  1716. for postactions in self._iter_post_close_action_sets():
  1717. yield closeactions + postactions
  1718. # used
  1719. for useactions in self._iter_use_action_sets('same', 'other'):
  1720. yield useactions
  1721. for closeactions in self._iter_close_action_sets('same', 'other'):
  1722. actions = useactions + closeactions
  1723. yield actions
  1724. for postactions in self._iter_post_close_action_sets():
  1725. yield actions + postactions
  1726. for closeactions in self._iter_close_action_sets('other', 'extra'):
  1727. actions = useactions + closeactions
  1728. yield actions
  1729. for postactions in self._iter_post_close_action_sets():
  1730. yield actions + postactions
  1731. for useactions in self._iter_use_action_sets('other', 'extra'):
  1732. yield useactions
  1733. for closeactions in self._iter_close_action_sets('same', 'other'):
  1734. actions = useactions + closeactions
  1735. yield actions
  1736. for postactions in self._iter_post_close_action_sets():
  1737. yield actions + postactions
  1738. for closeactions in self._iter_close_action_sets('other', 'extra'):
  1739. actions = useactions + closeactions
  1740. yield actions
  1741. for postactions in self._iter_post_close_action_sets():
  1742. yield actions + postactions
  1743. def _iter_use_action_sets(self, interp1, interp2):
  1744. interps = (interp1, interp2)
  1745. # only recv end used
  1746. yield [
  1747. ChannelAction('use', 'recv', interp1),
  1748. ]
  1749. yield [
  1750. ChannelAction('use', 'recv', interp2),
  1751. ]
  1752. yield [
  1753. ChannelAction('use', 'recv', interp1),
  1754. ChannelAction('use', 'recv', interp2),
  1755. ]
  1756. # never emptied
  1757. yield [
  1758. ChannelAction('use', 'send', interp1),
  1759. ]
  1760. yield [
  1761. ChannelAction('use', 'send', interp2),
  1762. ]
  1763. yield [
  1764. ChannelAction('use', 'send', interp1),
  1765. ChannelAction('use', 'send', interp2),
  1766. ]
  1767. # partially emptied
  1768. for interp1 in interps:
  1769. for interp2 in interps:
  1770. for interp3 in interps:
  1771. yield [
  1772. ChannelAction('use', 'send', interp1),
  1773. ChannelAction('use', 'send', interp2),
  1774. ChannelAction('use', 'recv', interp3),
  1775. ]
  1776. # fully emptied
  1777. for interp1 in interps:
  1778. for interp2 in interps:
  1779. for interp3 in interps:
  1780. for interp4 in interps:
  1781. yield [
  1782. ChannelAction('use', 'send', interp1),
  1783. ChannelAction('use', 'send', interp2),
  1784. ChannelAction('use', 'recv', interp3),
  1785. ChannelAction('use', 'recv', interp4),
  1786. ]
  1787. def _iter_close_action_sets(self, interp1, interp2):
  1788. ends = ('recv', 'send')
  1789. interps = (interp1, interp2)
  1790. for force in (True, False):
  1791. op = 'force-close' if force else 'close'
  1792. for interp in interps:
  1793. for end in ends:
  1794. yield [
  1795. ChannelAction(op, end, interp),
  1796. ]
  1797. for recvop in ('close', 'force-close'):
  1798. for sendop in ('close', 'force-close'):
  1799. for recv in interps:
  1800. for send in interps:
  1801. yield [
  1802. ChannelAction(recvop, 'recv', recv),
  1803. ChannelAction(sendop, 'send', send),
  1804. ]
  1805. def _iter_post_close_action_sets(self):
  1806. for interp in ('same', 'extra', 'other'):
  1807. yield [
  1808. ChannelAction('use', 'recv', interp),
  1809. ]
  1810. yield [
  1811. ChannelAction('use', 'send', interp),
  1812. ]
  1813. def run_actions(self, fix, actions):
  1814. for action in actions:
  1815. self.run_action(fix, action)
  1816. def run_action(self, fix, action, *, hideclosed=True):
  1817. end = action.resolve_end(fix.end)
  1818. interp = action.resolve_interp(fix.interp, fix.other, fix.extra)
  1819. fix.prep_interpreter(interp)
  1820. if interp.name == 'main':
  1821. result = run_action(
  1822. fix.cid,
  1823. action.action,
  1824. end,
  1825. fix.state,
  1826. hideclosed=hideclosed,
  1827. )
  1828. fix.record_action(action, result)
  1829. else:
  1830. _cid = interpreters.channel_create()
  1831. run_interp(interp.id, f"""
  1832. result = helpers.run_action(
  1833. {fix.cid},
  1834. {repr(action.action)},
  1835. {repr(end)},
  1836. {repr(fix.state)},
  1837. hideclosed={hideclosed},
  1838. )
  1839. interpreters.channel_send({_cid}, result.pending.to_bytes(1, 'little'))
  1840. interpreters.channel_send({_cid}, b'X' if result.closed else b'')
  1841. """)
  1842. result = ChannelState(
  1843. pending=int.from_bytes(interpreters.channel_recv(_cid), 'little'),
  1844. closed=bool(interpreters.channel_recv(_cid)),
  1845. )
  1846. fix.record_action(action, result)
  1847. def iter_fixtures(self):
  1848. # XXX threads?
  1849. interpreters = [
  1850. ('main', 'interp', 'extra'),
  1851. ('interp', 'main', 'extra'),
  1852. ('interp1', 'interp2', 'extra'),
  1853. ('interp1', 'interp2', 'main'),
  1854. ]
  1855. for interp, other, extra in interpreters:
  1856. for creator in ('same', 'other', 'creator'):
  1857. for end in ('send', 'recv'):
  1858. yield ChannelCloseFixture(end, interp, other, extra, creator)
  1859. def _close(self, fix, *, force):
  1860. op = 'force-close' if force else 'close'
  1861. close = ChannelAction(op, fix.end, 'same')
  1862. if not fix.expect_closed_error():
  1863. self.run_action(fix, close, hideclosed=False)
  1864. else:
  1865. with self.assertRaises(interpreters.ChannelClosedError):
  1866. self.run_action(fix, close, hideclosed=False)
  1867. def _assert_closed_in_interp(self, fix, interp=None):
  1868. if interp is None or interp.name == 'main':
  1869. with self.assertRaises(interpreters.ChannelClosedError):
  1870. interpreters.channel_recv(fix.cid)
  1871. with self.assertRaises(interpreters.ChannelClosedError):
  1872. interpreters.channel_send(fix.cid, b'spam')
  1873. with self.assertRaises(interpreters.ChannelClosedError):
  1874. interpreters.channel_close(fix.cid)
  1875. with self.assertRaises(interpreters.ChannelClosedError):
  1876. interpreters.channel_close(fix.cid, force=True)
  1877. else:
  1878. run_interp(interp.id, f"""
  1879. with helpers.expect_channel_closed():
  1880. interpreters.channel_recv(cid)
  1881. """)
  1882. run_interp(interp.id, f"""
  1883. with helpers.expect_channel_closed():
  1884. interpreters.channel_send(cid, b'spam')
  1885. """)
  1886. run_interp(interp.id, f"""
  1887. with helpers.expect_channel_closed():
  1888. interpreters.channel_close(cid)
  1889. """)
  1890. run_interp(interp.id, f"""
  1891. with helpers.expect_channel_closed():
  1892. interpreters.channel_close(cid, force=True)
  1893. """)
  1894. def _assert_closed(self, fix):
  1895. self.assertTrue(fix.state.closed)
  1896. for _ in range(fix.state.pending):
  1897. interpreters.channel_recv(fix.cid)
  1898. self._assert_closed_in_interp(fix)
  1899. for interp in ('same', 'other'):
  1900. interp = fix.get_interpreter(interp)
  1901. if interp.name == 'main':
  1902. continue
  1903. self._assert_closed_in_interp(fix, interp)
  1904. interp = fix.get_interpreter('fresh')
  1905. self._assert_closed_in_interp(fix, interp)
  1906. def _iter_close_tests(self, verbose=False):
  1907. i = 0
  1908. for actions in self.iter_action_sets():
  1909. print()
  1910. for fix in self.iter_fixtures():
  1911. i += 1
  1912. if i > 1000:
  1913. return
  1914. if verbose:
  1915. if (i - 1) % 6 == 0:
  1916. print()
  1917. print(i, fix, '({} actions)'.format(len(actions)))
  1918. else:
  1919. if (i - 1) % 6 == 0:
  1920. print(' ', end='')
  1921. print('.', end=''); sys.stdout.flush()
  1922. yield i, fix, actions
  1923. if verbose:
  1924. print('---')
  1925. print()
  1926. # This is useful for scanning through the possible tests.
  1927. def _skim_close_tests(self):
  1928. ChannelCloseFixture.QUICK = True
  1929. for i, fix, actions in self._iter_close_tests():
  1930. pass
  1931. def test_close(self):
  1932. for i, fix, actions in self._iter_close_tests():
  1933. with self.subTest('{} {} {}'.format(i, fix, actions)):
  1934. fix.prep_interpreter(fix.interp)
  1935. self.run_actions(fix, actions)
  1936. self._close(fix, force=False)
  1937. self._assert_closed(fix)
  1938. # XXX Things slow down if we have too many interpreters.
  1939. fix.clean_up()
  1940. def test_force_close(self):
  1941. for i, fix, actions in self._iter_close_tests():
  1942. with self.subTest('{} {} {}'.format(i, fix, actions)):
  1943. fix.prep_interpreter(fix.interp)
  1944. self.run_actions(fix, actions)
  1945. self._close(fix, force=True)
  1946. self._assert_closed(fix)
  1947. # XXX Things slow down if we have too many interpreters.
  1948. fix.clean_up()
  1949. if __name__ == '__main__':
  1950. unittest.main()