utils.py 10 KB

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