Skip to content

Commit e33f444

Browse files
authored
Add mocks for async_files to facilitate testing clients (#20942)
Signed-off-by: Raven Black <[email protected]>
1 parent e8b2b4f commit e33f444

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

test/extensions/common/async_files/BUILD

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
load(
22
"//bazel:envoy_build_system.bzl",
3+
"envoy_cc_mock",
34
"envoy_cc_test",
45
"envoy_package",
56
)
@@ -60,3 +61,12 @@ envoy_cc_test(
6061
"//source/extensions/common/async_files:status_after_file_error",
6162
],
6263
)
64+
65+
envoy_cc_mock(
66+
name = "mocks",
67+
srcs = ["mocks.cc"],
68+
hdrs = ["mocks.h"],
69+
deps = [
70+
"//source/extensions/common/async_files",
71+
],
72+
)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include "test/extensions/common/async_files/mocks.h"
2+
3+
#include <memory>
4+
5+
namespace Envoy {
6+
namespace Extensions {
7+
namespace Common {
8+
namespace AsyncFiles {
9+
10+
using ::testing::_;
11+
12+
MockAsyncFileContext::MockAsyncFileContext(std::shared_ptr<MockAsyncFileManager> manager)
13+
: manager_(manager) {
14+
ON_CALL(*this, createHardLink(_, _))
15+
.WillByDefault([this](absl::string_view, std::function<void(absl::Status)> on_complete) {
16+
return manager_->enqueue(
17+
std::shared_ptr<MockAsyncFileAction>(new TypedMockAsyncFileAction(on_complete)));
18+
});
19+
EXPECT_CALL(*this, close(_)).WillOnce([this](std::function<void(absl::Status)> on_complete) {
20+
manager_->enqueue(
21+
std::shared_ptr<MockAsyncFileAction>(new TypedMockAsyncFileAction(on_complete)));
22+
return absl::OkStatus();
23+
});
24+
ON_CALL(*this, read(_, _, _))
25+
.WillByDefault([this](off_t, size_t,
26+
std::function<void(absl::StatusOr<Buffer::InstancePtr>)> on_complete) {
27+
return manager_->enqueue(
28+
std::shared_ptr<MockAsyncFileAction>(new TypedMockAsyncFileAction(on_complete)));
29+
});
30+
ON_CALL(*this, write(_, _, _))
31+
.WillByDefault([this](Buffer::Instance&, off_t,
32+
std::function<void(absl::StatusOr<size_t>)> on_complete) {
33+
return manager_->enqueue(
34+
std::shared_ptr<MockAsyncFileAction>(new TypedMockAsyncFileAction(on_complete)));
35+
});
36+
ON_CALL(*this, duplicate(_))
37+
.WillByDefault(
38+
[this](
39+
std::function<void(absl::StatusOr<std::shared_ptr<AsyncFileContext>>)> on_complete) {
40+
return manager_->enqueue(
41+
std::shared_ptr<MockAsyncFileAction>(new TypedMockAsyncFileAction(on_complete)));
42+
});
43+
};
44+
45+
MockAsyncFileManager::MockAsyncFileManager() {
46+
ON_CALL(*this, enqueue(_)).WillByDefault([this](const std::shared_ptr<AsyncFileAction> action) {
47+
queue_.push_back(std::dynamic_pointer_cast<MockAsyncFileAction>(action));
48+
return [this]() { mockCancel(); };
49+
});
50+
ON_CALL(*this, createAnonymousFile(_, _))
51+
.WillByDefault([this](absl::string_view,
52+
std::function<void(absl::StatusOr<AsyncFileHandle>)> on_complete) {
53+
return enqueue(
54+
std::shared_ptr<MockAsyncFileAction>(new TypedMockAsyncFileAction(on_complete)));
55+
});
56+
ON_CALL(*this, openExistingFile(_, _, _))
57+
.WillByDefault([this](absl::string_view, Mode,
58+
std::function<void(absl::StatusOr<AsyncFileHandle>)> on_complete) {
59+
return enqueue(
60+
std::shared_ptr<MockAsyncFileAction>(new TypedMockAsyncFileAction(on_complete)));
61+
});
62+
ON_CALL(*this, unlink(_, _))
63+
.WillByDefault([this](absl::string_view, std::function<void(absl::Status)> on_complete) {
64+
return enqueue(
65+
std::shared_ptr<MockAsyncFileAction>(new TypedMockAsyncFileAction(on_complete)));
66+
});
67+
}
68+
69+
} // namespace AsyncFiles
70+
} // namespace Common
71+
} // namespace Extensions
72+
} // namespace Envoy
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#include "source/extensions/common/async_files/async_file_handle.h"
2+
#include "source/extensions/common/async_files/async_file_manager.h"
3+
#include "source/extensions/common/async_files/async_file_manager_factory.h"
4+
5+
#include "gmock/gmock.h"
6+
#include "gtest/gtest.h"
7+
8+
namespace Envoy {
9+
namespace Extensions {
10+
namespace Common {
11+
namespace AsyncFiles {
12+
13+
class MockAsyncFileManager;
14+
15+
class MockAsyncFileContext : public Extensions::Common::AsyncFiles::AsyncFileContext {
16+
public:
17+
MockAsyncFileContext() = default;
18+
explicit MockAsyncFileContext(std::shared_ptr<MockAsyncFileManager> manager);
19+
// The default behavior of the methods that would enqueue an action is to enqueue an
20+
// appropriate MockAsyncFileAction on the MockAsyncFileManager (if one was provided).
21+
// These can be consumed by calling MockAsyncFileManager::nextActionCompletes
22+
// with the desired parameter to the on_complete callback.
23+
MOCK_METHOD(absl::StatusOr<CancelFunction>, createHardLink,
24+
(absl::string_view filename, std::function<void(absl::Status)> on_complete));
25+
MOCK_METHOD(absl::Status, close, (std::function<void(absl::Status)> on_complete));
26+
MOCK_METHOD(absl::StatusOr<CancelFunction>, read,
27+
(off_t offset, size_t length,
28+
std::function<void(absl::StatusOr<Buffer::InstancePtr>)> on_complete));
29+
MOCK_METHOD(absl::StatusOr<CancelFunction>, write,
30+
(Buffer::Instance & contents, off_t offset,
31+
std::function<void(absl::StatusOr<size_t>)> on_complete));
32+
MOCK_METHOD(absl::StatusOr<CancelFunction>, duplicate,
33+
(std::function<void(absl::StatusOr<std::shared_ptr<AsyncFileContext>>)> on_complete));
34+
35+
private:
36+
std::shared_ptr<MockAsyncFileManager> manager_;
37+
};
38+
39+
using MockAsyncFileHandle = std::shared_ptr<MockAsyncFileContext>;
40+
41+
class MockAsyncFileAction : public AsyncFileAction {
42+
public:
43+
virtual std::string describe() const PURE;
44+
void execute() override{};
45+
};
46+
47+
template <typename T> class TypedMockAsyncFileAction : public MockAsyncFileAction {
48+
public:
49+
explicit TypedMockAsyncFileAction(T on_complete) : on_complete_(on_complete) {}
50+
T on_complete_;
51+
std::string describe() const override { return typeid(T).name(); }
52+
};
53+
54+
class MockAsyncFileManager : public Extensions::Common::AsyncFiles::AsyncFileManager {
55+
public:
56+
MockAsyncFileManager();
57+
// The default behavior of the methods that would enqueue an action is to enqueue a mock action.
58+
MOCK_METHOD(CancelFunction, createAnonymousFile,
59+
(absl::string_view path,
60+
std::function<void(absl::StatusOr<AsyncFileHandle>)> on_complete));
61+
MOCK_METHOD(CancelFunction, openExistingFile,
62+
(absl::string_view filename, Mode mode,
63+
std::function<void(absl::StatusOr<AsyncFileHandle>)> on_complete));
64+
MOCK_METHOD(CancelFunction, unlink,
65+
(absl::string_view filename, std::function<void(absl::Status)> on_complete));
66+
MOCK_METHOD(std::string, describe, (), (const));
67+
68+
// mockCancel is called any time any action queued by mock is cancelled. It isn't overriding
69+
// a function from the real class, it's just used for verification.
70+
MOCK_METHOD(void, mockCancel, ());
71+
72+
// With a non-overridden MockAsyncFileManager, action functions put the action into queue_,
73+
// and the actions can be completed by calling nextActionCompletes with the parameter to
74+
// be passed to the callback.
75+
// For callbacks taking StatusOr<T>, the value must be passed as explicitly a StatusOr<T>,
76+
// not just a Status or a T.
77+
template <typename T> void nextActionCompletes(T result) {
78+
ASSERT_FALSE(queue_.empty());
79+
auto action =
80+
std::dynamic_pointer_cast<TypedMockAsyncFileAction<std::function<void(T)>>>(queue_.front());
81+
ASSERT_TRUE(action.get() != nullptr)
82+
<< "mismatched type for nextActionCompletes: action is " << queue_.front()->describe()
83+
<< ", nextActionCompletes was given " << typeid(T).name();
84+
queue_.pop_front();
85+
action->on_complete_(std::move(result));
86+
}
87+
88+
std::deque<std::shared_ptr<MockAsyncFileAction>> queue_;
89+
90+
private:
91+
MOCK_METHOD(CancelFunction, enqueue, (const std::shared_ptr<AsyncFileAction> action));
92+
friend class MockAsyncFileContext;
93+
};
94+
95+
class MockAsyncFileManagerFactory : public Extensions::Common::AsyncFiles::AsyncFileManagerFactory {
96+
public:
97+
MOCK_METHOD(std::shared_ptr<AsyncFileManager>, getAsyncFileManager,
98+
(const envoy::extensions::common::async_files::v3::AsyncFileManagerConfig& config,
99+
Api::OsSysCalls* substitute_posix_file_operations));
100+
};
101+
102+
} // namespace AsyncFiles
103+
} // namespace Common
104+
} // namespace Extensions
105+
} // namespace Envoy

0 commit comments

Comments
 (0)