48TEST(ConcurrencyTestUtils, StartGateReleasesAllWorkersTogether)
51 std::atomic<size_t> passed{0};
52 std::vector<std::thread> threads;
54 for (
size_t i = 0; i < 3; ++i)
55 threads.emplace_back([&]
57 gate.arrive_and_wait();
58 passed.fetch_add(1, std::memory_order_relaxed);
63 EXPECT_EQ(passed.load(std::memory_order_relaxed), 0u);
66 for (
auto &thread : threads)
69 EXPECT_EQ(passed.load(std::memory_order_relaxed), 3u);
72TEST(ConcurrencyTestUtils, ProducerConsumerStressConservesValues)
74 std::queue<size_t> queue;
85 [&](
const size_t value)
87 std::lock_guard lock(mutex);
92 std::lock_guard lock(mutex);
95 value = queue.front();
100 ASSERT_FALSE(result.timed_out);
103 std::sort(result.consumed.begin(), result.consumed.end());
104 for (
size_t i = 0; i < result.consumed.size(); ++i)
105 EXPECT_EQ(result.consumed[i], i);
108TEST(ConcurrencyTestUtils, RandomOperationTraceIsDeterministic)
113 Trace_Operation_Kind::insert,
114 Trace_Operation_Kind::erase,
115 Trace_Operation_Kind::contains
120 Trace_Operation_Kind::insert,
121 Trace_Operation_Kind::erase,
122 Trace_Operation_Kind::contains
127 Trace_Operation_Kind::insert,
128 Trace_Operation_Kind::erase,
129 Trace_Operation_Kind::contains
132 EXPECT_EQ(first, second);
133 EXPECT_NE(first, different);
134 for (
const auto &op : first)
135 EXPECT_LT(op.key, 11u);
138TEST(ConcurrencyTestUtils, TraceReplayDetectsNoMismatchForEquivalentSets)
141 std::set<size_t> subject;
142 std::set<size_t> reference;
148 case Trace_Operation_Kind::insert:
149 return set.insert(op.key).second;
150 case Trace_Operation_Kind::erase:
151 return set.erase(op.key) != 0;
152 case Trace_Operation_Kind::contains:
153 return set.find(op.key) != set.end();
164 EXPECT_TRUE(mismatches.empty());
167TEST(ConcurrencyTestUtils, TraceReplayReportsMismatches)
169 std::vector<Trace_Operation> trace =
171 {Trace_Operation_Kind::insert, 1, 0},
172 {Trace_Operation_Kind::contains, 1, 0},
173 {Trace_Operation_Kind::erase, 1, 0},
174 {Trace_Operation_Kind::contains, 1, 0}
176 std::set<size_t> subject;
177 std::set<size_t> reference;
183 if (op.
kind == Trace_Operation_Kind::insert)
184 return subject.insert(op.
key).second;
185 if (op.
kind == Trace_Operation_Kind::erase)
186 return subject.erase(op.
key) != 0;
191 if (op.
kind == Trace_Operation_Kind::insert)
192 return reference.insert(op.
key).second;
193 if (op.
kind == Trace_Operation_Kind::erase)
194 return reference.erase(op.
key) != 0;
195 return reference.find(op.
key) != reference.end();
198 ASSERT_EQ(mismatches.size(), 1u);
199 EXPECT_EQ(mismatches[0], 3u);
std::vector< Trace_Operation > make_random_operation_trace(const size_t count, const uint32_t seed, const size_t key_range, const std::initializer_list< Trace_Operation_Kind > kinds={ Trace_Operation_Kind::insert, Trace_Operation_Kind::erase, Trace_Operation_Kind::contains })
Build a deterministic pseudo-random operation trace.