Ejemplo n.º 1
0
Archivo: main.py Proyecto: Godhart/fvf
 def rpyc_send(self, data):
     """
     Sends data to app via stdin
     :param data: Data to send over stdin. Could be an item like str, bytearray or list/tuple of items
     :return: True if data were sent successfully, otherwise - False
     """
     start_time = time.time()
     if (self._mock is None or data == 'exit') and self._connection is None:
         return proto_failure("No connection. Ensure start is complete")
     try:
         if not isinstance(data, (list, tuple)):
             data = data,
         for m in data:
             if self._mock is None or data == 'exit':  # TODO: why data=='exit' overrides self._mock?
                 self._connection.root.send(m)
             else:
                 try:
                     if self._mock_eval:
                         r = evaluate(m)
                     else:
                         r = m
                 except Exception as e:
                     r = None
                 self._mock.append(str(r))
         if self._mock is None or data == 'exit':  # TODO: why data=='exit' overrides self._mock?
             self._connection.root.flush()
     except Exception as e:
         eprint("Platform {}: exception occurred during send: {}".format(
             self.name, e))
         exprint()
         return proto_failure(
             "Failed to send due to exception {}".format(e), -2)
     tprint("rpyc_send elapsed {}".format(time.time() - start_time))
     return proto_success(None)
Ejemplo n.º 2
0
Archivo: main.py Proyecto: Godhart/fvf
    def _start(self, reply_contexts):
        """
        1. Update's host from parent platform if necessary
        2. Connects to a Caller
        :return: True if started successfully, otherwise - False
        """
        if self._port is None and self._service is None:
            eprint(
                "Platform {} failed to start - port or service should be specified"
                .format(self.name))
            return proto_failure(
                "Platform {} failed to start - port or service should be specified"
            )

        if self._port is not None and self._service is not None:
            eprint(
                "Platform {} failed to start - specify only port or service, but not both"
                .format(self.name))
            return proto_failure(
                "Platform {} failed to start - port or service should be specified"
            )

        if self._host is None and self.parent is not None:
            c = self.request(
                new_message("platformix", "get", "host"),
                self._generic_request_handler, [], {
                    "on_success":
                    lambda d: setattr(self, "_host", d["host"]),
                    "on_failure":
                    lambda d: eprint("Failed to get host due to {}:{}".format(
                        d["errcode"], d["state"]))
                })

        if self._host is None:
            eprint("Platform {} failed to start - can't get host".format(
                self.name))
            return proto_failure("Failed to start - can't get host")
        try:
            self._connection = rpyc.connect(self._host, self._port)
            # TODO: use service instead of port if it's specified
            if self._args is not None:
                self._connection.root.set_args(copy.copy(self._args))
            result = self._connection.root.run()
        except Exception as e:
            self._connection = None
            eprint("Platform {} failed to start due to exception {}".format(
                self.name, e))
            exprint()
            return proto_failure("Failed to start due to exception {}", -2)
        if result is False:
            self._connection = None
            eprint("Platform {} failed to start: rpyc server returned False".
                   format(self.name))
            return proto_failure("RPYC server returned False")
        if result and not self._mock:
            if self._start_sequence is not None and len(
                    self._start_sequence) > 0:
                self.rpyc_send(self._start_sequence)
        return super(SoftwareRunner, self)._start(reply_contexts)
Ejemplo n.º 3
0
Archivo: main.py Proyecto: Godhart/fvf
    def calculate(self, expression):
        """
        :param expression: string with expression to send to Calc App
        :return: ProtocolReply
        """
        start_time = time.time()
        if self._mock:
            try:
                result = evaluate(expression)
            except ZeroDivisionError:
                result = None
            except Exception as e:
                result = "Platform {}: exception occurred on calculate: {}".format(
                    self.name, e)
                exprint()
                tprint("calculate (with fail) elapsed {}".format(time.time() -
                                                                 start_time))
                return proto_failure(result, -2)
            tprint("calculate elapsed {}".format(time.time() - start_time))
            return proto_success(result)

        # NOTE: mock code just ended here. To avoid nesting there is no else, just flat code

        # TODO: optimize code - now it's way to hard (just send/receive and so much code!!!)
        c = self.request(new_message(self._io_interface, "send", expression),
                         None, [], {},
                         timeout=2.0)  # TODO: decrease timeout
        c_state = self._pop_request_state(c)
        if not self._request_state_is_success(c_state):
            tprint(
                "calculate (with fail result) elapsed {}".format(time.time() -
                                                                 start_time))
            return proto_failure("IO failed to send data")

        c = self.request(new_message(self._io_interface, "receive"),
                         None, [], {},
                         timeout=2.0)  # TODO: decrease timeout
        c_state = self._pop_request_state(c)
        if not self._request_state_is_success(c_state):
            tprint(
                "calculate (with fail result) elapsed {}".format(time.time() -
                                                                 start_time))
            return proto_failure("IO failed to receive response")
        # TODO: convert from string to number
        tprint("calculate elapsed {}".format(time.time() - start_time))
        result = PM.parse(c_state["__message__"]).reply_data["value"]
        if isinstance(
                result, (list, tuple)
        ):  # NOTE: softwarerunner returns list but stream_io returns single item
            result = result[0]
        if result.strip() == 'None':
            result = None
        else:
            try:
                result = int(result)
            except ValueError:
                result = float(result)
        return proto_success(result)
Ejemplo n.º 4
0
Archivo: main.py Proyecto: Godhart/fvf
 def rpyc_log(self):
     if self._connection is None:
         return proto_failure("No connection. Ensure start is complete")
     try:
         data = self._connection.root.log
     except Exception as e:
         eprint(
             "Platform {}: exception occurred while getting log: {}".format(
                 self.name, e))
         exprint()
         return proto_failure(
             "Failed to get log due to exception {}".format(e), -2)
     return proto_success(data)
Ejemplo n.º 5
0
 def _sequencer_run(self, context, fake_reply, runs=None):
     if not self._ensure_running(context, fake_reply):
         return
     if self._worker.remaining > 0:
         self._reply(context, proto_failure("Already running"), fake_reply)
     self._notify(context, "Calling run...")
     self._reply(context, self._worker.run(context, runs), fake_reply)
Ejemplo n.º 6
0
Archivo: main.py Proyecto: Godhart/fvf
 def rpyc_receive(self, count=1, timeout=1.0):
     """
     Get's data that were sent by app via stdout
     :param count: Amount of lines to receive.
             set count to 0 to receive as much as possible, and at least one message
             set count to -1 to receive as much as possible, but nothing is acceptable too
     :param timeout: Time in seconds to wait for data
     :return: True if successfully received Data, otherwise - False. Data itself is contained in a reply to channel
              and Data is list of strings
     """
     start_time = time.time()
     if not isinstance(count, int) or count < -1:
         raise ValueError(
             "Count should be an integer in a range from -1 and up to +infinity"
         )
     if self._mock is None and self._connection is None:
         return proto_failure("No connection. Ensure start is complete")
     try:
         data = []
         if self._mock is not None:
             data = self._mock[:count]
             self._mock = self._mock[count:]
         else:
             while len(data) < count or count == 0 or count == -1:
                 received = self._connection.root.receive(timeout)
                 if received is None or len(received) == 0:
                     break
                 if isinstance(received, (list, tuple)):
                     data += received
                 else:
                     data.append(received)
     except Exception as e:
         eprint("Platform {}: exception occurred during receive: {}".format(
             self.name, e))
         exprint()
         return proto_failure(
             "Failed to receive due to exception {}".format(e), -2)
     tprint("rpyc_receive elapsed {}".format(time.time() - start_time))
     if 0 < count != len(data):
         return proto_failure("Not all requested data were received")
         # TODO: need a way to return partially received data
     elif count == 0 and len(data) == 0:
         return proto_failure("No data were received")
     else:
         return proto_success(data)
Ejemplo n.º 7
0
 def _ensure_connected(self, context, fake_reply):
     if self._worker.connection is None or self._worker.connection is False:
         self._reply(
             context,
             proto_failure(
                 "No connection. Ensure start is complete successfully"),
             fake_reply)
         return False
     else:
         return True
Ejemplo n.º 8
0
 def _platformix_call(self, context, fake_reply, method, *args, **kwargs):
     """
     Calls host's method
     Call result is returned in a success message as value item
     :param context: messaging context
     :param method: method symbolic name
     :param args: args to method call
     :param kwargs: kwargs to method call
     :return: None
     """
     if hasattr(self.host, method):
         if not callable(getattr(self.host, method)):
             self._reply(
                 context,
                 proto_failure("Attribute {} of {} is a property".format(
                     property, self.host.name)), fake_reply)
             return
         try:
             result = getattr(self.host, method)(*args, **kwargs)
         except Exception as e:
             eprint(
                 "Platformix protocol: failed to call method {} of {} with args {}, kwargs {} "
                 "due to exception {}".format(method, self.host.name, args,
                                              kwargs, e))
             exprint()
             self._reply(
                 context,
                 proto_failure(
                     "Failed to call method {} of {} with args {}, kwargs {} "
                     "due to exception {}".format(method, self.host.name,
                                                  args, kwargs, e)),
                 fake_reply)
             return
         self._reply(context, proto_success(result), fake_reply)
     else:
         self._reply(
             context,
             proto_failure("Method {} not found on {}".format(
                 property, self.host.name)), fake_reply)
Ejemplo n.º 9
0
Archivo: main.py Proyecto: Godhart/fvf
    def _start(self, reply_contexts):
        """
        1. Update's host from parent platform if necessary
        2. Connects to a Caller
        :return: True if started successfully, otherwise - False
        """
        if self._port is None:
            eprint("Platform {} failed to start - port should be specified".format(self.name))
            return proto_failure("Platform {} failed to start - port or service should be specified")

        if self._host is None and self.parent is not None:
            c = self.request(new_message("platformix", "get", "host"),
                             self._generic_request_handler,
                             [], {"on_success": lambda d: setattr(self, "_host", d["host"]),
                                  "on_failure": lambda d: eprint("Failed to get host due to {}:{}".format(
                                      d["errcode"], d["state"]))
                                  })

        if self._host is None:
            eprint("Platform {} failed to start - can't get host".format(self.name))
            return proto_failure("Failed to start - can't get host")
        try:
            timeout = time.time() + self._connect_timeout
            while True:
                try:
                    if self._mock is None:
                        self._sock = sock = socket.socket()
                        sock.connect((self._host, self._port))
                        sock.settimeout(self._timeout)
                        break
                except ConnectionRefusedError as e:
                    if time.time() > timeout:
                        raise e
        except Exception as e:
            self._sock = None
            eprint("Platform {} failed to start due to exception {}".format(self.name, e))
            exprint()
            return proto_failure("Failed to start due to exception {}", -2)
        return super(TcpIO, self)._start(reply_contexts)
Ejemplo n.º 10
0
 def _platformix_set(self, context, fake_reply, prop, value):
     """
     Set host's property to a value
     :param context: messaging context
     :param prop: property symbolic name
     :param value: value to set
     :return: None
     """
     if hasattr(self.host, prop):
         if not callable(getattr(self.host, prop)):
             try:
                 setattr(self.host, prop, value)
             except Exception as e:
                 eprint(
                     "Platformix protocol: failed to set attribute {} of {} to value {} "
                     "due to exception {}".format(prop, self.host.name,
                                                  value, e))
                 exprint()
                 self._reply(
                     context,
                     proto_failure(
                         "Failed to set attribute {} of {} to value {} "
                         "due to exception {}".format(
                             prop, self.host.name, value, e)), fake_reply)
                 return
             self._reply(context,
                         proto_success(getattr(self.host, prop), prop),
                         fake_reply)
         else:
             self._reply(
                 context,
                 proto_failure("Attribute {} of {} is a method".format(
                     prop, self.host.name)), fake_reply)
     else:
         self._reply(
             context,
             proto_failure("Property {} not found on {}".format(
                 prop, self.host.name)), fake_reply)
Ejemplo n.º 11
0
Archivo: main.py Proyecto: Godhart/fvf
 def tcp_send(self, data):
     """
     Sends data to app via stdin
     :param data: Data to send over stdin. Could be an item like str, bytearray or list/tuple of items
     :return: True if data were sent successfully, otherwise - False
     """
     start_time = time.time()
     if self._mock is None and self._sock is None:
         return proto_failure("No connection. Ensure start is complete")
     try:
         if not isinstance(data, (list, tuple)):
             data = data,
         for m in data:
             if self._mock is None:
                 if not isinstance(m, bytearray):
                     if isinstance(m, str):
                         m = m.encode('UTF-8')
                     else:
                         return proto_failure("Send data is expected to be a string, bytearray or "
                                              "list/tuple of strings and bytearrays")
                 self._sock.sendall(m)
             else:
                 try:
                     if self._mock_eval and isinstance(m, str):
                         r = evaluate(m)
                     else:
                         r = m
                 except Exception as e:
                     r = None
                 self._mock.append(str(r))
     except Exception as e:
         eprint("Platform {} failed to send due to exception {}".format(self.name, e))
         exprint()
         return proto_failure("Failed to send due to exception {}".format(e), -2)
     tprint("tcp_send elapsed {}".format(time.time() - start_time))
     return proto_success(None)
Ejemplo n.º 12
0
 def _platformix_report(self, context, fake_reply, kind):
     """
     Reports about platform's state
     Currently only running and is_running supported
     * running - replies with retval True if platform is running, and False otherwise
     * is_running - successful reply if platform is running, and failure otherwise
     :param context:
     :param kind:
     :return:
     """
     if kind == "running":
         self._reply(context,
                     proto_success(["False", "True"][self._worker.running]),
                     fake_reply)
         return
     elif kind == "is_running":
         if self._worker.running:
             self._reply(context, proto_success("True", "state"),
                         fake_reply)
         else:
             self._reply(context, proto_failure("False"), fake_reply)
     else:
         self._reply(context, proto_failure("Unknown report request"),
                     fake_reply)
Ejemplo n.º 13
0
 def _platformix_get(self, context, fake_reply, prop):
     """
     Get host's property.
     Value is returned in a success message as item with index same as property name
     :param context: messaging context
     :param prop: property symbolic name
     :return: None
     """
     if hasattr(self.host, prop):
         self._reply(context, proto_success(getattr(self.host, prop), prop),
                     fake_reply)
     else:
         self._reply(
             context,
             proto_failure("Property {} not found on {}".format(
                 prop, self.host.name)), fake_reply)
Ejemplo n.º 14
0
Archivo: main.py Proyecto: Godhart/fvf
    def _start(self, reply_contexts):
        """
        Makes sure that incoming/outgoing streams are synchronised
        :return: True if all necessary actions complete successfully, otherwise - False
        """
        # Flush any junk that could occur on app start (a common case example)
        # NOTE: Or you could wait in a loop for a specific message depending on app used

        if not self._mock:
            c = self.request(new_message(self._io_interface, "receive", -1),
                             None, [], {},
                             timeout=2.0)
            # TODO: cleaning required for softwarerunner only
            # TODO: reduce receive timeout instead of increasing request timeout
            c_state = self._pop_request_state(c)
            if not self._request_state_is_success(c_state):
                return proto_failure("Failed to flush i/o on start")
        return super(Calc, self)._start(reply_contexts)
Ejemplo n.º 15
0
 def _platformix_start(
         self, context,
         fake_reply):  # TODO: Recursive option to start nested platforms
     """
     Starts platform instance (actually checks that necessary conditions are met and calls startup worker method)
     If parent platform or platforms in wait list are not running yet - will wait for them
     If start were deferred due to waiting of other platforms then start method should be called again later
     Usually it happens automatically after other platforms are replying on their's startup end
     :param context: messaging context
     :return: None
     """
     assert fake_reply is None, "platformix_start replies shouldn't be faked!"
     if self._worker.running:  # If already running - just do nothing
         self._reply(context, proto_success("already running", "state"),
                     None)
         return
     if self._worker.stopping:  # If in the middle of stop - do nothing
         self._reply(context, proto_failure("stop is in progress"), None)
         return
     new_thread = False
     if self._worker.starting:  # If were already starting - update reply list
         if context not in self._context["reply_to"]:
             new_thread = True
             self._context["reply_to"].append(context)
             self._notify(context, "waiting")
     else:
         new_thread = True
         self._worker.starting = True
         self._context = {
             "action": "start",
             "reply_to": [context],
             "waiting_for": [],
             "wait_ignore": []
         }
         self._notify(context, "received start signal")
         # TODO: do recursive start? parent->childs? and call only root platforms to get up and running?
     # TODO: lock as validation can intersect with stop action since stop can be called from different threads
     if not self._validate_context({"action": "start"}):
         return
     if not self._worker.starting:  # NOTE: in case if starting were interrupted by stop - just return
         return
     # Update waiting list
     self._context["waiting_for"] = [
         w for w in self._worker.wait
         if self._worker.farm.is_running(w) is False
     ]
     # If there is some platforms to wait - notify about this
     if self.waiting_count > 0 and new_thread:
         self._worker.register_reply_handler(
             context,
             self._platformix_start_reply_handler, [], {},
             timeout=self._worker.start_max_wait,
             force=True)
         self._notify(context, "waiting")
     # If no one left to wait for - do stop at last
     elif not self._worker.start_in_progress and self.waiting_count == 0:
         for c in self._context["reply_to"]:
             try:
                 self._worker.unregister_reply_handler(c,
                                                       True, {},
                                                       dont_check=True)
             except AssertionError:
                 pass
         self._worker.start_in_progress = True
         self._notify_all(self._context["reply_to"], "launching")
         if self._validate_context({"action": "start"}):
             result = self._worker.start(self._context["reply_to"])
             result_error = not isinstance(result, ProtocolReply)
         else:
             result = None
             result_error = False
         if self._validate_context({"action": "start"}):
             reply_to = self._context["reply_to"]
             self._context = None
         else:
             return  # TODO: probably need to fid a way to reply failure in that case
         assert result_error is False, "Worker should return result as ProtocolReply instance"
         if result is not None:
             if result.success:
                 self._reply_all(reply_to, result, None)
             else:
                 self._reply_all(reply_to, result, None)
Ejemplo n.º 16
0
Archivo: main.py Proyecto: Godhart/fvf
    def _stop(self, reply_contexts):
        """
        1. Sends exit sequence to app via stdin
        2. Receives exit log if necessary
        3. Closes connection to a Caller
        :return:
        """
        stop_failed = None
        try:
            if self._connection is not None:  # Check before proceeding as it can be emergency stop
                if self._exit_sequence is not None and len(
                        self._exit_sequence) > 0:
                    self.rpyc_send(self._exit_sequence)
                    exit_time = time.time() + self._stop_timeout
                    forced_stop = False
                else:
                    self._connection.root.stop(
                        "Stopped by intent of SoftwareRunner (_stop)",
                        force=True)
                    exit_time = time.time() + self._stop_timeout
                    forced_stop = True
                while self._connection.root.running and (
                        not forced_stop or time.time() < exit_time):
                    if not self._connection.root.running:
                        break
                    if time.time() >= exit_time and (not forced_stop):
                        self._connection.root.stop(
                            "Forced to stop by intent of SoftwareRunner (_stop)",
                            force=True)
                        exit_time = time.time() + self._stop_timeout
                        forced_stop = True
                        stop_failed = "Not stopped by stop sequence"
                if self._connection.root.running:
                    if stop_failed is not None:
                        stop_failed += ", "
                    else:
                        stop_failed = ""
                    stop_failed += "App not stopped"

                # TODO: check whether isntance is running and call stop explicitly
                if self._display_log_on_stop:
                    data = list(self._connection.root.log)
                    vprint("Platform {}. Exit log: {}".format(
                        self.name, '\n'.join(data)))
                self._connection.close()
        except Exception as e:
            eprint("Platform {} experienced exception on stop: {}".format(
                self.name, e))
            exprint()
            self._reply_all(
                reply_contexts,
                PM.notify(
                    "abnormal_stop: experienced exception on stop: {}".format(
                        e)))
            if stop_failed is not None:
                stop_failed += ", "
            else:
                stop_failed = ""
            stop_failed += "Experienced exception: {}".format(e)

        if stop_failed is not None:
            eprint("Software runner {} failed to stop app properly: {}".format(
                self.name, stop_failed))
            self._reply_all(
                reply_contexts,
                PM.notify("Software runner {} failed to stop app properly: {}".
                          format(self.name, stop_failed)))

        self._connection = None
        super_result = super(SoftwareRunner, self)._stop(reply_contexts)
        if stop_failed:
            return proto_failure(stop_failed)
        else:
            return super_result
Ejemplo n.º 17
0
Archivo: main.py Proyecto: Godhart/fvf
    def _platformix_smoke_test(self, tests_list=None):
        env = self._env
        # Accepts following values in tests_list:
        # "success, fake, report"
        # "no fail check"

        # TODO: check if there is required amount of responses

        # Start  # NOTE: startup is made by testenv itself now
        # assert env.transaction("#platforms", new_message("platformix", "start")) is True, "Failed to start platforms"

        # Test errors control
        if tests_list is not None:
            tests_list = list(tests_list)
        if tests_list is None or "[sanity check]" in tests_list:
            if tests_list is not None:
                del tests_list[tests_list.index("[sanity check]")]
            if env.transaction(
                    "@platform_b",
                    fake_op_message("platformix",
                                    proto_failure("Failed by intent (fake_next_op, "
                                                  "Single unit error in [all success] condition)"),
                                    on_channel="#platforms",
                                    on_message=new_message("platformix", "report", "is_running")
                                    ),
                    er.all_success + er.none_fail) is False:
                eprint("Failed to set fake_next_op on [sanity check]")
                return False
            # NOTE: both all and none in condition above are for testing purpose

            # No fail since it's another channel
            if env.transaction("@platform_b", new_message("platformix", "report", "is_running"), er.none_fail) is False:
                # NOTE: none in condition above is testing purpose
                eprint("Failed to pass [report is_running] or avoid faking on [sanity check]")
                return False

            # No fail since it's another command
            if env.transaction("#platforms", new_message("platformix", "report", "running")) is False:
                eprint("Failed to pass [report running] or avoid faking on [sanity check]")
                return False

            # Fail as we told platform_b to do so
            if env.transaction("#platforms", new_message("platformix", "report", "is_running")) is True:
                eprint("Failed to pass faking or [all success] fail check on [sanity check]")
                return False

        if tests_list is None or "[single fail] success check" in tests_list:
            if tests_list is not None:
                del tests_list[tests_list.index("[single fail] success check")]
            if env.transaction(
                    "@platform_b",
                    fake_op_message("platformix",
                                    proto_failure("Failed by intent (fake_next_op, Single unit error "
                                                  "in [single fail] condition)"),
                                    on_channel="#platforms",
                                    execute=True
                                    )) is False:
                eprint("Failed to set fake_next_op on [single fail] success check")
                return False

            # No fail as we expecting that platform_b about to fail (NOTE: - no message filtering here)
            if env.transaction("#platforms", new_message("platformix", "report", "running"),
                               er.fail("platform_b") + er.others_success) is False:
                eprint("Failed to pass [single fail] success check")
                return False

        if tests_list is None or "[any success] fail check" in tests_list:
            if tests_list is not None:
                del tests_list[tests_list.index("[any success] fail check")]
            if env.transaction(
                    "#platforms",
                    fake_op_message("platformix",
                                    proto_failure("Failed by intent (fake_next_op, All fail "
                                                  "on [any success] condition)"),
                                    on_channel="#platforms"
                                    )) is False:
                eprint("Failed to set fake_next_op on [any success] fail check")
                return False

            # Should fail
            if env.transaction("#platforms", new_message("platformix", "report", "running"), er.any_success) is True:
                eprint("Failed to pass [any success] fail check")
                return False

        if tests_list is None or "[not(any success)] fail check" in tests_list:
            if tests_list is not None:
                del tests_list[tests_list.index("[not(any success)] fail check")]
            # Should pass as condition is negated
            if env.transaction("#platforms", new_message("platformix", "report", "running"),
                               [("any", "success", True)]) is True:
                eprint("Failed to pass [not(any success)] fail check")
                return False

        if tests_list is None or "[any fail] success check" in tests_list:
            if tests_list is not None:
                del tests_list[tests_list.index("[any fail] success check")]
            if env.transaction(
                    "@platform_b",
                    fake_op_message("platformix",
                                    proto_failure("Failed by intent (fake_next_op, Should pass "
                                                  "as condition is negated)"),
                                    on_channel="#platforms"
                                    )) is False:
                eprint("Failed to set fake_next_op on [any fail] success check")
                return False

            # Should pass as one item failed, as expected
            if env.transaction("#platforms", new_message("platformix", "report", "running"), er.any_fail) is False:
                eprint("Failed to pass [any fail] success check")
                return False

        # Check request without response (should fail)
        if tests_list is None or "[no response] fail check" in tests_list:
            if tests_list is not None:
                del tests_list[tests_list.index("[no response] fail check")]
            if env.transaction("__void__", new_message(None, "platformix", "report", "running"), er.all_fail) is True:
                eprint("Failed to pass [no response] fail check")
                return False

        # Stop  # NOTE: stop is made by testenv itself now
        # assert env.transaction("#platforms", new_message("platformix", "stop")) is True, "Failed to stop platforms"

        if tests_list is not None and len(tests_list) > 0:
            eprint("There is unknown tests left in a list: {}".format(tests_list))
            return False

        return True
Ejemplo n.º 18
0
    def _platformix_stop(self, context, fake_reply):  # TODO: Force parameter
        """
        Stops platform instance
        Breaks startup process if the platform is in middle of startup
        Waits before nested platforms are stopped before actually do stop
        # TODO: also should wait platforms which are waiting for this one on start
        If parent platform or platforms in wait list are not running yet - will wait for them
        If stop were deferred due to waiting of other platforms then stop method should be called again later
        Usually it happens automatically after other platforms are replying on their's stopping end
        :param context: messaging context
        :return: None
        """
        assert fake_reply is None, "platformix_stop replies shouldn't be faked!"

        stopping = self._worker.stopping  # Store current stopping state
        need_stop = self._worker.stopping = self._worker.running or self._worker.starting
        self._worker.stopping = True  # Set _stopping right in the beginning

        new_thread = False
        if not stopping and self._context is not None:  # Break startup process if necessary
            self._reply_all(self._context["reply_to"],
                            proto_failure("interrupted by stop"), None)
            if self._worker.starting:
                self._worker.starting = False
                self._worker.start_in_progress = False
            self._context = None
        if not stopping and not need_stop:  # If not running and not starting - do nothing more
            self._worker.stopping = False
            self._reply(context, proto_success("already stopped", "state"),
                        None)
            return
        if stopping:  # If were already stopping - update reply list
            if context not in self._context["reply_to"]:
                new_thread = True
                self._context["reply_to"].append(context)
        else:  # Otherwise initiate context
            new_thread = True
            self._context = {
                "action": "stop",
                "reply_to": [context],
                "waiting_for": [],
                "wait_ignore": []
            }
            self._notify(context, "received stop signal")
            # TODO: do recursive stop? parent->childs? and call only root platforms stop?
        assert self._worker.stopping, "At this point stopping should be True"
        # Update waiting list
        # TODO: also wait those that are depends on this one
        self._context["waiting_for"] = [
            w.name for w in self.host.subplatforms + self.host.depended
            if w.running is True or w.stopping is True
            and w.name not in self._context["wait_ignore"]
        ]

        # If there is some platforms to wait - notify about this
        if self.waiting_count > 0 and new_thread:
            self._worker.register_reply_handler(
                context,
                self._platformix_stop_reply_handler, [], {},
                timeout=self._worker.stop_max_wait,
                force=True)
            self._notify_all(self._context["reply_to"], "waiting")
        # If no one left to wait for - do stop at last
        elif not self._worker.stop_in_progress and self.waiting_count == 0:
            for c in self._context["reply_to"]:
                self._worker.unregister_reply_handler(c,
                                                      True, {},
                                                      dont_check=True)
            self._worker.running = False
            self._worker.stop_in_progress = True
            self._notify_all(self._context["reply_to"], "stopping")
            result = self._worker.stop(self._context["reply_to"])
            reply_to = self._context["reply_to"]
            self._context = None
            assert isinstance(
                result, ProtocolReply
            ), "Worker should return result as ProtocolReply instance"
            if result.success:
                self._reply_all(reply_to, proto_success(None), None)
            else:
                self._reply_all(reply_to, result, None)
Ejemplo n.º 19
0
Archivo: main.py Proyecto: Godhart/fvf
    def tcp_receive(self, count=0, timeout=None, decode='UTF-8'):
        """
        Get's data that were sent by app via stdout
        :param count: Amount of bytes to receive.
                set count to 0 to receive as much as possible, at least something
                set count to -1 to receive as much as possible, but nothing is acceptable too
        :param timeout: Time in seconds to wait for data. If None then TCP socket timeout is used
        :param deoode: If not None then received data is decoded into string using specified decoder. Default: 'UTF-8'
        :return: True if successfully received Data, otherwise - False. Data itself is contained in a reply to channel
                 and Data is list of strings
        """
        start_time = time.time()
        if not isinstance(count, int) or count < -1:
            raise ValueError("Count should be an integer in a range from -1 and up to +infinity")
        if self._mock is None and self._sock is None:
            return proto_failure("No connection. Ensure start is complete")
        try:
            if self._mock is not None:
                data = self._mock.pop(0)
            else:
                data = bytearray()
                if count < 1:
                    recv_size = 1024
                else:
                    recv_size = count
                if timeout is not None:
                    timeout = time.time() + timeout
                while len(data) < count or count == 0 or count == -1:
                    try:
                        received = self._sock.recv(recv_size)
                    except TimeoutError:
                        received = None
                    except socket.timeout:
                        received = None

                    if received is None:
                        if count < 0:
                            break
                        if count == 0 and len(data) > 0:
                            break
                    else:
                        data += received

                    if timeout is not None and time.time() > timeout:
                        break

                    if count > 0:
                        recv_size = count - len(data)

                if decode is not None:
                    data = data.decode(decode)

        except Exception as e:
            eprint("Platform {} failed to receive due to exception {}".format(self.name, e))
            exprint()
            return proto_failure("Failed to receive due to exception {}".format(e), -2)
        tprint("rpyc_receive elapsed {}".format(time.time() - start_time))
        if 0 < count != len(data):
            return proto_failure("Not all requested data were received")
            # TODO: need a way to return partially received data
        elif count == 0 and len(data) == 0:
            return proto_failure("No data were received")
        else:
            return proto_success(data)
Ejemplo n.º 20
0
 def _platformix_start_reply_handler(self, context, message, dry_run,
                                     timeouted):
     """
     Handles replies for start operation (required when platform is waiting another one)
     :param context: messaging context
     :param message: message content
     :param dry_run: True if it's only required to check whether this message would be processed
     :param timeouted: True if handler were called due to timeout. In this case message and context are invalid
     :return: True if message were processed (can be processed) otherwise False
     """
     if not timeouted:
         # Ignore messages other than success or failure
         if not message.is_failure and not message.is_success:
             return False
     if not self._validate_context({"action": "start"}):
         return False
     if timeouted or message.sender in self._context["waiting_for"]:
         if dry_run:
             if timeouted:
                 return False
             else:
                 return True
         if timeouted or message.is_failure:
             self._worker.starting = False
             self._worker.start_in_progress = False
             self._context["action"] = "start_failed"
             for c in self._context["reply_to"]:
                 try:
                     status = {}
                     if timeouted:
                         status["__timeouted__"] = True
                     if message.is_failure:
                         status[
                             "dependency failed to start"] = message.sender
                     self._worker.unregister_reply_handler(c,
                                                           False,
                                                           status,
                                                           dont_check=True)
                 except AssertionError:
                     pass
             if not timeouted:
                 self._reply_all(
                     self._context["reply_to"],
                     proto_failure(
                         "Aborting start due to platform {} failed to start"
                         .format(message.sender)), None)
             else:
                 self._reply_all(
                     self._context["reply_to"],
                     proto_failure(
                         "Aborting start due to wait timeout. Platforms {} have not started within "
                         "timeout {}".format(self._context["waiting_for"],
                                             self._worker.start_max_wait)),
                     None)
             self._context = None
             if timeouted:
                 return False
             else:
                 return True
         else:  # Success
             self._platformix_start(context, None)
             return True
     return False