From 042515a2c689219b27ff223e8f936cb3597f6ae7 Mon Sep 17 00:00:00 2001 From: wu-hui Date: Tue, 13 May 2025 16:12:21 -0400 Subject: [PATCH] [realppl 8] realppl spec tests --- .../Firestore.xcodeproj/project.pbxproj | 100 +- .../Tests/SpecTests/FSTLevelDBSpecTests.mm | 14 + .../Tests/SpecTests/FSTMemorySpecTests.mm | 14 + .../Example/Tests/SpecTests/FSTSpecTests.h | 8 +- .../Example/Tests/SpecTests/FSTSpecTests.mm | 109 +- .../Tests/SpecTests/FSTSyncEngineTestDriver.h | 9 +- .../SpecTests/FSTSyncEngineTestDriver.mm | 67 +- .../SpecTests/json/bundle_spec_test.json | 4 +- .../json/existence_filter_spec_test.json | 4 +- .../Tests/SpecTests/json/index_spec_test.json | 12 +- .../Tests/SpecTests/json/limbo_spec_test.json | 1916 ++++++++++++++++- .../json/listen_source_spec_test.json | 18 +- .../SpecTests/json/listen_spec_test.json | 354 ++- .../Tests/SpecTests/json/query_spec_test.json | 318 +++ Firestore/core/src/core/event_manager.cc | 10 +- Firestore/core/src/core/pipeline_util.cc | 6 +- Firestore/core/src/remote/remote_event.cc | 68 +- Firestore/core/src/remote/serializer.cc | 4 +- .../unit/core/pipeline/canonify_eq_test.cc | 18 +- 19 files changed, 2890 insertions(+), 163 deletions(-) diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index f708dfe4c85..7307e9abf60 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -139,6 +139,7 @@ 1145D70555D8CDC75183A88C /* leveldb_mutation_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5C7942B6244F4C416B11B86C /* leveldb_mutation_queue_test.cc */; }; 11627F3A48F710D654829807 /* comparison_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 87DD1A65EBA9FFC1FFAAE657 /* comparison_test.cc */; }; 117AFA7934A52466633E12C1 /* FSTTestingHooks.mm in Sources */ = {isa = PBXBuildFile; fileRef = D85AC18C55650ED230A71B82 /* FSTTestingHooks.mm */; }; + 11A5189E73D954824F015424 /* pipeline_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0401C6FDE59C493BFBD5DFED /* pipeline_util_test.cc */; }; 11BC867491A6631D37DE56A8 /* async_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 872C92ABD71B12784A1C5520 /* async_testing.cc */; }; 11EBD28DBD24063332433947 /* value_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 40F9D09063A07F710811A84F /* value_util_test.cc */; }; 11F8EE69182C9699E90A9E3D /* database_info_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB38D92E20235D22000A432D /* database_info_test.cc */; }; @@ -334,7 +335,6 @@ 2AAEABFD550255271E3BAC91 /* to_string_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = B68B1E002213A764008977EF /* to_string_apple_test.mm */; }; 2ABA80088D70E7A58F95F7D8 /* delayed_constructor_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D0A6E9136804A41CEC9D55D4 /* delayed_constructor_test.cc */; }; 2AC442FEC73D872B5751523D /* error_handling_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B37729DE4DE097CBBCB9B0DD /* error_handling_test.cc */; }; - 2AD2CB51469AE35331C39258 /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 2AD8EE91928AE68DF268BEDA /* limbo_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129E1F315EE100DD57A1 /* limbo_spec_test.json */; }; 2AD98CD29CC6F820A74CDD5E /* Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B59C0A7B2A4548496ED4E7D /* Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json */; }; 2AE3914BBC4EDF91BD852939 /* memory_query_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8EF6A33BC2D84233C355F1D0 /* memory_query_engine_test.cc */; }; @@ -366,8 +366,8 @@ 2F8FDF35BBB549A6F4D2118E /* FSTMemorySpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */; }; 2FA0BAE32D587DF2EA5EEB97 /* async_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6FB467B208E9A8200554BA2 /* async_queue_test.cc */; }; 2FAE0BCBE559ED7214AEFEB7 /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 0D964D4936953635AC7E0834 /* Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json */; }; - 2FDBDA7CB161F4F26CD7E0DE /* utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1924149B429A2020C3CD94D6 /* utils.cc */; }; 2FC2B732841BF2C425EB35DF /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */; }; + 2FDBDA7CB161F4F26CD7E0DE /* utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1924149B429A2020C3CD94D6 /* utils.cc */; }; 3040FD156E1B7C92B0F2A70C /* ordered_code_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0473AFFF5567E667A125347B /* ordered_code_benchmark.cc */; }; 3056418E81BC7584FBE8AD6C /* user_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CCC9BD953F121B9E29F9AA42 /* user_test.cc */; }; 306E762DC6B829CED4FD995D /* target_id_generator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380CF82019382300D97691 /* target_id_generator_test.cc */; }; @@ -441,7 +441,6 @@ 3B37BD3C13A66625EC82CF77 /* hard_assert_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 444B7AB3F5A2929070CB1363 /* hard_assert_test.cc */; }; 3B47CC43DBA24434E215B8ED /* memory_index_manager_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = DB5A1E760451189DA36028B3 /* memory_index_manager_test.cc */; }; 3B496F47CE9E663B8A22FB43 /* nested_properties_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8AC88AA2B929CFEC2656E37D /* nested_properties_test.cc */; }; - 3B4CFB45208A7EEF1EA58ADC /* pipeline.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7142B5EC46E88349FAB3384F /* pipeline.pb.cc */; }; 3B5CEA04AC1627256A1AE8BA /* bloom_filter_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A2E6F09AD1EE0A6A452E9A08 /* bloom_filter_test.cc */; }; 3B843E4C1F3A182900548890 /* remote_store_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */; }; 3BA4EEA6153B3833F86B8104 /* writer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BC3C788D290A935C353CEAA1 /* writer_test.cc */; }; @@ -520,6 +519,7 @@ 48720B5768AFA2B2F3E14C04 /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = D8E530B27D5641B9C26A452C /* Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json */; }; 48926FF55484E996B474D32F /* Validation_BloomFilterTest_MD5_500_01_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = DD990FD89C165F4064B4F608 /* Validation_BloomFilterTest_MD5_500_01_membership_test_result.json */; }; 489D672CAA09B9BC66798E9F /* status.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9920B89AAC00B5BCE7 /* status.pb.cc */; }; + 48A9AD22B0601C52B0522CF7 /* pipeline_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0401C6FDE59C493BFBD5DFED /* pipeline_util_test.cc */; }; 48BC5801432127A90CFF55E3 /* index.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 395E8B07639E69290A929695 /* index.pb.cc */; }; 48D1B38B93D34F1B82320577 /* view_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = A5466E7809AD2871FFDE6C76 /* view_testing.cc */; }; 48F44AA226FAD5DE4EAC3798 /* leveldb_query_engine_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = DB1F1E1B1ED15E8D042144B1 /* leveldb_query_engine_test.cc */; }; @@ -702,7 +702,6 @@ 54C2294F1FECABAE007D065B /* log_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54C2294E1FECABAE007D065B /* log_test.cc */; }; 54C3242322D3B627000FE6DD /* CodableIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124C932B22C1642C00CA8C2D /* CodableIntegrationTests.swift */; }; 54D400D42148BACE001D2BCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 54D400D32148BACE001D2BCC /* GoogleService-Info.plist */; }; - 54D54C9289C8AD6254887E56 /* Pods_Firestore_FuzzTests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B037EE2F287E5D070C81D0F /* Pods_Firestore_FuzzTests_iOS.framework */; }; 54DA12A61F315EE100DD57A1 /* collection_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129C1F315EE100DD57A1 /* collection_spec_test.json */; }; 54DA12A71F315EE100DD57A1 /* existence_filter_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129D1F315EE100DD57A1 /* existence_filter_spec_test.json */; }; 54DA12A81F315EE100DD57A1 /* limbo_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129E1F315EE100DD57A1 /* limbo_spec_test.json */; }; @@ -719,6 +718,7 @@ 5556B648B9B1C2F79A706B4F /* common.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 544129D221C2DDC800EFB9CC /* common.pb.cc */; }; 55B9A6ACDF95D356EA501D92 /* Pods_Firestore_Example_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB5A5E6DD07DA3EB7AD46CA7 /* Pods_Firestore_Example_iOS.framework */; }; 55E84644D385A70E607A0F91 /* leveldb_local_store_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5FF903AEFA7A3284660FA4C5 /* leveldb_local_store_test.cc */; }; + 563FE05627C7E66469E99292 /* pipeline_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0401C6FDE59C493BFBD5DFED /* pipeline_util_test.cc */; }; 568EC1C0F68A7B95E57C8C6C /* leveldb_key_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54995F6E205B6E12004EFFA0 /* leveldb_key_test.cc */; }; 56D85436D3C864B804851B15 /* string_format_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFD366B783AE27B9E79EE7A /* string_format_apple_test.mm */; }; 57171BD004A1691B19A76453 /* Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = C939D1789E38C09F9A0C1157 /* Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json */; }; @@ -956,6 +956,7 @@ 75C6CECF607CA94F56260BAB /* memory_document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 29D9C76922DAC6F710BC1EF4 /* memory_document_overlay_cache_test.cc */; }; 75CC1D1F7F1093C2E09D9998 /* inequality_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A410E38FA5C3EB5AECDB6F1C /* inequality_test.cc */; }; 75D124966E727829A5F99249 /* FIRTypeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E071202154D600B64F25 /* FIRTypeTests.mm */; }; + 7676C06AF7FF67806747E4F0 /* pipeline_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0401C6FDE59C493BFBD5DFED /* pipeline_util_test.cc */; }; 76A5447D76F060E996555109 /* task_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 899FC22684B0F7BEEAE13527 /* task_test.cc */; }; 76AD5862714F170251BDEACB /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = A5D9044B72061CAF284BC9E4 /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json */; }; 76C18D1BA96E4F5DF1BF7F4B /* Validation_BloomFilterTest_MD5_500_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 8AB49283E544497A9C5A0E59 /* Validation_BloomFilterTest_MD5_500_1_membership_test_result.json */; }; @@ -1213,8 +1214,8 @@ A25FF76DEF542E01A2DF3B0E /* time_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5497CB76229DECDE000FB92F /* time_testing.cc */; }; A27096F764227BC73526FED3 /* leveldb_remote_document_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0840319686A223CC4AD3FAB1 /* leveldb_remote_document_cache_test.cc */; }; A27908A198E1D2230C1801AC /* bundle_serializer_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5C2A94EE24E60543F62CC35 /* bundle_serializer_test.cc */; }; - A29D82322423DA4EE09C81BE /* null_semantics_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = DD520991DBDF5C11BBFAFE6D /* null_semantics_test.cc */; }; A296B0110550890E1D8D59A3 /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */; }; + A29D82322423DA4EE09C81BE /* null_semantics_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = DD520991DBDF5C11BBFAFE6D /* null_semantics_test.cc */; }; A2E9978E02F7BCB016555F09 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 3369AC938F82A70685C5ED58 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json */; }; A3262936317851958C8EABAF /* byte_stream_cpp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 01D10113ECC5B446DB35E96D /* byte_stream_cpp_test.cc */; }; A405A976DB6444D3ED3FCAB2 /* timestamp_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 82DF854A7238D538FA53C908 /* timestamp_test.cc */; }; @@ -1224,7 +1225,6 @@ A4ECA8335000CBDF94586C94 /* FSTDatastoreTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E07E202154EC00B64F25 /* FSTDatastoreTests.mm */; }; A4F2B68E7EFADB0EB443CFF8 /* Pods_Firestore_Tests_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8294C2063C0096AE5E43F6DF /* Pods_Firestore_Tests_iOS.framework */; }; A5175CA2E677E13CC5F23D72 /* document_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB6B908320322E4D00CC290A /* document_test.cc */; }; - A5301AA55748A11801E3EE47 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = FAAF1A69F4A315C38357BDC4 /* field_behavior.pb.cc */; }; A53C9BA3D0E366DCCDD640BF /* canonify_eq_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 51004EAF5EE01ADCE8FE3788 /* canonify_eq_test.cc */; }; A55266E6C986251D283CE948 /* FIRCursorTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E070202154D600B64F25 /* FIRCursorTests.mm */; }; A5583822218F9D5B1E86FCAC /* overlay_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E1459FA70B8FC18DE4B80D0D /* overlay_test.cc */; }; @@ -1243,8 +1243,8 @@ A7309DAD4A3B5334536ECA46 /* remote_event_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 584AE2C37A55B408541A6FF3 /* remote_event_test.cc */; }; A7399FB3BEC50BBFF08EC9BA /* mutation_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3068AA9DFBBA86C1FE2A946E /* mutation_queue_test.cc */; }; A7669E72BCED7FBADA4B1314 /* thread_safe_memoizer_testing_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = EA10515F99A42D71DA2D2841 /* thread_safe_memoizer_testing_test.cc */; }; - A78366DBE0BFDE42474A728A /* TestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E73D03B9C02CAC7BEBAFA86 /* TestHelper.swift */; }; A76A3879A497533584C91D97 /* sort_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 15EAAEEE767299A3CDA96132 /* sort_test.cc */; }; + A78366DBE0BFDE42474A728A /* TestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E73D03B9C02CAC7BEBAFA86 /* TestHelper.swift */; }; A80D38096052F928B17E1504 /* user_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = CCC9BD953F121B9E29F9AA42 /* user_test.cc */; }; A833A216988ADFD4876763CD /* Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = C8FB22BCB9F454DA44BA80C8 /* Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json */; }; A841EEB5A94A271523EAE459 /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = A5D9044B72061CAF284BC9E4 /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json */; }; @@ -1642,6 +1642,7 @@ E1016ECF143B732E7821358E /* byte_stream_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7628664347B9C96462D4BF17 /* byte_stream_apple_test.mm */; }; E11DDA3DD75705F26245E295 /* FIRCollectionReferenceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E045202154AA00B64F25 /* FIRCollectionReferenceTests.mm */; }; E1264B172412967A09993EC6 /* byte_string_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5342CDDB137B4E93E2E85CCA /* byte_string_test.cc */; }; + E14DBE1D9FC94B5E7E391BEE /* pipeline_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0401C6FDE59C493BFBD5DFED /* pipeline_util_test.cc */; }; E15A05789FF01F44BCAE75EF /* fields_array_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA4CBA48204C9E25B56993BC /* fields_array_test.cc */; }; E186D002520881AD2906ADDB /* status.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9920B89AAC00B5BCE7 /* status.pb.cc */; }; E1DB8E1A4CF3DCE2AE8454D8 /* string_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = EEF23C7104A4D040C3A8CF9B /* string_test.cc */; }; @@ -1667,6 +1668,7 @@ E54AC3EA240C05B3720A2FE9 /* Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json in Resources */ = {isa = PBXBuildFile; fileRef = 728F617782600536F2561463 /* Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json */; }; E56EEC9DAC455E2BE77D110A /* memory_document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 29D9C76922DAC6F710BC1EF4 /* memory_document_overlay_cache_test.cc */; }; E59F597947D3E130A57E1B5E /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json in Resources */ = {isa = PBXBuildFile; fileRef = 3369AC938F82A70685C5ED58 /* Validation_BloomFilterTest_MD5_1_1_membership_test_result.json */; }; + E5FE2BEECD70D59361B51540 /* pipeline_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0401C6FDE59C493BFBD5DFED /* pipeline_util_test.cc */; }; E63342115B1DA65DB6F2C59A /* leveldb_local_store_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5FF903AEFA7A3284660FA4C5 /* leveldb_local_store_test.cc */; }; E6357221227031DD77EE5265 /* index_manager_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AE4A9E38D65688EE000EE2A1 /* index_manager_test.cc */; }; E6603BA4B16C9E1422DD3A4B /* FSTTestingHooks.mm in Sources */ = {isa = PBXBuildFile; fileRef = D85AC18C55650ED230A71B82 /* FSTTestingHooks.mm */; }; @@ -1691,8 +1693,8 @@ E8AB8024B70F6C960D8C7530 /* document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = FFCA39825D9678A03D1845D0 /* document_overlay_cache_test.cc */; }; E8BA7055EDB8B03CC99A528F /* recovery_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 9C1AFCC9E616EC33D6E169CF /* recovery_spec_test.json */; }; E8BB7CCF3928A5866B1C9B86 /* arithmetic_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 76EED4ED84056B623D92FE20 /* arithmetic_test.cc */; }; - E92D194F027C325631036B75 /* unicode_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 09C56D14F17CA02A07C60847 /* unicode_test.cc */; }; E9071BE412DC42300B936BAF /* explain_stats.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 428662F00938E9E21F7080D7 /* explain_stats.pb.cc */; }; + E92D194F027C325631036B75 /* unicode_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 09C56D14F17CA02A07C60847 /* unicode_test.cc */; }; E962CA641FB1312638593131 /* leveldb_document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AE89CFF09C6804573841397F /* leveldb_document_overlay_cache_test.cc */; }; E99D5467483B746D4AA44F74 /* fields_array_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA4CBA48204C9E25B56993BC /* fields_array_test.cc */; }; E9BC6A5BC2B209B1BA2F8BD6 /* field_behavior.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1F78CD3208A1D5885B4C134E /* field_behavior.pb.cc */; }; @@ -1897,6 +1899,7 @@ 014C60628830D95031574D15 /* random_access_queue_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = random_access_queue_test.cc; sourceTree = ""; }; 01D10113ECC5B446DB35E96D /* byte_stream_cpp_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = byte_stream_cpp_test.cc; sourceTree = ""; }; 03BD47161789F26754D3B958 /* Pods-Firestore_Benchmarks_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Benchmarks_iOS.release.xcconfig"; path = "Target Support Files/Pods-Firestore_Benchmarks_iOS/Pods-Firestore_Benchmarks_iOS.release.xcconfig"; sourceTree = ""; }; + 0401C6FDE59C493BFBD5DFED /* pipeline_util_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = pipeline_util_test.cc; sourceTree = ""; }; 0458BABD8F8738AD16F4A2FE /* array_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = array_test.cc; path = expressions/array_test.cc; sourceTree = ""; }; 045D39C4A7D52AF58264240F /* remote_document_cache_test.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = remote_document_cache_test.h; sourceTree = ""; }; 0473AFFF5567E667A125347B /* ordered_code_benchmark.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = ordered_code_benchmark.cc; sourceTree = ""; }; @@ -1914,8 +1917,8 @@ 129A369928CA555B005AE7E2 /* FIRCountTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRCountTests.mm; sourceTree = ""; }; 12F4357299652983A615F886 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 132E32997D781B896672D30A /* reference_set_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reference_set_test.cc; sourceTree = ""; }; - 15EAAEEE767299A3CDA96132 /* sort_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = sort_test.cc; path = pipeline/sort_test.cc; sourceTree = ""; }; 15249D092D85B40EFC8A1459 /* pipeline.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pipeline.pb.h; sourceTree = ""; }; + 15EAAEEE767299A3CDA96132 /* sort_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = sort_test.cc; path = pipeline/sort_test.cc; sourceTree = ""; }; 166CE73C03AB4366AAC5201C /* leveldb_index_manager_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_index_manager_test.cc; sourceTree = ""; }; 1924149B429A2020C3CD94D6 /* utils.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = utils.cc; path = pipeline/utils.cc; sourceTree = ""; }; 1A7D48A017ECB54FD381D126 /* Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json; sourceTree = ""; }; @@ -2167,7 +2170,6 @@ 73F1F73A2210F3D800E1F692 /* index_manager_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = index_manager_test.h; sourceTree = ""; }; 74FBEFA4FE4B12C435011763 /* memory_mutation_queue_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = memory_mutation_queue_test.cc; sourceTree = ""; }; 7515B47C92ABEEC66864B55C /* field_transform_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = field_transform_test.cc; sourceTree = ""; }; - 756DC5F038E54F8B82B64780 /* Pods-Firestore_FuzzTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_FuzzTests_iOS.debug.xcconfig"; path = "Target Support Files/Pods-Firestore_FuzzTests_iOS/Pods-Firestore_FuzzTests_iOS.debug.xcconfig"; sourceTree = ""; }; 75860CD13AF47EB1EA39EC2F /* leveldb_opener_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_opener_test.cc; sourceTree = ""; }; 75E24C5CD7BC423D48713100 /* counting_query_engine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = counting_query_engine.h; sourceTree = ""; }; 7628664347B9C96462D4BF17 /* byte_stream_apple_test.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = byte_stream_apple_test.mm; sourceTree = ""; }; @@ -2178,13 +2180,11 @@ 795AA8FC31D2AF6864B07D39 /* FIRIndexingTests.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = FIRIndexingTests.mm; sourceTree = ""; }; 79D4CD6A707ED3F7A6D2ECF5 /* view_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = view_testing.h; sourceTree = ""; }; 79EAA9F7B1B9592B5F053923 /* bundle_spec_test.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; path = bundle_spec_test.json; sourceTree = ""; }; - 7B037EE2F287E5D070C81D0F /* Pods_Firestore_FuzzTests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_FuzzTests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7B44DD11682C4803B73DCC34 /* Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json; sourceTree = ""; }; 7B65C996438B84DBC7616640 /* CodableTimestampTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CodableTimestampTests.swift; sourceTree = ""; }; 7C3F995E040E9E9C5E8514BB /* query_listener_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = query_listener_test.cc; sourceTree = ""; }; 7C5C40C7BFBB86032F1DC632 /* FSTExceptionCatcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = FSTExceptionCatcher.h; sourceTree = ""; }; 7EB299CF85034F09CFD6F3FD /* remote_document_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = remote_document_cache_test.cc; sourceTree = ""; }; - 80B9DCD61D9C9A3793248509 /* Pods-Firestore_FuzzTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_FuzzTests_iOS.release.xcconfig"; path = "Target Support Files/Pods-Firestore_FuzzTests_iOS/Pods-Firestore_FuzzTests_iOS.release.xcconfig"; sourceTree = ""; }; 81DFB7DE556603F7FDEDCA84 /* Pods-Firestore_Example_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS.debug.xcconfig"; path = "Target Support Files/Pods-Firestore_Example_iOS/Pods-Firestore_Example_iOS.debug.xcconfig"; sourceTree = ""; }; 8294C2063C0096AE5E43F6DF /* Pods_Firestore_Tests_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Tests_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 82DF854A7238D538FA53C908 /* timestamp_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = timestamp_test.cc; path = expressions/timestamp_test.cc; sourceTree = ""; }; @@ -2227,8 +2227,8 @@ A2E6F09AD1EE0A6A452E9A08 /* bloom_filter_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = bloom_filter_test.cc; sourceTree = ""; }; A366F6AE1A5A77548485C091 /* bundle.pb.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = bundle.pb.cc; sourceTree = ""; }; A410E38FA5C3EB5AECDB6F1C /* inequality_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; name = inequality_test.cc; path = pipeline/inequality_test.cc; sourceTree = ""; }; - A47DF1B9E7CDA6F76A0BFF57 /* Pods-Firestore_Example_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_tvOS.debug.xcconfig"; path = "Target Support Files/Pods-Firestore_Example_tvOS/Pods-Firestore_Example_tvOS.debug.xcconfig"; sourceTree = ""; }; A4192EB032E23129EF23605A /* field_behavior.pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = field_behavior.pb.h; sourceTree = ""; }; + A47DF1B9E7CDA6F76A0BFF57 /* Pods-Firestore_Example_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_tvOS.debug.xcconfig"; path = "Target Support Files/Pods-Firestore_Example_tvOS/Pods-Firestore_Example_tvOS.debug.xcconfig"; sourceTree = ""; }; A5466E7809AD2871FFDE6C76 /* view_testing.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = view_testing.cc; sourceTree = ""; }; A5D9044B72061CAF284BC9E4 /* Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.json; name = Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json; path = bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json; sourceTree = ""; }; A668C02CBF00BC56AEC81C2A /* Pods-Firestore_IntegrationTests_tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests_tvOS.debug.xcconfig"; path = "Target Support Files/Pods-Firestore_IntegrationTests_tvOS/Pods-Firestore_IntegrationTests_tvOS.debug.xcconfig"; sourceTree = ""; }; @@ -2443,7 +2443,6 @@ buildActionMask = 2147483647; files = ( 6EDD3B4620BF247500C33877 /* Foundation.framework in Frameworks */, - 54D54C9289C8AD6254887E56 /* Pods_Firestore_FuzzTests_iOS.framework in Frameworks */, 6EDD3B4820BF247500C33877 /* UIKit.framework in Frameworks */, 6EDD3B4920BF247500C33877 /* XCTest.framework in Frameworks */, ); @@ -2877,7 +2876,6 @@ BB5A5E6DD07DA3EB7AD46CA7 /* Pods_Firestore_Example_iOS.framework */, A17F8CBAFA07CAE9FFBC8BC5 /* Pods_Firestore_Example_macOS.framework */, 9A7EE8E1466BA54F199B0991 /* Pods_Firestore_Example_tvOS.framework */, - 7B037EE2F287E5D070C81D0F /* Pods_Firestore_FuzzTests_iOS.framework */, D9C9F60851E52197B30E0AF9 /* Pods_Firestore_IntegrationTests_iOS.framework */, 253A7A96FFAA2C8A8754D3CF /* Pods_Firestore_IntegrationTests_macOS.framework */, 453332546740E27077C65FDC /* Pods_Firestore_IntegrationTests_tvOS.framework */, @@ -3036,8 +3034,6 @@ 88B7F25F26338EB9C03AE440 /* Pods-Firestore_Example_macOS.release.xcconfig */, A47DF1B9E7CDA6F76A0BFF57 /* Pods-Firestore_Example_tvOS.debug.xcconfig */, F339B5B848F79BBDB2133210 /* Pods-Firestore_Example_tvOS.release.xcconfig */, - 756DC5F038E54F8B82B64780 /* Pods-Firestore_FuzzTests_iOS.debug.xcconfig */, - 80B9DCD61D9C9A3793248509 /* Pods-Firestore_FuzzTests_iOS.release.xcconfig */, 708BC2920AEF83DC6630887E /* Pods-Firestore_IntegrationTests_iOS.debug.xcconfig */, 62CF8E2E7611B285B46228FE /* Pods-Firestore_IntegrationTests_iOS.release.xcconfig */, 5C767F7D43A603B557327513 /* Pods-Firestore_IntegrationTests_macOS.debug.xcconfig */, @@ -3182,6 +3178,7 @@ AB38D92E20235D22000A432D /* database_info_test.cc */, 6F57521E161450FAF89075ED /* event_manager_test.cc */, F02F734F272C3C70D1307076 /* filter_test.cc */, + 0401C6FDE59C493BFBD5DFED /* pipeline_util_test.cc */, 7C3F995E040E9E9C5E8514BB /* query_listener_test.cc */, B9C261C26C5D311E1E3C0CB9 /* query_test.cc */, AB380CF82019382300D97691 /* target_id_generator_test.cc */, @@ -3192,14 +3189,6 @@ path = core; sourceTree = ""; }; - C7D3D622BB13EB3C3301DA4F /* TestHelper */ = { - isa = PBXGroup; - children = ( - 0E73D03B9C02CAC7BEBAFA86 /* TestHelper.swift */, - ); - name = TestHelper; - sourceTree = ""; - }; AD2E6E1CDE874DD15298E8F5 /* expressions */ = { isa = PBXGroup; children = ( @@ -3217,6 +3206,14 @@ name = expressions; sourceTree = ""; }; + C7D3D622BB13EB3C3301DA4F /* TestHelper */ = { + isa = PBXGroup; + children = ( + 0E73D03B9C02CAC7BEBAFA86 /* TestHelper.swift */, + ); + name = TestHelper; + sourceTree = ""; + }; DAFF0CF621E64AC30062958F /* macOS */ = { isa = PBXGroup; children = ( @@ -3533,12 +3530,10 @@ isa = PBXNativeTarget; buildConfigurationList = 6EDD3B5820BF247500C33877 /* Build configuration list for PBXNativeTarget "Firestore_FuzzTests_iOS" */; buildPhases = ( - A0E5B5F1FF12D2093E1A06D4 /* [CP] Check Pods Manifest.lock */, 6EDD3AD520BF247500C33877 /* Sources */, 6EDD3B4520BF247500C33877 /* Frameworks */, 6EDD3B4A20BF247500C33877 /* Resources */, 6E622C7A20F52C8300B7E93A /* Run Script */, - 39AA18B34547A803396E030C /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -4110,21 +4105,6 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 39AA18B34547A803396E030C /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Firestore_FuzzTests_iOS/Pods-Firestore_FuzzTests_iOS-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 42C55F231E24330A93F24CD3 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -4230,28 +4210,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - A0E5B5F1FF12D2093E1A06D4 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Firestore_FuzzTests_iOS-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; AC3A1FAA5AB14C1518AB82C3 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -4630,6 +4588,7 @@ DB7E9C5A59CCCDDB7F0C238A /* path_test.cc in Sources */, E30BF9E316316446371C956C /* persistence_testing.cc in Sources */, 60DA778E447F9ACD402FDA2F /* pipeline.pb.cc in Sources */, + E5FE2BEECD70D59361B51540 /* pipeline_util_test.cc in Sources */, 0455FC6E2A281BD755FD933A /* precondition_test.cc in Sources */, 5ECE040F87E9FCD0A5D215DB /* pretty_printing_test.cc in Sources */, 938F2AF6EC5CD0B839300DB0 /* query.pb.cc in Sources */, @@ -4676,8 +4635,8 @@ 482D503CC826265FCEAB53DE /* thread_safe_memoizer_testing.cc in Sources */, 451EFFB413364E5A420F8B2D /* thread_safe_memoizer_testing_test.cc in Sources */, 5497CB78229DECDE000FB92F /* time_testing.cc in Sources */, - B7EFE1206B6A5A1712BD6745 /* timestamp_test.cc in Sources */, ACC9369843F5ED3BD2284078 /* timestamp_test.cc in Sources */, + B7EFE1206B6A5A1712BD6745 /* timestamp_test.cc in Sources */, 2AAEABFD550255271E3BAC91 /* to_string_apple_test.mm in Sources */, 1E2AE064CF32A604DC7BFD4D /* to_string_test.cc in Sources */, AAFA9D7A0A067F2D3D8D5487 /* token_test.cc in Sources */, @@ -4882,6 +4841,7 @@ 0963F6D7B0F9AE1E24B82866 /* path_test.cc in Sources */, 92D7081085679497DC112EDB /* persistence_testing.cc in Sources */, 8429E18EFBAF473209731E01 /* pipeline.pb.cc in Sources */, + 48A9AD22B0601C52B0522CF7 /* pipeline_util_test.cc in Sources */, 152543FD706D5E8851C8DA92 /* precondition_test.cc in Sources */, 2639ABDA17EECEB7F62D1D83 /* pretty_printing_test.cc in Sources */, 5FA3DB52A478B01384D3A2ED /* query.pb.cc in Sources */, @@ -4928,8 +4888,8 @@ 3D6AC48D6197E6539BBBD28F /* thread_safe_memoizer_testing.cc in Sources */, 7801E06BFFB08FCE7AB54AD6 /* thread_safe_memoizer_testing_test.cc in Sources */, 5497CB79229DECDE000FB92F /* time_testing.cc in Sources */, - 02E1EA3818F4BEEA9CE40DAE /* timestamp_test.cc in Sources */, 26CB3D7C871BC56456C6021E /* timestamp_test.cc in Sources */, + 02E1EA3818F4BEEA9CE40DAE /* timestamp_test.cc in Sources */, 5BE49546D57C43DDFCDB6FBD /* to_string_apple_test.mm in Sources */, E500AB82DF2E7F3AFDB1AB3F /* to_string_test.cc in Sources */, 5C9B5696644675636A052018 /* token_test.cc in Sources */, @@ -5161,6 +5121,7 @@ 70A171FC43BE328767D1B243 /* path_test.cc in Sources */, EECC1EC64CA963A8376FA55C /* persistence_testing.cc in Sources */, 5CDD24225992674A4D3E3D4E /* pipeline.pb.cc in Sources */, + E14DBE1D9FC94B5E7E391BEE /* pipeline_util_test.cc in Sources */, 34D69886DAD4A2029BFC5C63 /* precondition_test.cc in Sources */, F56E9334642C207D7D85D428 /* pretty_printing_test.cc in Sources */, 22A00AC39CAB3426A943E037 /* query.pb.cc in Sources */, @@ -5440,6 +5401,7 @@ B3A309CCF5D75A555C7196E1 /* path_test.cc in Sources */, 46EAC2828CD942F27834F497 /* persistence_testing.cc in Sources */, D64792BBFA130E26CB3D1028 /* pipeline.pb.cc in Sources */, + 563FE05627C7E66469E99292 /* pipeline_util_test.cc in Sources */, 9EE1447AA8E68DF98D0590FF /* precondition_test.cc in Sources */, F6079BFC9460B190DA85C2E6 /* pretty_printing_test.cc in Sources */, 7B0F073BDB6D0D6E542E23D4 /* query.pb.cc in Sources */, @@ -5702,6 +5664,7 @@ 5A080105CCBFDB6BF3F3772D /* path_test.cc in Sources */, 21C17F15579341289AD01051 /* persistence_testing.cc in Sources */, C8889F3C37F1CC3E64558287 /* pipeline.pb.cc in Sources */, + 11A5189E73D954824F015424 /* pipeline_util_test.cc in Sources */, 549CCA5920A36E1F00BCEB75 /* precondition_test.cc in Sources */, 6A94393D83EB338DFAF6A0D2 /* pretty_printing_test.cc in Sources */, 544129DC21C2DDC800EFB9CC /* query.pb.cc in Sources */, @@ -5748,8 +5711,8 @@ 8D67BAAD6D2F1913BACA6AC1 /* thread_safe_memoizer_testing.cc in Sources */, BD0882A40BD8AE042629C179 /* thread_safe_memoizer_testing_test.cc in Sources */, 5497CB77229DECDE000FB92F /* time_testing.cc in Sources */, - 3D1365A99984C2F86C2B8A82 /* timestamp_test.cc in Sources */, ABF6506C201131F8005F2C74 /* timestamp_test.cc in Sources */, + 3D1365A99984C2F86C2B8A82 /* timestamp_test.cc in Sources */, B68B1E012213A765008977EF /* to_string_apple_test.mm in Sources */, B696858E2214B53900271095 /* to_string_test.cc in Sources */, D50232D696F19C2881AC01CE /* token_test.cc in Sources */, @@ -6000,6 +5963,7 @@ 6105A1365831B79A7DEEA4F3 /* path_test.cc in Sources */, CB8BEF34CC4A996C7BE85119 /* persistence_testing.cc in Sources */, BC9966788F245D79A63C2E47 /* pipeline.pb.cc in Sources */, + 7676C06AF7FF67806747E4F0 /* pipeline_util_test.cc in Sources */, 4194B7BB8B0352E1AC5D69B9 /* precondition_test.cc in Sources */, 0EA40EDACC28F445F9A3F32F /* pretty_printing_test.cc in Sources */, 63B91FC476F3915A44F00796 /* query.pb.cc in Sources */, @@ -6697,7 +6661,6 @@ }; 6EDD3B5920BF247500C33877 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 756DC5F038E54F8B82B64780 /* Pods-Firestore_FuzzTests_iOS.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = EQHXZ8M8AV; @@ -6712,7 +6675,6 @@ }; 6EDD3B5A20BF247500C33877 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 80B9DCD61D9C9A3793248509 /* Pods-Firestore_FuzzTests_iOS.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = EQHXZ8M8AV; diff --git a/Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.mm index 316ad7b243f..88977fcf2e9 100644 --- a/Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTLevelDBSpecTests.mm @@ -62,4 +62,18 @@ - (BOOL)shouldRunWithTags:(NSArray *)tags { @end +/** + * An implementation of FSTLevelDBSpecTests that runs tests in pipeline mode. + */ +@interface FSTLevelDBPipelineSpecTests : FSTLevelDBSpecTests +@end + +@implementation FSTLevelDBPipelineSpecTests + +- (BOOL)usePipelineMode { + return YES; +} + +@end + NS_ASSUME_NONNULL_END diff --git a/Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.mm index 437e577d425..22ba0887b82 100644 --- a/Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTMemorySpecTests.mm @@ -57,4 +57,18 @@ - (BOOL)shouldRunWithTags:(NSArray *)tags { @end +/** + * An implementation of FSTMemorySpecTests that runs tests in pipeline mode. + */ +@interface FSTMemoryPipelineSpecTests : FSTMemorySpecTests +@end + +@implementation FSTMemoryPipelineSpecTests + +- (BOOL)usePipelineMode { + return YES; +} + +@end + NS_ASSUME_NONNULL_END diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.h b/Firestore/Example/Tests/SpecTests/FSTSpecTests.h index afd3895a0d6..17c999f0cf5 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.h +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.h @@ -37,7 +37,10 @@ extern NSString *const kDurablePersistence; * + Subclass FSTSpecTests * + override -persistence to create and return an appropriate Persistence implementation. */ -@interface FSTSpecTests : XCTestCase +@interface FSTSpecTests : XCTestCase { + @protected + BOOL _convertToPipeline; +} /** Based on its tags, determine whether the test case should run. */ - (BOOL)shouldRunWithTags:(NSArray *)tags; @@ -45,6 +48,9 @@ extern NSString *const kDurablePersistence; /** Do any necessary setup for a single spec test */ - (void)setUpForSpecWithConfig:(NSDictionary *)config; +/** Determines if tests should run in pipeline mode. Subclasses can override. */ +- (BOOL)usePipelineMode; + @end NS_ASSUME_NONNULL_END diff --git a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm index c90b3048fb7..973f3c451e9 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSpecTests.mm @@ -158,6 +158,9 @@ // if `kRunBenchmarkTests` is set to 'YES'. static NSString *const kBenchmarkTag = @"benchmark"; +// A tag for tests that should skip its pipeline run. +static NSString *const kNoPipelineConversion = @"no-pipeline-conversion"; + NSString *const kEagerGC = @"eager-gc"; NSString *const kDurablePersistence = @"durable-persistence"; @@ -236,11 +239,14 @@ - (BOOL)shouldRunWithTags:(NSArray *)tags { return NO; } else if (!kRunBenchmarkTests && [tags containsObject:kBenchmarkTag]) { return NO; + } else if (self.usePipelineMode && [tags containsObject:kNoPipelineConversion]) { + return NO; } return YES; } - (void)setUpForSpecWithConfig:(NSDictionary *)config { + _convertToPipeline = [self usePipelineMode]; // Call new method _reader = FSTTestUserDataReader(); std::unique_ptr user_executor = Executor::CreateSerial("user executor"); user_executor_ = absl::ShareUniquePtr(std::move(user_executor)); @@ -261,6 +267,7 @@ - (void)setUpForSpecWithConfig:(NSDictionary *)config { self.driver = [[FSTSyncEngineTestDriver alloc] initWithPersistence:std::move(persistence) eagerGC:_useEagerGCForMemory + convertToPipeline:_convertToPipeline // Pass the flag initialUser:User::Unauthenticated() outstandingWrites:{} maxConcurrentLimboResolutions:_maxConcurrentLimboResolutions]; @@ -282,6 +289,11 @@ - (BOOL)isTestBaseClass { return [self class] == [FSTSpecTests class]; } +// Default implementation for pipeline mode. Subclasses can override. +- (BOOL)usePipelineMode { + return NO; +} + #pragma mark - Methods for constructing objects from specs. - (Query)parseQuery:(id)querySpec { @@ -645,6 +657,7 @@ - (void)doRestart { self.driver = [[FSTSyncEngineTestDriver alloc] initWithPersistence:std::move(persistence) eagerGC:_useEagerGCForMemory + convertToPipeline:_convertToPipeline // Pass the flag initialUser:currentUser outstandingWrites:outstandingWrites maxConcurrentLimboResolutions:_maxConcurrentLimboResolutions]; @@ -721,8 +734,42 @@ - (void)doStep:(NSDictionary *)step { } - (void)validateEvent:(FSTQueryEvent *)actual matches:(NSDictionary *)expected { - Query expectedQuery = [self parseQuery:expected[@"query"]]; - XCTAssertEqual(actual.query, expectedQuery); + // The 'expected' query from JSON is always a standard Query. + Query expectedJSONQuery = [self parseQuery:expected[@"query"]]; + core::QueryOrPipeline actualQueryOrPipeline = actual.queryOrPipeline; + + if (_convertToPipeline) { + XCTAssertTrue(actualQueryOrPipeline.IsPipeline(), + @"In pipeline mode, actual event query should be a pipeline. Actual: %@", + MakeNSString(actualQueryOrPipeline.ToString())); + + // Convert the expected JSON Query to a RealtimePipeline for comparison. + std::vector> expectedStages = + core::ToPipelineStages(expectedJSONQuery); + // TODO(specstest): Need access to the database_id for the serializer. + // Assuming self.driver.databaseInfo is accessible and provides it. + // This might require making databaseInfo public or providing a getter in + // FSTSyncEngineTestDriver. For now, proceeding with the assumption it's available. + auto serializer = absl::make_unique(self.driver.databaseInfo.database_id()); + api::RealtimePipeline expectedPipeline(std::move(expectedStages), std::move(serializer)); + auto expectedQoPForComparison = + core::QueryOrPipeline(expectedPipeline); // Wrap expected pipeline + + XCTAssertEqual(actualQueryOrPipeline.CanonicalId(), expectedQoPForComparison.CanonicalId(), + @"Pipeline canonical IDs do not match. Actual: %@, Expected: %@", + MakeNSString(actualQueryOrPipeline.CanonicalId()), + MakeNSString(expectedQoPForComparison.CanonicalId())); + + } else { + XCTAssertFalse(actualQueryOrPipeline.IsPipeline(), + @"In non-pipeline mode, actual event query should be a Query. Actual: %@", + MakeNSString(actualQueryOrPipeline.ToString())); + XCTAssertTrue(actualQueryOrPipeline.query() == expectedJSONQuery, + @"Queries do not match. Actual: %@, Expected: %@", + MakeNSString(actualQueryOrPipeline.query().ToString()), + MakeNSString(expectedJSONQuery.ToString())); + } + if ([expected[@"errorCode"] integerValue] != 0) { XCTAssertNotNil(actual.error); XCTAssertEqual(actual.error.code, [expected[@"errorCode"] integerValue]); @@ -787,14 +834,43 @@ - (void)validateExpectedSnapshotEvents:(NSArray *_Nullable)expectedEvents { XCTAssertEqual(events.count, expectedEvents.count); events = [events sortedArrayUsingComparator:^NSComparisonResult(FSTQueryEvent *q1, FSTQueryEvent *q2) { - return WrapCompare(q1.query.CanonicalId(), q2.query.CanonicalId()); - }]; - expectedEvents = [expectedEvents - sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *left, NSDictionary *right) { - Query leftQuery = [self parseQuery:left[@"query"]]; - Query rightQuery = [self parseQuery:right[@"query"]]; - return WrapCompare(leftQuery.CanonicalId(), rightQuery.CanonicalId()); + // Use QueryOrPipeline's CanonicalId for sorting + return WrapCompare(q1.queryOrPipeline.CanonicalId(), q2.queryOrPipeline.CanonicalId()); }]; + expectedEvents = [expectedEvents sortedArrayUsingComparator:^NSComparisonResult( + NSDictionary *left, NSDictionary *right) { + // Expected query from JSON is always a core::Query. + // For sorting consistency with actual events (which might be pipelines), + // we convert the expected query to QueryOrPipeline then get its CanonicalId. + // If _convertToPipeline is true, this will effectively sort expected items + // by their pipeline canonical ID. + Query leftJSONQuery = [self parseQuery:left[@"query"]]; + core::QueryOrPipeline leftQoP; + if (self->_convertToPipeline) { + std::vector> stages = + core::ToPipelineStages(leftJSONQuery); + auto serializer = + absl::make_unique(self.driver.databaseInfo.database_id()); + leftQoP = + core::QueryOrPipeline(api::RealtimePipeline(std::move(stages), std::move(serializer))); + } else { + leftQoP = core::QueryOrPipeline(leftJSONQuery); + } + + Query rightJSONQuery = [self parseQuery:right[@"query"]]; + core::QueryOrPipeline rightQoP; + if (self->_convertToPipeline) { + std::vector> stages = + core::ToPipelineStages(rightJSONQuery); + auto serializer = + absl::make_unique(self.driver.databaseInfo.database_id()); + rightQoP = + core::QueryOrPipeline(api::RealtimePipeline(std::move(stages), std::move(serializer))); + } else { + rightQoP = core::QueryOrPipeline(rightJSONQuery); + } + return WrapCompare(leftQoP.CanonicalId(), rightQoP.CanonicalId()); + }]; NSUInteger i = 0; for (; i < expectedEvents.count && i < events.count; ++i) { @@ -849,6 +925,7 @@ - (void)validateExpectedState:(nullable NSDictionary *)expectedState { NSArray *queriesJson = queryData[@"queries"]; std::vector queries; for (id queryJson in queriesJson) { + core::QueryOrPipeline qop; Query query = [self parseQuery:queryJson]; QueryPurpose purpose = QueryPurpose::Listen; @@ -980,9 +1057,13 @@ - (void)validateActiveTargets { // is ever made to be consistent. // XCTAssertEqualObjects(actualTargets[targetID], TargetData); const TargetData &actual = found->second; - + auto left = actual.target_or_pipeline(); + auto left_p = left.IsPipeline(); + auto right = targetData.target_or_pipeline(); + auto right_p = right.IsPipeline(); XCTAssertEqual(actual.purpose(), targetData.purpose()); - XCTAssertEqual(actual.target_or_pipeline(), targetData.target_or_pipeline()); + XCTAssertEqual(left_p, right_p); + XCTAssertEqual(left, right); XCTAssertEqual(actual.target_id(), targetData.target_id()); XCTAssertEqual(actual.snapshot_version(), targetData.snapshot_version()); XCTAssertEqual(actual.resume_token(), targetData.resume_token()); @@ -1032,6 +1113,8 @@ - (void)runSpecTestSteps:(NSArray *)steps config:(NSDictionary *)config { - (void)testSpecTests { if ([self isTestBaseClass]) return; + // LogSetLevel(firebase::firestore::util::kLogLevelDebug); + // Enumerate the .json files containing the spec tests. NSMutableArray *specFiles = [NSMutableArray array]; NSMutableArray *parsedSpecs = [NSMutableArray array]; @@ -1121,10 +1204,10 @@ - (void)testSpecTests { ++testPassCount; } else { ++testSkipCount; - NSLog(@" [SKIPPED] Spec test: %@", name); + // NSLog(@" [SKIPPED] Spec test: %@", name); NSString *comment = testDescription[@"comment"]; if (comment) { - NSLog(@" %@", comment); + // NSLog(@" %@", comment); } } }]; diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h index 978ae28a4e5..fed38804b0f 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.h @@ -26,6 +26,7 @@ #include "Firestore/core/src/api/load_bundle_task.h" #include "Firestore/core/src/bundle/bundle_reader.h" #include "Firestore/core/src/core/database_info.h" +#include "Firestore/core/src/core/pipeline_util.h" // For QueryOrPipeline #include "Firestore/core/src/core/query.h" #include "Firestore/core/src/core/view_snapshot.h" #include "Firestore/core/src/credentials/user.h" @@ -66,7 +67,7 @@ NS_ASSUME_NONNULL_BEGIN * given query. */ @interface FSTQueryEvent : NSObject -@property(nonatomic, assign) core::Query query; +@property(nonatomic, assign) core::QueryOrPipeline queryOrPipeline; @property(nonatomic, strong, nullable) NSError *error; - (const absl::optional &)viewSnapshot; @@ -115,7 +116,10 @@ typedef std:: * * Each method on the driver injects a different event into the system. */ -@interface FSTSyncEngineTestDriver : NSObject +@interface FSTSyncEngineTestDriver : NSObject { + @protected + BOOL _convertToPipeline; +} /** * Initializes the underlying FSTSyncEngine with the given local persistence implementation and @@ -124,6 +128,7 @@ typedef std:: */ - (instancetype)initWithPersistence:(std::unique_ptr)persistence eagerGC:(BOOL)eagerGC + convertToPipeline:(BOOL)convertToPipeline initialUser:(const credentials::User &)initialUser outstandingWrites:(const FSTOutstandingWriteQueues &)outstandingWrites maxConcurrentLimboResolutions:(size_t)maxConcurrentLimboResolutions NS_DESIGNATED_INITIALIZER; diff --git a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm index 82d2ff5dbea..e911e31f3e0 100644 --- a/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm +++ b/Firestore/Example/Tests/SpecTests/FSTSyncEngineTestDriver.mm @@ -34,6 +34,7 @@ #include "Firestore/core/src/core/database_info.h" #include "Firestore/core/src/core/event_manager.h" #include "Firestore/core/src/core/listen_options.h" +#include "Firestore/core/src/core/pipeline_util.h" // Added for ToRealtimePipeline #include "Firestore/core/src/core/query_listener.h" #include "Firestore/core/src/core/sync_engine.h" #include "Firestore/core/src/credentials/empty_credentials_provider.h" @@ -48,6 +49,7 @@ #include "Firestore/core/src/remote/firebase_metadata_provider.h" #include "Firestore/core/src/remote/firebase_metadata_provider_noop.h" #include "Firestore/core/src/remote/remote_store.h" +#include "Firestore/core/src/remote/serializer.h" // Added for RealtimePipeline constructor #include "Firestore/core/src/util/async_queue.h" #include "Firestore/core/src/util/delayed_constructor.h" #include "Firestore/core/src/util/error_apple.h" @@ -200,7 +202,7 @@ @implementation FSTSyncEngineTestDriver { DocumentKeySet _expectedEnqueuedLimboDocuments; /** A dictionary for tracking the listens on queries. */ - std::unordered_map> _queryListeners; + std::unordered_map> _queryListeners; DatabaseInfo _databaseInfo; User _currentUser; @@ -216,10 +218,12 @@ @implementation FSTSyncEngineTestDriver { - (instancetype)initWithPersistence:(std::unique_ptr)persistence eagerGC:(BOOL)eagerGC + convertToPipeline:(BOOL)convertToPipeline initialUser:(const User &)initialUser outstandingWrites:(const FSTOutstandingWriteQueues &)outstandingWrites maxConcurrentLimboResolutions:(size_t)maxConcurrentLimboResolutions { if (self = [super init]) { + _convertToPipeline = convertToPipeline; // Store the flag _maxConcurrentLimboResolutions = maxConcurrentLimboResolutions; // Do a deep copy. @@ -477,28 +481,55 @@ - (FSTOutstandingWrite *)receiveWriteError:(int)errorCode } - (TargetId)addUserListenerWithQuery:(Query)query options:(ListenOptions)options { - // TODO(dimond): Change spec tests to verify isFromCache on snapshots - auto listener = - QueryListener::Create(core::QueryOrPipeline(query), options, - [self, query](const StatusOr &maybe_snapshot) { - FSTQueryEvent *event = [[FSTQueryEvent alloc] init]; - event.query = query; - if (maybe_snapshot.ok()) { - [event setViewSnapshot:maybe_snapshot.ValueOrDie()]; - } else { - event.error = MakeNSError(maybe_snapshot.status()); - } - - [self.events addObject:event]; - }); - _queryListeners[query] = listener; + core::QueryOrPipeline qop_for_listen; + if (_convertToPipeline) { + std::vector> stages = + firebase::firestore::core::ToPipelineStages(query); + auto serializer = + absl::make_unique(_databaseInfo.database_id()); + firebase::firestore::api::RealtimePipeline pipeline(std::move(stages), std::move(serializer)); + qop_for_listen = core::QueryOrPipeline(pipeline); + } else { + qop_for_listen = core::QueryOrPipeline(query); + } + + auto listener = QueryListener::Create( + qop_for_listen, options, + [self, qop_for_listen](const StatusOr &maybe_snapshot) { + FSTQueryEvent *event = [[FSTQueryEvent alloc] init]; + event.queryOrPipeline = qop_for_listen; // Event now holds QueryOrPipeline + if (maybe_snapshot.ok()) { + [event setViewSnapshot:maybe_snapshot.ValueOrDie()]; + } else { + event.error = MakeNSError(maybe_snapshot.status()); + } + [self.events addObject:event]; + }); + + _queryListeners[qop_for_listen] = listener; // Use QueryOrPipeline as key TargetId targetID; + + // The actual call to EventManager still uses the listener based on the original Query. + // The expectation is that SyncEngine will be made mode-aware if _convertToPipeline is true, + // or that EventManager/QueryListener will be updated to handle QueryOrPipeline directly. _workerQueue->EnqueueBlocking([&] { targetID = _eventManager->AddQueryListener(listener); }); return targetID; } -- (void)removeUserListenerWithQuery:(const Query &)query { - auto found_iter = _queryListeners.find(query); +- (void)removeUserListenerWithQuery:(const core::Query &)query { + core::QueryOrPipeline qop; + if (_convertToPipeline) { + std::vector> stages = + firebase::firestore::core::ToPipelineStages(query); + auto serializer = + absl::make_unique(_databaseInfo.database_id()); + firebase::firestore::api::RealtimePipeline pipeline(std::move(stages), std::move(serializer)); + qop = core::QueryOrPipeline(pipeline); + } else { + qop = core::QueryOrPipeline(query); + } + + auto found_iter = _queryListeners.find(qop); if (found_iter != _queryListeners.end()) { std::shared_ptr listener = found_iter->second; _queryListeners.erase(found_iter); diff --git a/Firestore/Example/Tests/SpecTests/json/bundle_spec_test.json b/Firestore/Example/Tests/SpecTests/json/bundle_spec_test.json index 028895c50ac..53d26b5dce1 100644 --- a/Firestore/Example/Tests/SpecTests/json/bundle_spec_test.json +++ b/Firestore/Example/Tests/SpecTests/json/bundle_spec_test.json @@ -3,7 +3,8 @@ "describeName": "Bundles:", "itName": "Bundles query can be loaded and resumed from different tabs", "tags": [ - "multi-client" + "multi-client", + "no-pipeline-conversion" ], "config": { "numClients": 2, @@ -225,6 +226,7 @@ "describeName": "Bundles:", "itName": "Bundles query can be resumed from same query.", "tags": [ + "no-pipeline-conversion" ], "config": { "numClients": 1, diff --git a/Firestore/Example/Tests/SpecTests/json/existence_filter_spec_test.json b/Firestore/Example/Tests/SpecTests/json/existence_filter_spec_test.json index ae64f7aad82..cf0d49885d2 100644 --- a/Firestore/Example/Tests/SpecTests/json/existence_filter_spec_test.json +++ b/Firestore/Example/Tests/SpecTests/json/existence_filter_spec_test.json @@ -6967,9 +6967,9 @@ } ] }, - "Full re-query is triggered when bloom filter can not identify documents deleted": { + "Full re-query is triggered when bloom filter cannot identify documents deleted": { "describeName": "Existence Filters:", - "itName": "Full re-query is triggered when bloom filter can not identify documents deleted", + "itName": "Full re-query is triggered when bloom filter cannot identify documents deleted", "tags": [ ], "config": { diff --git a/Firestore/Example/Tests/SpecTests/json/index_spec_test.json b/Firestore/Example/Tests/SpecTests/json/index_spec_test.json index 9e704e75be1..c1880c15cee 100644 --- a/Firestore/Example/Tests/SpecTests/json/index_spec_test.json +++ b/Firestore/Example/Tests/SpecTests/json/index_spec_test.json @@ -71,7 +71,8 @@ "readTime": { "timestamp": { "nanoseconds": 0, - "seconds": 0 + "seconds": 0, + "type": "firestore/timestamp/1.0" } } }, @@ -115,7 +116,8 @@ "readTime": { "timestamp": { "nanoseconds": 0, - "seconds": 0 + "seconds": 0, + "type": "firestore/timestamp/1.0" } } }, @@ -192,7 +194,8 @@ "readTime": { "timestamp": { "nanoseconds": 0, - "seconds": 0 + "seconds": 0, + "type": "firestore/timestamp/1.0" } } }, @@ -236,7 +239,8 @@ "readTime": { "timestamp": { "nanoseconds": 0, - "seconds": 0 + "seconds": 0, + "type": "firestore/timestamp/1.0" } } }, diff --git a/Firestore/Example/Tests/SpecTests/json/limbo_spec_test.json b/Firestore/Example/Tests/SpecTests/json/limbo_spec_test.json index 6cb27ecc40d..19cdbaa2195 100644 --- a/Firestore/Example/Tests/SpecTests/json/limbo_spec_test.json +++ b/Firestore/Example/Tests/SpecTests/json/limbo_spec_test.json @@ -2944,6 +2944,1916 @@ } ] }, + "Fix #8474 - Handles code path of no ack for limbo resolution query before global snapshot": { + "describeName": "Limbo Documents:", + "itName": "Fix #8474 - Handles code path of no ack for limbo resolution query before global snapshot", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": false, + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1001" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1001 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": false, + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchEntity": { + "key": "collection/c", + "removedTargets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1002" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1002 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + "collection/c" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "", + "targetPurpose": "TargetPurposeLimboResolution" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "userListen": { + "options": { + "includeMetadataChanges": true, + "waitForSyncWhenOnline": true + }, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 4 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "", + "targetPurpose": "TargetPurposeLimboResolution" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 4 + ], + "expectedState": { + "activeLimboDocs": [ + "collection/c" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "", + "targetPurpose": "TargetPurposeLimboResolution" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchEntity": { + "key": "collection/a", + "removedTargets": [ + 4 + ] + } + }, + { + "watchCurrent": [ + [ + 4 + ], + "resume-token-1004" + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "targets": [ + 4 + ] + } + }, + { + "watchCurrent": [ + [ + 4 + ], + "resume-token-1005" + ] + }, + { + "watchEntity": { + "key": "collection/c", + "removedTargets": [ + 4 + ] + } + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "a" + }, + "version": 1007 + } + ], + "targets": [ + 4 + ] + } + }, + { + "watchCurrent": [ + [ + 4 + ], + "resume-token-1007" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + 2, + 1 + ], + "version": 1010 + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1010 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "modified": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "a" + }, + "version": 1007 + } + ], + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + }, + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "a" + }, + "version": 1007 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchAck": [ + 1 + ] + }, + { + "watchEntity": { + "doc": { + "createTime": 0, + "key": "collection/c", + "value": null, + "version": 1009 + }, + "removedTargets": [ + 1 + ] + } + }, + { + "watchCurrent": [ + [ + 1 + ], + "resume-token-1009" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + 1 + ], + "version": 1100 + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1101 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ] + }, + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + } + ] + }, + "Fix #8474 - Limbo resolution for document is removed even if document updates for the document occurred before documentDelete in the global snapshot window": { + "describeName": "Limbo Documents:", + "itName": "Fix #8474 - Limbo resolution for document is removed even if document updates for the document occurred before documentDelete in the global snapshot window", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": false, + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1001" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1001 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": false, + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchEntity": { + "key": "collection/c", + "removedTargets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1002" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1002 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + "collection/c" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "", + "targetPurpose": "TargetPurposeLimboResolution" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "userListen": { + "options": { + "includeMetadataChanges": true, + "waitForSyncWhenOnline": true + }, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 4 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "", + "targetPurpose": "TargetPurposeLimboResolution" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 1 + ] + }, + { + "watchAck": [ + 4 + ] + }, + { + "watchEntity": { + "doc": { + "createTime": 0, + "key": "collection/c", + "value": null, + "version": 1009 + }, + "removedTargets": [ + 1 + ] + } + }, + { + "watchCurrent": [ + [ + 1 + ], + "resume-token-1009" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + 1, + 2 + ], + "version": 1009 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/c" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "", + "targetPurpose": "TargetPurposeLimboResolution" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchEntity": { + "key": "collection/a", + "removedTargets": [ + 4 + ] + } + }, + { + "watchCurrent": [ + [ + 4 + ], + "resume-token-1004" + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "targets": [ + 4 + ] + } + }, + { + "watchCurrent": [ + [ + 4 + ], + "resume-token-1005" + ] + }, + { + "watchEntity": { + "key": "collection/c", + "removedTargets": [ + 4 + ] + } + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "a" + }, + "version": 1007 + } + ], + "targets": [ + 4 + ] + } + }, + { + "watchCurrent": [ + [ + 4 + ], + "resume-token-1007" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + 2, + 1 + ], + "version": 1010 + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1010 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "modified": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "a" + }, + "version": 1007 + } + ], + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ] + }, + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "a" + }, + "version": 1007 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1100 + } + } + ] + }, + "Fix #8474 - Limbo resolution for document is removed even if document updates for the document occurred in the global snapshot window and no document delete was received for the limbo resolution query": { + "describeName": "Limbo Documents:", + "itName": "Fix #8474 - Limbo resolution for document is removed even if document updates for the document occurred in the global snapshot window and no document delete was received for the limbo resolution query", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": false, + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1001" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1001 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": false, + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchEntity": { + "key": "collection/c", + "removedTargets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1002" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1002 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + "collection/c" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "", + "targetPurpose": "TargetPurposeLimboResolution" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "userListen": { + "options": { + "includeMetadataChanges": true, + "waitForSyncWhenOnline": true + }, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 4 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "", + "targetPurpose": "TargetPurposeLimboResolution" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 1 + ] + }, + { + "watchAck": [ + 4 + ] + }, + { + "watchCurrent": [ + [ + 1 + ], + "resume-token-1009" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + 1, + 2 + ], + "version": 1009 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/c" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "", + "targetPurpose": "TargetPurposeLimboResolution" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchEntity": { + "key": "collection/a", + "removedTargets": [ + 4 + ] + } + }, + { + "watchCurrent": [ + [ + 4 + ], + "resume-token-1004" + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ], + "targets": [ + 4 + ] + } + }, + { + "watchCurrent": [ + [ + 4 + ], + "resume-token-1005" + ] + }, + { + "watchEntity": { + "key": "collection/c", + "removedTargets": [ + 4 + ] + } + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "a" + }, + "version": 1007 + } + ], + "targets": [ + 4 + ] + } + }, + { + "watchCurrent": [ + [ + 4 + ], + "resume-token-1007" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + 2, + 1 + ], + "version": 1010 + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1010 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "modified": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "a" + }, + "version": 1007 + } + ], + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ] + }, + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "a" + }, + "version": 1007 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "included": true, + "key": "c" + }, + "version": 1002 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "included", + "==", + true + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1100 + } + } + ] + }, "Limbo docs are resolved by primary client": { "describeName": "Limbo Documents:", "itName": "Limbo docs are resolved by primary client", @@ -10103,7 +12013,8 @@ "describeName": "Limbo Documents:", "itName": "LimitToLast query from secondary results in expected limbo doc", "tags": [ - "multi-client" + "multi-client", + "no-pipeline-conversion" ], "config": { "numClients": 2, @@ -10462,7 +12373,8 @@ "describeName": "Limbo Documents:", "itName": "LimitToLast query from secondary results in no expected limbo doc", "tags": [ - "multi-client" + "multi-client", + "no-pipeline-conversion" ], "config": { "numClients": 2, diff --git a/Firestore/Example/Tests/SpecTests/json/listen_source_spec_test.json b/Firestore/Example/Tests/SpecTests/json/listen_source_spec_test.json index 1912afc320f..e390612aaaf 100644 --- a/Firestore/Example/Tests/SpecTests/json/listen_source_spec_test.json +++ b/Firestore/Example/Tests/SpecTests/json/listen_source_spec_test.json @@ -1603,7 +1603,7 @@ } ], "errorCode": 0, - "fromCache": true, + "fromCache": false, "hasPendingWrites": false, "query": { "filters": [ @@ -1655,7 +1655,7 @@ } ], "errorCode": 0, - "fromCache": true, + "fromCache": false, "hasPendingWrites": false, "query": { "filters": [ @@ -1996,7 +1996,8 @@ "describeName": "Listens source options:", "itName": "Mirror queries being listened from different sources while listening to server in primary tab", "tags": [ - "multi-client" + "multi-client", + "no-pipeline-conversion" ], "config": { "numClients": 2, @@ -2211,7 +2212,7 @@ } ], "errorCode": 0, - "fromCache": true, + "fromCache": false, "hasPendingWrites": false, "query": { "filters": [ @@ -3233,7 +3234,8 @@ "describeName": "Listens source options:", "itName": "Mirror queries from different sources while listening to server in secondary tab", "tags": [ - "multi-client" + "multi-client", + "no-pipeline-conversion" ], "config": { "numClients": 2, @@ -3482,7 +3484,7 @@ } ], "errorCode": 0, - "fromCache": true, + "fromCache": false, "hasPendingWrites": false, "query": { "filters": [ @@ -5490,7 +5492,7 @@ } ], "errorCode": 0, - "fromCache": true, + "fromCache": false, "hasPendingWrites": false, "query": { "filters": [ @@ -5556,7 +5558,7 @@ } ], "errorCode": 0, - "fromCache": true, + "fromCache": false, "hasPendingWrites": true, "query": { "filters": [ diff --git a/Firestore/Example/Tests/SpecTests/json/listen_spec_test.json b/Firestore/Example/Tests/SpecTests/json/listen_spec_test.json index 7370a0cd675..b2810738225 100644 --- a/Firestore/Example/Tests/SpecTests/json/listen_spec_test.json +++ b/Firestore/Example/Tests/SpecTests/json/listen_spec_test.json @@ -333,6 +333,7 @@ "describeName": "Listens:", "itName": "Can listen/unlisten to mirror queries.", "tags": [ + "no-pipeline-conversion" ], "config": { "numClients": 1, @@ -3534,6 +3535,345 @@ } ] }, + "Global snapshots would not alter query state if there is no changes": { + "describeName": "Listens:", + "itName": "Global snapshots would not alter query state if there is no changes", + "tags": [ + "multi-client" + ], + "config": { + "numClients": 2, + "useEagerGCForMemory": false + }, + "steps": [ + { + "clientIndex": 0, + "drainQueue": true + }, + { + "applyClientState": { + "visibility": "visible" + }, + "clientIndex": 0, + "expectedState": { + "isPrimary": true + } + }, + { + "clientIndex": 0, + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "clientIndex": 0, + "watchAck": [ + 2 + ] + }, + { + "clientIndex": 0, + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "clientIndex": 0, + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "clientIndex": 0, + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "clientIndex": 0, + "userUnlisten": [ + 2, + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "expectedState": { + "activeTargets": { + } + } + }, + { + "clientIndex": 0, + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "clientIndex": 0, + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + } + } + } + }, + { + "clientIndex": 0, + "watchAck": [ + 2 + ] + }, + { + "clientIndex": 0, + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "clientIndex": 0, + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "clientIndex": 0, + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "clientIndex": 0, + "watchSnapshot": { + "resumeToken": "resume-token-3000", + "targetIds": [ + ], + "version": 3000 + } + }, + { + "clientIndex": 1, + "drainQueue": true + }, + { + "clientIndex": 1, + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + } + ] + }, "Ignores update from inactive target": { "describeName": "Listens:", "itName": "Ignores update from inactive target", @@ -5984,7 +6324,8 @@ "describeName": "Listens:", "itName": "Mirror queries from different secondary client", "tags": [ - "multi-client" + "multi-client", + "no-pipeline-conversion" ], "config": { "numClients": 3, @@ -6424,7 +6765,8 @@ "describeName": "Listens:", "itName": "Mirror queries from primary and secondary client", "tags": [ - "multi-client" + "multi-client", + "no-pipeline-conversion" ], "config": { "numClients": 2, @@ -7136,7 +7478,8 @@ "describeName": "Listens:", "itName": "Mirror queries from same secondary client", "tags": [ - "multi-client" + "multi-client", + "no-pipeline-conversion" ], "config": { "numClients": 2, @@ -13270,7 +13613,10 @@ "describeName": "Listens:", "itName": "Secondary client advances query state with global snapshot from primary", "tags": [ - "multi-client" + "multi-client", + "no-web", + "no-ios", + "no-android" ], "config": { "numClients": 2, diff --git a/Firestore/Example/Tests/SpecTests/json/query_spec_test.json b/Firestore/Example/Tests/SpecTests/json/query_spec_test.json index 7aed45ec207..986a8307be5 100644 --- a/Firestore/Example/Tests/SpecTests/json/query_spec_test.json +++ b/Firestore/Example/Tests/SpecTests/json/query_spec_test.json @@ -1617,5 +1617,323 @@ } } ] + }, + "Queries in different tabs will not interfere": { + "describeName": "Queries:", + "itName": "Queries in different tabs will not interfere", + "tags": [ + "multi-client" + ], + "config": { + "numClients": 2, + "useEagerGCForMemory": false + }, + "steps": [ + { + "clientIndex": 0, + "drainQueue": true + }, + { + "applyClientState": { + "visibility": "visible" + }, + "clientIndex": 0, + "expectedState": { + "isPrimary": true + } + }, + { + "clientIndex": 0, + "userListen": { + "query": { + "filters": [ + [ + "key", + "==", + "a" + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + [ + "key", + "==", + "a" + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "clientIndex": 0, + "watchAck": [ + 2 + ] + }, + { + "clientIndex": 0, + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "clientIndex": 1, + "drainQueue": true + }, + { + "clientIndex": 1, + "userListen": { + "query": { + "filters": [ + [ + "key", + "==", + "b" + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 4 + }, + "expectedState": { + "activeTargets": { + "4": { + "queries": [ + { + "filters": [ + [ + "key", + "==", + "b" + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "clientIndex": 0, + "drainQueue": true, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + [ + "key", + "==", + "a" + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "key", + "==", + "b" + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "clientIndex": 0, + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "clientIndex": 0, + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "key", + "==", + "a" + ] + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "clientIndex": 1, + "drainQueue": true + }, + { + "clientIndex": 0, + "drainQueue": true + }, + { + "clientIndex": 0, + "watchAck": [ + 4 + ] + }, + { + "clientIndex": 0, + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b" + }, + "version": 1000 + } + ], + "targets": [ + 4 + ] + } + }, + { + "clientIndex": 0, + "watchCurrent": [ + [ + 4 + ], + "resume-token-2000" + ] + }, + { + "clientIndex": 0, + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + } + }, + { + "clientIndex": 1, + "drainQueue": true, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "key", + "==", + "b" + ] + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + } + ] } } diff --git a/Firestore/core/src/core/event_manager.cc b/Firestore/core/src/core/event_manager.cc index 4f613ee92a2..0711903e93c 100644 --- a/Firestore/core/src/core/event_manager.cc +++ b/Firestore/core/src/core/event_manager.cc @@ -37,15 +37,11 @@ EventManager::EventManager(QueryEventSource* query_event_source) model::TargetId EventManager::AddQueryListener( std::shared_ptr listener) { const QueryOrPipeline& query_or_pipeline = listener->query(); - if (query_or_pipeline.IsPipeline()) { - HARD_FAIL("Unimplemented"); - } - const auto& query = query_or_pipeline.query(); ListenerSetupAction listener_action = ListenerSetupAction::NoSetupActionRequired; - auto inserted = queries_.emplace(query, QueryListenersInfo{}); + auto inserted = queries_.emplace(query_or_pipeline, QueryListenersInfo{}); // If successfully inserted, it means we haven't listened to this query // before. bool first_listen = inserted.second; @@ -98,10 +94,6 @@ model::TargetId EventManager::AddQueryListener( void EventManager::RemoveQueryListener( std::shared_ptr listener) { const auto& query_or_pipeline = listener->query(); - if (query_or_pipeline.IsPipeline()) { - HARD_FAIL("Unimplemented"); - } - ListenerRemovalAction listener_action = ListenerRemovalAction::NoRemovalActionRequired; diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index 677c95a67c6..5bd397daab9 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -335,11 +335,11 @@ bool QueryOrPipeline::Matches(const model::Document& doc) const { model::DocumentComparator QueryOrPipeline::Comparator() const { if (IsPipeline()) { // Capture pipeline by reference. Orderings captured by value inside lambda. - const auto& p = pipeline(); + const api::RealtimePipeline& p = pipeline(); const auto& orderings = GetLastEffectiveSortOrderings(p); return model::DocumentComparator( - [&p, &orderings](const model::Document& d1, - const model::Document& d2) -> util::ComparisonResult { + [p, orderings](const model::Document& d1, + const model::Document& d2) -> util::ComparisonResult { auto context = const_cast(p).evaluate_context(); diff --git a/Firestore/core/src/remote/remote_event.cc b/Firestore/core/src/remote/remote_event.cc index 4ab8e9132e6..88a72991798 100644 --- a/Firestore/core/src/remote/remote_event.cc +++ b/Firestore/core/src/remote/remote_event.cc @@ -237,11 +237,44 @@ create_existence_filter_mismatch_info_for_testing_hooks( std::move(bloom_filter_info)}; } -bool IsSingleDocumentTarget(const core::TargetOrPipeline target_or_pipeline) { - // TODO(pipeline): We only handle the non-pipeline case because realtime - // pipeline does not support single document lookup yet. - return !target_or_pipeline.IsPipeline() && - target_or_pipeline.target().IsDocumentQuery(); +absl::optional GetSingleDocumentPath( + const core::TargetOrPipeline target_or_pipeline) { + if (target_or_pipeline.IsPipeline()) { + if (core::GetPipelineSourceType(target_or_pipeline.pipeline()) == + core::PipelineSourceType::kDocuments) { + const auto& documents = + core::GetPipelineDocuments(target_or_pipeline.pipeline()); + if (documents.has_value() && documents.value().size() == 1) { + return model::ResourcePath::FromString(documents.value()[0]); + } + } + } else if (target_or_pipeline.target().IsDocumentQuery()) { + return target_or_pipeline.target().path(); + } + + return absl::nullopt; +} + +absl::optional> GetDocumentPaths( + const core::TargetOrPipeline target_or_pipeline) { + if (target_or_pipeline.IsPipeline()) { + if (core::GetPipelineSourceType(target_or_pipeline.pipeline()) == + core::PipelineSourceType::kDocuments) { + const auto& documents = + core::GetPipelineDocuments(target_or_pipeline.pipeline()); + if (documents.has_value()) { + std::vector results; + for (const std::string& document : documents.value()) { + results.push_back(model::ResourcePath::FromString(document)); + } + return results; + } + } + } else if (target_or_pipeline.target().IsDocumentQuery()) { + return std::vector{target_or_pipeline.target().path()}; + } + + return absl::nullopt; } } // namespace @@ -256,7 +289,8 @@ void WatchChangeAggregator::HandleExistenceFilter( const core::TargetOrPipeline& target_or_pipeline = target_data->target_or_pipeline(); - if (!IsSingleDocumentTarget(target_or_pipeline)) { + auto single_doc_path = GetSingleDocumentPath(target_or_pipeline); + if (!single_doc_path.has_value()) { int current_size = GetCurrentDocumentCountForTarget(target_id); if (current_size != expected_count) { // Apply bloom filter to identify and mark removed documents. @@ -292,7 +326,7 @@ void WatchChangeAggregator::HandleExistenceFilter( // another query that will raise this document as part of a snapshot // until it is resolved, essentially exposing inconsistency between // queries. - DocumentKey key{target_or_pipeline.target().path()}; + DocumentKey key{std::move(single_doc_path.value())}; RemoveDocumentFromTarget( target_id, key, MutableDocument::NoDocument(key, SnapshotVersion::None())); @@ -377,20 +411,22 @@ RemoteEvent WatchChangeAggregator::CreateRemoteEvent( absl::optional target_data = TargetDataForActiveTarget(target_id); if (target_data) { - if (target_state.current() && - IsSingleDocumentTarget(target_data->target_or_pipeline())) { + auto doc_paths = GetDocumentPaths(target_data->target_or_pipeline()); + if (target_state.current() && doc_paths.has_value()) { // Document queries for document that don't exist can produce an empty // result set. To update our local cache, we synthesize a document // delete if we have not previously received the document. This resolves // the limbo state of the document, removing it from // SyncEngine::limbo_document_refs_. - DocumentKey key{target_data->target_or_pipeline().target().path()}; - if (pending_document_updates_.find(key) == - pending_document_updates_.end() && - !TargetContainsDocument(target_id, key)) { - RemoveDocumentFromTarget( - target_id, key, - MutableDocument::NoDocument(key, snapshot_version)); + for (const model::ResourcePath& single_doc_path : doc_paths.value()) { + DocumentKey key{std::move(single_doc_path)}; + if (pending_document_updates_.find(key) == + pending_document_updates_.end() && + !TargetContainsDocument(target_id, key)) { + RemoveDocumentFromTarget( + target_id, key, + MutableDocument::NoDocument(key, snapshot_version)); + } } } diff --git a/Firestore/core/src/remote/serializer.cc b/Firestore/core/src/remote/serializer.cc index faa2e687a69..932064a01a9 100644 --- a/Firestore/core/src/remote/serializer.cc +++ b/Firestore/core/src/remote/serializer.cc @@ -1622,8 +1622,8 @@ std::unique_ptr Serializer::DecodeStage( document_paths.reserve(args_count); for (pb_size_t i = 0; i < args_count; ++i) { if (current_args[i].which_value_type == - google_firestore_v1_Value_string_value_tag) { - document_paths.push_back(DecodeString(current_args[i].string_value)); + google_firestore_v1_Value_reference_value_tag) { + document_paths.push_back(DecodeString(current_args[i].reference_value)); } else { context->Fail(StringFormat( "Invalid argument type for 'documents' stage at index %zu: " diff --git a/Firestore/core/test/unit/core/pipeline/canonify_eq_test.cc b/Firestore/core/test/unit/core/pipeline/canonify_eq_test.cc index c8c2e7b8bf7..7a8f4caab57 100644 --- a/Firestore/core/test/unit/core/pipeline/canonify_eq_test.cc +++ b/Firestore/core/test/unit/core/pipeline/canonify_eq_test.cc @@ -75,7 +75,7 @@ using testutil::EqExpr; // Helper to get canonical ID directly for RealtimePipeline std::string GetPipelineCanonicalId(const RealtimePipeline& pipeline) { - QueryOrPipeline variant = pipeline; + QueryOrPipeline variant = QueryOrPipeline(pipeline); // Use the specific helper for QueryOrPipeline canonicalization return variant.CanonicalId(); } @@ -246,8 +246,8 @@ TEST_F(CanonifyEqPipelineTest, EqReturnsTrueForIdenticalPipelines) { p2 = p2.AddingStage(std::make_shared(EqExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); - QueryOrPipeline v1 = p1; - QueryOrPipeline v2 = p2; + QueryOrPipeline v1 = QueryOrPipeline(p1); + QueryOrPipeline v2 = QueryOrPipeline(p2); EXPECT_TRUE(v1 == v2); // Expect TRUE based on TS } @@ -259,8 +259,8 @@ TEST_F(CanonifyEqPipelineTest, EqReturnsFalseForDifferentStages) { RealtimePipeline p2 = StartPipeline("test"); p2 = p2.AddingStage(std::make_shared(10)); - QueryOrPipeline v1 = p1; - QueryOrPipeline v2 = p2; + QueryOrPipeline v1 = QueryOrPipeline(p1); + QueryOrPipeline v2 = QueryOrPipeline(p2); EXPECT_FALSE(v1 == v2); // Expect FALSE based on TS } @@ -274,8 +274,8 @@ TEST_F(CanonifyEqPipelineTest, EqReturnsFalseForDifferentParamsInStage) { EqExpr({std::make_shared("bar"), SharedConstant(Value(42LL))}))); // Different field - QueryOrPipeline v1 = p1; - QueryOrPipeline v2 = p2; + QueryOrPipeline v1 = QueryOrPipeline(p1); + QueryOrPipeline v2 = QueryOrPipeline(p2); EXPECT_FALSE(v1 == v2); // Expect FALSE based on TS } @@ -290,8 +290,8 @@ TEST_F(CanonifyEqPipelineTest, EqReturnsFalseForDifferentStageOrder) { p2 = p2.AddingStage(std::make_shared(EqExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); - QueryOrPipeline v1 = p1; - QueryOrPipeline v2 = p2; + QueryOrPipeline v1 = QueryOrPipeline(p1); + QueryOrPipeline v2 = QueryOrPipeline(p2); EXPECT_FALSE(v1 == v2); // Expect FALSE based on TS }