import unittest import sys import os import sys import time import json import urllib import urllib2 import subprocess import signal import random sys.path.append("interface/HUTN") from hutn_compiler.compiler import main as do_compile username = "test_user" parallel_push = True ports = [] def getFreePort(): while 1: port = random.randint(10000, 20000) ports.append(port) exists = False for p in ports: if p == port: if not exists: # We have hopefully found our own exists = True else: # We seem to be the second entry, so chose another one ports.remove(port) break else: # Didn't find a duplicate return port def execute(scriptname, parameters=[], wait=False): if os.name not in ["nt", "posix"]: # Stop now, as we would have no clue on how to kill its subtree raise Exception("Unknown OS version: " + str(os.name)) command = [sys.executable, "scripts/%s.py" % scriptname] + parameters if wait: return subprocess.call(command, shell=False) else: return subprocess.Popen(command, shell=False) def kill(process): if os.name == "nt": subprocess.call(["taskkill", "/F", "/T", "/PID", "%i" % process.pid]) elif os.name == "posix": subprocess.call(["pkill", "-P", "%i" % process.pid]) def flush_data(address, data): if data: urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": json.dumps(data), "username": username})), timeout=10).read() return [] def compile_file(address, mod_filename, filename, mode, proc): # Load in the file required try: timeout_val = 240 import random username = str(random.random()) while 1: proc2 = execute("compile", [address, mod_filename, username, filename, mode], wait=False) if proc.returncode is not None: # Modelverse has already terminated, which isn't a good sign! raise Exception("Modelverse died!") while proc2.returncode is None: time.sleep(0.01) proc2.poll() timeout_val -= 0.01 if timeout_val < 0: kill(proc2) print("Compilation timeout expired!") return False if proc2.returncode != 2: break # Make sure everything stopped correctly assert proc2.returncode == 0 if proc2.returncode != 0: return False except: raise finally: try: kill(proc2) except UnboundLocalError: pass def run_file(files, parameters, expected, mode): # Resolve file import os.path time.sleep(0.01) port = getFreePort() address = "http://127.0.0.1:%i" % port try: # Run Modelverse server proc = execute("run_local_modelverse", [str(port)], wait=False) threads = [] for filename in files: if os.path.isfile("integration/code/%s" % filename): mod_filename = "integration/code/%s" % filename elif os.path.isfile("bootstrap/%s" % filename): mod_filename = "bootstrap/%s" % filename else: raise Exception("File not found: %s" % filename) print("Found file " + str(mod_filename)) if parallel_push: import threading threads.append(threading.Thread(target=compile_file, args=[address, mod_filename, filename, mode, proc])) threads[-1].start() else: compile_file(address, mod_filename, filename, mode, proc) # After the first file, which can be whatever we want, we just have to compile dependencies, all of which are PO for efficiency mode = "PO" if parallel_push: for t in threads: t.join() if mode[-1] == "O": # Fire up the linker val = execute("link_and_load", [address, username] + files, wait=True) if val != 0: raise Exception("Linking error") # Send the request ... flush_data(address, parameters) # ... and wait for replies for e in expected: c = len(e) if isinstance(e, set) else 1 for _ in range(c): val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=240).read() val = json.loads(val) if proc.returncode is not None: # Modelverse has already terminated, which isn't a good sign! raise Exception("Modelverse died!") print("Got %s, expect %s" % (val, e)) if isinstance(e, set): assert val in e if val not in e: return False else: assert val == e if val != e: return False # All passed! return True except: raise finally: try: kill(proc) except UnboundLocalError: pass def run_barebone(parameters, expected, interface="0", timeout=False, wait=False, link=None, inputs=[]): port = getFreePort() address = "http://127.0.0.1:%i" % port try: # Run Modelverse server proc = execute("run_local_modelverse", [str(port)], wait=False) # Create user and set interface timeout_val = 15 start = time.time() while 1: proc.poll() if proc.returncode is not None: # Modelverse has already terminated, which isn't a good sign! return False try: urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % username, "username": "user_manager"})), timeout=1).read() if interface is not None: urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "element_type": "V", "value": interface, "username": username})), timeout=1).read() break except: time.sleep(0.01) if time.time() - start > timeout_val: raise # Send the request flush_data(address, parameters) # Now do linking and loading if link is not None: # Execute linker timeout_val = 10 proc2 = execute("link_and_load", [address, username] + link, wait=False) while proc2.returncode is None: time.sleep(0.01) proc2.poll() timeout_val -= 0.01 if timeout_val < 0: kill(proc2) print("Linking timeout expired!") return False if proc.returncode is not None: # Modelverse has already terminated, which isn't a good sign! return False for inp in inputs: urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "element_type": "V", "value": inp, "username": username})), timeout=1).read() proc.poll() if proc.returncode is not None: # Modelverse has already terminated, which isn't a good sign! return False counter = 0 for e in expected: print("Expect " + str(e)) c = len(e) if isinstance(e, set) else 1 for _ in range(c): try: proc.poll() if proc.returncode is not None: # Modelverse has already terminated, which isn't a good sign! return False val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=240 if not timeout else 20).read() val = json.loads(val) except: if timeout: return True else: raise print("Got %s, expect %s" % (val, e)) if isinstance(e, set): assert val in e if val not in e: return False else: assert val == e if val != e: return False # All passed! return not timeout finally: kill(proc) def get_constructor(code): with open("__constraint.al", "w") as f: f.write(code) f.flush() constructors = do_compile("__constraint.al", "interface/HUTN/grammars/actionlanguage.g", "CS") return constructors