|
1 | 1 | # |
2 | 2 | # Copyright (c) 2023 Airbyte, Inc., all rights reserved. |
3 | 3 | # |
4 | | -from unittest.mock import MagicMock |
| 4 | +from unittest.mock import MagicMock, patch |
5 | 5 |
|
6 | 6 | import pytest |
7 | 7 |
|
8 | 8 | from airbyte_cdk.models import ConfiguredAirbyteCatalogSerializer |
| 9 | +from airbyte_cdk.sources.declarative.retrievers.simple_retriever import SimpleRetriever |
| 10 | +from airbyte_cdk.sources.declarative.types import Record, StreamSlice |
9 | 11 | from airbyte_cdk.test.entrypoint_wrapper import read |
10 | 12 | from airbyte_cdk.test.state_builder import StateBuilder |
11 | 13 | from unit_tests.conftest import get_source |
@@ -97,6 +99,65 @@ def test_notion_properties_transformation(components_module): |
97 | 99 | ] |
98 | 100 |
|
99 | 101 |
|
| 102 | +def test_blocks_retriever_depth_restored_after_children(components_module): |
| 103 | + """ |
| 104 | + Test to verify that current_block_depth is correctly incremented and decremented during recursive calls. |
| 105 | +
|
| 106 | + This test creates a scenario with two sibling blocks at the same level, both having children: |
| 107 | + - Block A (has_children=True) |
| 108 | + - Block A1 (has_children=False) |
| 109 | + - Block B (has_children=True) |
| 110 | + - Block B1 (has_children=False) |
| 111 | +
|
| 112 | + The depth counter should properly increment when entering a child level and decrement when |
| 113 | + returning to the parent level. This ensures sibling blocks are processed at the correct depth. |
| 114 | + """ |
| 115 | + |
| 116 | + retriever = components_module.BlocksRetriever( |
| 117 | + name="test", |
| 118 | + primary_key=["id"], |
| 119 | + requester=MagicMock(), |
| 120 | + record_selector=MagicMock(), |
| 121 | + paginator=MagicMock(), |
| 122 | + config={}, |
| 123 | + parameters={}, |
| 124 | + ) |
| 125 | + retriever._paginator = MagicMock() |
| 126 | + depth_tracker = [] |
| 127 | + |
| 128 | + block_a = Record( |
| 129 | + data={"id": "block-a", "has_children": True}, stream_name="blocks", associated_slice=StreamSlice(partition={}, cursor_slice={}) |
| 130 | + ) |
| 131 | + block_a1 = Record( |
| 132 | + data={"id": "block-a1", "has_children": False}, stream_name="blocks", associated_slice=StreamSlice(partition={}, cursor_slice={}) |
| 133 | + ) |
| 134 | + block_b = Record( |
| 135 | + data={"id": "block-b", "has_children": True}, stream_name="blocks", associated_slice=StreamSlice(partition={}, cursor_slice={}) |
| 136 | + ) |
| 137 | + block_b1 = Record( |
| 138 | + data={"id": "block-b1", "has_children": False}, stream_name="blocks", associated_slice=StreamSlice(partition={}, cursor_slice={}) |
| 139 | + ) |
| 140 | + |
| 141 | + def mock_super_read_records(self, records_schema, stream_slice=None): |
| 142 | + depth_tracker.append(retriever.current_block_depth) |
| 143 | + |
| 144 | + if stream_slice is None or not stream_slice.partition: |
| 145 | + yield block_a |
| 146 | + yield block_b |
| 147 | + elif stream_slice.partition.get("block_id") == "block-a": |
| 148 | + yield block_a1 |
| 149 | + elif stream_slice.partition.get("block_id") == "block-b": |
| 150 | + yield block_b1 |
| 151 | + |
| 152 | + with patch.object(SimpleRetriever, "read_records", mock_super_read_records): |
| 153 | + stream_slice = StreamSlice(partition={}, cursor_slice={}) |
| 154 | + results = list(retriever.read_records({}, stream_slice)) |
| 155 | + |
| 156 | + assert len(depth_tracker) == 3, f"Expected 3 depth measurements, got {len(depth_tracker)}: {depth_tracker}" |
| 157 | + assert depth_tracker == [0, 1, 1], f"Depth should be properly managed. Depth tracker: {depth_tracker}" |
| 158 | + assert retriever.current_block_depth == 0, f"Final depth should be 0, got {retriever.current_block_depth}" |
| 159 | + |
| 160 | + |
100 | 161 | def test_blocks_retriever(requests_mock): |
101 | 162 | page_response_data = { |
102 | 163 | "object": "list", |
|
0 commit comments