def generic_test_two_clients_with_message_list(self, message_list): with make_client(endpoint=endpoint, appkey=appkey, reconnect_interval=0) as subscriber: with make_client(endpoint=endpoint, appkey=appkey) as publisher: co1 = ClientObserver() subscriber.observer = co1 co2 = ClientObserver() publisher.observer = co2 so = sync_subscribe(subscriber, channel) for msg in message_list: publisher.publish(channel, msg) sync_publish(publisher, channel, 'finalizer') while 'finalizer' !=\ so.last_received_channel_data['messages'][-1]: print(so.last_received_channel_data) last_data = so.wait_for_channel_data() if last_data['messages'][-1] == 'finalizer': break got_messages = so.extract_received_messages() self.assertEqual(got_messages, message_list + ['finalizer'])
def on_enter_stopped(this): ClientObserver.on_enter_stopped(this) global step if step == 1: step = 2 client.start() elif step == 3: exit.set()
def test_exception_in_solicited_pdu_callback(self): observer = ClientObserver() with make_client(endpoint=endpoint, appkey=appkey, observer=observer) as client: def crashy(ack): print(ack["no-such-field"]) observer.stopped.clear() client.publish(channel, 'message', callback=crashy) observer.wait_stopped()
def test_wrong_subscribe_ack(self): with make_client(endpoint=endpoint, appkey=appkey, reconnect_interval=10) as client: client.observer = ClientObserver() old_received_message =\ client._internal.connection.on_incoming_json client._internal.connection.on_incoming_json =\ lambda *args: None so = SubscriptionObserver() client.subscribe('test_wrong_subscribe_ack', SubscriptionMode.ADVANCED, so) client._queue.join() old_received_message({ u"action": u"rtm/publish/ok", u"body": {}, u"id": 0 }) client._queue.join() expected_log = ['on_leave_connected', 'on_enter_awaiting'] self.assertEqual(client.observer.log[:2], expected_log)
def test_wrong_unsubscribe_ack(self): with make_client(endpoint=endpoint, appkey=appkey) as client: client.observer = ClientObserver() sync_subscribe(client, channel) old_received_message =\ client._internal.connection.on_incoming_text_frame client._internal.connection.on_incoming_text_frame =\ lambda *args: None client.unsubscribe(channel) client._queue.join() old_received_message( b'{"action":"rtm/publish/ok","body":{},"id":1}') client._queue.join() client.observer.wait_connected() expected_log = [ 'on_leave_connected', 'on_enter_awaiting', 'on_leave_awaiting', 'on_enter_connecting', 'on_leave_connecting', 'on_enter_connected', ] self.assertEqual(client.observer.log, expected_log)
def test_reconnect(self): client = Client( endpoint=endpoint, appkey=appkey, reconnect_interval=0, fail_count_threshold=1) client.observer = ClientObserver() client.start() client.observer.wait_connected('First connect timeout') emulate_websocket_disconnect(client) client.observer.wait_disconnected() client.observer.wait_connected('Second connect timeout') client.stop() client.observer.wait_stopped() client.dispose() expected_log = [ 'on_leave_stopped', 'on_enter_connecting', 'on_leave_connecting', 'on_enter_connected', 'on_leave_connected', 'on_enter_awaiting', 'on_leave_awaiting', 'on_enter_connecting', 'on_leave_connecting', 'on_enter_connected', 'on_leave_connected', 'on_enter_stopping', 'on_leave_stopping', 'on_enter_stopped', 'on_leave_stopped', 'on_enter_disposed'] self.assertEqual(client.observer.log, expected_log)
def test_reconnect_zero_threshold(self): client = Client( endpoint=endpoint, appkey=appkey, reconnect_interval=0, fail_count_threshold=0) client.observer = ClientObserver() client.start() client.observer.wait_connected() client._internal._endpoint = 'ws://bogus' emulate_websocket_disconnect(client) client.observer.wait_disconnected() client.observer.wait_stopped() client.dispose() expected_log = [ 'on_leave_stopped', 'on_enter_connecting', 'on_leave_connecting', 'on_enter_connected', 'on_leave_connected', 'on_enter_awaiting', 'on_leave_awaiting', 'on_enter_connecting', 'on_leave_connecting', 'on_enter_stopped', 'on_leave_stopped', 'on_enter_disposed'] self.assertEqual(client.observer.log, expected_log)
def test_start_stop(self): client = Client(endpoint=endpoint, appkey=appkey) client.observer = ClientObserver() client.start() client.observer.wait_connected() client.stop() client.observer.wait_stopped() expected_log_1 = [ 'on_leave_stopped', 'on_enter_connecting', 'on_leave_connecting', 'on_enter_connected', 'on_leave_connected', 'on_enter_stopping', 'on_leave_stopping', 'on_enter_stopped'] expected_log_2 = [ 'on_leave_stopped', 'on_enter_connecting', 'on_leave_connecting', 'on_enter_stopped'] try: self.assertEqual(client.observer.log, expected_log_1) except: self.assertEqual(client.observer.log, expected_log_2)
def test_two_clients_with_best_effort_delivery(self): with make_client(endpoint=endpoint, appkey=appkey, reconnect_interval=0) as subscriber: with make_client(endpoint=endpoint, appkey=appkey) as publisher: co1 = ClientObserver() subscriber.observer = co1 co2 = ClientObserver() publisher.observer = co2 try: so = sync_subscribe(subscriber, channel, mode=SubscriptionMode.RELIABLE) sync_publish(publisher, channel, 'first-message') so.wait_for_channel_data('First receive timeout') emulate_websocket_disconnect(subscriber) so.wait_not_subscribed() # send a message while subscriber is disconnected sync_publish(publisher, channel, 'second-message') so.wait_subscribed('Second subscribe timeout') so.wait_for_channel_data('Second receive timeout') # send a message after subscribed reconnected publisher.publish(channel, 'third-message') so.wait_for_channel_data('Third receive timeout') expected_messages =\ ['first-message', 'second-message', 'third-message'] got_messages = [] for log_entry in so.log: if log_entry[0] == 'data': got_messages += log_entry[1]['messages'] self.assertEqual(got_messages, expected_messages) except Exception: print('Subscriber log: {0}'.format(co1.log)) print('Publisher log: {0}'.format(co2.log)) print('Subscription log: {0}'.format(so.log)) raise
def test_exception_in_subscription_data_callback(self): observer = ClientObserver() with make_client(endpoint=endpoint, appkey=appkey, observer=observer) as client: class CrashyObserver(SubscriptionObserver): def on_subscription_data(this, data): SubscriptionObserver.on_subscription_data(this, data) raise ValueError('Error in on_subscription_data') observer.stopped.clear() so = CrashyObserver() client.subscribe(channel, SubscriptionMode.SIMPLE, so) so.wait_subscribed() client.publish(channel, 'message') observer.wait_stopped()
def test_stop_already_stopped(self): client = Client(endpoint=endpoint, appkey=appkey) client.observer = ClientObserver() client.stop() client.dispose() expected_log = ['on_leave_stopped', 'on_enter_disposed'] self.assertEqual(client.observer.log, expected_log)
def test_subscribe_error_and_resubscribe_with_no_position(self): with make_client(endpoint=endpoint, appkey=appkey, reconnect_interval=1) as client: client.observer = ClientObserver() ev = threading.Event() threads = [] class RecoveringSubscriptionObserver(SubscriptionObserver): def on_enter_failed(this, error): this.log.append(('on_enter_failed', error)) if error == 'Subscribe error': import threading def resubscribe_sans_position(): client.unsubscribe(channel) client.subscribe(channel, SubscriptionMode.ADVANCED, this) ev.set() t = threading.Thread( target=resubscribe_sans_position, name='test_resubscribe_sans_position') t.start() threads.append(t) so = RecoveringSubscriptionObserver() client.subscribe(channel, SubscriptionMode.ADVANCED, so, args={'position': 'this_is_invalid_position'}) ev.wait(10) so.wait_subscribed() expected_log = [ 'on_leave_unsubscribed', 'on_enter_subscribing', 'on_leave_subscribing', ('on_enter_failed', 'Subscribe error'), 'on_leave_failed', 'on_enter_unsubscribed', 'on_deleted', 'on_created', 'on_leave_unsubscribed', 'on_enter_subscribing', 'on_leave_subscribing', 'on_enter_subscribed' ] self.assertEqual(so.log, expected_log) sync_publish(client, channel, 'message') data = so.wait_for_channel_data() self.assertEqual(data['subscription_id'], channel) self.assertEqual(data['messages'], ['message']) threads[0].join()
def test_fast_forward(self): with make_client(endpoint=endpoint, appkey=appkey) as client: sync_subscribe(client, channel) co = ClientObserver() client.observer = co emulate_fast_forward(client, channel) client._queue.join() self.assertEqual([('on_fast_forward', channel)], co.log)
def test_two_clients(self): with make_client(endpoint=endpoint, appkey=appkey, reconnect_interval=0) as subscriber: with make_client(endpoint=endpoint, appkey=appkey) as publisher: co1 = ClientObserver() subscriber.observer = co1 co2 = ClientObserver() publisher.observer = co2 try: so = sync_subscribe(subscriber, channel) sync_publish(publisher, channel, 'first-message') so.wait_for_channel_data('First receive timeout') emulate_websocket_disconnect(subscriber) so.wait_not_subscribed() # send a message while subscriber is disconnected sync_publish(publisher, channel, 'second-message') so.wait_subscribed('Second subscribe timeout') so.wait_for_channel_data('Second receive timeout') # send a message after subscribed reconnected publisher.publish(channel, 'third-message') so.wait_for_channel_data('Third receive timeout') expected_messages =\ ['first-message', 'second-message', 'third-message'] got_messages = so.extract_received_messages() self.assertEqual(got_messages, expected_messages) except Exception: print('Subscriber log: {0}'.format(co1.log)) print('Publisher log: {0}'.format(co2.log)) print('Subscription log: {0}'.format(so.log)) raise
def test_ack_with_no_id(self): with make_client( endpoint=endpoint, appkey=appkey, reconnect_interval=10)\ as client: client.observer = ClientObserver() client._internal.connection.on_incoming_text_frame( b'{"action":"rtm/publish/ok", "body":{}}') client._queue.join() expected_log = ['on_leave_connected', 'on_enter_awaiting'] self.assertEqual(client.observer.log, expected_log)
def test_unsolicited_error(self): with make_client( endpoint=endpoint, appkey=appkey, reconnect_interval=10)\ as client: client.observer = ClientObserver() client._internal.connection.on_incoming_text_frame( b'{"action":"/error", "body":{"error":"bad"}}') client._queue.join() expected_log = ['on_leave_connected', 'on_enter_awaiting'] self.assertEqual(client.observer.log, expected_log)
def test_change_observer(self): with make_client(endpoint=endpoint, appkey=appkey) as client: co = ClientObserver() client.observer = co channel = make_channel_name('change_observer') so1 = sync_subscribe(client, channel) client.unsubscribe(channel) so2 = SubscriptionObserver() client.subscribe(channel, SubscriptionMode.ADVANCED, subscription_observer=so2) so2.wait_subscribed() client.stop() co.wait_disconnected() self.maxDiff = None expected_so1_log = [ 'on_leave_unsubscribed', 'on_enter_subscribing', 'on_leave_subscribing', 'on_enter_subscribed', 'on_leave_subscribed', 'on_enter_unsubscribing', 'on_leave_unsubscribing', 'on_enter_unsubscribed', 'on_deleted' ] expected_so2_log = [ 'on_created', 'on_leave_unsubscribed', 'on_enter_subscribing', 'on_leave_subscribing', 'on_enter_subscribed' ] self.assertEqual(so1.log, expected_so1_log) self.assertEqual(so2.log, expected_so2_log)
def test_reauth(self): client = Client(endpoint=endpoint, appkey=appkey, reconnect_interval=0) auth_delegate = auth.RoleSecretAuthDelegate(role, secret) auth_event = threading.Event() mailbox = [] co = ClientObserver() client.observer = co client.start() co.wait_connected() def auth_callback(auth_result): if type(auth_result) == auth.Done: mailbox.append('Auth success') auth_event.set() else: mailbox.append('Auth failure: {0}'.format( auth_result.message)) auth_event.set() client.authenticate(auth_delegate, auth_callback) if not auth_event.wait(30): raise RuntimeError("Auth timeout") self.assertEqual(mailbox, ['Auth success']) so = sync_subscribe(client, restricted_channel) message1 = make_channel_name('before disconnect') sync_publish(client, restricted_channel, message1) first_data = so.wait_for_channel_data() self.assertTrue(message1 in first_data['messages']) emulate_websocket_disconnect(client) co.wait_disconnected() co.wait_connected() message2 = make_channel_name('after reconnect') sync_publish(client, restricted_channel, message2) second_data = so.wait_for_channel_data() self.assertTrue(message2 in second_data['messages']) client.stop() client.dispose()
def test_pdu_with_no_action(self): with make_client( endpoint=endpoint, appkey=appkey, reconnect_interval=10)\ as client: client.observer = ClientObserver() client._internal.connection.on_incoming_json({ u"body": {}, u"id": 42 }) client._queue.join() expected_log = ['on_leave_connected', 'on_enter_awaiting'] self.assertEqual(client.observer.log, expected_log)
def test_automatic_resubscribe(self): client = Client( endpoint=endpoint, appkey=appkey, reconnect_interval=0) client.observer = ClientObserver() channel = make_channel_name('resubscribe') client.start() client.observer.wait_connected('First connect timeout') so = sync_subscribe(client, channel) sync_publish(client, channel, 'first-message') first_channel_data = so.wait_for_channel_data() emulate_websocket_disconnect(client) so.wait_not_subscribed() client.observer.wait_disconnected() client.observer.wait_connected('Second connect timeout') so.wait_subscribed('Second subscribe timeout') sync_publish(client, channel, 'second-message') second_channel_data = so.wait_for_channel_data() client.unsubscribe(channel) so.wait_not_subscribed() client.stop() client.dispose() expected_log = [ 'on_leave_unsubscribed', 'on_enter_subscribing', 'on_leave_subscribing', 'on_enter_subscribed', ('data', first_channel_data), # point of disconnect 'on_leave_subscribed', 'on_enter_unsubscribed', # point of reconnect 'on_leave_unsubscribed', 'on_enter_subscribing', 'on_leave_subscribing', 'on_enter_subscribed', ('data', second_channel_data), 'on_leave_subscribed', 'on_enter_unsubscribing', 'on_leave_unsubscribing', 'on_enter_unsubscribed', 'on_deleted'] self.assertEqual(so.log, expected_log)
def test_subscribe_error(self): with make_client(endpoint=endpoint, appkey=appkey, reconnect_interval=1) as client: client.observer = ClientObserver() so = SubscriptionObserver() client.subscribe(channel, SubscriptionMode.ADVANCED, so, {'position': 'this_is_invalid_position'}) so.wait_failed() expected_log = [ 'on_leave_unsubscribed', 'on_enter_subscribing', 'on_leave_subscribing', ('on_enter_failed', 'Subscribe error') ] self.assertEqual(so.log, expected_log)
def test_start_wait_stop(self): client = Client(endpoint=endpoint, appkey=appkey) client.observer = ClientObserver() client.start() client.observer.wait_connected() client.stop() client.observer.wait_stopped() client.dispose() expected_log = [ 'on_leave_stopped', 'on_enter_connecting', 'on_leave_connecting', 'on_enter_connected', 'on_leave_connected', 'on_enter_stopping', 'on_leave_stopping', 'on_enter_stopped', 'on_leave_stopped', 'on_enter_disposed' ] self.assertEqual(client.observer.log, expected_log)
def test_missing_pong(self): satori.rtm.connection.ping_interval_in_seconds = 0.4 client = Client(endpoint=endpoint, appkey=appkey, reconnect_interval=0) co = ClientObserver() client.observer = co client.start() client.observer.wait_connected('First connect timeout') # emulate the absence of server pongs and silence in the socket client._internal.connection.on_ws_ponged = lambda: None client._internal.connection.last_ponged_time = 0 client._internal.connection.on_ws_pong = lambda x, y: None client.observer.wait_disconnected('First disconnect timeout') client.observer.wait_connected('Second connect timeout') client.stop() client.dispose() satori.rtm.connection.ping_interval_in_seconds = 60
def test_double_subscribe(self): with make_client(endpoint=endpoint, appkey=appkey, reconnect_interval=1) as client: client.observer = ClientObserver() so = sync_subscribe(client, channel) client.subscribe(channel, SubscriptionMode.ADVANCED, subscription_observer=so) sync_publish(client, channel, 'message') data = so.wait_for_channel_data() expected_log = [ 'on_leave_unsubscribed', 'on_enter_subscribing', 'on_leave_subscribing', 'on_enter_subscribed', ('data', data) ] self.assertEqual(so.log, expected_log)
def test_before_start(self): client = Client(endpoint=endpoint, appkey=appkey) co = ClientObserver() client.observer = co so = SubscriptionObserver() client.subscribe(channel, SubscriptionMode.ADVANCED, subscription_observer=so) client.start() co.wait_connected() sync_publish(client, channel, 'message') channel_data = so.wait_for_channel_data() self.assertEqual(channel_data['messages'], ['message']) client.stop() co.wait_stopped()
def test_resubscribe_after_manual_reconnect(self): with make_client(endpoint, appkey) as client: channel = make_channel_name('manual_reconnect') so = sync_subscribe(client, channel) sync_publish(client, channel, 'first-message') m = so.wait_for_channel_data() self.assertEqual(m['messages'], ['first-message']) client.observer = ClientObserver() client.stop() client.observer.wait_disconnected() client.start() client._queue.join() client.observer.wait_connected() sync_publish(client, channel, 'second-message') m = so.wait_for_channel_data() self.assertEqual(m['messages'], ['second-message'])
def test_internal_error(self): with make_client( endpoint=endpoint, appkey=appkey, reconnect_interval=10)\ as client: client.observer = ClientObserver() old_received_message =\ client._internal.connection.on_incoming_text_frame client._internal.connection.on_incoming_text_frame =\ lambda *args: None so = SubscriptionObserver() client.subscribe('test_internal_error', SubscriptionMode.ADVANCED, so) old_received_message("not-a-json-object") client._queue.join() expected_log = ['on_leave_connected', 'on_enter_awaiting'] self.assertEqual(client.observer.log, expected_log)
def test_repeat_second_message(self): client = Client(endpoint=endpoint, appkey=appkey, reconnect_interval=1) client.observer = ClientObserver() channel = make_channel_name('resubscribe') client.start() client.observer.wait_connected() so = sync_subscribe(client, channel) sync_publish(client, channel, 'first-message') first_channel_data = so.wait_for_channel_data() sync_publish(client, channel, 'second-message') second_channel_data = so.wait_for_channel_data() client.unsubscribe(channel) client.subscribe(channel, SubscriptionMode.ADVANCED, so, args={'position': first_channel_data['position']}) self.assertEqual(second_channel_data['messages'], so.wait_for_channel_data()['messages']) client.unsubscribe(channel) so.wait_not_subscribed() client.stop() client.dispose()
def on_enter_stopped(this): ClientObserver.on_enter_stopped(this) client.dispose() raise ValueError('Division by zero')
def on_enter_connected(this): ClientObserver.on_enter_connected(this) global step if step == 2: step = 3 client.stop()