|
| 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