diff options
Diffstat (limited to 'test/fixtures/mock_file_source.cpp')
-rw-r--r-- | test/fixtures/mock_file_source.cpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/test/fixtures/mock_file_source.cpp b/test/fixtures/mock_file_source.cpp new file mode 100644 index 0000000000..b420ba7298 --- /dev/null +++ b/test/fixtures/mock_file_source.cpp @@ -0,0 +1,163 @@ +#include "../fixtures/util.hpp" +#include "mock_file_source.hpp" + +#include <mbgl/storage/request.hpp> +#include <mbgl/util/io.hpp> +#include <mbgl/util/thread.hpp> + +#include <algorithm> + +namespace { + +const uint64_t timeout = 1000000; + +} + +namespace mbgl { + +class MockFileSource::Impl { +public: + Impl(Type type, const std::string& match) + : type_(type), match_(match), timer_(util::RunLoop::getLoop()) { + timer_.start(timeout, timeout, [this] { dispatchPendingRequests(); }); + timer_.unref(); + } + + ~Impl() { + timer_.stop(); + } + + void setOnRequestDelayedCallback(std::function<void(void)> callback) { + requestEnqueuedCallback_ = callback; + } + + void handleRequest(Request* req); + void cancelRequest(Request* req); + +private: + void replyWithSuccess(Request* req) const; + void replyWithSuccessWithDelay(Request* req); + void replyWithFailure(Request* req) const; + void replyWithCorruptedData(Request* req) const; + + void dispatchPendingRequests(); + + Type type_; + std::string match_; + std::vector<Request*> pendingRequests_; + uv::timer timer_; + + std::function<void(void)> requestEnqueuedCallback_; +}; + +void MockFileSource::Impl::replyWithSuccess(Request* req) const { + std::shared_ptr<Response> res = std::make_shared<Response>(); + res->status = Response::Status::Successful; + + try { + res->data = util::read_file(req->resource.url); + } catch (const std::exception& err) { + res->status = Response::Status::Error; + res->message = err.what(); + } + + req->notify(res); +} + +void MockFileSource::Impl::replyWithSuccessWithDelay(Request* req) { + if (req->resource.url.find(match_) == std::string::npos) { + replyWithSuccess(req); + return; + } + + pendingRequests_.push_back(req); + requestEnqueuedCallback_(); +} + +void MockFileSource::Impl::replyWithFailure(Request* req) const { + if (req->resource.url.find(match_) == std::string::npos) { + replyWithSuccess(req); + return; + } + + std::shared_ptr<Response> res = std::make_shared<Response>(); + res->status = Response::Status::Error; + res->message = "Failed by the test case"; + + req->notify(res); +} + +void MockFileSource::Impl::replyWithCorruptedData(Request* req) const { + if (req->resource.url.find(match_) == std::string::npos) { + replyWithSuccess(req); + return; + } + + std::shared_ptr<Response> res = std::make_shared<Response>(); + res->status = Response::Status::Successful; + res->data = util::read_file(req->resource.url); + res->data.insert(0, "CORRUPTED"); + + req->notify(res); +} + +void MockFileSource::Impl::handleRequest(Request* req) { + switch (type_) { + case Type::Success: + replyWithSuccess(req); + break; + case Type::SuccessWithDelay: + replyWithSuccessWithDelay(req); + break; + case Type::RequestFail: + replyWithFailure(req); + break; + case Type::RequestWithCorruptedData: + replyWithCorruptedData(req); + break; + default: + EXPECT_TRUE(false) << "Should never be reached."; + } +} + +void MockFileSource::Impl::cancelRequest(Request* req) { + auto it = std::find(pendingRequests_.begin(), pendingRequests_.end(), req); + if (it != pendingRequests_.end()) { + pendingRequests_.erase(it); + } else { + // There is no request for this URL anymore. Likely, the request already completed + // before we got around to process the cancelation request. + } + + req->destruct(); +} + +void MockFileSource::Impl::dispatchPendingRequests() { + for (auto req : pendingRequests_) { + replyWithSuccess(req); + } + + pendingRequests_.clear(); +} + +MockFileSource::MockFileSource(Type type, const std::string& match) + : thread_(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"FileSource", util::ThreadType::Unknown, util::ThreadPriority::Low}, type, match)) { +} + +void MockFileSource::setOnRequestDelayedCallback(std::function<void(void)> callback) { + thread_->invokeSync(&Impl::setOnRequestDelayedCallback, callback); +} + +Request* MockFileSource::request(const Resource& resource, uv_loop_t* loop, Callback callback) { + Request* req = new Request(resource, loop, std::move(callback)); + thread_->invoke(&Impl::handleRequest, req); + + return req; +} + +void MockFileSource::cancel(Request* req) { + req->cancel(); + thread_->invoke(&Impl::cancelRequest, req); +} + +} |