• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "icing/monkey_test/icing-monkey-test-runner.h"
16 
17 #include <algorithm>
18 #include <array>
19 #include <cstdint>
20 #include <functional>
21 #include <memory>
22 #include <random>
23 #include <string>
24 #include <utility>
25 #include <vector>
26 
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "icing/absl_ports/str_cat.h"
30 #include "icing/file/destructible-directory.h"
31 #include "icing/icing-search-engine.h"
32 #include "icing/monkey_test/in-memory-icing-search-engine.h"
33 #include "icing/monkey_test/monkey-test-generators.h"
34 #include "icing/monkey_test/monkey-test-util.h"
35 #include "icing/monkey_test/monkey-tokenized-document.h"
36 #include "icing/portable/equals-proto.h"
37 #include "icing/proto/document.pb.h"
38 #include "icing/proto/initialize.pb.h"
39 #include "icing/proto/schema.pb.h"
40 #include "icing/proto/scoring.pb.h"
41 #include "icing/proto/search.pb.h"
42 #include "icing/proto/status.pb.h"
43 #include "icing/proto/term.pb.h"
44 #include "icing/result/result-state-manager.h"
45 #include "icing/testing/common-matchers.h"
46 #include "icing/testing/tmp-directory.h"
47 #include "icing/util/logging.h"
48 
49 namespace icing {
50 namespace lib {
51 
52 namespace {
53 
54 using ::icing::lib::portable_equals_proto::EqualsProto;
55 using ::testing::Eq;
56 using ::testing::Le;
57 using ::testing::Not;
58 using ::testing::SizeIs;
59 using ::testing::UnorderedElementsAreArray;
60 
GenerateRandomSearchSpecProto(MonkeyTestRandomEngine * random,MonkeyDocumentGenerator * document_generator)61 SearchSpecProto GenerateRandomSearchSpecProto(
62     MonkeyTestRandomEngine* random,
63     MonkeyDocumentGenerator* document_generator) {
64   // Get a random token from the language set as a single term query.
65   std::string query(document_generator->GetToken());
66   std::uniform_int_distribution<> dist(0, 1);
67   TermMatchType::Code term_match_type = TermMatchType::EXACT_ONLY;
68   if (dist(*random) == 1) {
69     term_match_type = TermMatchType::PREFIX;
70     // Randomly drop a suffix of query to test prefix query.
71     std::uniform_int_distribution<> size_dist(1, query.size());
72     query.resize(size_dist(*random));
73   }
74   // 50% chance of getting a section restriction.
75   if (dist(*random) == 1) {
76     const SchemaTypeConfigProto& type_config = document_generator->GetType();
77     if (type_config.properties_size() > 0) {
78       std::uniform_int_distribution<> prop_dist(
79           0, type_config.properties_size() - 1);
80       query = absl_ports::StrCat(
81           type_config.properties(prop_dist(*random)).property_name(), ":",
82           query);
83     }
84   }
85   SearchSpecProto search_spec;
86   search_spec.set_term_match_type(term_match_type);
87   search_spec.set_query(query);
88   return search_spec;
89 }
90 
GenerateRandomScoringSpec(MonkeyTestRandomEngine * random)91 ScoringSpecProto GenerateRandomScoringSpec(MonkeyTestRandomEngine* random) {
92   ScoringSpecProto scoring_spec;
93 
94   constexpr std::array<ScoringSpecProto::RankingStrategy::Code, 3>
95       ranking_strategies = {
96           ScoringSpecProto::RankingStrategy::DOCUMENT_SCORE,
97           ScoringSpecProto::RankingStrategy::CREATION_TIMESTAMP,
98           ScoringSpecProto::RankingStrategy::RELEVANCE_SCORE};
99 
100   std::uniform_int_distribution<> dist(0, ranking_strategies.size() - 1);
101   scoring_spec.set_rank_by(ranking_strategies[dist(*random)]);
102   return scoring_spec;
103 }
104 
GenerateRandomSnippetSpecProto(MonkeyTestRandomEngine * random,const ResultSpecProto & result_spec)105 ResultSpecProto::SnippetSpecProto GenerateRandomSnippetSpecProto(
106     MonkeyTestRandomEngine* random, const ResultSpecProto& result_spec) {
107   ResultSpecProto::SnippetSpecProto snippet_spec;
108 
109   std::uniform_int_distribution<> num_to_snippet_dist(
110       0, result_spec.num_per_page() * 2);
111   snippet_spec.set_num_to_snippet(num_to_snippet_dist(*random));
112 
113   std::uniform_int_distribution<> num_matches_per_property_dist(0, 10);
114   snippet_spec.set_num_matches_per_property(
115       num_matches_per_property_dist(*random));
116 
117   std::uniform_int_distribution<> dist(0, 4);
118   int random_num = dist(*random);
119   // 1/5 chance of getting one of 0 (disabled), 8, 32, 128, 512
120   int max_window_utf32_length =
121       random_num == 0 ? 0 : (1 << (2 * random_num + 1));
122   snippet_spec.set_max_window_utf32_length(max_window_utf32_length);
123   return snippet_spec;
124 }
125 
GenerateTypePropertyMask(MonkeyTestRandomEngine * random,const SchemaTypeConfigProto & type_config)126 TypePropertyMask GenerateTypePropertyMask(
127     MonkeyTestRandomEngine* random, const SchemaTypeConfigProto& type_config) {
128   TypePropertyMask type_property_mask;
129   type_property_mask.set_schema_type(type_config.schema_type());
130   for (const auto& properties : type_config.properties()) {
131     // 25% chance of adding the current property to the mask.
132     std::uniform_int_distribution<> dist(0, 3);
133     if (dist(*random) == 0) {
134       type_property_mask.add_paths(properties.property_name());
135     }
136   }
137   return type_property_mask;
138 }
139 
GenerateRandomResultSpecProto(MonkeyTestRandomEngine * random,const SchemaProto * schema)140 ResultSpecProto GenerateRandomResultSpecProto(MonkeyTestRandomEngine* random,
141                                               const SchemaProto* schema) {
142   std::uniform_int_distribution<> dist(0, 4);
143   ResultSpecProto result_spec;
144   // 1/5 chance of getting one of 1, 4, 16, 64, 256
145   int num_per_page = 1 << (2 * dist(*random));
146   result_spec.set_num_per_page(num_per_page);
147   *result_spec.mutable_snippet_spec() =
148       GenerateRandomSnippetSpecProto(random, result_spec);
149 
150   // 1/5 chance of enabling projection.
151   if (dist(*random) == 0) {
152     for (const SchemaTypeConfigProto& type_config : schema->types()) {
153       // 25% chance of adding the current type to the projection.
154       std::uniform_int_distribution<> dist(0, 3);
155       if (dist(*random) == 0) {
156         *result_spec.add_type_property_masks() =
157             GenerateTypePropertyMask(random, type_config);
158       }
159     }
160   }
161   return result_spec;
162 }
163 
SortDocuments(std::vector<DocumentProto> & documents)164 void SortDocuments(std::vector<DocumentProto>& documents) {
165   std::sort(documents.begin(), documents.end(),
166             [](const DocumentProto& doc1, const DocumentProto& doc2) {
167               if (doc1.namespace_() != doc2.namespace_()) {
168                 return doc1.namespace_() < doc2.namespace_();
169               }
170               return doc1.uri() < doc2.uri();
171             });
172 }
173 
174 }  // namespace
175 
IcingMonkeyTestRunner(IcingMonkeyTestRunnerConfiguration config)176 IcingMonkeyTestRunner::IcingMonkeyTestRunner(
177     IcingMonkeyTestRunnerConfiguration config)
178     : config_(std::move(config)),
179       random_(config_.seed),
180       in_memory_icing_(std::make_unique<InMemoryIcingSearchEngine>(&random_)),
181       schema_generator_(
182           std::make_unique<MonkeySchemaGenerator>(&random_, &config_)) {
183   ICING_LOG(INFO) << "Monkey test runner started with seed: " << config_.seed;
184   std::string dir = GetTestTempDir() + "/icing/monkey";
185   filesystem_.DeleteDirectoryRecursively(dir.c_str());
186   icing_dir_ = std::make_unique<DestructibleDirectory>(&filesystem_, dir);
187 }
188 
Run(uint32_t num)189 void IcingMonkeyTestRunner::Run(uint32_t num) {
190   ASSERT_TRUE(icing_ != nullptr)
191       << "Icing search engine has not yet been created. Please call "
192          "Initialize() first";
193 
194   uint32_t frequency_sum = 0;
195   for (const auto& schedule : config_.monkey_api_schedules) {
196     frequency_sum += schedule.second;
197   }
198   std::uniform_int_distribution<> dist(0, frequency_sum - 1);
199   for (; num; --num) {
200     int p = dist(random_);
201     for (const auto& schedule : config_.monkey_api_schedules) {
202       if (p < schedule.second) {
203         ASSERT_NO_FATAL_FAILURE(schedule.first(this));
204         break;
205       }
206       p -= schedule.second;
207     }
208     ICING_LOG(INFO) << "Completed Run #" << num
209                     << ". Documents in the in-memory icing: "
210                     << in_memory_icing_->GetNumAliveDocuments();
211   }
212 }
213 
SetSchema(SchemaProto && schema)214 SetSchemaResultProto IcingMonkeyTestRunner::SetSchema(SchemaProto&& schema) {
215   in_memory_icing_->SetSchema(std::move(schema));
216   document_generator_ = std::make_unique<MonkeyDocumentGenerator>(
217       &random_, in_memory_icing_->GetSchema(), &config_);
218   return icing_->SetSchema(*in_memory_icing_->GetSchema(),
219                            /*ignore_errors_and_delete_documents=*/true);
220 }
221 
Initialize()222 void IcingMonkeyTestRunner::Initialize() {
223   ASSERT_NO_FATAL_FAILURE(CreateIcingSearchEngine());
224 
225   SchemaProto schema = schema_generator_->GenerateSchema();
226   ICING_LOG(DBG) << "Schema Generated: " << schema.DebugString();
227 
228   ASSERT_THAT(SetSchema(std::move(schema)).status(), ProtoIsOk());
229 }
230 
DoUpdateSchema()231 void IcingMonkeyTestRunner::DoUpdateSchema() {
232   ICING_LOG(INFO) << "Monkey updating schema";
233 
234   MonkeySchemaGenerator::UpdateSchemaResult result =
235       schema_generator_->UpdateSchema(*in_memory_icing_->GetSchema());
236   if (result.is_invalid_schema) {
237     SetSchemaResultProto set_schema_result =
238         icing_->SetSchema(result.schema,
239                           /*ignore_errors_and_delete_documents=*/true);
240     ASSERT_THAT(set_schema_result.status(), Not(ProtoIsOk()));
241     return;
242   }
243   ICING_LOG(DBG) << "Updating schema to: " << result.schema.DebugString();
244   SetSchemaResultProto icing_set_schema_result =
245       SetSchema(std::move(result.schema));
246   ASSERT_THAT(icing_set_schema_result.status(), ProtoIsOk());
247   ASSERT_THAT(icing_set_schema_result.deleted_schema_types(),
248               UnorderedElementsAreArray(result.schema_types_deleted));
249   ASSERT_THAT(icing_set_schema_result.incompatible_schema_types(),
250               UnorderedElementsAreArray(result.schema_types_incompatible));
251   ASSERT_THAT(
252       icing_set_schema_result.index_incompatible_changed_schema_types(),
253       UnorderedElementsAreArray(result.schema_types_index_incompatible));
254 
255   // Update in-memory icing
256   for (const std::string& deleted_type : result.schema_types_deleted) {
257     ICING_ASSERT_OK(in_memory_icing_->DeleteBySchemaType(deleted_type));
258   }
259   for (const std::string& incompatible_type :
260        result.schema_types_incompatible) {
261     ICING_ASSERT_OK(in_memory_icing_->DeleteBySchemaType(incompatible_type));
262   }
263 }
264 
DoGet()265 void IcingMonkeyTestRunner::DoGet() {
266   InMemoryIcingSearchEngine::PickDocumentResult document =
267       in_memory_icing_->RandomPickDocument(/*p_alive=*/0.70, /*p_all=*/0.28,
268                                            /*p_other=*/0.02);
269   ICING_LOG(INFO) << "Monkey getting namespace: " << document.name_space
270                   << ", uri: " << document.uri;
271   GetResultProto get_result =
272       icing_->Get(document.name_space, document.uri,
273                   GetResultSpecProto::default_instance());
274   if (document.document.has_value()) {
275     ASSERT_THAT(get_result.status(), ProtoIsOk())
276         << "Cannot find the document that is supposed to exist.";
277     ASSERT_THAT(get_result.document(), EqualsProto(document.document.value()))
278         << "The document found does not match with the value in the in-memory "
279            "icing.";
280   } else {
281     // Should expect that no document has been found.
282     if (get_result.status().code() != StatusProto::NOT_FOUND) {
283       if (get_result.status().code() == StatusProto::OK) {
284         FAIL() << "Found a document that is not supposed to be found.";
285       }
286       FAIL() << "Icing search engine failure (code "
287              << get_result.status().code()
288              << "): " << get_result.status().message();
289     }
290   }
291 }
292 
DoGetAllNamespaces()293 void IcingMonkeyTestRunner::DoGetAllNamespaces() {
294   ICING_LOG(INFO) << "Monkey getting all namespaces";
295   GetAllNamespacesResultProto get_result = icing_->GetAllNamespaces();
296   ASSERT_THAT(get_result.status(), ProtoIsOk());
297   ASSERT_THAT(get_result.namespaces(),
298               UnorderedElementsAreArray(in_memory_icing_->GetAllNamespaces()));
299 }
300 
DoPut()301 void IcingMonkeyTestRunner::DoPut() {
302   MonkeyTokenizedDocument doc = document_generator_->GenerateDocument();
303   ICING_LOG(INFO) << "Monkey document generated, namespace: "
304                   << doc.document.namespace_()
305                   << ", uri: " << doc.document.uri();
306   ICING_LOG(DBG) << doc.document.DebugString();
307   in_memory_icing_->Put(doc);
308   ASSERT_THAT(icing_->Put(doc.document).status(), ProtoIsOk());
309 }
310 
DoDelete()311 void IcingMonkeyTestRunner::DoDelete() {
312   InMemoryIcingSearchEngine::PickDocumentResult document =
313       in_memory_icing_->RandomPickDocument(/*p_alive=*/0.70, /*p_all=*/0.2,
314                                            /*p_other=*/0.1);
315   ICING_LOG(INFO) << "Monkey deleting namespace: " << document.name_space
316                   << ", uri: " << document.uri;
317   DeleteResultProto delete_result =
318       icing_->Delete(document.name_space, document.uri);
319   if (document.document.has_value()) {
320     ICING_ASSERT_OK(
321         in_memory_icing_->Delete(document.name_space, document.uri));
322     ASSERT_THAT(delete_result.status(), ProtoIsOk())
323         << "Cannot delete an existing document.";
324   } else {
325     // Should expect that no document has been deleted.
326     if (delete_result.status().code() != StatusProto::NOT_FOUND) {
327       if (delete_result.status().code() == StatusProto::OK) {
328         FAIL() << "Deleted a non-existing document without an error.";
329       }
330       FAIL() << "Icing search engine failure (code "
331              << delete_result.status().code()
332              << "): " << delete_result.status().message();
333     }
334   }
335 }
336 
DoDeleteByNamespace()337 void IcingMonkeyTestRunner::DoDeleteByNamespace() {
338   std::string name_space = document_generator_->GetNamespace();
339   ICING_LOG(INFO) << "Monkey deleting namespace: " << name_space;
340   DeleteByNamespaceResultProto delete_result =
341       icing_->DeleteByNamespace(name_space);
342   ICING_ASSERT_OK_AND_ASSIGN(uint32_t num_docs_deleted,
343                              in_memory_icing_->DeleteByNamespace(name_space));
344   if (num_docs_deleted != 0) {
345     ASSERT_THAT(delete_result.status(), ProtoIsOk())
346         << "Cannot delete an existing namespace.";
347     ASSERT_THAT(delete_result.delete_stats().num_documents_deleted(),
348                 Eq(num_docs_deleted));
349   } else {
350     // Should expect that no document has been deleted.
351     if (delete_result.status().code() != StatusProto::NOT_FOUND) {
352       if (delete_result.status().code() == StatusProto::OK) {
353         FAIL() << "Deleted a non-existing namespace without an error.";
354       }
355       FAIL() << "Icing search engine failure (code "
356              << delete_result.status().code()
357              << "): " << delete_result.status().message();
358     }
359   }
360 }
361 
DoDeleteBySchemaType()362 void IcingMonkeyTestRunner::DoDeleteBySchemaType() {
363   std::string schema_type = document_generator_->GetType().schema_type();
364   ICING_LOG(INFO) << "Monkey deleting type: " << schema_type;
365   DeleteBySchemaTypeResultProto delete_result =
366       icing_->DeleteBySchemaType(schema_type);
367   ICING_ASSERT_OK_AND_ASSIGN(uint32_t num_docs_deleted,
368                              in_memory_icing_->DeleteBySchemaType(schema_type));
369   if (num_docs_deleted != 0) {
370     ASSERT_THAT(delete_result.status(), ProtoIsOk())
371         << "Cannot delete an existing schema type.";
372     ASSERT_THAT(delete_result.delete_stats().num_documents_deleted(),
373                 Eq(num_docs_deleted));
374   } else {
375     // Should expect that no document has been deleted.
376     if (delete_result.status().code() != StatusProto::NOT_FOUND) {
377       if (delete_result.status().code() == StatusProto::OK) {
378         FAIL() << "Deleted a non-existing schema type without an error.";
379       }
380       FAIL() << "Icing search engine failure (code "
381              << delete_result.status().code()
382              << "): " << delete_result.status().message();
383     }
384   }
385 }
386 
DoDeleteByQuery()387 void IcingMonkeyTestRunner::DoDeleteByQuery() {
388   SearchSpecProto search_spec =
389       GenerateRandomSearchSpecProto(&random_, document_generator_.get());
390   ICING_LOG(INFO) << "Monkey deleting by query: " << search_spec.query();
391   DeleteByQueryResultProto delete_result = icing_->DeleteByQuery(search_spec);
392   ICING_ASSERT_OK_AND_ASSIGN(uint32_t num_docs_deleted,
393                              in_memory_icing_->DeleteByQuery(search_spec));
394   if (num_docs_deleted != 0) {
395     ASSERT_THAT(delete_result.status(), ProtoIsOk())
396         << "Cannot delete documents that matches with the query.";
397     ASSERT_THAT(delete_result.delete_by_query_stats().num_documents_deleted(),
398                 Eq(num_docs_deleted));
399   } else {
400     // Should expect that no document has been deleted.
401     if (delete_result.status().code() != StatusProto::NOT_FOUND) {
402       if (delete_result.status().code() == StatusProto::OK) {
403         FAIL() << "Deleted documents that should not match with the query "
404                   "without an error.";
405       }
406       FAIL() << "Icing search engine failure (code "
407              << delete_result.status().code()
408              << "): " << delete_result.status().message();
409     }
410   }
411   ICING_LOG(INFO)
412       << delete_result.delete_by_query_stats().num_documents_deleted()
413       << " documents deleted by query.";
414 }
415 
DoSearch()416 void IcingMonkeyTestRunner::DoSearch() {
417   std::unique_ptr<SearchSpecProto> search_spec =
418       std::make_unique<SearchSpecProto>(
419           GenerateRandomSearchSpecProto(&random_, document_generator_.get()));
420   std::unique_ptr<ScoringSpecProto> scoring_spec =
421       std::make_unique<ScoringSpecProto>(GenerateRandomScoringSpec(&random_));
422   std::unique_ptr<ResultSpecProto> result_spec =
423       std::make_unique<ResultSpecProto>(GenerateRandomResultSpecProto(
424           &random_, in_memory_icing_->GetSchema()));
425   const ResultSpecProto::SnippetSpecProto snippet_spec =
426       result_spec->snippet_spec();
427   bool is_projection_enabled = !result_spec->type_property_masks().empty();
428 
429   ICING_LOG(INFO) << "Monkey searching by query: " << search_spec->query()
430                   << ", term_match_type: " << search_spec->term_match_type();
431   ICING_VLOG(1) << "search_spec:\n" << search_spec->DebugString();
432   ICING_VLOG(1) << "scoring_spec:\n" << scoring_spec->DebugString();
433   ICING_VLOG(1) << "result_spec:\n" << result_spec->DebugString();
434 
435   ICING_ASSERT_OK_AND_ASSIGN(std::vector<DocumentProto> exp_documents,
436                              in_memory_icing_->Search(*search_spec));
437 
438   SearchResultProto search_result =
439       icing_->Search(*search_spec, *scoring_spec, *result_spec);
440   ASSERT_THAT(search_result.status(), ProtoIsOk());
441 
442   // Delete all of the specs used in the search. GetNextPage should have no
443   // problem because it shouldn't be keeping any references to them.
444   search_spec.reset();
445   scoring_spec.reset();
446   result_spec.reset();
447 
448   std::vector<DocumentProto> actual_documents;
449   int num_snippeted = 0;
450   while (true) {
451     for (const SearchResultProto::ResultProto& doc : search_result.results()) {
452       actual_documents.push_back(doc.document());
453       if (!doc.snippet().entries().empty()) {
454         ++num_snippeted;
455         for (const SnippetProto::EntryProto& entry : doc.snippet().entries()) {
456           ASSERT_THAT(entry.snippet_matches(),
457                       SizeIs(Le(snippet_spec.num_matches_per_property())));
458         }
459       }
460     }
461     if (search_result.next_page_token() == kInvalidNextPageToken) {
462       break;
463     }
464     search_result = icing_->GetNextPage(search_result.next_page_token());
465     ASSERT_THAT(search_result.status(), ProtoIsOk());
466   }
467   // The maximum number of scored documents allowed in Icing is 30000, in which
468   // case we are not able to compare the results with the in-memory Icing.
469   if (exp_documents.size() >= 30000) {
470     return;
471   }
472   if (snippet_spec.num_matches_per_property() > 0 && !is_projection_enabled) {
473     ASSERT_THAT(num_snippeted,
474                 Eq(std::min<uint32_t>(exp_documents.size(),
475                                       snippet_spec.num_to_snippet())));
476   }
477   SortDocuments(exp_documents);
478   SortDocuments(actual_documents);
479   ASSERT_THAT(actual_documents, SizeIs(exp_documents.size()));
480   for (int i = 0; i < exp_documents.size(); ++i) {
481     if (is_projection_enabled) {
482       ASSERT_THAT(actual_documents[i].namespace_(),
483                   Eq(exp_documents[i].namespace_()));
484       ASSERT_THAT(actual_documents[i].uri(), Eq(exp_documents[i].uri()));
485       continue;
486     }
487     ASSERT_THAT(actual_documents[i], EqualsProto(exp_documents[i]));
488   }
489   ICING_LOG(INFO) << exp_documents.size() << " documents found by query.";
490 }
491 
ReloadFromDisk()492 void IcingMonkeyTestRunner::ReloadFromDisk() {
493   ICING_LOG(INFO) << "Monkey reloading from disk";
494   // Destruct the icing search engine by resetting the unique pointer.
495   icing_.reset();
496   ASSERT_NO_FATAL_FAILURE(CreateIcingSearchEngine());
497 }
498 
DoOptimize()499 void IcingMonkeyTestRunner::DoOptimize() {
500   ICING_LOG(INFO) << "Monkey doing optimization";
501   ASSERT_THAT(icing_->Optimize().status(), ProtoIsOk());
502 }
503 
CreateIcingSearchEngine()504 void IcingMonkeyTestRunner::CreateIcingSearchEngine() {
505   std::uniform_int_distribution<> dist(0, 1);
506 
507   bool always_rebuild_index_optimize = dist(random_);
508   float optimize_rebuild_index_threshold =
509       always_rebuild_index_optimize ? 0.0 : 0.9;
510 
511   IcingSearchEngineOptions icing_options;
512   icing_options.set_index_merge_size(config_.index_merge_size);
513   icing_options.set_base_dir(icing_dir_->dir());
514   icing_options.set_optimize_rebuild_index_threshold(
515       optimize_rebuild_index_threshold);
516   // The method will be called every time when we ReloadFromDisk(), so randomly
517   // flip this flag to test document store's compatibility.
518   icing_options.set_document_store_namespace_id_fingerprint(
519       (bool)dist(random_));
520   icing_ = std::make_unique<IcingSearchEngine>(icing_options);
521   ASSERT_THAT(icing_->Initialize().status(), ProtoIsOk());
522 }
523 
524 }  // namespace lib
525 }  // namespace icing
526