Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/test/test_common/utility.cc
Line
Count
Source (jump to first uncovered line)
1
#include "utility.h"
2
3
#include <cstdint>
4
#include <fstream>
5
#include <iomanip>
6
#include <iostream>
7
#include <list>
8
#include <regex>
9
#include <stdexcept>
10
#include <string>
11
#include <vector>
12
13
#include "envoy/buffer/buffer.h"
14
#include "envoy/common/platform.h"
15
#include "envoy/config/bootstrap/v3/bootstrap.pb.h"
16
#include "envoy/config/cluster/v3/cluster.pb.h"
17
#include "envoy/config/endpoint/v3/endpoint.pb.h"
18
#include "envoy/config/listener/v3/listener.pb.h"
19
#include "envoy/config/route/v3/route.pb.h"
20
#include "envoy/config/route/v3/route_components.pb.h"
21
#include "envoy/http/codec.h"
22
#include "envoy/server/overload/thread_local_overload_state.h"
23
#include "envoy/service/runtime/v3/rtds.pb.h"
24
25
#include "source/common/api/api_impl.h"
26
#include "source/common/common/fmt.h"
27
#include "source/common/common/lock_guard.h"
28
#include "source/common/common/thread_impl.h"
29
#include "source/common/common/utility.h"
30
#include "source/common/filesystem/directory.h"
31
#include "source/common/filesystem/filesystem_impl.h"
32
#include "source/common/http/header_utility.h"
33
#include "source/common/json/json_loader.h"
34
#include "source/common/network/address_impl.h"
35
#include "source/common/network/utility.h"
36
37
#include "test/mocks/common.h"
38
#include "test/mocks/stats/mocks.h"
39
#include "test/test_common/printers.h"
40
#include "test/test_common/resources.h"
41
#include "test/test_common/test_time.h"
42
43
#include "absl/container/fixed_array.h"
44
#include "absl/strings/str_cat.h"
45
#include "absl/strings/string_view.h"
46
#include "absl/synchronization/notification.h"
47
#include "gtest/gtest.h"
48
49
namespace Envoy {
50
51
bool TestUtility::headerMapEqualIgnoreOrder(const Http::HeaderMap& lhs,
52
0
                                            const Http::HeaderMap& rhs) {
53
0
  absl::flat_hash_set<std::string> lhs_keys;
54
0
  absl::flat_hash_set<std::string> rhs_keys;
55
0
  lhs.iterate([&lhs_keys](const Http::HeaderEntry& header) -> Http::HeaderMap::Iterate {
56
0
    const std::string key{header.key().getStringView()};
57
0
    lhs_keys.insert(key);
58
0
    return Http::HeaderMap::Iterate::Continue;
59
0
  });
60
0
  bool values_match = true;
61
0
  rhs.iterate([&values_match, &lhs, &rhs,
62
0
               &rhs_keys](const Http::HeaderEntry& header) -> Http::HeaderMap::Iterate {
63
0
    const std::string key{header.key().getStringView()};
64
    // Compare with canonicalized multi-value headers. This ensures we respect order within
65
    // a header.
66
0
    const auto lhs_entry =
67
0
        Http::HeaderUtility::getAllOfHeaderAsString(lhs, Http::LowerCaseString(key));
68
0
    const auto rhs_entry =
69
0
        Http::HeaderUtility::getAllOfHeaderAsString(rhs, Http::LowerCaseString(key));
70
0
    ASSERT(rhs_entry.result());
71
0
    if (lhs_entry.result() != rhs_entry.result()) {
72
0
      values_match = false;
73
0
      return Http::HeaderMap::Iterate::Break;
74
0
    }
75
0
    rhs_keys.insert(key);
76
0
    return Http::HeaderMap::Iterate::Continue;
77
0
  });
78
0
  return values_match && lhs_keys.size() == rhs_keys.size();
79
0
}
80
81
0
bool TestUtility::buffersEqual(const Buffer::Instance& lhs, const Buffer::Instance& rhs) {
82
0
  if (lhs.length() != rhs.length()) {
83
0
    return false;
84
0
  }
85
86
  // Check whether the two buffers contain the same content. It is valid for the content
87
  // to be arranged differently in the buffers. For example, lhs could have one slice
88
  // containing 10 bytes while rhs has ten slices containing one byte each.
89
0
  Buffer::RawSliceVector lhs_slices = lhs.getRawSlices();
90
0
  Buffer::RawSliceVector rhs_slices = rhs.getRawSlices();
91
92
0
  size_t rhs_slice = 0;
93
0
  size_t rhs_offset = 0;
94
0
  for (auto& lhs_slice : lhs_slices) {
95
0
    for (size_t lhs_offset = 0; lhs_offset < lhs_slice.len_; lhs_offset++) {
96
0
      while (rhs_offset >= rhs_slices[rhs_slice].len_) {
97
0
        rhs_slice++;
98
0
        ASSERT(rhs_slice < rhs_slices.size());
99
0
        rhs_offset = 0;
100
0
      }
101
0
      auto lhs_str = static_cast<const uint8_t*>(lhs_slice.mem_);
102
0
      auto rhs_str = static_cast<const uint8_t*>(rhs_slices[rhs_slice].mem_);
103
0
      if (lhs_str[lhs_offset] != rhs_str[rhs_offset]) {
104
0
        return false;
105
0
      }
106
0
      rhs_offset++;
107
0
    }
108
0
  }
109
110
0
  return true;
111
0
}
112
113
bool TestUtility::rawSlicesEqual(const Buffer::RawSlice* lhs, const Buffer::RawSlice* rhs,
114
0
                                 size_t num_slices) {
115
0
  for (size_t slice = 0; slice < num_slices; slice++) {
116
0
    auto rhs_slice = rhs[slice];
117
0
    auto lhs_slice = lhs[slice];
118
0
    if (rhs_slice.len_ != lhs_slice.len_) {
119
0
      return false;
120
0
    }
121
0
    auto rhs_slice_data = static_cast<const uint8_t*>(rhs_slice.mem_);
122
0
    auto lhs_slice_data = static_cast<const uint8_t*>(lhs_slice.mem_);
123
0
    for (size_t offset = 0; offset < rhs_slice.len_; offset++) {
124
0
      if (rhs_slice_data[offset] != lhs_slice_data[offset]) {
125
0
        return false;
126
0
      }
127
0
    }
128
0
  }
129
0
  return true;
130
0
}
131
132
void TestUtility::feedBufferWithRandomCharacters(Buffer::Instance& buffer, uint64_t n_char,
133
0
                                                 uint64_t seed) {
134
0
  const std::string sample = "Neque porro quisquam est qui dolorem ipsum..";
135
0
  std::mt19937 generate(seed);
136
0
  std::uniform_int_distribution<> distribute(1, sample.length() - 1);
137
0
  std::string str{};
138
0
  for (uint64_t n = 0; n < n_char; ++n) {
139
0
    str += sample.at(distribute(generate));
140
0
  }
141
0
  buffer.add(str);
142
0
}
143
144
17.8k
Stats::CounterSharedPtr TestUtility::findCounter(Stats::Store& store, const std::string& name) {
145
17.8k
  return findByName(store.counters(), name);
146
17.8k
}
147
148
868
Stats::GaugeSharedPtr TestUtility::findGauge(Stats::Store& store, const std::string& name) {
149
868
  return findByName(store.gauges(), name);
150
868
}
151
152
Stats::TextReadoutSharedPtr TestUtility::findTextReadout(Stats::Store& store,
153
0
                                                         const std::string& name) {
154
0
  return findByName(store.textReadouts(), name);
155
0
}
156
157
Stats::ParentHistogramSharedPtr TestUtility::findHistogram(Stats::Store& store,
158
0
                                                           const std::string& name) {
159
0
  return findByName(store.histograms(), name);
160
0
}
161
162
AssertionResult TestUtility::waitForCounterEq(Stats::Store& store, const std::string& name,
163
                                              uint64_t value, Event::TestTimeSystem& time_system,
164
                                              std::chrono::milliseconds timeout,
165
550
                                              Event::Dispatcher* dispatcher) {
166
550
  Event::TestTimeSystem::RealTimeBound bound(timeout);
167
559
  while (findCounter(store, name) == nullptr || findCounter(store, name)->value() != value) {
168
9
    time_system.advanceTimeWait(std::chrono::milliseconds(10));
169
9
    if (timeout != std::chrono::milliseconds::zero() && !bound.withinBound()) {
170
0
      std::string current_value;
171
0
      if (findCounter(store, name)) {
172
0
        current_value = absl::StrCat(findCounter(store, name)->value());
173
0
      } else {
174
0
        current_value = "nil";
175
0
      }
176
0
      return AssertionFailure() << fmt::format(
177
0
                 "timed out waiting for {} to be {}, current value {}", name, value, current_value);
178
0
    }
179
9
    if (dispatcher != nullptr) {
180
0
      dispatcher->run(Event::Dispatcher::RunType::NonBlock);
181
0
    }
182
9
  }
183
550
  return AssertionSuccess();
184
550
}
185
186
AssertionResult TestUtility::waitForCounterGe(Stats::Store& store, const std::string& name,
187
                                              uint64_t value, Event::TestTimeSystem& time_system,
188
0
                                              std::chrono::milliseconds timeout) {
189
0
  Event::TestTimeSystem::RealTimeBound bound(timeout);
190
0
  while (findCounter(store, name) == nullptr || findCounter(store, name)->value() < value) {
191
0
    time_system.advanceTimeWait(std::chrono::milliseconds(10));
192
0
    if (timeout != std::chrono::milliseconds::zero() && !bound.withinBound()) {
193
0
      return AssertionFailure() << fmt::format("timed out waiting for {} to be >= {}", name, value);
194
0
    }
195
0
  }
196
0
  return AssertionSuccess();
197
0
}
198
199
AssertionResult TestUtility::waitForGaugeGe(Stats::Store& store, const std::string& name,
200
                                            uint64_t value, Event::TestTimeSystem& time_system,
201
0
                                            std::chrono::milliseconds timeout) {
202
0
  Event::TestTimeSystem::RealTimeBound bound(timeout);
203
0
  while (findGauge(store, name) == nullptr || findGauge(store, name)->value() < value) {
204
0
    time_system.advanceTimeWait(std::chrono::milliseconds(10));
205
0
    if (timeout != std::chrono::milliseconds::zero() && !bound.withinBound()) {
206
0
      return AssertionFailure() << fmt::format("timed out waiting for {} to be {}", name, value);
207
0
    }
208
0
  }
209
0
  return AssertionSuccess();
210
0
}
211
212
AssertionResult TestUtility::waitForGaugeEq(Stats::Store& store, const std::string& name,
213
                                            uint64_t value, Event::TestTimeSystem& time_system,
214
402
                                            std::chrono::milliseconds timeout) {
215
402
  Event::TestTimeSystem::RealTimeBound bound(timeout);
216
413
  while (findGauge(store, name) == nullptr || findGauge(store, name)->value() != value) {
217
11
    time_system.advanceTimeWait(std::chrono::milliseconds(10));
218
11
    if (timeout != std::chrono::milliseconds::zero() && !bound.withinBound()) {
219
0
      std::string current_value;
220
0
      if (findGauge(store, name)) {
221
0
        current_value = absl::StrCat(findGauge(store, name)->value());
222
0
      } else {
223
0
        current_value = "nil";
224
0
      }
225
0
      return AssertionFailure() << fmt::format(
226
0
                 "timed out waiting for {} to be {}, current value {}", name, value, current_value);
227
0
    }
228
11
  }
229
402
  return AssertionSuccess();
230
402
}
231
232
AssertionResult TestUtility::waitForProactiveOverloadResourceUsageEq(
233
    Server::ThreadLocalOverloadState& overload_state,
234
    const Server::OverloadProactiveResourceName resource_name, int64_t expected_value,
235
    Event::TestTimeSystem& time_system, Event::Dispatcher& dispatcher,
236
0
    std::chrono::milliseconds timeout) {
237
0
  Event::TestTimeSystem::RealTimeBound bound(timeout);
238
0
  const auto& monitor = overload_state.getProactiveResourceMonitorForTest(resource_name);
239
0
  while (monitor->currentResourceUsage() != expected_value) {
240
0
    time_system.advanceTimeWait(std::chrono::milliseconds(10));
241
0
    if (timeout != std::chrono::milliseconds::zero() && !bound.withinBound()) {
242
0
      uint64_t current_value;
243
0
      current_value = monitor->currentResourceUsage();
244
0
      return AssertionFailure() << fmt::format(
245
0
                 "timed out waiting for proactive resource to be {}, current value {}",
246
0
                 expected_value, current_value);
247
0
    }
248
0
    dispatcher.run(Event::Dispatcher::RunType::NonBlock);
249
0
  }
250
0
  return AssertionSuccess();
251
0
}
252
253
AssertionResult TestUtility::waitForGaugeDestroyed(Stats::Store& store, const std::string& name,
254
0
                                                   Event::TestTimeSystem& time_system) {
255
0
  while (findGauge(store, name) != nullptr) {
256
0
    time_system.advanceTimeWait(std::chrono::milliseconds(10));
257
0
  }
258
0
  return AssertionSuccess();
259
0
}
260
261
AssertionResult TestUtility::waitForNumHistogramSamplesGe(Stats::Store& store,
262
                                                          const std::string& name,
263
                                                          uint64_t min_sample_count_required,
264
                                                          Event::TestTimeSystem& time_system,
265
                                                          Event::Dispatcher& main_dispatcher,
266
0
                                                          std::chrono::milliseconds timeout) {
267
0
  Event::TestTimeSystem::RealTimeBound bound(timeout);
268
0
  while (true) {
269
0
    auto histo = findByName<Stats::ParentHistogramSharedPtr>(store.histograms(), name);
270
0
    if (histo) {
271
0
      uint64_t sample_count = readSampleCount(main_dispatcher, *histo);
272
0
      if (sample_count >= min_sample_count_required) {
273
0
        break;
274
0
      }
275
0
    }
276
277
0
    time_system.advanceTimeWait(std::chrono::milliseconds(10));
278
279
0
    if (timeout != std::chrono::milliseconds::zero() && !bound.withinBound()) {
280
0
      return AssertionFailure() << fmt::format("timed out waiting for {} to have {} samples", name,
281
0
                                               min_sample_count_required);
282
0
    }
283
0
  }
284
0
  return AssertionSuccess();
285
0
}
286
287
AssertionResult TestUtility::waitUntilHistogramHasSamples(Stats::Store& store,
288
                                                          const std::string& name,
289
                                                          Event::TestTimeSystem& time_system,
290
                                                          Event::Dispatcher& main_dispatcher,
291
0
                                                          std::chrono::milliseconds timeout) {
292
0
  return waitForNumHistogramSamplesGe(store, name, 1, time_system, main_dispatcher, timeout);
293
0
}
294
295
uint64_t TestUtility::readSampleCount(Event::Dispatcher& main_dispatcher,
296
0
                                      const Stats::ParentHistogram& histogram) {
297
  // Note: we need to read the sample count from the main thread, to avoid data races.
298
0
  uint64_t sample_count = 0;
299
0
  absl::Notification notification;
300
301
0
  main_dispatcher.post([&] {
302
0
    sample_count = histogram.cumulativeStatistics().sampleCount();
303
0
    notification.Notify();
304
0
  });
305
0
  notification.WaitForNotification();
306
307
0
  return sample_count;
308
0
}
309
310
double TestUtility::readSampleSum(Event::Dispatcher& main_dispatcher,
311
0
                                  const Stats::ParentHistogram& histogram) {
312
  // Note: we need to read the sample count from the main thread, to avoid data races.
313
0
  double sample_sum = 0;
314
0
  absl::Notification notification;
315
316
0
  main_dispatcher.post([&] {
317
0
    sample_sum = histogram.cumulativeStatistics().sampleSum();
318
0
    notification.Notify();
319
0
  });
320
0
  notification.WaitForNotification();
321
322
0
  return sample_sum;
323
0
}
324
325
std::list<Network::DnsResponse>
326
0
TestUtility::makeDnsResponse(const std::list<std::string>& addresses, std::chrono::seconds ttl) {
327
0
  std::list<Network::DnsResponse> ret;
328
0
  for (const auto& address : addresses) {
329
0
    ret.emplace_back(Network::DnsResponse(Network::Utility::parseInternetAddress(address), ttl));
330
0
  }
331
0
  return ret;
332
0
}
333
334
0
std::vector<std::string> TestUtility::listFiles(const std::string& path, bool recursive) {
335
0
  std::vector<std::string> file_names;
336
0
  Filesystem::Directory directory(path);
337
0
  for (const Filesystem::DirectoryEntry& entry : directory) {
338
0
    std::string file_name = fmt::format("{}/{}", path, entry.name_);
339
0
    if (entry.type_ == Filesystem::FileType::Directory) {
340
0
      if (recursive && entry.name_ != "." && entry.name_ != "..") {
341
0
        std::vector<std::string> more_file_names = listFiles(file_name, recursive);
342
0
        file_names.insert(file_names.end(), more_file_names.begin(), more_file_names.end());
343
0
      }
344
0
    } else { // regular file
345
0
      file_names.push_back(file_name);
346
0
    }
347
0
  }
348
0
  return file_names;
349
0
}
350
351
2.63k
std::string TestUtility::uniqueFilename(absl::string_view prefix) {
352
2.63k
  return absl::StrCat(prefix, "_", getpid(), "_",
353
2.63k
                      std::chrono::system_clock::now().time_since_epoch().count());
354
2.63k
}
355
356
0
std::string TestUtility::addLeftAndRightPadding(absl::string_view to_pad, int desired_length) {
357
0
  int line_fill_len = desired_length - to_pad.length();
358
0
  int first_half_len = line_fill_len / 2;
359
0
  int second_half_len = line_fill_len - first_half_len;
360
0
  return absl::StrCat(std::string(first_half_len, '='), to_pad, std::string(second_half_len, '='));
361
0
}
362
363
0
std::vector<std::string> TestUtility::split(const std::string& source, char split) {
364
0
  return TestUtility::split(source, std::string{split});
365
0
}
366
367
std::vector<std::string> TestUtility::split(const std::string& source, const std::string& split,
368
0
                                            bool keep_empty_string) {
369
0
  std::vector<std::string> ret;
370
0
  const auto tokens_sv = StringUtil::splitToken(source, split, keep_empty_string);
371
0
  std::transform(tokens_sv.begin(), tokens_sv.end(), std::back_inserter(ret),
372
0
                 [](absl::string_view sv) { return std::string(sv); });
373
0
  return ret;
374
0
}
375
376
// static
377
0
absl::Time TestUtility::parseTime(const std::string& input, const std::string& input_format) {
378
0
  absl::Time time;
379
0
  std::string parse_error;
380
0
  EXPECT_TRUE(absl::ParseTime(input_format, input, &time, &parse_error))
381
0
      << " error \"" << parse_error << "\" from failing to parse timestamp \"" << input
382
0
      << "\" with format string \"" << input_format << "\"";
383
0
  return time;
384
0
}
385
386
// static
387
0
std::string TestUtility::formatTime(const absl::Time input, const std::string& output_format) {
388
0
  static const absl::TimeZone utc = absl::UTCTimeZone();
389
0
  return absl::FormatTime(output_format, input, utc);
390
0
}
391
392
// static
393
0
std::string TestUtility::formatTime(const SystemTime input, const std::string& output_format) {
394
0
  return TestUtility::formatTime(absl::FromChrono(input), output_format);
395
0
}
396
397
// static
398
std::string TestUtility::convertTime(const std::string& input, const std::string& input_format,
399
0
                                     const std::string& output_format) {
400
0
  return TestUtility::formatTime(TestUtility::parseTime(input, input_format), output_format);
401
0
}
402
403
// static
404
0
std::string TestUtility::nonZeroedGauges(const std::vector<Stats::GaugeSharedPtr>& gauges) {
405
  // Returns all gauges that are 0 except the circuit_breaker remaining resource
406
  // gauges which default to the resource max.
407
0
  std::regex omitted(".*circuit_breakers\\..*\\.remaining.*");
408
0
  std::string non_zero;
409
0
  for (const Stats::GaugeSharedPtr& gauge : gauges) {
410
0
    if (!std::regex_match(gauge->name(), omitted) && gauge->value() != 0) {
411
0
      non_zero.append(fmt::format("{}: {}; ", gauge->name(), gauge->value()));
412
0
    }
413
0
  }
414
0
  return non_zero;
415
0
}
416
417
// static
418
0
bool TestUtility::gaugesZeroed(const std::vector<Stats::GaugeSharedPtr>& gauges) {
419
0
  return nonZeroedGauges(gauges).empty();
420
0
}
421
422
// static
423
bool TestUtility::gaugesZeroed(
424
0
    const std::vector<std::pair<absl::string_view, Stats::PrimitiveGaugeReference>>& gauges) {
425
  // Returns true if all gauges are 0 except the circuit_breaker remaining resource
426
  // gauges which default to the resource max.
427
0
  std::regex omitted(".*circuit_breakers\\..*\\.remaining.*");
428
0
  for (const auto& gauge : gauges) {
429
0
    if (!std::regex_match(std::string(gauge.first), omitted) && gauge.second.get().value() != 0) {
430
0
      return false;
431
0
    }
432
0
  }
433
0
  return true;
434
0
}
435
436
5.31k
void ConditionalInitializer::setReady() {
437
5.31k
  absl::MutexLock lock(&mutex_);
438
5.31k
  EXPECT_FALSE(ready_);
439
5.31k
  ready_ = true;
440
5.31k
}
441
442
5.31k
void ConditionalInitializer::waitReady() {
443
5.31k
  absl::MutexLock lock(&mutex_);
444
5.31k
  if (ready_) {
445
4
    ready_ = false;
446
4
    return;
447
4
  }
448
449
5.30k
  mutex_.Await(absl::Condition(&ready_));
450
5.30k
  EXPECT_TRUE(ready_);
451
5.30k
  ready_ = false;
452
5.30k
}
453
454
0
void ConditionalInitializer::wait() {
455
0
  absl::MutexLock lock(&mutex_);
456
0
  mutex_.Await(absl::Condition(&ready_));
457
0
  EXPECT_TRUE(ready_);
458
0
}
459
460
namespace Api {
461
462
class TestImplProvider {
463
protected:
464
  Event::GlobalTimeSystem global_time_system_;
465
  testing::NiceMock<Stats::MockIsolatedStatsStore> default_stats_store_;
466
  testing::NiceMock<Random::MockRandomGenerator> mock_random_generator_;
467
  envoy::config::bootstrap::v3::Bootstrap empty_bootstrap_;
468
};
469
470
class TestImpl : public TestImplProvider, public Impl {
471
public:
472
  TestImpl(Thread::ThreadFactory& thread_factory, Filesystem::Instance& file_system,
473
           Stats::Store* stats_store = nullptr, Event::TimeSystem* time_system = nullptr,
474
           Random::RandomGenerator* random = nullptr)
475
      : Impl(thread_factory, stats_store ? *stats_store : default_stats_store_,
476
             time_system ? *time_system : global_time_system_, file_system,
477
62.3k
             random ? *random : mock_random_generator_, empty_bootstrap_) {}
478
};
479
480
57.0k
ApiPtr createApiForTest() {
481
57.0k
  return std::make_unique<TestImpl>(Thread::threadFactoryForTest(),
482
57.0k
                                    Filesystem::fileSystemForTest());
483
57.0k
}
484
485
0
ApiPtr createApiForTest(Filesystem::Instance& filesystem) {
486
0
  return std::make_unique<TestImpl>(Thread::threadFactoryForTest(), filesystem);
487
0
}
488
489
0
ApiPtr createApiForTest(Random::RandomGenerator& random) {
490
0
  return std::make_unique<TestImpl>(Thread::threadFactoryForTest(), Filesystem::fileSystemForTest(),
491
0
                                    nullptr, nullptr, &random);
492
0
}
493
494
2.66k
ApiPtr createApiForTest(Stats::Store& stat_store) {
495
2.66k
  return std::make_unique<TestImpl>(Thread::threadFactoryForTest(), Filesystem::fileSystemForTest(),
496
2.66k
                                    &stat_store);
497
2.66k
}
498
499
0
ApiPtr createApiForTest(Stats::Store& stat_store, Random::RandomGenerator& random) {
500
0
  return std::make_unique<TestImpl>(Thread::threadFactoryForTest(), Filesystem::fileSystemForTest(),
501
0
                                    &stat_store, nullptr, &random);
502
0
}
503
504
2
ApiPtr createApiForTest(Event::TimeSystem& time_system) {
505
2
  return std::make_unique<TestImpl>(Thread::threadFactoryForTest(), Filesystem::fileSystemForTest(),
506
2
                                    nullptr, &time_system);
507
2
}
508
509
2.64k
ApiPtr createApiForTest(Stats::Store& stat_store, Event::TimeSystem& time_system) {
510
2.64k
  return std::make_unique<TestImpl>(Thread::threadFactoryForTest(), Filesystem::fileSystemForTest(),
511
2.64k
                                    &stat_store, &time_system);
512
2.64k
}
513
514
} // namespace Api
515
} // namespace Envoy