|
5 | 5 | from concurrent.futures import ThreadPoolExecutor |
6 | 6 | from pathlib import Path |
7 | 7 |
|
| 8 | +import pytest |
| 9 | + |
8 | 10 | from fbclient.client import FBClient |
9 | 11 | from fbclient.config import Config, HTTPConfig |
10 | 12 | from fbclient.data_storage import InMemoryDataStorage |
@@ -470,3 +472,88 @@ def close(self, status=None): |
470 | 472 | streaming.stop() |
471 | 473 | broadcaster.stop() |
472 | 474 | streaming_module._WEBSOCKET_TIMEOUT_LOCK.release() |
| 475 | + |
| 476 | + |
| 477 | +class _RecordingWebSocketApp: |
| 478 | + def __init__(self): |
| 479 | + self.close_statuses = [] |
| 480 | + |
| 481 | + def close(self, status=None): |
| 482 | + self.close_statuses.append(status) |
| 483 | + |
| 484 | + |
| 485 | +def _idle_streaming(): |
| 486 | + broadcaster = NoticeBroadcater() |
| 487 | + streaming = Streaming(Config(FAKE_ENV_SECRET, FAKE_URL, FAKE_URL), broadcaster, |
| 488 | + DataUpdateStatusProviderImpl(InMemoryDataStorage()), threading.Event()) |
| 489 | + return streaming, broadcaster |
| 490 | + |
| 491 | + |
| 492 | +@pytest.mark.parametrize('message', [ |
| 493 | + '{"messageType":"pong","data":{}}', |
| 494 | + '{"messageType":"unknown","data":{}}', |
| 495 | + '{"data":{}}', |
| 496 | + '[]', |
| 497 | + 'null', |
| 498 | +]) |
| 499 | +def test_streaming_non_data_sync_message_keeps_connection_open(message): |
| 500 | + streaming, broadcaster = _idle_streaming() |
| 501 | + wsapp = _RecordingWebSocketApp() |
| 502 | + try: |
| 503 | + streaming._on_message(wsapp, message) |
| 504 | + assert wsapp.close_statuses == [] |
| 505 | + assert not streaming._Streaming__self_closed() |
| 506 | + finally: |
| 507 | + streaming.stop() |
| 508 | + broadcaster.stop() |
| 509 | + |
| 510 | + |
| 511 | +@pytest.mark.parametrize('message', [ |
| 512 | + 'invalid json', |
| 513 | + '{"messageType":"data-sync","data":{}}', |
| 514 | + '{"messageType":"data-sync","data":null}', |
| 515 | +]) |
| 516 | +def test_streaming_invalid_message_is_logged_and_next_sync_is_processed(message, mocker): |
| 517 | + streaming, broadcaster = _idle_streaming() |
| 518 | + wsapp = _RecordingWebSocketApp() |
| 519 | + process_data = mocker.patch.object(streaming, '_on_process_data', return_value=True) |
| 520 | + error_log = mocker.patch.object(streaming_module.log, 'error') |
| 521 | + exception_log = mocker.patch.object(streaming_module.log, 'exception') |
| 522 | + try: |
| 523 | + streaming._on_message(wsapp, message) |
| 524 | + assert wsapp.close_statuses == [] |
| 525 | + assert not streaming._Streaming__self_closed() |
| 526 | + process_data.assert_not_called() |
| 527 | + assert error_log.called or exception_log.called |
| 528 | + |
| 529 | + streaming._on_message(wsapp, '{"messageType":"data-sync","data":' |
| 530 | + '{"eventType":"full","featureFlags":[],"segments":[]}}') |
| 531 | + process_data.assert_called_once_with({'eventType': 'full', 'featureFlags': [], 'segments': []}) |
| 532 | + assert wsapp.close_statuses == [] |
| 533 | + finally: |
| 534 | + streaming.stop() |
| 535 | + broadcaster.stop() |
| 536 | + |
| 537 | + |
| 538 | +def test_streaming_data_processing_failure_keeps_connection_open(mocker): |
| 539 | + streaming, broadcaster = _idle_streaming() |
| 540 | + wsapp = _RecordingWebSocketApp() |
| 541 | + streaming._Streaming__wsapp = wsapp |
| 542 | + process_data = mocker.patch.object(streaming, '_on_process_data', side_effect=[False, True]) |
| 543 | + error_log = mocker.patch.object(streaming_module.log, 'error') |
| 544 | + message = ('{"messageType":"data-sync","data":' |
| 545 | + '{"eventType":"full","featureFlags":[],"segments":[]}}') |
| 546 | + try: |
| 547 | + streaming._on_message(wsapp, message) |
| 548 | + assert wsapp.close_statuses == [] |
| 549 | + assert not streaming._Streaming__self_closed() |
| 550 | + error_log.assert_called_once() |
| 551 | + |
| 552 | + streaming._on_message(wsapp, message) |
| 553 | + assert process_data.call_count == 2 |
| 554 | + assert wsapp.close_statuses == [] |
| 555 | + assert not streaming._Streaming__self_closed() |
| 556 | + error_log.assert_called_once() |
| 557 | + finally: |
| 558 | + streaming.stop() |
| 559 | + broadcaster.stop() |
0 commit comments