utils.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import unittest
  2. import sys
  3. import os
  4. import sys
  5. import time
  6. import json
  7. import urllib
  8. import urllib2
  9. import subprocess
  10. import signal
  11. import random
  12. username = "test_user"
  13. parallel_push = True
  14. ports = []
  15. def getFreePort():
  16. while 1:
  17. port = random.randint(10000, 20000)
  18. ports.append(port)
  19. exists = False
  20. for p in ports:
  21. if p == port:
  22. if not exists:
  23. # We have hopefully found our own
  24. exists = True
  25. else:
  26. # We seem to be the second entry, so chose another one
  27. ports.remove(port)
  28. break
  29. else:
  30. # Didn't find a duplicate
  31. return port
  32. def serialize(value):
  33. if isinstance(value, str):
  34. return '"%s"' % value
  35. else:
  36. return str(value)
  37. def execute(scriptname, parameters=[], wait=False):
  38. if os.name not in ["nt", "posix"]:
  39. # Stop now, as we would have no clue on how to kill its subtree
  40. raise Exception("Unknown OS version: " + str(os.name))
  41. command = [sys.executable, "scripts/%s.py" % scriptname] + parameters
  42. if wait:
  43. return subprocess.call(command, shell=False)
  44. else:
  45. return subprocess.Popen(command, shell=False)
  46. def kill(process):
  47. if os.name == "nt":
  48. subprocess.call(["taskkill", "/F", "/T", "/PID", "%i" % process.pid])
  49. elif os.name == "posix":
  50. subprocess.call(["pkill", "-P", "%i" % process.pid])
  51. def flush_data(address, data):
  52. if data:
  53. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": json.dumps(data), "username": username})), timeout=10).read()
  54. return []
  55. def compile_file(address, mod_filename, filename, mode, proc):
  56. # Load in the file required
  57. try:
  58. timeout_val = 120
  59. import random
  60. username = str(random.random())
  61. while 1:
  62. proc2 = execute("compile", [address, mod_filename, username, filename, mode], wait=False)
  63. if proc.returncode is not None:
  64. # Modelverse has already terminated, which isn't a good sign!
  65. raise Exception("Modelverse died!")
  66. while proc2.returncode is None:
  67. time.sleep(0.01)
  68. proc2.poll()
  69. timeout_val -= 0.01
  70. if timeout_val < 0:
  71. kill(proc2)
  72. print("Compilation timeout expired!")
  73. return False
  74. if proc2.returncode != 2:
  75. break
  76. # Make sure everything stopped correctly
  77. assert proc2.returncode == 0
  78. if proc2.returncode != 0:
  79. return False
  80. except:
  81. raise
  82. finally:
  83. try:
  84. kill(proc2)
  85. except UnboundLocalError:
  86. pass
  87. def run_file(files, parameters, expected, mode):
  88. # Resolve file
  89. import os.path
  90. time.sleep(0.01)
  91. port = getFreePort()
  92. address = "http://127.0.0.1:%i" % port
  93. try:
  94. # Run Modelverse server
  95. proc = execute("run_local_modelverse", [str(port)], wait=False)
  96. threads = []
  97. for filename in files:
  98. if filename == "--fast":
  99. continue
  100. if os.path.isfile("integration/code/%s" % filename):
  101. mod_filename = "integration/code/%s" % filename
  102. elif os.path.isfile("bootstrap/%s" % filename):
  103. mod_filename = "bootstrap/%s" % filename
  104. else:
  105. raise Exception("File not found: %s" % filename)
  106. print("Found file " + str(mod_filename))
  107. if parallel_push:
  108. import threading
  109. threads.append(threading.Thread(target=compile_file, args=[address, mod_filename, filename, mode, proc]))
  110. threads[-1].start()
  111. else:
  112. compile_file(address, mod_filename, filename, mode, proc)
  113. # After the first file, which can be whatever we want, we just have to compile dependencies, all of which are PO for efficiency
  114. mode = "PO"
  115. if parallel_push:
  116. for t in threads:
  117. t.join()
  118. if mode[-1] == "O":
  119. # Fire up the linker
  120. val = execute("link_and_load", [address, username] + files, wait=True)
  121. if val != 0:
  122. raise Exception("Linking error")
  123. # Send in the actual request and wait for replies
  124. data = []
  125. for p in parameters:
  126. if isinstance(p, tuple):
  127. for v in p:
  128. data.append(["V", serialize(v)])
  129. else:
  130. data.append(["V", serialize(p)])
  131. flush_data(address, data)
  132. for e in expected:
  133. c = len(e) if isinstance(e, set) else 1
  134. for _ in range(c):
  135. val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=30).read()
  136. if proc.returncode is not None:
  137. # Modelverse has already terminated, which isn't a good sign!
  138. raise Exception("Modelverse died!")
  139. val = val.split("=", 2)[2]
  140. print("Got %s, expect %s" % (val, e))
  141. if isinstance(e, set):
  142. assert str(val) in e
  143. if str(val) not in e:
  144. return False
  145. else:
  146. assert str(val) == e
  147. if str(val) != e:
  148. return False
  149. # All passed!
  150. return True
  151. except:
  152. raise
  153. finally:
  154. try:
  155. kill(proc)
  156. except UnboundLocalError:
  157. pass
  158. def run_barebone(parameters, expected, interface="0", timeout=False, wait=False, link=None, inputs=[]):
  159. port = getFreePort()
  160. address = "http://127.0.0.1:%i" % port
  161. try:
  162. # Run Modelverse server
  163. proc = execute("run_local_modelverse", [str(port)], wait=False)
  164. # Create user and set interface
  165. timeout_val = 15
  166. start = time.time()
  167. while 1:
  168. proc.poll()
  169. if proc.returncode is not None:
  170. # Modelverse has already terminated, which isn't a good sign!
  171. return False
  172. try:
  173. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % username, "username": "user_manager"})), timeout=1).read()
  174. if interface is not None:
  175. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "element_type": "V", "value": interface, "username": username})), timeout=1).read()
  176. break
  177. except:
  178. time.sleep(0.01)
  179. if time.time() - start > timeout_val:
  180. raise
  181. # Send in the actual request and wait for replies
  182. var_list = {}
  183. data = []
  184. for p in parameters:
  185. if isinstance(p, int):
  186. if p not in var_list:
  187. data = flush_data(address, data)
  188. proc.poll()
  189. if proc.returncode is not None:
  190. # Modelverse has already terminated, which isn't a good sign!
  191. return False
  192. val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=10).read()
  193. val = val.split("=", 2)[1].split("&", 1)[0]
  194. var_list[p] = val
  195. continue
  196. else:
  197. val = var_list[p]
  198. t = "R"
  199. else:
  200. val = p
  201. t = "V"
  202. data.append([t, val])
  203. data = flush_data(address, data)
  204. # Now do linking and loading
  205. if link is not None:
  206. # Execute linker
  207. timeout_val = 10
  208. proc2 = execute("link_and_load", [address, username] + link, wait=False)
  209. while proc2.returncode is None:
  210. time.sleep(0.01)
  211. proc2.poll()
  212. timeout_val -= 0.01
  213. if timeout_val < 0:
  214. kill(proc2)
  215. print("Linking timeout expired!")
  216. return False
  217. if proc.returncode is not None:
  218. # Modelverse has already terminated, which isn't a good sign!
  219. return False
  220. for inp in inputs:
  221. urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "element_type": "V", "value": inp, "username": username})), timeout=1).read()
  222. proc.poll()
  223. if proc.returncode is not None:
  224. # Modelverse has already terminated, which isn't a good sign!
  225. return False
  226. counter = 0
  227. for e in expected:
  228. print("Expect " + str(e))
  229. c = len(e) if isinstance(e, set) else 1
  230. for _ in range(c):
  231. try:
  232. proc.poll()
  233. if proc.returncode is not None:
  234. # Modelverse has already terminated, which isn't a good sign!
  235. return False
  236. val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=120).read()
  237. except:
  238. if timeout:
  239. return True
  240. else:
  241. raise
  242. val = val.split("=", 2)[2]
  243. print("Got %s, expect %s" % (val, e))
  244. if isinstance(e, set):
  245. assert str(val) in e
  246. if str(val) not in e:
  247. return False
  248. else:
  249. assert str(val) == e
  250. if str(val) != e:
  251. return False
  252. # All passed!
  253. return not timeout
  254. finally:
  255. kill(proc)