@@ -1460,6 +1460,279 @@ def run_incremental_parent_state_test(
1460
1460
],
1461
1461
},
1462
1462
),
1463
+ (
1464
+ "test_incremental_parent_state_one_record_without_cursor" ,
1465
+ SUBSTREAM_MANIFEST ,
1466
+ [
1467
+ # Fetch the first page of posts
1468
+ (
1469
+ f"https://api.example.com/community/posts?per_page=100&start_time={ PARENT_POSTS_CURSOR } " ,
1470
+ {
1471
+ "posts" : [
1472
+ {"id" : 1 , "updated_at" : POST_1_UPDATED_AT },
1473
+ ]
1474
+ },
1475
+ ),
1476
+ # Fetch the first page of comments for post 1
1477
+ (
1478
+ "https://api.example.com/community/posts/1/comments?per_page=100" ,
1479
+ {
1480
+ "comments" : [
1481
+ {
1482
+ "id" : 9 ,
1483
+ "post_id" : 1 ,
1484
+ "updated_at" : COMMENT_9_OLDEST ,
1485
+ },
1486
+ {
1487
+ "id" : 10 ,
1488
+ "post_id" : 1 ,
1489
+ "updated_at" : COMMENT_10_UPDATED_AT ,
1490
+ },
1491
+ {
1492
+ "id" : 11 ,
1493
+ "post_id" : 1 ,
1494
+ "updated_at" : COMMENT_11_UPDATED_AT ,
1495
+ },
1496
+ ]
1497
+ },
1498
+ ),
1499
+ # Fetch the first page of votes for comment 10 of post 1 (vote without cursor field)
1500
+ (
1501
+ f"https://api.example.com/community/posts/1/comments/10/votes?per_page=100&start_time={ INITIAL_STATE_PARTITION_10_CURSOR } " ,
1502
+ {
1503
+ "votes" : [
1504
+ {
1505
+ "id" : 100 ,
1506
+ "comment_id" : 10 ,
1507
+ }
1508
+ ],
1509
+ },
1510
+ ),
1511
+ # Fetch the first page of votes for comment 11 of post 1
1512
+ (
1513
+ f"https://api.example.com/community/posts/1/comments/11/votes"
1514
+ f"?per_page=100&start_time={ INITIAL_STATE_PARTITION_11_CURSOR } " ,
1515
+ {"votes" : [{"id" : 111 , "comment_id" : 11 , "created_at" : VOTE_111_CREATED_AT }]},
1516
+ ),
1517
+ # Requests with intermediate states
1518
+ # Fetch votes for comment 11 of post 1
1519
+ (
1520
+ f"https://api.example.com/community/posts/1/comments/11/votes?per_page=100&start_time={ VOTE_111_CREATED_AT } " ,
1521
+ {
1522
+ "votes" : [{"id" : 111 , "comment_id" : 11 , "created_at" : VOTE_111_CREATED_AT }],
1523
+ },
1524
+ ),
1525
+ ],
1526
+ # Expected records
1527
+ [
1528
+ {"comment_id" : 10 , "comment_updated_at" : COMMENT_10_UPDATED_AT , "id" : 100 },
1529
+ {
1530
+ "comment_id" : 11 ,
1531
+ "comment_updated_at" : COMMENT_11_UPDATED_AT ,
1532
+ "created_at" : "2024-01-13T00:00:00Z" ,
1533
+ "id" : 111 ,
1534
+ },
1535
+ ],
1536
+ # Number of intermediate states - 6 as number of parent partitions
1537
+ 2 ,
1538
+ # Initial state
1539
+ {
1540
+ "parent_state" : {
1541
+ "post_comments" : {
1542
+ "states" : [
1543
+ {
1544
+ "partition" : {"id" : 1 , "parent_slice" : {}},
1545
+ "cursor" : {"updated_at" : PARENT_COMMENT_CURSOR_PARTITION_1 },
1546
+ }
1547
+ ],
1548
+ "parent_state" : {"posts" : {"updated_at" : PARENT_POSTS_CURSOR }},
1549
+ }
1550
+ },
1551
+ "state" : {"created_at" : INITIAL_GLOBAL_CURSOR },
1552
+ "states" : [
1553
+ {
1554
+ "partition" : {
1555
+ "id" : 10 ,
1556
+ "parent_slice" : {"id" : 1 , "parent_slice" : {}},
1557
+ },
1558
+ "cursor" : {"created_at" : INITIAL_STATE_PARTITION_10_CURSOR },
1559
+ },
1560
+ {
1561
+ "partition" : {
1562
+ "id" : 11 ,
1563
+ "parent_slice" : {"id" : 1 , "parent_slice" : {}},
1564
+ },
1565
+ "cursor" : {"created_at" : INITIAL_STATE_PARTITION_11_CURSOR },
1566
+ },
1567
+ ],
1568
+ "lookback_window" : 86400 ,
1569
+ },
1570
+ # Expected state
1571
+ {
1572
+ "state" : {"created_at" : VOTE_111_CREATED_AT },
1573
+ "parent_state" : {
1574
+ "post_comments" : {
1575
+ "use_global_cursor" : False ,
1576
+ "state" : {"updated_at" : COMMENT_10_UPDATED_AT }, # 10 is the "latest"
1577
+ "parent_state" : {
1578
+ "posts" : {"updated_at" : POST_1_UPDATED_AT }
1579
+ }, # post 1 is the latest
1580
+ "lookback_window" : 1 ,
1581
+ "states" : [
1582
+ {
1583
+ "partition" : {"id" : 1 , "parent_slice" : {}},
1584
+ "cursor" : {"updated_at" : COMMENT_10_UPDATED_AT },
1585
+ },
1586
+ ],
1587
+ }
1588
+ },
1589
+ "lookback_window" : 1 ,
1590
+ "use_global_cursor" : False ,
1591
+ "states" : [
1592
+ {
1593
+ "partition" : {"id" : 10 , "parent_slice" : {"id" : 1 , "parent_slice" : {}}},
1594
+ # initial state because record doesn't have a cursor field
1595
+ "cursor" : {"created_at" : INITIAL_STATE_PARTITION_10_CURSOR },
1596
+ },
1597
+ {
1598
+ "partition" : {"id" : 11 , "parent_slice" : {"id" : 1 , "parent_slice" : {}}},
1599
+ "cursor" : {"created_at" : VOTE_111_CREATED_AT },
1600
+ },
1601
+ ],
1602
+ },
1603
+ ),
1604
+ (
1605
+ "test_incremental_parent_state_all_records_without_cursor" ,
1606
+ SUBSTREAM_MANIFEST ,
1607
+ [
1608
+ # Fetch the first page of posts
1609
+ (
1610
+ f"https://api.example.com/community/posts?per_page=100&start_time={ PARENT_POSTS_CURSOR } " ,
1611
+ {
1612
+ "posts" : [
1613
+ {"id" : 1 , "updated_at" : POST_1_UPDATED_AT },
1614
+ ]
1615
+ },
1616
+ ),
1617
+ # Fetch the first page of comments for post 1
1618
+ (
1619
+ "https://api.example.com/community/posts/1/comments?per_page=100" ,
1620
+ {
1621
+ "comments" : [
1622
+ {
1623
+ "id" : 9 ,
1624
+ "post_id" : 1 ,
1625
+ "updated_at" : COMMENT_9_OLDEST ,
1626
+ },
1627
+ {
1628
+ "id" : 10 ,
1629
+ "post_id" : 1 ,
1630
+ "updated_at" : COMMENT_10_UPDATED_AT ,
1631
+ },
1632
+ {
1633
+ "id" : 11 ,
1634
+ "post_id" : 1 ,
1635
+ "updated_at" : COMMENT_11_UPDATED_AT ,
1636
+ },
1637
+ ]
1638
+ },
1639
+ ),
1640
+ # Fetch the first page of votes for comment 10 of post 1 (vote without cursor field)
1641
+ (
1642
+ f"https://api.example.com/community/posts/1/comments/10/votes?per_page=100&start_time={ INITIAL_STATE_PARTITION_10_CURSOR } " ,
1643
+ {
1644
+ "votes" : [
1645
+ {
1646
+ "id" : 100 ,
1647
+ "comment_id" : 10 ,
1648
+ }
1649
+ ],
1650
+ },
1651
+ ),
1652
+ # Fetch the first page of votes for comment 11 of post 1 (vote without cursor field)
1653
+ (
1654
+ f"https://api.example.com/community/posts/1/comments/11/votes"
1655
+ f"?per_page=100&start_time={ INITIAL_STATE_PARTITION_11_CURSOR } " ,
1656
+ {"votes" : [{"id" : 111 , "comment_id" : 11 }]},
1657
+ ),
1658
+ ],
1659
+ # Expected records
1660
+ [
1661
+ {"comment_id" : 10 , "comment_updated_at" : COMMENT_10_UPDATED_AT , "id" : 100 },
1662
+ {
1663
+ "comment_id" : 11 ,
1664
+ "comment_updated_at" : COMMENT_11_UPDATED_AT ,
1665
+ "id" : 111 ,
1666
+ },
1667
+ ],
1668
+ # Number of intermediate states - 6 as number of parent partitions
1669
+ 2 ,
1670
+ # Initial state
1671
+ {
1672
+ "parent_state" : {
1673
+ "post_comments" : {
1674
+ "states" : [
1675
+ {
1676
+ "partition" : {"id" : 1 , "parent_slice" : {}},
1677
+ "cursor" : {"updated_at" : PARENT_COMMENT_CURSOR_PARTITION_1 },
1678
+ }
1679
+ ],
1680
+ "parent_state" : {"posts" : {"updated_at" : PARENT_POSTS_CURSOR }},
1681
+ }
1682
+ },
1683
+ "state" : {"created_at" : INITIAL_GLOBAL_CURSOR },
1684
+ "states" : [
1685
+ {
1686
+ "partition" : {
1687
+ "id" : 10 ,
1688
+ "parent_slice" : {"id" : 1 , "parent_slice" : {}},
1689
+ },
1690
+ "cursor" : {"created_at" : INITIAL_STATE_PARTITION_10_CURSOR },
1691
+ },
1692
+ {
1693
+ "partition" : {
1694
+ "id" : 11 ,
1695
+ "parent_slice" : {"id" : 1 , "parent_slice" : {}},
1696
+ },
1697
+ "cursor" : {"created_at" : INITIAL_STATE_PARTITION_11_CURSOR },
1698
+ },
1699
+ ],
1700
+ "lookback_window" : 86400 ,
1701
+ },
1702
+ # Expected state
1703
+ {
1704
+ "state" : {"created_at" : INITIAL_STATE_PARTITION_11_CURSOR },
1705
+ "parent_state" : {
1706
+ "post_comments" : {
1707
+ "use_global_cursor" : False ,
1708
+ "state" : {"updated_at" : COMMENT_10_UPDATED_AT }, # 10 is the "latest"
1709
+ "parent_state" : {
1710
+ "posts" : {"updated_at" : POST_1_UPDATED_AT }
1711
+ }, # post 1 is the latest
1712
+ "lookback_window" : 1 ,
1713
+ "states" : [
1714
+ {
1715
+ "partition" : {"id" : 1 , "parent_slice" : {}},
1716
+ "cursor" : {"updated_at" : COMMENT_10_UPDATED_AT },
1717
+ },
1718
+ ],
1719
+ }
1720
+ },
1721
+ "lookback_window" : 1 ,
1722
+ "use_global_cursor" : False ,
1723
+ "states" : [
1724
+ {
1725
+ "partition" : {"id" : 10 , "parent_slice" : {"id" : 1 , "parent_slice" : {}}},
1726
+ # initial state because record doesn't have a cursor field
1727
+ "cursor" : {"created_at" : INITIAL_STATE_PARTITION_10_CURSOR },
1728
+ },
1729
+ {
1730
+ "partition" : {"id" : 11 , "parent_slice" : {"id" : 1 , "parent_slice" : {}}},
1731
+ "cursor" : {"created_at" : INITIAL_STATE_PARTITION_11_CURSOR },
1732
+ },
1733
+ ],
1734
+ },
1735
+ ),
1463
1736
],
1464
1737
)
1465
1738
def test_incremental_parent_state (
0 commit comments