Esempio n. 1
0
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.'
Esempio n. 2
0
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.'
Esempio n. 3
0
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>.'
Esempio n. 4
0
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.'
Esempio n. 5
0
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.'
Esempio n. 6
0
    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")
Esempio n. 7
0
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
Esempio n. 8
0
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'
Esempio n. 9
0
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'
Esempio n. 10
0
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()