// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include #include #include // Include this first to avoid type conflicts with CEF headers. #include "tests/unittests/chromium_includes.h" #include "include/base/cef_bind.h" #include "include/cef_stream.h" #include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_stream_resource_handler.h" #include "testing/gtest/include/gtest/gtest.h" #include "tests/unittests/routing_test_handler.h" namespace { const char kTestUrl[] = "http://tests-srh/test.html"; const size_t kReadBlockSize = 1024U; // 1k. // The usual network buffer size is about 32k. Choose a value that's larger. const size_t kReadDesiredSize = 100U * 1024U; // 100k class ReadHandler : public CefReadHandler { public: explicit ReadHandler(bool may_block) : may_block_(may_block), offset_(0), expected_result_(0) { } void CreateContent() { // To verify that the data transers successfully we're going to make a big // math problem. content_.reserve(kReadDesiredSize + 50U); content_ = ""; } int GetExpectedResult() const { return expected_result_; } size_t Read(void* ptr, size_t size, size_t n) override { EXPECT_EQ(1U, size); // Read the minimum of requested size, remaining size or kReadBlockSize. const size_t read_bytes = std::min(std::min(size * n, content_.size() - offset_), kReadBlockSize); if (read_bytes > 0) { memcpy(ptr, content_.c_str() + offset_, read_bytes); offset_ += read_bytes; } return read_bytes; } int Seek(int64 offset, int whence) override { EXPECT_TRUE(false); // Not reached. return 0; } int64 Tell() override { EXPECT_TRUE(false); // Not reached. return 0; } int Eof() override { EXPECT_TRUE(false); // Not reached. return 0; } bool MayBlock() override { return may_block_; } private: const bool may_block_; std::string content_; size_t offset_; int expected_result_; IMPLEMENT_REFCOUNTING(ReadHandler); }; class ReadTestHandler : public RoutingTestHandler { public: explicit ReadTestHandler(bool may_block) : may_block_(may_block), expected_result_(0) {} void RunTest() override { // Create the browser. CreateBrowser(kTestUrl); // Time out the test after a reasonable period of time. SetTestTimeout(); } CefRefPtr GetResourceHandler( CefRefPtr browser, CefRefPtr frame, CefRefPtr request) override { got_resource_handler_.yes(); const std::string& url = request->GetURL(); EXPECT_STREQ(kTestUrl, url.c_str()); CefRefPtr handler = new ReadHandler(may_block_); handler->CreateContent(); expected_result_ = handler->GetExpectedResult(); CefRefPtr stream = CefStreamReader::CreateForHandler(handler.get()); return new CefStreamResourceHandler("text/html", stream); } bool OnQuery(CefRefPtr browser, CefRefPtr frame, int64 query_id, const CefString& request, bool persistent, CefRefPtr callback) override { got_on_query_.yes(); const int actual_result = atoi(request.ToString().c_str()); EXPECT_EQ(expected_result_, actual_result); DestroyTestIfDone(); return true; } void OnLoadingStateChange(CefRefPtr browser, bool isLoading, bool canGoBack, bool canGoForward) override { if (!isLoading) { got_on_loading_state_change_done_.yes(); DestroyTestIfDone(); } } private: void DestroyTestIfDone() { if (got_on_query_ && got_on_loading_state_change_done_) DestroyTest(); } void DestroyTest() override { EXPECT_TRUE(got_resource_handler_); EXPECT_TRUE(got_on_query_); EXPECT_TRUE(got_on_loading_state_change_done_); RoutingTestHandler::DestroyTest(); } const bool may_block_; int expected_result_; TrackCallback got_resource_handler_; TrackCallback got_on_query_; TrackCallback got_on_loading_state_change_done_; }; } // namespace TEST(StreamResourceHandlerTest, ReadWillBlock) { CefRefPtr handler = new ReadTestHandler(true); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } TEST(StreamResourceHandlerTest, ReadWontBlock) { CefRefPtr handler = new ReadTestHandler(false); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); }