|
28 | 28 | ) |
29 | 29 | from airbyte_cdk.sources.concurrent_source.stream_thread_exception import StreamThreadException |
30 | 30 | from airbyte_cdk.sources.concurrent_source.thread_pool_manager import ThreadPoolManager |
| 31 | +from airbyte_cdk.sources.declarative.partition_routers.substream_partition_router import ( |
| 32 | + SubstreamPartitionRouter, |
| 33 | +) |
31 | 34 | from airbyte_cdk.sources.message import LogMessage, MessageRepository |
32 | 35 | from airbyte_cdk.sources.streams.concurrent.abstract_stream import AbstractStream |
| 36 | +from airbyte_cdk.sources.streams.concurrent.default_stream import DefaultStream |
33 | 37 | from airbyte_cdk.sources.streams.concurrent.partition_enqueuer import PartitionEnqueuer |
34 | 38 | from airbyte_cdk.sources.streams.concurrent.partition_reader import PartitionReader |
35 | 39 | from airbyte_cdk.sources.streams.concurrent.partitions.partition import Partition |
@@ -822,18 +826,22 @@ def _create_mock_stream(self, name: str, block_simultaneous_read: str = ""): |
822 | 826 | def _create_mock_stream_with_parent( |
823 | 827 | self, name: str, parent_stream, block_simultaneous_read: str = "" |
824 | 828 | ): |
825 | | - """Helper to create a mock stream with a parent stream""" |
826 | | - stream = self._create_mock_stream(name, block_simultaneous_read) |
| 829 | + """Helper to create a mock stream with a parent stream.""" |
| 830 | + stream = Mock(spec=DefaultStream) |
| 831 | + stream.name = name |
| 832 | + stream.block_simultaneous_read = block_simultaneous_read |
| 833 | + stream.as_airbyte_stream.return_value = AirbyteStream( |
| 834 | + name=name, |
| 835 | + json_schema={}, |
| 836 | + supported_sync_modes=[SyncMode.full_refresh], |
| 837 | + ) |
| 838 | + stream.cursor.ensure_at_least_one_state_emitted = Mock() |
827 | 839 |
|
828 | | - # Mock the retriever and partition router for parent relationship |
829 | | - mock_retriever = Mock() |
830 | | - mock_partition_router = Mock() |
| 840 | + mock_partition_router = Mock(spec=SubstreamPartitionRouter) |
831 | 841 | mock_parent_config = Mock() |
832 | 842 | mock_parent_config.stream = parent_stream |
833 | | - |
834 | 843 | mock_partition_router.parent_stream_configs = [mock_parent_config] |
835 | | - mock_retriever.partition_router = mock_partition_router |
836 | | - stream.retriever = mock_retriever |
| 844 | + stream.get_partition_router.return_value = mock_partition_router |
837 | 845 |
|
838 | 846 | return stream |
839 | 847 |
|
@@ -1396,3 +1404,39 @@ def test_child_starts_after_parent_completes_via_partition_complete_sentinel(sel |
1396 | 1404 | ] |
1397 | 1405 | assert len(started_messages) == 1 |
1398 | 1406 | assert started_messages[0].trace.stream_status.stream_descriptor.name == "child" |
| 1407 | + |
| 1408 | + |
| 1409 | +def test_is_done_raises_when_partition_generation_queue_not_empty(): |
| 1410 | + """Test is_done raises AirbyteTracedException if streams remain in the partition generation queue.""" |
| 1411 | + partition_enqueuer = Mock(spec=PartitionEnqueuer) |
| 1412 | + thread_pool_manager = Mock(spec=ThreadPoolManager) |
| 1413 | + logger = Mock(spec=logging.Logger) |
| 1414 | + slice_logger = Mock(spec=SliceLogger) |
| 1415 | + message_repository = Mock(spec=MessageRepository) |
| 1416 | + message_repository.consume_queue.return_value = [] |
| 1417 | + partition_reader = Mock(spec=PartitionReader) |
| 1418 | + |
| 1419 | + stream = Mock(spec=AbstractStream) |
| 1420 | + stream.name = "stuck_stream" |
| 1421 | + stream.block_simultaneous_read = "" |
| 1422 | + stream.as_airbyte_stream.return_value = AirbyteStream( |
| 1423 | + name="stuck_stream", |
| 1424 | + json_schema={}, |
| 1425 | + supported_sync_modes=[SyncMode.full_refresh], |
| 1426 | + ) |
| 1427 | + |
| 1428 | + handler = ConcurrentReadProcessor( |
| 1429 | + [stream], |
| 1430 | + partition_enqueuer, |
| 1431 | + thread_pool_manager, |
| 1432 | + logger, |
| 1433 | + slice_logger, |
| 1434 | + message_repository, |
| 1435 | + partition_reader, |
| 1436 | + ) |
| 1437 | + |
| 1438 | + # Artificially mark the stream as done without removing it from the partition generation queue |
| 1439 | + handler._streams_done.add("stuck_stream") |
| 1440 | + |
| 1441 | + with pytest.raises(AirbyteTracedException, match="remained in the partition generation queue"): |
| 1442 | + handler.is_done() |
0 commit comments