Skip to content

Commit

Permalink
add opaque type support to vector fuzzer (#11189)
Browse files Browse the repository at this point in the history
Summary:

In preparation for supporting Opaque types in Presto page serialization, I'd like to add support to fuzz testing to them.

The idea is that each custom type will have to provide its own randomizing function, since it's otherwise impossible for the framework to do so.

Differential Revision: D63998462
  • Loading branch information
Guilherme Kunigami authored and facebook-github-bot committed Oct 8, 2024
1 parent e014dab commit 36dc40b
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
23 changes: 23 additions & 0 deletions velox/vector/fuzzer/VectorFuzzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,8 @@ VectorPtr VectorFuzzer::fuzzFlat(const TypePtr& type, vector_size_t size) {
}

return fuzzRow(std::move(childrenVectors), rowType.names(), size);
} else if (type->isOpaque()) {
return fuzzFlatOpaque(type, size);
} else {
VELOX_UNREACHABLE();
}
Expand Down Expand Up @@ -629,6 +631,27 @@ VectorPtr VectorFuzzer::fuzzComplex(const TypePtr& type, vector_size_t size) {
return nullptr; // no-op.
}

VectorPtr VectorFuzzer::fuzzFlatOpaque(
const TypePtr& type,
vector_size_t size) {
auto vector = BaseVector::create(type, size, pool_);
using TFlat = typename KindToFlatVector<TypeKind::OPAQUE>::type;

auto& opaqueType = type->asOpaque();
auto flatVector = vector->as<TFlat>();
auto& opaqueTypeGenerator = opaqueTypeGenerators_[opaqueType.typeIndex()];
for (size_t i = 0; i < vector->size(); ++i) {
flatVector->set(i, opaqueTypeGenerator(rng_));
}

for (size_t i = 0; i < vector->size(); ++i) {
if (coinToss(opts_.nullRatio)) {
flatVector->setNull(i, true);
}
}
return vector;
}

VectorPtr VectorFuzzer::fuzzDictionary(const VectorPtr& vector) {
return fuzzDictionary(vector, vector->size());
}
Expand Down
17 changes: 17 additions & 0 deletions velox/vector/fuzzer/VectorFuzzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,22 @@ class VectorFuzzer {
/// pointing to (baseVectorSize-1).
BufferPtr fuzzIndices(vector_size_t size, vector_size_t baseVectorSize);

template <typename Class>
void registerOpaqueTypeGenerator(
std::function<std::shared_ptr<Class>(FuzzerGenerator& rng)> generator) {
auto generatorTypeErased = [generator](FuzzerGenerator& rng) {
return generator(rng);
};
opaqueTypeGenerators_[std::type_index(typeid(Class))] = generatorTypeErased;
}

private:
// Generates a flat vector for primitive types.
VectorPtr fuzzFlatPrimitive(const TypePtr& type, vector_size_t size);

// Generates a flat vector for opaque types.
VectorPtr fuzzFlatOpaque(const TypePtr& type, vector_size_t size);

// Generates random precision in range [1, maxPrecision]
// and scale in range [0, random precision generated].
// @param maximum precision.
Expand Down Expand Up @@ -374,6 +386,11 @@ class VectorFuzzer {
// function. C++ does not guarantee the order in which arguments are
// evaluated, which can lead to inconsistent results across platforms.
FuzzerGenerator rng_;

std::unordered_map<
std::type_index,
std::function<std::shared_ptr<void>(FuzzerGenerator& rng)>>
opaqueTypeGenerators_;
};

/// Generates a random type, including maps, structs, and arrays. maxDepth
Expand Down
33 changes: 33 additions & 0 deletions velox/vector/fuzzer/tests/VectorFuzzerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

#include <boost/random/uniform_int_distribution.hpp>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

Expand Down Expand Up @@ -173,6 +174,38 @@ TEST_F(VectorFuzzerTest, flatNotNull) {
ASSERT_FALSE(vector->mayHaveNulls());
}

struct Foo {
explicit Foo(int64_t id) : id_(id) {}
int64_t id_;
};

TEST_F(VectorFuzzerTest, flatOpaque) {
VectorFuzzer::Options opts;
opts.nullRatio = 0.5;
VectorFuzzer fuzzer(opts, pool());
fuzzer.registerOpaqueTypeGenerator<Foo>([](FuzzerGenerator& rng) {
int64_t id = boost::random::uniform_int_distribution<int64_t>(1, 10)(rng);
return std::make_shared<Foo>(id);
});

auto opaqueType = OPAQUE<Foo>();
VectorPtr vector = fuzzer.fuzzFlat(opaqueType);
ASSERT_EQ(VectorEncoding::Simple::FLAT, vector->encoding());
ASSERT_TRUE(vector->type()->kindEquals(opaqueType));
ASSERT_EQ(opts.vectorSize, vector->size());
ASSERT_TRUE(vector->mayHaveNulls());

auto flatVector = vector->asFlatVector<std::shared_ptr<void>>();
for (auto i = 0; i < vector->size(); ++i) {
if (flatVector->isNullAt(i)) {
continue;
}
auto element = std::reinterpret_pointer_cast<Foo>(flatVector->valueAt(i));
ASSERT_GT(element->id_, 0);
ASSERT_LT(element->id_, 11);
}
}

TEST_F(VectorFuzzerTest, dictionary) {
VectorFuzzer::Options opts;
VectorFuzzer fuzzer(opts, pool());
Expand Down

0 comments on commit 36dc40b

Please sign in to comment.