def test_ret_type_exception_string(port): client = KoheronClient('127.0.0.1', port) tests = ExceptionTests(client) with pytest.raises(TypeError) as excinfo: tests.ret_type_exception_string() assert str( excinfo.value) == 'ExceptionTests::ret_type_exception returns a bool.'
def test_invalid_number_arguments_exception(port): client = KoheronClient('127.0.0.1', port) tests = ExceptionTests(client) with pytest.raises(ValueError) as excinfo: tests.ret_type_exception(42) # Musn't take a parameter assert str(excinfo.value ) == 'Invalid number of arguments. Expected 0 but received 1.'
def test_std_tuple_exception(port): client = KoheronClient('127.0.0.1', port) tests = ExceptionTests(client) with pytest.raises(TypeError) as excinfo: tests.std_tuple_exception() assert str( excinfo.value ) == 'ExceptionTests::std_tuple_exception returns a std::tuple<unsigned int, float>.'
def test_std_array_size_exception(port): client = KoheronClient('127.0.0.1', port) tests = ExceptionTests(client) with pytest.raises(ValueError) as excinfo: tests.std_array_size_exception() assert str( excinfo.value ) == 'ExceptionTests::std_array_size_exception expects 10 elements.'
def test_std_vector_exception(port): client = KoheronClient('127.0.0.1', port) tests = ExceptionTests(client) with pytest.raises(TypeError) as excinfo: tests.std_vector_exception() assert str( excinfo.value ) == 'ExceptionTests::std_vector_exception expects elements of type uint32_t.'
def start_client(self): time.sleep(0.2) # To be sure server is up log("info", "Connecting to server...") self.client = KoheronClient("127.0.0.1") if self.client.is_connected: log("info", "Connected to server") time.sleep(0.2) self.common = Common(self.client) log("info", "Common driver initialized") self.common.init() else: log("error", "Failed to connect to server")
class KoheronAPIApp(Flask): def __init__(self, *args, **kwargs): super(KoheronAPIApp, self).__init__(*args, **kwargs) self.config["INSTRUMENTS_DIR"] = "/usr/local/instruments/" self.instruments = {} self.load_metadata() self.live_instrument = {"name": None, "sha": None} self.start_last_deployed_instrument() self.get_instruments() def load_metadata(self): self.metadata = {} with open("metadata.json", "r") as f: self.metadata = json.load(f) def unzip_static(self): if os.path.exists("/tmp/static"): shutil.rmtree("/tmp/static") subprocess.call(["/usr/bin/unzip", "-o", "/tmp/static.zip", "-d", "/tmp/static"]) def update_live(self): if os.path.exists("/tmp/instrument"): shutil.rmtree("/tmp/instrument") subprocess.call(["/usr/bin/unzip", "-o", "/tmp/live.zip", "-d", "/tmp/instrument"]) def copy_static(self): copy_tree("/tmp/static/ui", "/var/www/ui") # ------------------------ # koheron-server client # ------------------------ def start_client(self): time.sleep(0.2) # To be sure server is up log("info", "Connecting to server...") self.client = KoheronClient("127.0.0.1") if self.client.is_connected: log("info", "Connected to server") time.sleep(0.2) self.common = Common(self.client) log("info", "Common driver initialized") self.common.init() else: log("error", "Failed to connect to server") def stop_client(self): if hasattr(self, "client"): self.client.__del__() def ping(self): val = self.common.get_led() for i in range(255): time.sleep(0.01) self.common.set_led(i) self.common.set_led(val) def init(self): self.common.init() # ------------------------ # Instruments # ------------------------ def get_instruments(self): if os.path.exists(self.config["INSTRUMENTS_DIR"]): for file_ in os.listdir(self.config["INSTRUMENTS_DIR"]): if self.is_valid_instrument_file(file_): self.append_instrument_to_list(file_) def append_instrument_to_list(self, zip_filename): name_, sha_ = self._tokenize_zipfilename(zip_filename) for name, shas in self.instruments.iteritems(): if name == name_ and (sha_ not in shas): shas.append(sha_) return self.instruments[name_] = [sha_] # New instrument def remove_instrument_from_list(self, zip_filename): name_, sha_ = self._tokenize_zipfilename(zip_filename) for name, shas in self.instruments.iteritems(): if name == name_ and sha_ in shas: shas.remove(sha_) if len(shas) == 0: del self.instruments[name] return def save_uploaded_instrument(self, zip_filename): if not os.path.exists(self.config["INSTRUMENTS_DIR"]): os.makedirs(self.config["INSTRUMENTS_DIR"]) shutil.copy(zip_filename, self.config["INSTRUMENTS_DIR"]) def delete_uploaded_instrument(self, zip_filename): if os.path.exists(self.config["INSTRUMENTS_DIR"]): os.remove(os.path.join(self.config["INSTRUMENTS_DIR"], zip_filename)) def install_instrument(self, zip_filename): if not os.path.exists(zip_filename): log("error", "Instrument zip file not found.\nNo installation done.") return name, sha = self._tokenize_zipfilename(zip_filename) print("Installing instrument " + name + " with version " + sha) self.stop_client() # http://stackoverflow.com/questions/21936597/blocking-and-non-blocking-subprocess-calls subprocess.call(["/bin/bash", "api_app/install_instrument.sh", zip_filename, name]) self.start_client() if not self.client.is_connected: self.handle_instrument_install_failure() return "client_not_connected" self.live_instrument = {"name": name, "sha": sha, "server_version": self.common.get_server_version()} self.store_last_deployed_zip(zip_filename) return "success" if self.is_bitstream_id_valid() else "invalid_bitstream_id" def handle_instrument_install_failure(self): # Check whether we are installing the last deployed instrument to avoid infinite recursion: last_deployed_instrument = self.get_last_deployed_instrument() if (not "name" in last_deployed_instrument) or ( last_deployed_instrument["name"] == self.live_instrument["name"] and last_deployed_instrument["sha"] == self.live_instrument["sha"] ): self._start_first_instrument_found(exclude=self.live_instrument) else: self.start_last_deployed_instrument() def is_bitstream_id_valid(self): id_ = self.common.get_bitstream_id() hash_ = hashlib.sha256(self.live_instrument["name"] + "-" + self.live_instrument["sha"]) if not hash_.hexdigest() == id_: log( "error", "Corrupted instrument: ID mismatch" + "\n* Bitstream ID:\n" + id_ + "\n* Expected:\n" + hash_.hexdigest(), ) return False return True def store_last_deployed_zip(self, zip_filename): zip_store_filename = os.path.join(self.config["INSTRUMENTS_DIR"], os.path.basename(zip_filename)) if not os.path.exists(zip_store_filename): shutil.copy(zip_filename, self.config["INSTRUMENTS_DIR"]) with open(os.path.join(self.config["INSTRUMENTS_DIR"], ".instruments"), "w") as f: f.write("last_deployed: " + zip_store_filename) def get_last_deployed_instrument(self): with open(os.path.join(self.config["INSTRUMENTS_DIR"], ".instruments"), "r") as f: tokens = f.readline().split(":") if tokens[0].strip() != "last_deployed": log("error", "Corrupted file .instruments") return {} name, sha = self._tokenize_zipfilename(os.path.basename(tokens[1].strip())) return {"name": name, "sha": sha} return {} def start_last_deployed_instrument(self): log("notice", "Start last deployed instrument") instrument_path = os.path.join(self.config["INSTRUMENTS_DIR"], ".instruments") if os.path.exists(instrument_path): with open(instrument_path, "r") as f: tokens = f.readline().split(":") if tokens[0].strip() != "last_deployed": log("error", "Corrupted file .instruments") self._start_first_instrument_found() return zip_filename = os.path.join(self.config["INSTRUMENTS_DIR"], os.path.basename(tokens[1].strip())) if os.path.exists(zip_filename): self.install_instrument(zip_filename) else: log("error", "Last deployed instrument zip file not found") self._start_first_instrument_found() else: self._start_first_instrument_found() def _start_first_instrument_found(self, exclude=None): for filename in os.listdir(self.config["INSTRUMENTS_DIR"]): if self.is_valid_instrument_file(filename): name, sha = self._tokenize_zipfilename(filename) if exclude == None or (name != exclude["name"] and sha != exclude["sha"]): self.install_instrument(os.path.join(self.config["INSTRUMENTS_DIR"], filename)) return log("error", "No instrument found: Load backup") self.start_from_backup() def start_from_backup(self): backup_dir = self.restore_backup() for filename in os.listdir(backup_dir): if self.is_valid_instrument_file(filename): self.install_instrument(os.path.join(backup_dir, filename)) return log("critical", "No instrument found") def restore_backup(self): backup_dir = os.path.join(self.config["INSTRUMENTS_DIR"], "backup") copy_tree(backup_dir, self.config["INSTRUMENTS_DIR"]) return backup_dir def is_valid_instrument_file(self, filename): return self.is_zip_file(filename) def is_valid_app_file(self, filename): return self.is_zip_file(filename) def is_zip_file(self, filename): filebase = os.path.basename(filename) return "." in filebase and filebase.rsplit(".", 1)[1] == "zip" def _tokenize_zipfilename(self, zip_filename): tokens = os.path.basename(zip_filename).split(".")[0].split("-") name = "-".join(tokens[:-1]) sha = tokens[-1] return name, sha
def test_unix_connect_fail_exception(): with pytest.raises(ConnectionError) as excinfo: client = KoheronClient(unixsock='dummy/path') assert str( excinfo.value) == 'Failed to connect to unix socket address dummy/path'
def test_tcp_connect_fail_exception(): with pytest.raises(ConnectionError) as excinfo: client = KoheronClient('127.0.0.1', 3600) # Instead of 36000 assert str( excinfo.value ) == 'Failed to connect to 127.0.0.1:3600 : [Errno 111] Connection refused'
from koheron import KoheronClient, command, __version__ class UsesContext: def __init__(self, client): self.client = client @command() def set_float_from_tests(self, f): return self.client.recv_bool() @command() def is_myself(self): return self.client.recv_bool() port = int(os.getenv('PYTEST_PORT', '36000')) client = KoheronClient('127.0.0.1', port) uses_ctx = UsesContext(client) @pytest.mark.parametrize('uses_ctx', [uses_ctx]) def test_set_float_from_tests(uses_ctx): assert uses_ctx.set_float_from_tests(12.5) @pytest.mark.parametrize('uses_ctx', [uses_ctx]) def test_is_myself(uses_ctx): assert uses_ctx.is_myself()