X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2Fio%2Ftest%2FCompressionTest.cpp;h=a97b5bcf56ec0b0a548478845cccf889f33f11eb;hp=a1d48b9d6e2e494308cf10aa3ddb50fc5bde7026;hb=0659842527913025d998860811fe135cc6170044;hpb=95fb46dbe9c171dc3d0a549822d84a3c4cdf728b diff --git a/folly/io/test/CompressionTest.cpp b/folly/io/test/CompressionTest.cpp index a1d48b9d..a97b5bcf 100644 --- a/folly/io/test/CompressionTest.cpp +++ b/folly/io/test/CompressionTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,18 +17,19 @@ #include #include +#include #include #include #include #include -#include #include #include #include #include #include +#include namespace folly { namespace io { namespace test { @@ -119,40 +120,83 @@ constexpr size_t dataSizeLog2 = 27; // 128MiB RandomDataHolder randomDataHolder(dataSizeLog2); ConstantDataHolder constantDataHolder(dataSizeLog2); +// The intersection of the provided codecs & those that are compiled in. +static std::vector supportedCodecs(std::vector const& v) { + std::vector supported; + + std::copy_if( + std::begin(v), + std::end(v), + std::back_inserter(supported), + hasCodec); + + return supported; +} + +// All compiled-in compression codecs. +static std::vector availableCodecs() { + std::vector codecs; + + for (size_t i = 0; i < static_cast(CodecType::NUM_CODEC_TYPES); ++i) { + auto type = static_cast(i); + if (hasCodec(type)) { + codecs.push_back(type); + } + } + + return codecs; +} + TEST(CompressionTestNeedsUncompressedLength, Simple) { - EXPECT_FALSE(getCodec(CodecType::NO_COMPRESSION)->needsUncompressedLength()); - EXPECT_TRUE(getCodec(CodecType::LZ4)->needsUncompressedLength()); - EXPECT_FALSE(getCodec(CodecType::SNAPPY)->needsUncompressedLength()); - EXPECT_FALSE(getCodec(CodecType::ZLIB)->needsUncompressedLength()); - EXPECT_FALSE(getCodec(CodecType::LZ4_VARINT_SIZE)->needsUncompressedLength()); - EXPECT_TRUE(getCodec(CodecType::LZMA2)->needsUncompressedLength()); - EXPECT_FALSE(getCodec(CodecType::LZMA2_VARINT_SIZE) - ->needsUncompressedLength()); - EXPECT_TRUE(getCodec(CodecType::ZSTD_BETA)->needsUncompressedLength()); - EXPECT_FALSE(getCodec(CodecType::GZIP)->needsUncompressedLength()); + static const struct { CodecType type; bool needsUncompressedLength; } + expectations[] = { + { CodecType::NO_COMPRESSION, false }, + { CodecType::LZ4, true }, + { CodecType::SNAPPY, false }, + { CodecType::ZLIB, false }, + { CodecType::LZ4_VARINT_SIZE, false }, + { CodecType::LZMA2, true }, + { CodecType::LZMA2_VARINT_SIZE, false }, + { CodecType::ZSTD, false }, + { CodecType::GZIP, false }, + { CodecType::LZ4_FRAME, false }, + }; + + for (auto const& test : expectations) { + if (hasCodec(test.type)) { + EXPECT_EQ(getCodec(test.type)->needsUncompressedLength(), + test.needsUncompressedLength); + } + } } class CompressionTest - : public testing::TestWithParam> { - protected: - void SetUp() override { - auto tup = GetParam(); - uncompressedLength_ = uint64_t(1) << std::tr1::get<0>(tup); - codec_ = getCodec(std::tr1::get<1>(tup)); - } + : public testing::TestWithParam> { + protected: + void SetUp() override { + auto tup = GetParam(); + uncompressedLength_ = uint64_t(1) << std::tr1::get<0>(tup); + chunks_ = std::tr1::get<1>(tup); + codec_ = getCodec(std::tr1::get<2>(tup)); + } + + void runSimpleIOBufTest(const DataHolder& dh); + + void runSimpleStringTest(const DataHolder& dh); - void runSimpleTest(const DataHolder& dh); + private: + std::unique_ptr split(std::unique_ptr data) const; - uint64_t uncompressedLength_; - std::unique_ptr codec_; + uint64_t uncompressedLength_; + size_t chunks_; + std::unique_ptr codec_; }; -void CompressionTest::runSimpleTest(const DataHolder& dh) { - auto original = IOBuf::wrapBuffer(dh.data(uncompressedLength_)); - auto compressed = codec_->compress(original.get()); +void CompressionTest::runSimpleIOBufTest(const DataHolder& dh) { + const auto original = split(IOBuf::wrapBuffer(dh.data(uncompressedLength_))); + const auto compressed = split(codec_->compress(original.get())); if (!codec_->needsUncompressedLength()) { auto uncompressed = codec_->uncompress(compressed.get()); - EXPECT_EQ(uncompressedLength_, uncompressed->computeChainDataLength()); EXPECT_EQ(dh.hash(uncompressedLength_), hashIOBuf(uncompressed.get())); } @@ -164,27 +208,72 @@ void CompressionTest::runSimpleTest(const DataHolder& dh) { } } +void CompressionTest::runSimpleStringTest(const DataHolder& dh) { + const auto original = std::string( + reinterpret_cast(dh.data(uncompressedLength_).data()), + uncompressedLength_); + const auto compressed = codec_->compress(original); + if (!codec_->needsUncompressedLength()) { + auto uncompressed = codec_->uncompress(compressed); + EXPECT_EQ(uncompressedLength_, uncompressed.length()); + EXPECT_EQ(uncompressed, original); + } + { + auto uncompressed = codec_->uncompress(compressed, uncompressedLength_); + EXPECT_EQ(uncompressedLength_, uncompressed.length()); + EXPECT_EQ(uncompressed, original); + } +} + +// Uniformly split data into (potentially empty) chunks. +std::unique_ptr CompressionTest::split( + std::unique_ptr data) const { + if (data->isChained()) { + data->coalesce(); + } + + const size_t size = data->computeChainDataLength(); + + std::multiset splits; + for (size_t i = 1; i < chunks_; ++i) { + splits.insert(Random::rand64(size)); + } + + folly::IOBufQueue result; + + size_t offset = 0; + for (size_t split : splits) { + result.append(IOBuf::copyBuffer(data->data() + offset, split - offset)); + offset = split; + } + result.append(IOBuf::copyBuffer(data->data() + offset, size - offset)); + + return result.move(); +} + TEST_P(CompressionTest, RandomData) { - runSimpleTest(randomDataHolder); + runSimpleIOBufTest(randomDataHolder); } TEST_P(CompressionTest, ConstantData) { - runSimpleTest(constantDataHolder); + runSimpleIOBufTest(constantDataHolder); +} + +TEST_P(CompressionTest, RandomDataString) { + runSimpleStringTest(randomDataHolder); +} + +TEST_P(CompressionTest, ConstantDataString) { + runSimpleStringTest(constantDataHolder); } INSTANTIATE_TEST_CASE_P( CompressionTest, CompressionTest, - testing::Combine(testing::Values(0, 1, 12, 22, 25, 27), - testing::Values(CodecType::NO_COMPRESSION, - CodecType::LZ4, - CodecType::SNAPPY, - CodecType::ZLIB, - CodecType::LZ4_VARINT_SIZE, - CodecType::LZMA2, - CodecType::LZMA2_VARINT_SIZE, - CodecType::ZSTD_BETA, - CodecType::GZIP))); + testing::Combine( + testing::Values(0, 1, 12, 22, 25, 27), + testing::Values(1, 2, 3, 8, 65), + testing::ValuesIn(availableCodecs()))); class CompressionVarintTest : public testing::TestWithParam> { @@ -227,7 +316,9 @@ void CompressionVarintTest::runSimpleTest(const DataHolder& dh) { EXPECT_EQ(dh.hash(uncompressedLength_), hashIOBuf(uncompressed.get())); } -TEST_P(CompressionVarintTest, RandomData) { runSimpleTest(randomDataHolder); } +TEST_P(CompressionVarintTest, RandomData) { + runSimpleTest(randomDataHolder); +} TEST_P(CompressionVarintTest, ConstantData) { runSimpleTest(constantDataHolder); @@ -236,9 +327,12 @@ TEST_P(CompressionVarintTest, ConstantData) { INSTANTIATE_TEST_CASE_P( CompressionVarintTest, CompressionVarintTest, - testing::Combine(testing::Values(0, 1, 12, 22, 25, 27), - testing::Values(CodecType::LZ4_VARINT_SIZE, - CodecType::LZMA2_VARINT_SIZE))); + testing::Combine( + testing::Values(0, 1, 12, 22, 25, 27), + testing::ValuesIn(supportedCodecs({ + CodecType::LZ4_VARINT_SIZE, + CodecType::LZMA2_VARINT_SIZE, + })))); class CompressionCorruptionTest : public testing::TestWithParam { protected: @@ -292,12 +386,15 @@ TEST_P(CompressionCorruptionTest, ConstantData) { INSTANTIATE_TEST_CASE_P( CompressionCorruptionTest, CompressionCorruptionTest, - testing::Values( + testing::ValuesIn( // NO_COMPRESSION can't detect corruption // LZ4 can't detect corruption reliably (sigh) - CodecType::SNAPPY, - CodecType::ZLIB)); - + supportedCodecs({ + CodecType::SNAPPY, + CodecType::ZLIB, + CodecType::ZSTD, + CodecType::LZ4_FRAME, + }))); }}} // namespaces int main(int argc, char *argv[]) {