def test_WBEMListener_incorrect_headers(desc, headers, exp_status, exp_headers): # pylint: disable=unused-argument """ Verify that WBEMListener send fails when incorrect HTTP headers are used (along with the correct POST method). """ host = 'localhost' http_port = 50000 url = 'http://{}:{}'.format(host, http_port) # headers = copy(headers) listener = WBEMListener(host, http_port) listener.add_callback(process_indication) listener.start() try: # The code to be tested is running in listener thread response = post_bsl(url, headers=headers, data=None) assert response.status_code == exp_status for header_name in exp_headers: assert header_name in response.headers exp_header_pattern = exp_headers[header_name] assert re.match(exp_header_pattern, response.headers[header_name]) finally: listener.stop()
def test_WBEMListener_incorrect_method(method, exp_status): """ Verify that WBEMListener send fails when an incorrect HTTP method is used. """ host = 'localhost' http_port = 50000 url = 'http://{}:{}'.format(host, http_port) headers = { 'Content-Type': 'application/xml; charset=utf-8', 'CIMExport': 'MethodRequest', 'CIMExportMethod': 'ExportIndication', 'Accept-Encoding': 'Identity', 'CIMProtocolVersion': '1.4', } listener = WBEMListener(host, http_port) listener.add_callback(process_indication) listener.start() try: # The code to be tested is running in listener thread response = requests.request(method, url, headers=headers, timeout=4) assert response.status_code == exp_status finally: listener.stop()
def test_WBEMListener_init(testcase, init_args, init_kwargs, exp_attrs): """ Test function for WBEMListener.__init__() """ # The code to be tested obj = WBEMListener(*init_args, **init_kwargs) # Ensure that exceptions raised in the remainder of this function # are not mistaken as expected exceptions assert testcase.exp_exc_types is None # Verify specified expected attributes for attr_name in exp_attrs: exp_attr = exp_attrs[attr_name] act_attr = getattr(obj, attr_name) assert act_attr == exp_attr assert isinstance(act_attr, type(exp_attr)) # Verify attributes not set via init arguments assert isinstance(obj.logger, logging.Logger) assert re.match(r'pywbem\.listener\.', obj.logger.name) assert obj.http_started is False assert obj.https_started is False
def test_context_mgr(self): # pylint: disable=no-self-use """ Test starting the listener and automatic closing in a context manager. """ host = 'localhost' # Don't use this port in other tests, to be on the safe side # as far as port reuse is concerned. http_port = '59998' # The code to be tested (is the context manager) with WBEMListener(host, http_port) as listener1: # Verify that CM enter returns the listener assert isinstance(listener1, WBEMListener) listener1.start() assert listener1.http_started is True # Verify that CM exit stops the listener assert listener1.http_started is False # Verify that the TCP/IP port can be used again listener2 = WBEMListener(host, http_port) listener2.start() assert listener2.http_started is True listener2.stop()
def createlistener(host, http_port=None, https_port=None, certfile=None, keyfile=None): """ Create and start a listener based on host, ports, etc. """ global RCV_COUNT # pylint: disable=global-statement global LISTENER # pylint: disable=global-statement global RCV_FAIL # pylint: disable=global-statement RCV_FAIL = False # pylint: disable=global-statement _logging.basicConfig(stream=_sys.stderr, level=_logging.WARNING, format='%(levelname)s: %(message)s') RCV_COUNT = 0 LISTENER = WBEMListener(host=host, http_port=http_port, https_port=https_port, certfile=certfile, keyfile=keyfile) LISTENER.add_callback(_process_indication) LISTENER.start()
def test_attrs(self): """ Test WBEMListener attributes. """ host = 'localhost' http_port = '50000' # as a string exp_http_port = 50000 # as an integer listener = WBEMListener(host, http_port) assert listener.host == host assert listener.http_port == exp_http_port assert listener.https_port is None assert listener.certfile is None assert listener.keyfile is None assert isinstance(listener.logger, _logging.Logger) assert listener.http_started is False assert listener.https_started is False
def test_WBEMListener_incorrect_payload2(desc, payload, exp_status, exp_headers, exp_payload): # pylint: disable=unused-argument """ Verify that WBEMListener send fails with export response indicating error when incorrect HTTP payload is used that triggers that. """ host = 'localhost' http_port = 50000 url = 'http://{}:{}'.format(host, http_port) headers = { 'Content-Type': 'application/xml; charset=utf-8', 'CIMExport': 'MethodRequest', 'CIMExportMethod': 'ExportIndication', 'Accept-Encoding': 'Identity', 'CIMProtocolVersion': '1.4', } listener = WBEMListener(host, http_port) listener.add_callback(process_indication) listener.start() try: # The code to be tested is running in listener thread response = post_bsl(url, headers=headers, data=payload) assert response.status_code == exp_status for header_name in exp_headers: assert header_name in response.headers exp_header_pattern = exp_headers[header_name] assert re.match(exp_header_pattern, response.headers[header_name]) act_payload = response.content re.match(exp_payload, act_payload, re.MULTILINE) finally: listener.stop()
def test_WBEMListener_send_indications(send_count): """ Test performance of sending indications to the pywbem.WBEMListener. """ if send_count > 100 and sys.platform == 'win32': pytest.skip("Skipping test due to lengthy elapsed time") host = 'localhost' http_port = 50000 listener = WBEMListener(host, http_port) listener.add_callback(process_indication) listener.start() # Warm up send_indications(host, http_port, 10) repetitions = 5 try: times = [] for _ in range(0, repetitions): time = send_indications(host, http_port, send_count) times.append(time) mean_time = statistics.mean(times) stdev_time = statistics.stdev(times) mean_rate = send_count / mean_time print("\nSent {} indications ({} repetitions): mean: {:.3f} s, " "stdev: {:.3f} s, mean rate: {:.0f} ind/s". format(send_count, repetitions, mean_time, stdev_time, mean_rate)) sys.stdout.flush() finally: listener.stop() # Give some time to free up the port sleep(1.0)
def test_WBEMListener_start_stop(): """ Test starting and stopping of the listener. """ host = 'localhost' http_port = '50000' listener = WBEMListener(host, http_port) assert listener.http_started is False assert listener.https_started is False listener.start() assert listener.http_started is True assert listener.https_started is False listener.stop() assert listener.http_started is False assert listener.https_started is False
def createlistener(host, http_port=None, https_port=None, certfile=None, keyfile=None): global RCV_COUNT global LISTENER global RCV_FAIL RCV_FAIL = False _logging.basicConfig(stream=_sys.stderr, level=_logging.WARNING, format='%(levelname)s: %(message)s') RCV_COUNT = 0 LISTENER = WBEMListener(host=host, http_port=http_port, https_port=https_port, certfile=certfile, keyfile=keyfile) LISTENER.add_callback(_process_indication) LISTENER.start()
def test_start_stop(self): # pylint: disable=no-self-use """ Test starting and stopping of the the listener. """ host = 'localhost' http_port = '50000' listener = WBEMListener(host, http_port) assert listener.http_started is False assert listener.https_started is False listener.start() assert listener.http_started is True assert listener.https_started is False listener.stop() assert listener.http_started is False assert listener.https_started is False
def test_port_in_use(self): # pylint: disable=no-self-use """ Test starting the listener when port is in use by another listener. """ host = 'localhost' # Don't use this port in other tests, to be on the safe side # as far as port reuse is concerned. http_port = '59999' exp_exc_type = OSError listener1 = WBEMListener(host, http_port) listener1.start() assert listener1.http_started is True listener2 = WBEMListener(host, http_port) try: # The code to be tested listener2.start() except Exception as exc: # pylint: disable=broad-except # e.g. on Linux assert isinstance(exc, exp_exc_type) assert getattr(exc, 'errno', None) == errno.EADDRINUSE assert listener2.http_started is False else: # e.g. on Windows assert listener2.http_started is True # Verify that in any case, listener1 is still started assert listener1.http_started is True listener1.stop() # cleanup listener2.stop() # cleanup (for cases where it started)
def test_WBEMListener_send_indications(send_count): """ Test WBEMListener with an indication generator. This test sends the number of indications defined by the send_count parameter using HTTP. It confirms that they are all received by the listener. This test validates the main paths of the listener and that the listener can receive large numbers of indications without duplicates or dropping indications. It does not validate all of the possible xml options on indications. Creates the listener, starts the listener, creates the indication XML and adds sequence number and time to the indication instance and sends that instance using requests. The indication instance is modified for each indication count so that each carries its own sequence number. """ # Note: Global variables that are modified must be declared global global RCV_COUNT # pylint: disable=global-statement global RCV_ERRORS # pylint: disable=global-statement # Enable logging for this test function if LOGLEVEL > logging.NOTSET: logging.getLogger('').setLevel(LOGLEVEL) # Fixes issue #528 where on Windows, localhost adds multisecond delay # probably due to hosts table or DNS misconfiguration. if sys.platform == 'win32': host = '127.0.0.1' else: host = 'localhost' http_port = 50000 listener = WBEMListener(host, http_port) listener.add_callback(process_indication) listener.start() try: start_time = time() url = 'http://{}:{}'.format(host, http_port) cim_protocol_version = '1.4' headers = { 'Content-Type': 'application/xml; charset=utf-8', 'CIMExport': 'MethodRequest', 'CIMExportMethod': 'ExportIndication', 'Accept-Encoding': 'Identity', 'CIMProtocolVersion': cim_protocol_version, } # We include Accept-Encoding because of requests issue. # He supplies it if we don't. TODO try None delta_time = time() - start_time random_base = randint(1, 10000) timer = ElapsedTimer() RCV_COUNT = 0 RCV_ERRORS = False for i in range(send_count): msg_id = random_base + i payload = create_indication_data(msg_id, i, delta_time, cim_protocol_version) LOGGER.debug("Testcase sending indication #%s", i) try: response = post_bsl(url, headers=headers, data=payload) except requests.exceptions.RequestException as exc: msg = ("Testcase sending indication #{} raised {}: {}".format( i, exc.__class__.__name__, exc)) LOGGER.error(msg) new_exc = AssertionError(msg) new_exc.__cause__ = None # Disable to see original traceback raise new_exc LOGGER.debug( "Testcase received response from sending " "indication #%s", i) if response.status_code != 200: msg = ("Testcase sending indication #{} failed with HTTP " "status {}".format(i, response.status_code)) LOGGER.error(msg) raise AssertionError(msg) endtime = timer.elapsed_sec() # Make sure the listener thread has processed all indications sleep(1) if VERBOSE_SUMMARY: print("\nSent {} indications in {} sec or {:.2f} ind/sec".format( send_count, endtime, (send_count / endtime))) sys.stdout.flush() assert not RCV_ERRORS, \ "Errors occurred in process_indication(), as printed to stdout" assert send_count == RCV_COUNT, \ "Mismatch between total send count {} and receive count {}". \ format(send_count, RCV_COUNT) finally: listener.stop() # Disable logging for this test function if LOGLEVEL > logging.NOTSET: logging.getLogger('').setLevel(logging.NOTSET)
assert isinstance(obj.logger, logging.Logger) assert re.match(r'pywbem\.listener\.', obj.logger.name) assert obj.http_started is False assert obj.https_started is False TESTCASES_WBEMLISTENER_STR = [ # Testcases for WBEMListener.__str__() / str() # Each list item is a testcase tuple with these items: # * obj: WBEMListener object to be tested. (WBEMListener(host='woot.com', http_port=6997, https_port=6998, certfile='certfile.pem', keyfile='keyfile.pem')), ] @pytest.mark.parametrize("obj", TESTCASES_WBEMLISTENER_STR) def test_WBEMListener_str(obj): """ Test function for WBEMListener.__str__() / str() """ # The code to be tested result = str(obj) assert re.match(r'^WBEMListener\(', result)
def run_test(svr_url, listener_host, user, password, http_listener_port, \ https_listener_port, requested_indications, repeat_loop): """ Runs a test that: 1. Creates a server 2. Creates a dynamic listener and starts ti 3. Creates a filter and subscription 4. Calls the server to execute a method that creates an indication 5. waits for indications to be received. 6. Removes the filter and subscription and stops the listener """ if os.path.exists(LOGFILE): os.remove(LOGFILE) try: conn = WBEMConnection(svr_url, (user, password), no_verification=True) server = WBEMServer(conn) # Create subscription_manager here to be sure we can communicate with # server before Creating listener, etc. sub_mgr = WBEMSubscriptionManager( subscription_manager_id='pegasusIndicationTest') # Add server to subscription manager server_id = sub_mgr.add_server(server) old_filters = sub_mgr.get_all_filters(server_id) old_subs = sub_mgr.get_all_subscriptions(server_id) # TODO filter for our sub mgr if len(old_subs) != 0 or len(old_filters) != 0: sub_mgr.remove_subscriptions(server_id, [inst.path for inst in old_subs]) for filter_ in old_filters: sub_mgr.remove_filter(server_id, filter_.path) except ConnectionError as ce: print('Connection Error %s with %s' % (ce, svr_url)) sys.exit(2) except Error as er: print('Error communicationg with WBEMServer %s' % er) sys.exit(1) # Create the listener and listener call back and start the listener #pylint: disable=global-statement global LISTENER ####stream=sys.stderr, logging.basicConfig(filename='pegasusindicationtest.log', level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s') # Create and start local listener LISTENER = WBEMListener(listener_host, http_port=http_listener_port, https_port=https_listener_port) # Start connect and start listener. LISTENER.add_callback(consume_indication) LISTENER.start() listener_url = '%s://%s:%s' % ('http', 'localhost', http_listener_port) sub_mgr.add_listener_destinations(server_id, listener_url) # Create a dynamic alert indication filter and subscribe for it filter_ = sub_mgr.add_filter(server_id, TEST_CLASS_NAMESPACE, TEST_QUERY, query_language="DMTF:CQL") subscriptions = sub_mgr.add_subscriptions(server_id, filter_.path) # Request server to create indications by invoking method # This is pegasus specific class_name = CIMClassName(TEST_CLASS, namespace=TEST_CLASS_NAMESPACE) while repeat_loop > 0: repeat_loop += -1 global RECEIVED_INDICATION_COUNT, INDICATION_START_TIME RECEIVED_INDICATION_COUNT = 0 INDICATION_START_TIME = None if send_request_for_indications(conn, class_name, requested_indications): # Wait for indications to be received. success = wait_for_indications(requested_indications) if not success: insts = conn.EnumerateInstances('PG_ListenerDestinationQueue', namespace='root/PG_Internal') for inst in insts: print('%s queueFullDropped %s, maxretry %s, InQueue %s' % \ (inst['ListenerDestinationName'], inst['QueueFullDroppedIndications'], inst['RetryAttemptsExceededIndications'], inst['CurrentIndications'])) if repeat_loop > 0: time.sleep(requested_indications / 150) sub_mgr.remove_subscriptions(server_id, [inst.path for inst in subscriptions]) sub_mgr.remove_filter(server_id, filter_.path) sub_mgr.remove_server(server_id) LISTENER.stop() # Test for all expected indications received. if RECEIVED_INDICATION_COUNT != requested_indications: print('Incorrect count of indications received expected=%s, received' '=%s' % (requested_indications, RECEIVED_INDICATION_COUNT)) sys.exit(1) else: print('Success, %s indications' % requested_indications) print('Max time between indications %s' % MAX_TIME_BETWEEN_INDICATIONS)
def run_test( svr_url, listener_host, user, password, http_listener_port, https_listener_port, requested_indications, repeat_loop ): """ Runs a test that: 1. Creates a server 2. Creates a dynamic listener and starts ti 3. Creates a filter and subscription 4. Calls the server to execute a method that creates an indication 5. waits for indications to be received. 6. Removes the filter and subscription and stops the listener """ if os.path.exists(LOGFILE): os.remove(LOGFILE) try: conn = WBEMConnection(svr_url, (user, password), no_verification=True) server = WBEMServer(conn) # Create subscription_manager here to be sure we can communicate with # server before Creating listener, etc. sub_mgr = WBEMSubscriptionManager(subscription_manager_id="pegasusIndicationTest") # Add server to subscription manager server_id = sub_mgr.add_server(server) old_filters = sub_mgr.get_all_filters(server_id) old_subs = sub_mgr.get_all_subscriptions(server_id) # TODO filter for our sub mgr if len(old_subs) != 0 or len(old_filters) != 0: sub_mgr.remove_subscriptions(server_id, [inst.path for inst in old_subs]) for filter_ in old_filters: sub_mgr.remove_filter(server_id, filter_.path) except ConnectionError as ce: print("Connection Error %s with %s" % (ce, svr_url)) sys.exit(2) except Error as er: print("Error communicationg with WBEMServer %s" % er) sys.exit(1) # Create the listener and listener call back and start the listener # pylint: disable=global-statement global LISTENER ####stream=sys.stderr, logging.basicConfig( filename="pegasusindicationtest.log", level=logging.INFO, format="%(asctime)s %(levelname)s: %(message)s" ) # Create and start local listener LISTENER = WBEMListener(listener_host, http_port=http_listener_port, https_port=https_listener_port) # Start connect and start listener. LISTENER.add_callback(consume_indication) LISTENER.start() listener_url = "%s://%s:%s" % ("http", "localhost", http_listener_port) sub_mgr.add_listener_destinations(server_id, listener_url) # Create a dynamic alert indication filter and subscribe for it filter_ = sub_mgr.add_filter(server_id, TEST_CLASS_NAMESPACE, TEST_QUERY, query_language="DMTF:CQL") subscriptions = sub_mgr.add_subscriptions(server_id, filter_.path) # Request server to create indications by invoking method # This is pegasus specific class_name = CIMClassName(TEST_CLASS, namespace=TEST_CLASS_NAMESPACE) while repeat_loop > 0: repeat_loop += -1 global RECEIVED_INDICATION_COUNT, INDICATION_START_TIME RECEIVED_INDICATION_COUNT = 0 INDICATION_START_TIME = None if send_request_for_indications(conn, class_name, requested_indications): # Wait for indications to be received. success = wait_for_indications(requested_indications) if not success: insts = conn.EnumerateInstances("PG_ListenerDestinationQueue", namespace="root/PG_Internal") for inst in insts: print( "%s queueFullDropped %s, maxretry %s, InQueue %s" % ( inst["ListenerDestinationName"], inst["QueueFullDroppedIndications"], inst["RetryAttemptsExceededIndications"], inst["CurrentIndications"], ) ) if repeat_loop > 0: time.sleep(requested_indications / 150) sub_mgr.remove_subscriptions(server_id, [inst.path for inst in subscriptions]) sub_mgr.remove_filter(server_id, filter_.path) sub_mgr.remove_server(server_id) LISTENER.stop() # Test for all expected indications received. if RECEIVED_INDICATION_COUNT != requested_indications: print( "Incorrect count of indications received expected=%s, received" "=%s" % (requested_indications, RECEIVED_INDICATION_COUNT) ) sys.exit(1) else: print("Success, %s indications" % requested_indications) print("Max time between indications %s" % MAX_TIME_BETWEEN_INDICATIONS)