def handle_stimuli_execute(self, event): # TODO should we check if stimuli is implemented or not? if event.node == self.node and self.implemented_stimuli_list and event.step_id not in self.implemented_stimuli_list: self.log('[%s] STIMULI (%s) doesnt seem to be implemented by automated IUT:' % ( self.node if self.node else "misc.", event.step_id, )) if event.node == self.node: step = event.step_id addr = event.target_address # may be None try: self._execute_stimuli(step, addr) # blocking till stimuli execution publish_message(self.connection, MsgStepStimuliExecuted(node=self.node)) except NotImplementedError as e: # either method not overriden, or stimuli step not implemented :/ publish_message(self.connection, MsgStepStimuliExecuted(description=str(e), node=self.node)) else: self.log('[%s] Event received and ignored: \n\tEVENT:%s \n\tNODE:%s \n\tSTEP: %s' % ( self.node if self.node else "misc.", type(event), event.node, event.step_id, ))
def __init__(self, amqp_url, amqp_exchange, routing_table): assert routing_table threading.Thread.__init__(self) self.exchange_name = amqp_exchange self.url = amqp_url self.routing_table = routing_table # component identification & bus params self.component_id = COMPONENT_ID # init logging to stnd output and log files self.logger = logging.getLogger(self.component_id) self.logger.setLevel(LOG_LEVEL) self.logger.info( 'routing table (rkey_src:[rkey_dst]) : \n{table}'.format( table=tabulate.tabulate( [[k, list(v)] for k, v in self.routing_table.items()], tablefmt="grid"))) self.message_count = 0 self.pending_number_of_packets_to_drop = 0 self._set_up_connection() self._queues_init() msg = MsgTestingToolComponentReady(component='packetrouting') publish_message(self.connection, msg) self.logger.info('Waiting for new messages in the data plane..')
def handle_testing_tool_configured(self, event): """ Behaviour: if tooling configured, then user triggers start of test suite """ m = MsgTestSuiteStart() publish_message(self.connection, m) self.log('Event received: %s' % type(event)) self.log('Event description: %s' % event.description) self.log('Event pushed: %s' % m)
def serialize_and_publish_all_messages(self): for i in self.serializable_messages_types: try: m = i() except Exception as e: self.fail('%s found, while serializing %s' % (e, str(i))) logging.info("publishing message type %s" % str(type(m))) publish_message(self.conn, m)
def signal_int_handler(signal, frame): connection = pika.BlockingConnection(pika.URLParameters(AMQP_URL)) publish_message( connection, MsgTestingToolComponentShutdown(component='automated-iut') ) logging.info('got SIGINT. Bye bye!') sys.exit(0)
def handle_test_case_ready(self, event): if not self.implemented_testcases_list: # either is None or [] self.log('IUT didnt declare testcases capabilities, we assume that any can be run') return if event.testcase_id not in self.implemented_testcases_list: time.sleep(0.1) self.log('IUT %s (%s) CANNOT handle test case: %s' % (self.component_id, self.node, event.testcase_id)) publish_message(self.connection, MsgTestCaseSkip(testcase_id=event.testcase_id)) else: self.log('IUT %s (%s) READY to handle test case: %s' % (self.component_id, self.node, event.testcase_id))
def _exit(self): m = MsgTestingToolComponentShutdown( component="{comp}.{node}".format( comp=self.component_id, node=self.node ) ) publish_message(self.connection, m) time.sleep(2) self.connection.close() sys.exit(0)
def handle_configuration_execute(self, event): if event.node == self.node: self.log('Configure test case %s' % event.testcase_id) # TODO fix me _execute_config should pass an arbitrary dict, which # will be used later for building the fields of the ret message ipaddr = self._execute_configuration(event.testcase_id, event.node) # blocking till complete config execution if ipaddr != '': m = MsgConfigurationExecuted(testcase_id=event.testcase_id, node=event.node, ipv6_address=ipaddr) publish_message(self.connection, m) else: self.log('Event received and ignored: %s' % type(event))
def handle_test_case_ready(self, event): self.log('Event received: %s' % type(event)) self.log('Event description: %s' % event.description) if self.implemented_testcases_list and event.testcase_id not in self.implemented_testcases_list: m = MsgTestCaseSkip(testcase_id=event.testcase_id) publish_message(self.connection, m) self.log('Event pushed: %s' % m) else: m = MsgTestCaseStart() publish_message(self.connection, m) self.log('Event pushed: %s' % m)
def __init__(self, node): self._init_logger() configuration = {} for i in ['implemented_testcases_list', 'component_id', 'node', 'process_log_file']: configuration[i] = getattr(self, i, "not defined") self.log("Initializing automated IUT: \n%s " % json.dumps(configuration, indent=4, sort_keys=True)) threading.Thread.__init__(self) self.node = node self.event_to_handler_map = { MsgTestCaseReady: self.handle_test_case_ready, MsgStepVerifyExecute: self.handle_test_case_verify_execute, MsgStepStimuliExecute: self.handle_stimuli_execute, MsgTestSuiteReport: self.handle_test_suite_report, MsgTestingToolTerminate: self.handle_testing_tool_terminate, MsgConfigurationExecute: self.handle_configuration_execute, MsgAutomatedIutTestPing: self.handle_test_ping, } # lets setup the AMQP stuff self.connection = pika.BlockingConnection(pika.URLParameters(AMQP_URL)) self.channel = self.connection.channel() self.message_count = 0 # queues & default exchange declaration queue_name = '%s::eventbus_subscribed_messages' % "{comp}.{node}".format( comp=self.component_id, node=self.node ) self.channel.queue_declare(queue=queue_name, auto_delete=True) for ev in self.event_to_handler_map: self.channel.queue_bind(exchange=AMQP_EXCHANGE, queue=queue_name, routing_key=ev.routing_key) # send hello message publish_message( self.connection, MsgTestingToolComponentReady( component="{comp}.{node}".format( comp=self.component_id, node=self.node ) ) ) self.channel.basic_qos(prefetch_count=1) self.channel.basic_consume(on_message_callback=self.on_request, queue=queue_name)
def publish_terminate_signal_on_report_received(message: Message): if isinstance(message, MsgTestSuiteReport): logging.info('Got final report %s' % repr(message)) connection = pika.BlockingConnection(pika.URLParameters(AMQP_URL)) publish_message( connection, MsgTestingToolTerminate( description="Received report, functional test finished..")) for tc_result_i in message.tc_results: logging.info('-' * 30) logging.info( 'TESTCASE: %s \n%s' % (tc_result_i['testcase_id'], pprint.pformat(tc_result_i))) logging.info('-' * 30)
def stop(self): self.shutdown = True if not self.connection.is_open: self.connection = pika.BlockingConnection( pika.URLParameters(AMQP_URL)) publish_message( self.connection, MsgTestingToolComponentShutdown(component=self.component_id)) if self.channel.is_open: self.channel.stop_consuming() self.connection.close()
def handle_test_case_verify_execute(self, event): if event.node == self.node: step = event.step_id self._execute_verify(step) publish_message(self.connection, MsgStepVerifyExecuted(verify_response=True, node=self.node )) else: self.log('Event received and ignored: %s (node: %s - step: %s)' % ( type(event), event.node, event.step_id, ))
def handle_verif_step_execute(self, event): if event.node in self.iut_to_mock_verifications_for: publish_message( self.connection, MsgStepVerifyExecuted(verify_response=True, node=event.node)) self.log('Mocked verify response for m: %s (node: %s - step: %s)' % ( type(event), event.node, event.step_id, )) else: self.log('Event received and ignored: %s (node: %s - step: %s)' % ( type(event), event.node, event.step_id, ))
def process_message(self, message): if isinstance(message, MsgUiRequestSessionConfiguration): resp = { "configuration": default_configuration, "id": '666', "testSuite": "someTestingToolName", "users": ['pablo', 'bengoechea'], } m = MsgUiSessionConfigurationReply(message, **resp) publish_message(self.connection, m) elif isinstance(message, MsgTestingToolTerminate): logger.info("Received termination message. Stopping %s" % self.__class__.__name__) self.stop() else: logger.warning('Got not expected message type %s' % type(message))
def __init__(self, iut_testcases=None, iut_to_mock_verifications_for=None): self._init_logger() threading.Thread.__init__(self) self.iut_to_mock_verifications_for = iut_to_mock_verifications_for self.event_to_handler_map = { MsgTestCaseReady: self.handle_test_case_ready, MsgTestingToolReady: self.handle_testing_tool_ready, MsgTestingToolConfigured: self.handle_testing_tool_configured, MsgTestSuiteReport: self.handle_test_suite_report, MsgTestCaseVerdict: self.handle_test_case_verdict, MsgTestingToolTerminate: self.handle_testing_tool_terminate, MsgStepVerifyExecute: self.handle_verif_step_execute, # MsgTestCaseConfiguration: self.handle_test_case_configurate, } self.shutdown = False self.connection = pika.BlockingConnection(pika.URLParameters(AMQP_URL)) self.channel = self.connection.channel() self.message_count = 0 # if implemented_testcases_list is None then all test cases should be executed self.implemented_testcases_list = iut_testcases # queues & default exchange declaration queue_name = '%s::eventbus_subscribed_messages' % self.component_id self.channel.queue_declare(queue=queue_name, auto_delete=True) for ev in self.event_to_handler_map: self.channel.queue_bind(exchange=AMQP_EXCHANGE, queue=queue_name, routing_key=ev.routing_key) publish_message( self.connection, MsgTestingToolComponentReady(component=self.component_id)) self.channel.basic_qos(prefetch_count=1) self.channel.basic_consume(on_message_callback=self.on_request, queue=queue_name)
def _03_get_capture(self): time.sleep(5) forged_agent_raw_packet = MsgPacketSniffedRaw() forged_agent_raw_packet.routing_key = self.routing_key_data_packet publish_message(self.connection, forged_agent_raw_packet) publish_message(self.connection, forged_agent_raw_packet) time.sleep(1) response = amqp_request( connection=self.connection, request_message=MsgSniffingGetCaptureLast(), component_id=self.__class__.__name__, retries=10, use_message_typing=True, ) assert response.ok, 'Returned %s' % repr(response) logging.info(repr(response))
def handle_test_ping(self, event): if event.node == self.node: self.log('Testing L3 reachability.') reachable = AutomatedIUT.test_l3_reachability(event.target_address) if reachable: success = True msg = "Ping reply received, peer is reachable" else: success = False msg = "Ping reply not received, peer is unreachable" m = MsgAutomatedIutTestPingReply( # request=event.request, ok=success, description=msg, node=event.node, target_address=event.target_address ) publish_message(self.connection, m) self.log('Event pushed: %s' % m)
def run(self): self.connect() msg = MsgTestingToolComponentReady(component='sniffing') publish_message(self.connection, msg) try: self.logger.info("Awaiting AMQP requests on bus") self.channel.start_consuming() except pika.exceptions.ConnectionClosed as cc: self.logger.error(' AMQP connection closed: %s' % str(cc)) sys.exit(1) except KeyboardInterrupt as KI: self.logger.info('SIGINT detected') self.notify_component_shutdown() sys.exit(0) except Exception as e: self.logger.error(' Unexpected error \n More: %s' % traceback.format_exc()) sys.exit(1) finally: # close AMQP connection if self.connection: self.connection.close()
def run(self): logging.info( "[%s] lets start 'blindly' generating the messages which take part on a coap session " "(for a coap client)" % (self.__class__.__name__)) try: while self.keepOnRunning: time.sleep(self.wait_time_between_pubs) m = self.messages.pop(0) publish_message(self.connection, m) logging.info("[%s] Publishing in the bus: %s" % (self.__class__.__name__, repr(m))) except IndexError: # list finished, lets wait so all messages are sent and processed time.sleep(5) pass except pika.exceptions.ChannelClosed: pass finally: logging.info("[%s] shutting down.. " % (self.__class__.__name__)) self.connection.close()
channel = connection.channel() bootstrap_q_name = 'bootstrapping' bootstrap_q = channel.queue_declare(queue=bootstrap_q_name, auto_delete=True) # starting verification of the testing tool components channel.queue_bind( exchange=AMQP_EXCHANGE, queue='bootstrapping', routing_key=MsgTestingToolComponentReady.routing_key, ) msg = MsgTestingToolComponentReady(component='testcoordination') publish_message(connection, msg) if no_component_checks: logger.info('Skipping testing tool component readiness checks') else: def on_ready_signal(ch, method, props, body): ch.basic_ack(delivery_tag=method.delivery_tag) event = Message.load_from_pika(method, props, body) if isinstance(event, MsgTestingToolComponentReady): component = event.component logger.info('ready signals received %s' % component) if component in TT_check_list: TT_check_list.remove(component) return
def run(self): try: for th in self.threads: th.start() self.check_session_start_status() logger.info("Sending session configuration to start tests") publish_message( self.connection, MsgSessionConfiguration(configuration=default_configuration), ) # configures test suite, this triggers start of userMock also t = 0 # wait until we get MsgTestSuiteReport while t < SESSION_TIMEOUT and MsgTestSuiteReport not in self.msg_logger_th.messages_by_type_dict: time.sleep(5) t += 5 if t % 15 == 0: self.get_status() if t >= SESSION_TIMEOUT: r = amqp_request(self.connection, MsgTestSuiteGetStatus(), COMPONENT_ID) logger.warning('Test TIMED-OUT! Test suite status:\n%s' % pprint.pformat(r.to_dict())) else: assert MsgTestSuiteReport in self.msg_logger_th.messages_by_type_dict # we can now terminate the session publish_message( self.connection, MsgTestingToolTerminate(description="Received report, functional test finished..") ) time.sleep(2) except Exception as e: self.error_state = True logger.error("Exception encountered in %s:\n%s" % (self.__class__.__name__, e)) logger.error("Traceback:\n%s", traceback.format_exc()) finally: if MsgTestingToolTerminate not in self.msg_logger_th.messages_by_type_dict: logger.warning('Never received TERMINATE signal') publish_message( self.connection, MsgTestingToolTerminate(description="Integration test of CoAP interop test: sth went wrong :/") ) time.sleep(10) # so threads process TERMINATE signal try: for th in self.threads: if th.is_alive(): logger.warning("Thread %s didn't stop" % th.name) th.stop() except Exception as e: # i dont want this to make my tests fail logger.warning('Exception thrown while stopping threads:\n%s' % e)
def test_amqp_api_smoke_tests(self): """ This basically checks that the testing tool doesnt crash while user is pushing message inputs into to the bus. We check for: - log errors in the bus - malformed messages in the bus - every request has a reply """ # prepare the message generator messages = [] # list of messages to send messages += user_sequence messages += service_api_calls messages.append(MsgTestingToolTerminate() ) # message that triggers stop_generator_signal # thread thread_msg_gen = MessageGenerator( amqp_url=AMQP_URL, amqp_exchange=AMQP_EXCHANGE, messages_list=messages, # att (!) some test run cycles of more that 100 messages, so this factor will change enourmosuly the time it # takes to complete a test wait_time_between_pubs=0.25) # thread thread_msg_listener = AmqpListener( amqp_url=AMQP_URL, amqp_exchange=AMQP_EXCHANGE, callback=run_checks_on_message_received, topics=['#'], use_message_typing=True) threads = [thread_msg_listener, thread_msg_gen] for th in threads: th.setName(th.__class__.__name__) time.sleep( 15) # wait for the testing tool to enter test suite ready state try: for th in threads: th.start() publish_message( self.connection, MsgSessionConfiguration(configuration=default_configuration), ) # configures test suite time.sleep(1) publish_message(self.connection, MsgTestSuiteStart()) # this starts test suite's FS self.connection.close() # waits THREAD_JOIN_TIMEOUT for the session to terminate for th in threads: th.join(THREAD_JOIN_TIMEOUT) except Exception as e: self.fail("Exception encountered %s" % e) finally: for th in threads: if th.is_alive(): th.stop() logger.warning("Thread %s didnt stop" % th.name) # finally checks check_request_with_no_correlation_id( event_messages_sniffed_on_bus_list) check_every_request_has_a_reply(event_messages_sniffed_on_bus_list)
def tearDown(self): publish_message(self.connection, MsgTestingToolTerminate()) self.connection.close() self.sniffer_as_a_process.terminate()
def on_request(self, ch, method, props, body): # ack message received ch.basic_ack(delivery_tag=method.delivery_tag) self.logger.info('Identifying request with rkey: %s' % method.routing_key) try: request = Message.load_from_pika(method, props, body) except Exception as e: self.logger.info(str(e)) return if isinstance(request, MsgSniffingGetCaptureLast): self.logger.debug('HANDLING request: %s' % repr(request)) if self.last_capture_name: capture_id = self.last_capture_name try: file = TMPDIR + '/%s.pcap' % capture_id # check if the size of PCAP is not zero if os.path.getsize(file) == 0: # raise SnifferError(message='Problem encountered with the requested PCAP') self.logger.error('Problem encountered with the requested PCAP') return except FileNotFoundError as fne: publish_message( self.connection, MsgErrorReply(request, error_message=str(fne)) ) self.logger.info(str(fne)) return except Exception as e: publish_message( self.connection, MsgErrorReply(request, error_message=str(e)) ) self.logger.info(str(e)) return self.logger.info("Encoding PCAP file into base64 ...") try: # do not dump into PCAP_DIR, coordinator puts the PCAPS there with open(TMPDIR + "/%s.pcap" % capture_id, "rb") as file: enc = base64.b64encode(file.read()) response = MsgSniffingGetCaptureLastReply( request, ok=True, filename='%s.pcap' % capture_id, value=enc.decode("utf-8") ) except Exception as e: err_mess = str(e) m_resp = MsgErrorReply(request, error_message=err_mess) publish_message(self.connection, m_resp) logging.warning(err_mess) return self.logger.info("Response ready, PCAP bytes: \n" + repr(response)) self.logger.info("Sending response through AMQP interface ...") publish_message(self.connection, response) else: err_mess = 'No previous capture found.' m_resp = MsgErrorReply(request, error_message=err_mess) publish_message(self.connection, m_resp) logging.warning(err_mess) return elif isinstance(request, MsgSniffingGetCapture): self.logger.debug('HANDLING request: %s' % repr(request)) try: capture_id = request.capture_id filename = "{0}.pcap".format(capture_id) full_path = os.path.join(TMPDIR, filename) # check if the size of PCAP is not zero if os.path.getsize(full_path) == 0: # raise SnifferError(message='Problem encountered with the requested PCAP') self.logger.error('Problem encountered with the requested PCAP') return except FileNotFoundError as fne: logging.warning('Coulnt retrieve file %s from dir' % capture_id) logging.warning(str(fne)) publish_message( self.connection, MsgErrorReply( request, error_message=str(fne) ) ) return self.logger.info("Encoding PCAP file into base64 ...") # do not dump into PCAP_DIR, coordinator puts the PCAPS there with open(full_path, "rb") as file: enc = base64.b64encode(file.read()) response = MsgSniffingGetCaptureReply( request, ok=True, filename="{0}.pcap".format(capture_id), value=enc.decode("utf-8") ) self.logger.info("Response ready, PCAP bytes: \n" + repr(response)) publish_message(self.connection, response) return elif isinstance(request, MsgSniffingStart): self.logger.debug('HANDLING request: %s' % repr(request)) try: capture_id = request.capture_id filename = "{0}.pcap".format(capture_id) full_path = os.path.join(TMPDIR, filename) except: err_mess = 'No capture id provided' m_resp = MsgErrorReply(request, error_message=err_mess) publish_message(self.connection, m_resp) self.logger.info(err_mess) return try: # start process for sniffing packets if self.pcap_dumper_subprocess is not None: m = "Sniffer process is already running, please stop before if you meant to restart it" response = MsgErrorReply(request, ok=False, error_message=m) self.logger.info(m) else: self.pcap_dumper_subprocess = multiprocessing.Process( target=packet_dumper.launch_amqp_data_to_pcap_dumper, name='process_%s_%s' % (self.COMPONENT_ID, capture_id), args=( TMPDIR, LOG_LEVEL, filename, self.traffic_dlt, self.url, self.exchange, self.DEFAULT_TOPICS)) self.pcap_dumper_subprocess.start() self.logger.info("Sniffer process started %s, pid %s" % ( self.pcap_dumper_subprocess, self.pcap_dumper_subprocess.pid)) response = MsgSniffingStartReply(request, ok=True) except Exception as e: m = 'Didnt succeed starting the sniffer process, the exception captured is %s' % str(e) self.logger.error(m) response = MsgErrorReply(request, ok=False, error_message=m) self.last_capture_name = capture_id # keep track of the undergoing capture name # send reponse to API call publish_message(self.connection, response) elif isinstance(request, MsgSniffingStop): if self.pcap_dumper_subprocess is None: self.logger.info("Sniffer process not running") response = MsgSniffingStopReply(request, ok=True) else: try: # the process stops on it's own, we just verify it is stopped time.sleep(TIME_WAIT_FOR_COMPONENTS_FINISH_EXECUTION) # to avoid race conditions if self.pcap_dumper_subprocess.is_alive(): response = MsgSniffingStopReply(request, ok=False) self.logger.info("Sniffer process couldnt be stopped") else: response = MsgSniffingStopReply(request, ok=True) self.logger.info("Sniffer process stopped correctly") self.pcap_dumper_subprocess = None except: m = "Sniffer process couldnt be stopped" self.logger.error(m) response = MsgErrorReply(request, ok=False, error_message=m) # send final response to API call publish_message(self.connection, response) else: pass
def connect_and_publish_message(message: Message): connection = pika.BlockingConnection(pika.URLParameters(AMQP_URL)) publish_message(connection, message)