Skip to content

Commit 7a347b4

Browse files
committed
Add faulty injection in writer fuzzer
1 parent e67f11b commit 7a347b4

File tree

7 files changed

+176
-10
lines changed

7 files changed

+176
-10
lines changed

velox/common/file/tests/FaultyFileSystem.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ class FaultyFileSystem : public FileSystem {
5555

5656
std::unique_ptr<ReadFile> openFileForRead(
5757
std::string_view path,
58-
const FileOptions& options) override;
58+
const FileOptions& options = {}) override;
5959

6060
std::unique_ptr<WriteFile> openFileForWrite(
6161
std::string_view path,
62-
const FileOptions& options) override;
62+
const FileOptions& options = {}) override;
6363

6464
void remove(std::string_view path) override;
6565

velox/dwio/common/tests/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# limitations under the License.
1414

1515
add_subdirectory(utils)
16+
velox_add_library(velox_dwio_faulty_file_sink FaultyFileSink.cpp)
17+
velox_link_libraries(velox_dwio_faulty_file_sink velox_file_test_utils)
1618

1719
add_executable(
1820
velox_dwio_common_test
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "velox/common/base/Fs.h"
18+
#include "velox/common/file/FileSystems.h"
19+
#include "velox/dwio/common/FileSink.h"
20+
#include "velox/dwio/common/exception/Exception.h"
21+
#include "velox/dwio/common/tests/FaultyFileSink.h"
22+
#include "velox/common/file/tests/FaultyFileSystem.h"
23+
24+
namespace facebook::velox::dwio::common {
25+
namespace {
26+
constexpr std::string_view kFileScheme("faulty:");
27+
constexpr std::string_view kFileSep("/");
28+
29+
std::unique_ptr<FileSink> faultyFileSink(
30+
const std::string& filePath,
31+
const FileSink::Options& options) {
32+
if (filePath.find(kFileScheme) == 0) {
33+
return std::make_unique<FaultyFileSink>(filePath, options);
34+
}
35+
return nullptr;
36+
}
37+
} // namespace
38+
39+
FaultyFileSink::FaultyFileSink(const std::string& name, const Options& options)
40+
: FileSink{name, options}, writeFile_() {
41+
const auto dir = fs::path(name.substr(7)).parent_path();
42+
if (!fs::exists(dir)) {
43+
VELOX_CHECK(velox::common::generateFileDirectory(dir.c_str()));
44+
}
45+
auto fs = std::dynamic_pointer_cast<tests::utils::FaultyFileSystem>(
46+
filesystems::getFileSystem(name_, nullptr));
47+
writeFile_ = fs->openFileForWrite(name_);
48+
}
49+
50+
void FaultyFileSink::write(std::vector<DataBuffer<char>>& buffers) {
51+
writeImpl(buffers, [&](auto& buffer) {
52+
const uint64_t size = buffer.size();
53+
writeFile_->append({buffer.data(), size});
54+
return size;
55+
});
56+
}
57+
58+
void FaultyFileSink::doClose() {
59+
if (writeFile_ != nullptr) {
60+
writeFile_->close();
61+
}
62+
}
63+
64+
VELOX_REGISTER_DATA_SINK_METHOD_DEFINITION(FaultyFileSink, faultyFileSink);
65+
66+
void registerFaultyFileSinks() {
67+
dwio::common::FaultyFileSink::registerFactory();
68+
}
69+
} // namespace facebook::velox::dwio::common
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <chrono>
20+
21+
#include "velox/common/config/Config.h"
22+
#include "velox/common/file/File.h"
23+
#include "velox/common/io/IoStatistics.h"
24+
#include "velox/dwio/common/Closeable.h"
25+
#include "velox/dwio/common/DataBuffer.h"
26+
#include "velox/dwio/common/MetricsLog.h"
27+
#include "velox/dwio/common/FileSink.h"
28+
#include "velox/common/file/tests/FaultyFile.h"
29+
30+
namespace facebook::velox::dwio::common {
31+
using namespace facebook::velox::io;
32+
33+
class FaultyFileSink : public FileSink {
34+
public:
35+
FaultyFileSink(const std::string& name, const Options& options);
36+
37+
~FaultyFileSink() override {
38+
destroy();
39+
}
40+
41+
using FileSink::write;
42+
43+
void write(std::vector<DataBuffer<char>>& buffers) override;
44+
45+
static void registerFactory();
46+
47+
protected:
48+
void doClose() override;
49+
50+
private:
51+
std::unique_ptr<WriteFile> writeFile_;
52+
};
53+
54+
void registerFaultyFileSinks();
55+
56+
} // namespace facebook::velox::dwio::common

velox/exec/fuzzer/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ target_link_libraries(
2929
velox_hive_connector
3030
velox_dwio_dwrf_reader
3131
velox_dwio_dwrf_writer
32-
velox_dwio_catalog_fbhive)
32+
velox_dwio_catalog_fbhive
33+
velox_dwio_faulty_file_sink)
3334

3435
add_library(velox_aggregation_fuzzer_base AggregationFuzzerBase.cpp)
3536

velox/exec/fuzzer/WriterFuzzer.cpp

+41-7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "velox/common/base/Fs.h"
2323
#include "velox/common/encode/Base64.h"
2424
#include "velox/common/file/FileSystems.h"
25+
#include "velox/common/file/tests/FaultyFileSystem.h"
2526
#include "velox/connectors/hive/HiveConnector.h"
2627
#include "velox/connectors/hive/HiveConnectorSplit.h"
2728
#include "velox/connectors/hive/TableHandle.h"
@@ -123,7 +124,8 @@ class WriterFuzzer {
123124
const std::vector<std::string>& bucketColumns,
124125
int32_t sortColumnOffset,
125126
const std::vector<std::shared_ptr<const HiveSortingColumn>>& sortBy,
126-
const std::string& outputDirectoryPath);
127+
const std::string& outputDirectoryPath,
128+
const bool writeErrorInjected);
127129

128130
// Generates table column handles based on table column properties
129131
std::unordered_map<std::string, std::shared_ptr<connector::ColumnHandle>>
@@ -256,7 +258,8 @@ void writerFuzzer(
256258

257259
std::vector<std::string> listFolders(std::string_view path) {
258260
std::vector<std::string> folders;
259-
auto fileSystem = filesystems::getFileSystem("/", nullptr);
261+
auto fileSystem = std::dynamic_pointer_cast<tests::utils::FaultyFileSystem>(
262+
filesystems::getFileSystem("/", nullptr));
260263
for (auto& p : std::filesystem::recursive_directory_iterator(
261264
fileSystem->extractPath(path))) {
262265
if (p.is_directory())
@@ -340,7 +343,26 @@ void WriterFuzzer::go() {
340343
}
341344
auto input = generateInputData(names, types, partitionOffset);
342345

343-
auto tempDirPath = exec::test::TempDirectoryPath::create();
346+
auto tempDirPath = exec::test::TempDirectoryPath::create(true);
347+
348+
bool writeErrorInjected = false;
349+
auto fs = std::dynamic_pointer_cast<tests::utils::FaultyFileSystem>(
350+
filesystems::getFileSystem(tempDirPath->getPath(), {}));
351+
if (partitionKeys.empty() && vectorFuzzer_.coinToss(1)) {
352+
fs->setFileInjectionError(
353+
std::make_exception_ptr(VeloxRuntimeError(
354+
"file_name",
355+
1,
356+
"function_name()",
357+
"operator()",
358+
"test message",
359+
"",
360+
error_code::kArithmeticError,
361+
false)),
362+
{tests::utils::FaultFileOperation::Type::kWrite});
363+
writeErrorInjected = true;
364+
}
365+
344366
verifyWriter(
345367
input,
346368
names,
@@ -351,7 +373,10 @@ void WriterFuzzer::go() {
351373
bucketColumns,
352374
sortColumnOffset,
353375
sortBy,
354-
tempDirPath->getPath());
376+
tempDirPath->getPath(),
377+
writeErrorInjected);
378+
379+
fs->clearFileFaultInjections();
355380

356381
LOG(INFO) << "==============================> Done with iteration "
357382
<< iteration++;
@@ -423,7 +448,8 @@ void WriterFuzzer::verifyWriter(
423448
const std::vector<std::string>& bucketColumns,
424449
const int32_t sortColumnOffset,
425450
const std::vector<std::shared_ptr<const HiveSortingColumn>>& sortBy,
426-
const std::string& outputDirectoryPath) {
451+
const std::string& outputDirectoryPath,
452+
const bool writeErrorInjected) {
427453
const auto plan = PlanBuilder()
428454
.values(input)
429455
.tableWrite(
@@ -436,7 +462,14 @@ void WriterFuzzer::verifyWriter(
436462

437463
const auto maxDrivers =
438464
boost::random::uniform_int_distribution<int32_t>(1, 16)(rng_);
439-
const auto result = veloxToPrestoResult(execute(plan, maxDrivers));
465+
RowVectorPtr result;
466+
try {
467+
result = veloxToPrestoResult(execute(plan, maxDrivers));
468+
} catch (VeloxRuntimeError&) {
469+
VELOX_CHECK(
470+
writeErrorInjected, "write plan failed with no writeErrorInjected");
471+
return;
472+
}
440473

441474
const auto dropSql = "DROP TABLE IF EXISTS tmp_write";
442475
const auto sql = referenceQueryRunner_->toSql(plan).value();
@@ -661,7 +694,8 @@ void WriterFuzzer::comparePartitionAndBucket(
661694
// static
662695
std::map<std::string, int32_t> WriterFuzzer::getPartitionNameAndFilecount(
663696
const std::string& tableDirectoryPath) {
664-
auto fileSystem = filesystems::getFileSystem("/", nullptr);
697+
auto fileSystem = std::dynamic_pointer_cast<tests::utils::FaultyFileSystem>(
698+
filesystems::getFileSystem("/", nullptr));
665699
auto directories = listFolders(tableDirectoryPath);
666700
std::map<std::string, int32_t> partitionNameAndFileCount;
667701

velox/exec/fuzzer/WriterFuzzerRunner.h

+4
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
#include <vector>
2424

2525
#include "velox/common/file/FileSystems.h"
26+
#include "velox/common/file/tests/FaultyFileSystem.h"
2627
#include "velox/connectors/hive/HiveConnector.h"
2728
#include "velox/dwio/common/FileSink.h"
29+
#include "velox/dwio/common/tests/FaultyFileSink.h"
2830
#include "velox/dwio/dwrf/RegisterDwrfReader.h"
2931
#include "velox/dwio/dwrf/RegisterDwrfWriter.h"
3032
#include "velox/exec/fuzzer/FuzzerUtil.h"
@@ -74,6 +76,7 @@ class WriterFuzzerRunner {
7476
size_t seed,
7577
std::unique_ptr<ReferenceQueryRunner> referenceQueryRunner) {
7678
filesystems::registerLocalFileSystem();
79+
tests::utils::registerFaultyFileSystem();
7780
connector::registerConnectorFactory(
7881
std::make_shared<connector::hive::HiveConnectorFactory>());
7982
auto hiveConnector =
@@ -87,6 +90,7 @@ class WriterFuzzerRunner {
8790
dwrf::registerDwrfReaderFactory();
8891
dwrf::registerDwrfWriterFactory();
8992
dwio::common::registerFileSinks();
93+
dwio::common::registerFaultyFileSinks();
9094
facebook::velox::exec::test::writerFuzzer(
9195
seed, std::move(referenceQueryRunner));
9296
// Calling gtest here so that it can be recognized as tests in CI systems.

0 commit comments

Comments
 (0)