req1 = fs.request(revalidateSame, uv_default_loop(), [&](const Response &res) { // This callback can get triggered multiple times. We only care about the first invocation. // It will get triggered again when refreshing the req2 (see below). static bool first = true; if (!first) { return; } first = false; EXPECT_EQ(Response::Successful, res.status); EXPECT_EQ(false, res.stale); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Response", *res.data); EXPECT_EQ(0, res.expires); EXPECT_EQ(0, res.modified); EXPECT_EQ("snowfall", res.etag); EXPECT_EQ("", res.message); req2 = fs.request(revalidateSame, uv_default_loop(), [&, res](const Response &res2) { if (res2.stale) { // Discard stale responses, if any. return; } ASSERT_TRUE(req1); fs.cancel(req1); req1 = nullptr; ASSERT_TRUE(req2); fs.cancel(req2); req2 = nullptr; EXPECT_EQ(Response::Successful, res2.status); EXPECT_EQ(false, res.stale); ASSERT_TRUE(res2.data.get()); EXPECT_EQ(res.data, res2.data); EXPECT_EQ("Response", *res2.data); // We use this to indicate that a 304 reply came back. EXPECT_LT(0, res2.expires); EXPECT_EQ(0, res2.modified); // We're not sending the ETag in the 304 reply, but it should still be there. EXPECT_EQ("snowfall", res2.etag); EXPECT_EQ("", res2.message); CacheRevalidateSame.finish(); }); });
TEST_F(Storage, HTTPExpiresParsing) { SCOPED_TEST(HTTPExpiresTest) using namespace mbgl; DefaultFileSource fs(nullptr); util::RunLoop loop(uv_default_loop()); std::unique_ptr<FileRequest> req1 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test?modified=1420794326&expires=1420797926&etag=foo" }, [&](Response res) { req1.reset(); EXPECT_EQ(nullptr, res.error); EXPECT_EQ(false, res.stale); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); EXPECT_EQ(1420797926, res.expires.count()); EXPECT_EQ(1420794326, res.modified.count()); EXPECT_EQ("foo", res.etag); loop.stop(); HTTPExpiresTest.finish(); }); uv_run(uv_default_loop(), UV_RUN_DEFAULT); } TEST_F(Storage, HTTPCacheControlParsing) { SCOPED_TEST(HTTPCacheControlTest) using namespace mbgl;
#include <mbgl/storage/default_file_source.hpp> #include <mbgl/util/chrono.hpp> #include <mbgl/util/run_loop.hpp> TEST_F(Storage, HTTPOtherLoop) { SCOPED_TEST(HTTPOtherLoop) using namespace mbgl; // This file source launches a separate thread to do the processing. util::RunLoop loop; DefaultFileSource fs(nullptr); std::unique_ptr<FileRequest> req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" }, [&](Response res) { req.reset(); EXPECT_EQ(nullptr, res.error); EXPECT_EQ(false, res.stale); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); EXPECT_EQ(Seconds::zero(), res.expires); EXPECT_EQ(Seconds::zero(), res.modified); EXPECT_EQ("", res.etag); loop.stop(); HTTPOtherLoop.finish(); }); loop.run(); }
SCOPED_TEST(HTTPNetworkStatusChange) using namespace mbgl; util::RunLoop loop; DefaultFileSource fs(nullptr); const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/delayed" }; // This request takes 200 milliseconds to answer. std::unique_ptr<FileRequest> req = fs.request(resource, [&](Response res) { req.reset(); EXPECT_EQ(nullptr, res.error); EXPECT_EQ(false, res.stale); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Response", *res.data); EXPECT_EQ(Seconds::zero(), res.expires); EXPECT_EQ(Seconds::zero(), res.modified); EXPECT_EQ("", res.etag); loop.stop(); HTTPNetworkStatusChange.finish(); }); // After 50 milliseconds, we're going to trigger a NetworkStatus change. util::Timer reachableTimer; reachableTimer.start(std::chrono::milliseconds(50), Duration::zero(), [] () { mbgl::NetworkStatus::Reachable(); }); // This timer will keep the loop alive to make sure we would be getting a response in caes the // network status change triggered another change (which it shouldn't). util::Timer delayTimer;
const Resource revalidateSame { Resource::Unknown, "http://127.0.0.1:3000/revalidate-same" }; fs.request(revalidateSame, uv_default_loop(), env, [&](const Response &res) { EXPECT_EQ(Response::Successful, res.status); EXPECT_EQ("Response", res.data); EXPECT_EQ(0, res.expires); EXPECT_EQ(0, res.modified); EXPECT_EQ("snowfall", res.etag); EXPECT_EQ("", res.message); fs.request(revalidateSame, uv_default_loop(), env, [&, res](const Response &res2) { EXPECT_EQ(Response::Successful, res2.status); EXPECT_EQ("Response", res2.data); // We use this to indicate that a 304 reply came back. EXPECT_LT(0, res2.expires); EXPECT_EQ(0, res2.modified); // We're not sending the ETag in the 304 reply, but it should still be there. EXPECT_EQ("snowfall", res2.etag); EXPECT_EQ("", res2.message); CacheRevalidateSame.finish(); }); }); const Resource revalidateModified{ Resource::Unknown, "http://127.0.0.1:3000/revalidate-modified" }; fs.request(revalidateModified, uv_default_loop(), env, [&](const Response &res) { EXPECT_EQ(Response::Successful, res.status); EXPECT_EQ("Response", res.data); EXPECT_EQ(0, res.expires); EXPECT_EQ(1420070400, res.modified); EXPECT_EQ("", res.etag);
int number = 1; std::unique_ptr<FileRequest> reqs[concurrency]; std::function<void(int)> req = [&](int i) { const auto current = number++; reqs[i] = fs.request({ Resource::Unknown, std::string("http://127.0.0.1:3000/load/") + std::to_string(current) }, [&, i, current](Response res) { reqs[i].reset(); EXPECT_EQ(nullptr, res.error); EXPECT_EQ(false, res.stale); ASSERT_TRUE(res.data.get()); EXPECT_EQ(std::string("Request ") + std::to_string(current), *res.data); EXPECT_EQ(0, res.expires); EXPECT_EQ(0, res.modified); EXPECT_EQ("", res.etag); if (number <= max) { req(i); } else if (current == max) { loop.stop(); HTTPLoad.finish(); } }); }; for (int i = 0; i < concurrency; i++) { req(i); }
#include <uv.h> #include <mbgl/storage/default_file_source.hpp> #include <mbgl/storage/network_status.hpp> #include <cmath> TEST_F(Storage, HTTPCancel) { SCOPED_TEST(HTTPCancel) using namespace mbgl; DefaultFileSource fs(nullptr); auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" }, uv_default_loop(), [&](const Response &) { ADD_FAILURE() << "Callback should not be called"; }); fs.cancel(req); HTTPCancel.finish(); uv_run(uv_default_loop(), UV_RUN_DEFAULT); } TEST_F(Storage, HTTPCancelMultiple) { SCOPED_TEST(HTTPCancelMultiple) using namespace mbgl; DefaultFileSource fs(nullptr); const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" };
#include "storage.hpp" #include <uv.h> #include <mbgl/storage/default_file_source.hpp> TEST_F(Storage, HTTPOtherLoop) { SCOPED_TEST(HTTPOtherLoop) using namespace mbgl; // This file source launches a separate thread to do the processing. DefaultFileSource fs(nullptr); Request* req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" }, uv_default_loop(), [&](const Response &res) { fs.cancel(req); EXPECT_EQ(Response::Successful, res.status); EXPECT_EQ(false, res.stale); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Hello World!", *res.data); EXPECT_EQ(0, res.expires); EXPECT_EQ(0, res.modified); EXPECT_EQ("", res.etag); EXPECT_EQ("", res.message); HTTPOtherLoop.finish(); }); uv_run(uv_default_loop(), UV_RUN_DEFAULT); }
TEST_F(Storage, HTTPNetworkStatusChange) { SCOPED_TEST(HTTPNetworkStatusChange) using namespace mbgl; DefaultFileSource fs(nullptr); const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/delayed" }; // This request takes 200 milliseconds to answer. Request* req = fs.request(resource, uv_default_loop(), [&](const Response& res) { fs.cancel(req); EXPECT_EQ(nullptr, res.error); EXPECT_EQ(false, res.stale); ASSERT_TRUE(res.data.get()); EXPECT_EQ("Response", *res.data); EXPECT_EQ(0, res.expires); EXPECT_EQ(0, res.modified); EXPECT_EQ("", res.etag); HTTPNetworkStatusChange.finish(); }); // After 50 milliseconds, we're going to trigger a NetworkStatus change. uv::timer reachableTimer(uv_default_loop()); reachableTimer.start(50, 0, [] () { mbgl::NetworkStatus::Reachable(); }); // This timer will keep the loop alive to make sure we would be getting a response in caes the // network status change triggered another change (which it shouldn't). uv::timer delayTimer(uv_default_loop());
// will notify as expected, the second one will have bound a DefaultFileRequest* in the lambda that // gets invalidated by the first notify's pending.erase, and when it gets notified, the crash // occurs. TEST_F(Storage, HTTPIssue1369) { SCOPED_TEST(HTTPIssue1369) using namespace mbgl; SQLiteCache cache; DefaultFileSource fs(&cache); const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" }; auto req = fs.request(resource, uv_default_loop(), [&](const Response&) { ADD_FAILURE() << "Callback should not be called"; }); fs.cancel(req); fs.request(resource, uv_default_loop(), [&](const Response &res) { EXPECT_EQ(Response::Successful, res.status); EXPECT_EQ("Hello World!", res.data); EXPECT_EQ(0, res.expires); EXPECT_EQ(0, res.modified); EXPECT_EQ("", res.etag); EXPECT_EQ("", res.message); HTTPIssue1369.finish(); }); uv_run(uv_default_loop(), UV_RUN_DEFAULT); }