Interleave calls for two conflict sets in tests

This commit is contained in:
2024-07-23 11:12:02 -07:00
parent ec85a06d01
commit c649bc7964
3 changed files with 113 additions and 64 deletions

View File

@@ -3928,7 +3928,7 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion,
bool &success, ConflictSet::Impl *impl) {
checkVersionsGeqOldestExtant(node,
InternalVersionT(impl->oldestExtantVersion));
auto expected = InternalVersionT::zero;
auto expected = oldestVersion;
if (node->entryPresent) {
expected = std::max(expected, node->entry.pointVersion);
}
@@ -4151,26 +4151,42 @@ int main(void) { printTree(); }
#ifdef ENABLE_FUZZ
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
TestDriver<ConflictSet::Impl> driver{data, size};
Arbitrary arbitrary({data, size});
TestDriver<ConflictSet::Impl> driver1{arbitrary};
TestDriver<ConflictSet::Impl> driver2{arbitrary};
bool done1 = false;
bool done2 = false;
for (;;) {
bool done = driver.next();
if (!driver.ok) {
debugPrintDot(stdout, driver.cs.root, &driver.cs);
fflush(stdout);
abort();
if (!done1) {
done1 = driver1.next();
if (!driver1.ok) {
debugPrintDot(stdout, driver1.cs.root, &driver1.cs);
fflush(stdout);
abort();
}
if (!checkCorrectness(driver1.cs.root, driver1.cs.oldestVersion,
&driver1.cs)) {
debugPrintDot(stdout, driver1.cs.root, &driver1.cs);
fflush(stdout);
abort();
}
}
#if DEBUG_VERBOSE && !defined(NDEBUG)
fprintf(stderr, "Check correctness\n");
#endif
bool success =
checkCorrectness(driver.cs.root, driver.cs.oldestVersion, &driver.cs);
if (!success) {
debugPrintDot(stdout, driver.cs.root, &driver.cs);
fflush(stdout);
abort();
if (!done2) {
done2 = driver2.next();
if (!driver2.ok) {
debugPrintDot(stdout, driver2.cs.root, &driver2.cs);
fflush(stdout);
abort();
}
if (!checkCorrectness(driver2.cs.root, driver2.cs.oldestVersion,
&driver2.cs)) {
debugPrintDot(stdout, driver2.cs.root, &driver2.cs);
fflush(stdout);
abort();
}
}
if (done) {
if (done1 && done2) {
break;
}
}

View File

@@ -580,11 +580,10 @@ namespace {
template <class ConflictSetImpl, bool kEnableAssertions = true>
struct TestDriver {
Arbitrary arbitrary;
explicit TestDriver(const uint8_t *data, size_t size)
: arbitrary({data, size}) {}
Arbitrary *arbitrary;
explicit TestDriver(Arbitrary &a) : arbitrary(&a) {}
int64_t oldestVersion = arbitrary.next();
int64_t oldestVersion = arbitrary->next();
int64_t writeVersion = oldestVersion;
ConflictSetImpl cs{oldestVersion};
ReferenceImpl refImpl{oldestVersion};
@@ -593,33 +592,34 @@ struct TestDriver {
bool ok = true;
const int prefixLen = arbitrary.bounded(512);
const int prefixByte = arbitrary.randT<uint8_t>();
const int prefixLen = arbitrary->bounded(512);
const int prefixByte = arbitrary->randT<uint8_t>();
// Call until it returns true, for "done". Check internal invariants etc
// between calls to next.
bool next() {
assert(cs.getBytes() >= 0);
if (!arbitrary.hasEntropy()) {
if (!arbitrary->hasEntropy()) {
return true;
}
Arena arena;
{
int numPointWrites = arbitrary.bounded(100);
int numRangeWrites = arbitrary.bounded(100);
int64_t v = (writeVersion += arbitrary.bounded(10) ? arbitrary.bounded(10)
: arbitrary.next());
int numPointWrites = arbitrary->bounded(100);
int numRangeWrites = arbitrary->bounded(100);
int64_t v =
(writeVersion +=
arbitrary->bounded(10) ? arbitrary->bounded(10) : arbitrary->next());
auto *writes =
new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites];
auto keys = set<std::string_view>(arena);
while (int(keys.size()) < numPointWrites + numRangeWrites * 2) {
if (!arbitrary.hasEntropy()) {
if (!arbitrary->hasEntropy()) {
return true;
}
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
auto *begin = new (arena) uint8_t[keyLen];
memset(begin, prefixByte, prefixLen);
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen);
arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen);
keys.insert(std::string_view((const char *)begin, keyLen));
}
@@ -629,7 +629,7 @@ struct TestDriver {
rangesRemaining = numRangeWrites;
pointsRemaining > 0 || rangesRemaining > 0; ++i) {
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
? bool(arbitrary.bounded(2))
? bool(arbitrary->bounded(2))
: pointsRemaining > 0;
if (pointRead) {
assert(pointsRemaining > 0);
@@ -667,14 +667,14 @@ struct TestDriver {
// Test non-canonical writes
if (numPointWrites > 0) {
int overlaps = arbitrary.bounded(numPointWrites);
int overlaps = arbitrary->bounded(numPointWrites);
for (int i = 0; i < numPointWrites + numRangeWrites && overlaps > 0;
++i) {
if (writes[i].end.len == 0) {
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
auto *begin = new (arena) uint8_t[keyLen];
memset(begin, prefixByte, prefixLen);
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen);
arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen);
writes[i].end.len = keyLen;
writes[i].end.p = begin;
auto c =
@@ -692,10 +692,10 @@ struct TestDriver {
}
}
}
if (arbitrary.bounded(2)) {
if (arbitrary->bounded(2)) {
// Shuffle writes
for (int i = numPointWrites + numRangeWrites - 1; i > 0; --i) {
int j = arbitrary.bounded(i + 1);
int j = arbitrary->bounded(i + 1);
if (i != j) {
using std::swap;
swap(writes[i], writes[j]);
@@ -704,7 +704,7 @@ struct TestDriver {
}
oldestVersion +=
arbitrary.bounded(10) ? arbitrary.bounded(10) : arbitrary.next();
arbitrary->bounded(10) ? arbitrary->bounded(10) : arbitrary->next();
oldestVersion = std::min(oldestVersion, writeVersion);
#ifdef THREAD_TEST
@@ -739,24 +739,24 @@ struct TestDriver {
#endif
}
{
int numPointReads = arbitrary.bounded(100);
int numRangeReads = arbitrary.bounded(100);
int numPointReads = arbitrary->bounded(100);
int numRangeReads = arbitrary->bounded(100);
int64_t v = std::max<int64_t>(writeVersion - (arbitrary.bounded(10)
? arbitrary.bounded(10)
: arbitrary.next()),
int64_t v = std::max<int64_t>(writeVersion - (arbitrary->bounded(10)
? arbitrary->bounded(10)
: arbitrary->next()),
0);
auto *reads =
new (arena) ConflictSet::ReadRange[numPointReads + numRangeReads];
auto keys = set<std::string_view>(arena);
while (int(keys.size()) < numPointReads + numRangeReads * 2) {
if (!arbitrary.hasEntropy()) {
if (!arbitrary->hasEntropy()) {
return true;
}
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
auto *begin = new (arena) uint8_t[keyLen];
memset(begin, prefixByte, prefixLen);
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen);
arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen);
keys.insert(std::string_view((const char *)begin, keyLen));
}
@@ -765,7 +765,7 @@ struct TestDriver {
for (int pointsRemaining = numPointReads, rangesRemaining = numRangeReads;
pointsRemaining > 0 || rangesRemaining > 0; ++i) {
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
? bool(arbitrary.bounded(2))
? bool(arbitrary->bounded(2))
: pointsRemaining > 0;
if (pointRead) {
assert(pointsRemaining > 0);

View File

@@ -13,25 +13,58 @@ int main(int argc, char **argv) {
std::stringstream buffer;
buffer << t.rdbuf();
auto str = buffer.str();
TestDriver<ConflictSet, !PERF_TEST> driver{(const uint8_t *)str.data(),
str.size()};
while (!driver.next())
;
if (!driver.ok) {
abort();
Arbitrary arbitrary({(const uint8_t *)str.data(), str.size()});
TestDriver<ConflictSet, !PERF_TEST> driver1{arbitrary};
TestDriver<ConflictSet, !PERF_TEST> driver2{arbitrary};
bool done1 = false;
bool done2 = false;
for (;;) {
if (!done1) {
done1 = driver1.next();
if (!driver1.ok) {
abort();
}
}
if (!done2) {
done2 = driver2.next();
if (!driver2.ok) {
abort();
}
}
if (done1 && done2) {
break;
}
}
ConflictSet::MetricsV1 *metrics;
int metricsCount;
driver.cs.getMetricsV1(&metrics, &metricsCount);
printf("#################### METRICS FOR %s ####################\n",
argv[i]);
for (int i = 0; i < metricsCount; ++i) {
printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
printf("# TYPE %s %s\n", metrics[i].name,
metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
printf("%s %g\n", metrics[i].name, metrics[i].getValue());
{
ConflictSet::MetricsV1 *metrics;
int metricsCount;
driver1.cs.getMetricsV1(&metrics, &metricsCount);
printf("#################### METRICS for ConflictSet 1 for %s "
"####################\n",
argv[i]);
for (int i = 0; i < metricsCount; ++i) {
printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
printf("# TYPE %s %s\n", metrics[i].name,
metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
printf("%s %g\n", metrics[i].name, metrics[i].getValue());
}
puts("");
}
{
ConflictSet::MetricsV1 *metrics;
int metricsCount;
driver2.cs.getMetricsV1(&metrics, &metricsCount);
printf("#################### METRICS for ConflictSet 2 for %s "
"####################\n",
argv[i]);
for (int i = 0; i < metricsCount; ++i) {
printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
printf("# TYPE %s %s\n", metrics[i].name,
metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
printf("%s %g\n", metrics[i].name, metrics[i].getValue());
}
puts("");
}
puts("");
}
}