summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-03-24 15:28:13 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-04-14 14:18:19 -0700
commit7de9e196d776e5be972d2e75fc5b290b5e01b33c (patch)
tree5cded3a4044356581967f99238902dbc7ed50535 /test
parent3af3e72bb3cb3f05b33be304d59e66cc244ef4d9 (diff)
downloadqtlocation-mapboxgl-7de9e196d776e5be972d2e75fc5b290b5e01b33c.tar.gz
[tests] Rationalize storage tests
Properly divide Storage tests into DefaultFileSource, OnlineFileSource, and HTTPFileSource tests.
Diffstat (limited to 'test')
-rw-r--r--test/src/mbgl/test/test.cpp3
-rw-r--r--test/storage/asset_file_source.cpp111
-rw-r--r--test/storage/default_file_source.cpp68
-rw-r--r--test/storage/headers.cpp4
-rw-r--r--test/storage/http_cancel.cpp55
-rw-r--r--test/storage/http_error.cpp87
-rw-r--r--test/storage/http_expires.cpp105
-rw-r--r--test/storage/http_file_source.cpp195
-rw-r--r--test/storage/http_header_parsing.cpp56
-rw-r--r--test/storage/http_issue_1369.cpp44
-rw-r--r--test/storage/http_load.cpp49
-rw-r--r--test/storage/http_other_loop.cpp30
-rw-r--r--test/storage/http_reading.cpp181
-rw-r--r--test/storage/http_retry_network_status.cpp125
-rw-r--r--test/storage/http_timeout.cpp37
-rw-r--r--test/storage/online_file_source.cpp361
-rw-r--r--test/storage/storage.cpp13
-rw-r--r--test/storage/storage.hpp17
-rw-r--r--test/test.gypi16
19 files changed, 645 insertions, 912 deletions
diff --git a/test/src/mbgl/test/test.cpp b/test/src/mbgl/test/test.cpp
index cbc6cfb102..37447f9d94 100644
--- a/test/src/mbgl/test/test.cpp
+++ b/test/src/mbgl/test/test.cpp
@@ -1,9 +1,12 @@
#include <mbgl/test.hpp>
+#include <mbgl/test/util.hpp>
+
#include <gtest/gtest.h>
namespace mbgl {
int runTests(int argc, char *argv[]) {
+ auto server = std::make_unique<test::Server>("test/storage/server.js");
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/test/storage/asset_file_source.cpp b/test/storage/asset_file_source.cpp
index c6a25f83dd..4a9866601a 100644
--- a/test/storage/asset_file_source.cpp
+++ b/test/storage/asset_file_source.cpp
@@ -1,11 +1,11 @@
-#include "storage.hpp"
-
#include <mbgl/storage/asset_file_source.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/thread.hpp>
+#include <gtest/gtest.h>
+
namespace {
std::string getFileSourceRoot() {
@@ -17,45 +17,11 @@ std::string getFileSourceRoot() {
#endif
}
-class TestWorker {
-public:
- TestWorker(mbgl::AssetFileSource* fs_) : fs(fs_) {}
-
- void run(std::function<void()> endCallback) {
- const std::string asset("asset://nonempty");
-
- requestCallback = [this, asset, endCallback](mbgl::Response res) {
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("content is here\n", *res.data);
-
- if (!--numRequests) {
- endCallback();
- request.reset();
- } else {
- request = fs->request({ mbgl::Resource::Unknown, asset }, requestCallback);
- }
- };
-
- request = fs->request({ mbgl::Resource::Unknown, asset }, requestCallback);
- }
-
-private:
- unsigned numRequests = 1000;
-
- mbgl::AssetFileSource* fs;
- std::unique_ptr<mbgl::AsyncRequest> request;
-
- std::function<void(mbgl::Response)> requestCallback;
-};
-
} // namespace
-TEST_F(Storage, AssetStress) {
- SCOPED_TEST(AssetStress)
-
- using namespace mbgl;
+using namespace mbgl;
+TEST(AssetFileSource, Stress) {
util::RunLoop loop;
AssetFileSource fs(getFileSourceRoot());
@@ -73,6 +39,38 @@ TEST_F(Storage, AssetStress) {
}
};
+ class TestWorker {
+ public:
+ TestWorker(mbgl::AssetFileSource* fs_) : fs(fs_) {}
+
+ void run(std::function<void()> endCallback) {
+ const std::string asset("asset://nonempty");
+
+ requestCallback = [this, asset, endCallback](mbgl::Response res) {
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("content is here\n", *res.data);
+
+ if (!--numRequests) {
+ endCallback();
+ request.reset();
+ } else {
+ request = fs->request({ mbgl::Resource::Unknown, asset }, requestCallback);
+ }
+ };
+
+ request = fs->request({ mbgl::Resource::Unknown, asset }, requestCallback);
+ }
+
+ private:
+ unsigned numRequests = 1000;
+
+ mbgl::AssetFileSource* fs;
+ std::unique_ptr<mbgl::AsyncRequest> request;
+
+ std::function<void(mbgl::Response)> requestCallback;
+ };
+
std::vector<std::unique_ptr<util::Thread<TestWorker>>> threads;
std::vector<std::unique_ptr<mbgl::AsyncRequest>> requests;
util::ThreadContext context = { "Test", util::ThreadType::Map, util::ThreadPriority::Regular };
@@ -88,15 +86,9 @@ TEST_F(Storage, AssetStress) {
}
loop.run();
-
- AssetStress.finish();
}
-TEST_F(Storage, AssetEmptyFile) {
- SCOPED_TEST(EmptyFile)
-
- using namespace mbgl;
-
+TEST(AssetFileSource, EmptyFile) {
util::RunLoop loop;
AssetFileSource fs(getFileSourceRoot());
@@ -107,17 +99,12 @@ TEST_F(Storage, AssetEmptyFile) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("", *res.data);
loop.stop();
- EmptyFile.finish();
});
loop.run();
}
-TEST_F(Storage, AssetNonEmptyFile) {
- SCOPED_TEST(NonEmptyFile)
-
- using namespace mbgl;
-
+TEST(AssetFileSource, NonEmptyFile) {
util::RunLoop loop;
AssetFileSource fs(getFileSourceRoot());
@@ -128,17 +115,12 @@ TEST_F(Storage, AssetNonEmptyFile) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("content is here\n", *res.data);
loop.stop();
- NonEmptyFile.finish();
});
loop.run();
}
-TEST_F(Storage, AssetNonExistentFile) {
- SCOPED_TEST(NonExistentFile)
-
- using namespace mbgl;
-
+TEST(AssetFileSource, NonExistentFile) {
util::RunLoop loop;
AssetFileSource fs(getFileSourceRoot());
@@ -150,17 +132,12 @@ TEST_F(Storage, AssetNonExistentFile) {
ASSERT_FALSE(res.data.get());
// Do not assert on platform-specific error message.
loop.stop();
- NonExistentFile.finish();
});
loop.run();
}
-TEST_F(Storage, AssetReadDirectory) {
- SCOPED_TEST(ReadDirectory)
-
- using namespace mbgl;
-
+TEST(AssetFileSource, ReadDirectory) {
util::RunLoop loop;
AssetFileSource fs(getFileSourceRoot());
@@ -172,17 +149,12 @@ TEST_F(Storage, AssetReadDirectory) {
ASSERT_FALSE(res.data.get());
// Do not assert on platform-specific error message.
loop.stop();
- ReadDirectory.finish();
});
loop.run();
}
-TEST_F(Storage, AssetURLEncoding) {
- SCOPED_TEST(NonEmptyFile)
-
- using namespace mbgl;
-
+TEST(AssetFileSource, URLEncoding) {
util::RunLoop loop;
AssetFileSource fs(getFileSourceRoot());
@@ -193,7 +165,6 @@ TEST_F(Storage, AssetURLEncoding) {
ASSERT_TRUE(res.data.get());
EXPECT_EQ("content is here\n", *res.data);
loop.stop();
- NonEmptyFile.finish();
});
loop.run();
diff --git a/test/storage/default_file_source.cpp b/test/storage/default_file_source.cpp
index a3453a83bc..8061470fca 100644
--- a/test/storage/default_file_source.cpp
+++ b/test/storage/default_file_source.cpp
@@ -1,15 +1,10 @@
-#include "storage.hpp"
-
+#include <mbgl/test/util.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/util/run_loop.hpp>
-class DefaultFileSourceTest : public Storage {};
-
-TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheResponse)) {
- SCOPED_TEST(CacheResponse);
-
- using namespace mbgl;
+using namespace mbgl;
+TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheResponse)) {
util::RunLoop loop;
DefaultFileSource fs(":memory:", ".");
@@ -41,18 +36,13 @@ TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheResponse)) {
EXPECT_EQ(response.etag, res2.etag);
loop.stop();
- CacheResponse.finish();
});
});
loop.run();
}
-TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheRevalidateSame)) {
- SCOPED_TEST(CacheRevalidateSame)
-
- using namespace mbgl;
-
+TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateSame)) {
util::RunLoop loop;
DefaultFileSource fs(":memory:", ".");
@@ -89,7 +79,6 @@ TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheRevalidateSame)) {
EXPECT_EQ("snowfall", *res2.etag);
loop.stop();
- CacheRevalidateSame.finish();
}
});
});
@@ -97,11 +86,7 @@ TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheRevalidateSame)) {
loop.run();
}
-TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheRevalidateModified)) {
- SCOPED_TEST(CacheRevalidateModified)
-
- using namespace mbgl;
-
+TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateModified)) {
util::RunLoop loop;
DefaultFileSource fs(":memory:", ".");
@@ -138,7 +123,6 @@ TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheRevalidateModified)) {
EXPECT_FALSE(res2.etag);
loop.stop();
- CacheRevalidateModified.finish();
}
});
});
@@ -146,11 +130,7 @@ TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheRevalidateModified)) {
loop.run();
}
-TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheRevalidateEtag)) {
- SCOPED_TEST(CacheRevalidateEtag)
-
- using namespace mbgl;
-
+TEST(DefaultFileSource, TEST_REQUIRES_SERVER(CacheRevalidateEtag)) {
util::RunLoop loop;
DefaultFileSource fs(":memory:", ".");
@@ -187,10 +167,44 @@ TEST_F(DefaultFileSourceTest, TEST_REQUIRES_SERVER(CacheRevalidateEtag)) {
EXPECT_EQ("response-2", *res2.etag);
loop.stop();
- CacheRevalidateEtag.finish();
}
});
});
loop.run();
}
+
+// Test for https://github.com/mapbox/mapbox-gl-native/issue/1369
+//
+// A request for http://example.com is made. This triggers a cache get. While the cache get is
+// pending, the request is canceled. This removes it from pending. Then, still while the cache get
+// is pending, a second request is made for the same resource. This adds an entry back to pending
+// and queues another cache request, even though the first one is still pending. Now both cache
+// requests resolve to misses, resulting in two HTTP requests for the same resource. The first one
+// 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(DefaultFileSource, TEST_REQUIRES_SERVER(HTTPIssue1369)) {
+ util::RunLoop loop;
+ DefaultFileSource fs(":memory:", ".");
+
+ const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" };
+
+ auto req = fs.request(resource, [&](Response) {
+ ADD_FAILURE() << "Callback should not be called";
+ });
+ req.reset();
+ req = fs.request(resource, [&](Response res) {
+ req.reset();
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Hello World!", *res.data);
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
diff --git a/test/storage/headers.cpp b/test/storage/headers.cpp
index 3ef4fe25e5..b879c43b12 100644
--- a/test/storage/headers.cpp
+++ b/test/storage/headers.cpp
@@ -1,9 +1,7 @@
-#include "storage.hpp"
#include <mbgl/test/util.hpp>
-
#include <mbgl/util/http_header.hpp>
-TEST_F(Storage, HTTPHeaderParsing) {
+TEST(HTTPHeader, Parsing) {
using namespace mbgl;
http::CacheControl cc;
diff --git a/test/storage/http_cancel.cpp b/test/storage/http_cancel.cpp
deleted file mode 100644
index bda274c547..0000000000
--- a/test/storage/http_cancel.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/storage/network_status.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <cmath>
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPCancel)) {
- SCOPED_TEST(HTTPCancel)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- auto req =
- fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" },
- [&](Response) { ADD_FAILURE() << "Callback should not be called"; });
-
- req.reset();
- HTTPCancel.finish();
-
- loop.runOnce();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPCancelMultiple)) {
- SCOPED_TEST(HTTPCancelMultiple)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" };
-
- std::unique_ptr<AsyncRequest> req2 = fs.request(resource, [&](Response) {
- ADD_FAILURE() << "Callback should not be called";
- });
- std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
- req.reset();
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Hello World!", *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTPCancelMultiple.finish();
- });
- req2.reset();
-
- loop.run();
-}
diff --git a/test/storage/http_error.cpp b/test/storage/http_error.cpp
deleted file mode 100644
index dfe4a55973..0000000000
--- a/test/storage/http_error.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/storage/network_status.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <cmath>
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPTemporaryError)) {
- SCOPED_TEST(HTTPTemporaryError)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- const auto start = Clock::now();
-
- std::unique_ptr<AsyncRequest> req1 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/temporary-error" }, [&](Response res) {
- static int counter = 0;
- switch (counter++) {
- case 0: {
- const auto duration = std::chrono::duration<const double>(Clock::now() - start).count();
- EXPECT_GT(0.2, duration) << "Initial error request took too long";
- ASSERT_NE(nullptr, res.error);
- EXPECT_EQ(Response::Error::Reason::Server, res.error->reason);
- EXPECT_EQ("HTTP status code 500", res.error->message);
- ASSERT_FALSE(bool(res.data));
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- } break;
- case 1: {
- req1.reset();
- const auto duration = std::chrono::duration<const double>(Clock::now() - start).count();
- EXPECT_LT(0.99, duration) << "Backoff timer didn't wait 1 second";
- EXPECT_GT(1.2, duration) << "Backoff timer fired too late";
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Hello World!", *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTPTemporaryError.finish();
- } break;
- }
- });
-
- loop.run();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPConnectionError)) {
- SCOPED_TEST(HTTPConnectionError)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- const auto start = Clock::now();
-
- std::unique_ptr<AsyncRequest> req2 = fs.request({ Resource::Unknown, "http://127.0.0.1:3001/" }, [&](Response res) {
- static int counter = 0;
- static int wait = 0;
- const auto duration = std::chrono::duration<const double>(Clock::now() - start).count();
- EXPECT_LT(wait - 0.01, duration) << "Backoff timer didn't wait 1 second";
- EXPECT_GT(wait + 0.2, duration) << "Backoff timer fired too late";
- ASSERT_NE(nullptr, res.error);
- EXPECT_EQ(Response::Error::Reason::Connection, res.error->reason);
- ASSERT_FALSE(res.data.get());
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
-
- if (counter == 2) {
- req2.reset();
- loop.stop();
- HTTPConnectionError.finish();
- }
- wait += (1 << counter);
- counter++;
- });
-
- loop.run();
-}
diff --git a/test/storage/http_expires.cpp b/test/storage/http_expires.cpp
deleted file mode 100644
index 787d3e540b..0000000000
--- a/test/storage/http_expires.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/default_file_source.hpp>
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/timer.hpp>
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPRetryDelayOnExpiredTile)) {
- SCOPED_TEST(HTTPRetryDelayOnExpiredTile)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- int counter = 0;
-
- const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test?expires=10000" };
- std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
- counter++;
- EXPECT_EQ(nullptr, res.error);
- EXPECT_GT(SystemClock::now(), res.expires);
- });
-
- util::Timer timer;
- timer.start(Milliseconds(500), Duration::zero(), [&] () {
- loop.stop();
- });
-
- loop.run();
-
- EXPECT_EQ(1, counter);
-
- HTTPRetryDelayOnExpiredTile.finish();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPRetryOnClockSkew)) {
- SCOPED_TEST(HTTPRetryOnClockSkew)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- DefaultFileSource fs(":memory:", ".");
-
- int counter = 0;
-
- const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/clockskew" };
- std::unique_ptr<AsyncRequest> req1 = fs.request(resource, [&](Response res) {
- switch (counter++) {
- case 0: {
- EXPECT_EQ(nullptr, res.error);
- EXPECT_GT(SystemClock::now(), res.expires);
- } break;
- case 1: {
- EXPECT_EQ(nullptr, res.error);
-
- auto now = SystemClock::now();
- EXPECT_LT(now + Seconds(40), res.expires) << "Expiration not interpolated to 60s";
- EXPECT_GT(now + Seconds(80), res.expires) << "Expiration not interpolated to 60s";
-
- loop.stop();
- } break;
- }
- });
-
- loop.run();
-
- HTTPRetryOnClockSkew.finish();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPRespectPriorExpires)) {
- SCOPED_TEST(HTTPRespectPriorExpires)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- DefaultFileSource fs(":memory:", ".");
-
- // Very long expiration time, should never arrive.
- Resource resource1{ Resource::Unknown, "http://127.0.0.1:3000/test" };
- resource1.priorExpires = SystemClock::now() + Seconds(100000);
-
- std::unique_ptr<AsyncRequest> req1 = fs.request(resource1, [&](Response) {
- FAIL() << "Should never be called";
- });
-
- // No expiration time, should be requested immediately.
- Resource resource2{ Resource::Unknown, "http://127.0.0.1:3000/test" };
-
- std::unique_ptr<AsyncRequest> req2 = fs.request(resource2, [&](Response) {
- HTTPRespectPriorExpires.finish();
- loop.stop();
- });
-
- // Very long expiration time, should never arrive.
- Resource resource3{ Resource::Unknown, "http://127.0.0.1:3000/test" };
- resource3.priorExpires = SystemClock::now() + Seconds(100000);
-
- std::unique_ptr<AsyncRequest> req3 = fs.request(resource3, [&](Response) {
- FAIL() << "Should never be called";
- });
-
- loop.run();
-}
diff --git a/test/storage/http_file_source.cpp b/test/storage/http_file_source.cpp
new file mode 100644
index 0000000000..53d9a248c2
--- /dev/null
+++ b/test/storage/http_file_source.cpp
@@ -0,0 +1,195 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/storage/http_file_source.hpp>
+#include <mbgl/util/exception.hpp>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/run_loop.hpp>
+
+using namespace mbgl;
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(Cancel)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" }, [&](Response) {
+ ADD_FAILURE() << "Callback should not be called";
+ });
+
+ loop.runOnce();
+}
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP200)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" }, [&](Response res) {
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Hello World!", *res.data);
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP404)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/doesnotexist" }, [&](Response res) {
+ ASSERT_NE(nullptr, res.error);
+ EXPECT_EQ(Response::Error::Reason::NotFound, res.error->reason);
+ EXPECT_EQ("HTTP status code 404", res.error->message);
+ EXPECT_FALSE(bool(res.data));
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTPTile404)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ auto req = fs.request({ Resource::Tile, "http://127.0.0.1:3000/doesnotexist" }, [&](Response res) {
+ EXPECT_TRUE(res.noContent);
+ EXPECT_FALSE(bool(res.error));
+ EXPECT_FALSE(bool(res.data));
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP200EmptyData)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/empty-data" }, [&](Response res) {
+ EXPECT_FALSE(res.noContent);
+ EXPECT_FALSE(bool(res.error));
+ EXPECT_EQ(*res.data, std::string());
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP204)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/no-content" }, [&](Response res) {
+ EXPECT_TRUE(res.noContent);
+ EXPECT_FALSE(bool(res.error));
+ EXPECT_FALSE(bool(res.data));
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(HTTP500)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/permanent-error" }, [&](Response res) {
+ ASSERT_NE(nullptr, res.error);
+ EXPECT_EQ(Response::Error::Reason::Server, res.error->reason);
+ EXPECT_EQ("HTTP status code 500", res.error->message);
+ EXPECT_FALSE(bool(res.data));
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(ExpiresParsing)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ auto req = fs.request({ Resource::Unknown,
+ "http://127.0.0.1:3000/test?modified=1420794326&expires=1420797926&etag=foo" }, [&](Response res) {
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Hello World!", *res.data);
+ EXPECT_EQ(SystemClock::from_time_t(1420797926), res.expires);
+ EXPECT_EQ(SystemClock::from_time_t(1420794326), res.modified);
+ EXPECT_EQ("foo", *res.etag);
+ loop.stop();
+ });
+
+ loop.run();
+}
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(CacheControlParsing)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test?cachecontrol=max-age=120" }, [&](Response res) {
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Hello World!", *res.data);
+ EXPECT_GT(Seconds(2), util::abs(*res.expires - SystemClock::now() - Seconds(120))) << "Expiration date isn't about 120 seconds in the future";
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
+
+TEST(HTTPFileSource, TEST_REQUIRES_SERVER(Load)) {
+ util::RunLoop loop;
+ HTTPFileSource fs;
+
+ const int concurrency = 50;
+ const int max = 10000;
+ int number = 1;
+
+ std::unique_ptr<AsyncRequest> 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);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ(std::string("Request ") + std::to_string(current), *res.data);
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+
+ if (number <= max) {
+ req(i);
+ } else if (current == max) {
+ loop.stop();
+ }
+ });
+ };
+
+ for (int i = 0; i < concurrency; i++) {
+ req(i);
+ }
+
+ loop.run();
+}
diff --git a/test/storage/http_header_parsing.cpp b/test/storage/http_header_parsing.cpp
deleted file mode 100644
index cdebe8db5d..0000000000
--- a/test/storage/http_header_parsing.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <cmath>
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPExpiresParsing)) {
- SCOPED_TEST(HTTPExpiresTest)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- std::unique_ptr<AsyncRequest> 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);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Hello World!", *res.data);
- EXPECT_EQ(SystemClock::from_time_t(1420797926), res.expires);
- EXPECT_EQ(SystemClock::from_time_t(1420794326), res.modified);
- EXPECT_EQ("foo", *res.etag);
- loop.stop();
- HTTPExpiresTest.finish();
- });
-
- loop.run();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPCacheControlParsing)) {
- SCOPED_TEST(HTTPCacheControlTest)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- std::unique_ptr<AsyncRequest> req2 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test?cachecontrol=max-age=120" },
- [&](Response res) {
- req2.reset();
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Hello World!", *res.data);
- EXPECT_GT(Seconds(2), util::abs(*res.expires - SystemClock::now() - Seconds(120))) << "Expiration date isn't about 120 seconds in the future";
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTPCacheControlTest.finish();
- });
-
- loop.run();
-}
diff --git a/test/storage/http_issue_1369.cpp b/test/storage/http_issue_1369.cpp
deleted file mode 100644
index d6890953fa..0000000000
--- a/test/storage/http_issue_1369.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/default_file_source.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-// Test for https://github.com/mapbox/mapbox-gl-native/issue/1369
-//
-// A request for http://example.com is made. This triggers a cache get. While the cache get is
-// pending, the request is canceled. This removes it from pending. Then, still while the cache get
-// is pending, a second request is made for the same resource. This adds an entry back to pending
-// and queues another cache request, even though the first one is still pending. Now both cache
-// requests resolve to misses, resulting in two HTTP requests for the same resource. The first one
-// 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, TEST_REQUIRES_SERVER(HTTPIssue1369)) {
- SCOPED_TEST(HTTPIssue1369)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- DefaultFileSource fs(":memory:", ".");
-
- const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" };
-
- auto req = fs.request(resource, [&](Response) {
- ADD_FAILURE() << "Callback should not be called";
- });
- req.reset();
- req = fs.request(resource, [&](Response res) {
- req.reset();
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Hello World!", *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTPIssue1369.finish();
- });
-
- loop.run();
-}
diff --git a/test/storage/http_load.cpp b/test/storage/http_load.cpp
deleted file mode 100644
index 4feb790cbc..0000000000
--- a/test/storage/http_load.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPLoad)) {
- SCOPED_TEST(HTTPLoad)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- const int concurrency = 50;
- const int max = 10000;
- int number = 1;
-
- std::unique_ptr<AsyncRequest> 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);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ(std::string("Request ") + std::to_string(current), *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
-
- if (number <= max) {
- req(i);
- } else if (current == max) {
- loop.stop();
- HTTPLoad.finish();
- }
- });
- };
-
-
- for (int i = 0; i < concurrency; i++) {
- req(i);
- }
-
- loop.run();
-}
diff --git a/test/storage/http_other_loop.cpp b/test/storage/http_other_loop.cpp
deleted file mode 100644
index 20e7e2356a..0000000000
--- a/test/storage/http_other_loop.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPOtherLoop)) {
- SCOPED_TEST(HTTPOtherLoop)
-
- using namespace mbgl;
-
- // This file source launches a separate thread to do the processing.
- util::RunLoop loop;
- OnlineFileSource fs;
-
- std::unique_ptr<AsyncRequest> req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" },
- [&](Response res) {
- req.reset();
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Hello World!", *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTPOtherLoop.finish();
- });
-
- loop.run();
-}
diff --git a/test/storage/http_reading.cpp b/test/storage/http_reading.cpp
deleted file mode 100644
index 9682ec93cf..0000000000
--- a/test/storage/http_reading.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/thread_context.hpp>
-
-#include <future>
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPTest)) {
- SCOPED_TEST(HTTPTest)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- std::unique_ptr<AsyncRequest> req1 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" },
- [&](Response res) {
- req1.reset();
- EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Hello World!", *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTPTest.finish();
- });
-
- loop.run();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTP404)) {
- SCOPED_TEST(HTTP404)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- std::unique_ptr<AsyncRequest> req2 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/doesnotexist" },
- [&](Response res) {
- req2.reset();
- EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
- ASSERT_NE(nullptr, res.error);
- EXPECT_EQ(Response::Error::Reason::NotFound, res.error->reason);
- EXPECT_EQ("HTTP status code 404", res.error->message);
- EXPECT_FALSE(bool(res.data));
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTP404.finish();
- });
-
- loop.run();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPTile404)) {
- SCOPED_TEST(HTTPTile404)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- std::unique_ptr<AsyncRequest> req2 = fs.request({ Resource::Tile, "http://127.0.0.1:3000/doesnotexist" },
- [&](Response res) {
- req2.reset();
- EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
- EXPECT_TRUE(res.noContent);
- EXPECT_FALSE(bool(res.error));
- EXPECT_FALSE(bool(res.data));
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTPTile404.finish();
- });
-
- loop.run();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTP200EmptyData)) {
- SCOPED_TEST(HTTP200EmptyData)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- std::unique_ptr<AsyncRequest> req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/empty-data" },
- [&](Response res) {
- req.reset();
- EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
- EXPECT_FALSE(res.noContent);
- EXPECT_FALSE(bool(res.error));
- EXPECT_EQ(*res.data, std::string());
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTP200EmptyData.finish();
- });
-
- loop.run();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTP204)) {
- SCOPED_TEST(HTTP204)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- std::unique_ptr<AsyncRequest> req2 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/no-content" },
- [&](Response res) {
- req2.reset();
- EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
- EXPECT_TRUE(res.noContent);
- EXPECT_FALSE(bool(res.error));
- EXPECT_FALSE(bool(res.data));
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTP204.finish();
- });
-
- loop.run();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTP500)) {
- SCOPED_TEST(HTTP500)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- std::unique_ptr<AsyncRequest> req3 = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/permanent-error" },
- [&](Response res) {
- req3.reset();
- EXPECT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Main));
- ASSERT_NE(nullptr, res.error);
- EXPECT_EQ(Response::Error::Reason::Server, res.error->reason);
- EXPECT_EQ("HTTP status code 500", res.error->message);
- EXPECT_FALSE(bool(res.data));
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTP500.finish();
- });
-
- loop.run();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPNoCallback)) {
- SCOPED_TEST(HTTPNoCallback)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- try {
- fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" },
- nullptr);
- } catch (const util::MisuseException& ex) {
- EXPECT_EQ(std::string(ex.what()), "FileSource callback can't be empty");
- } catch (const std::exception&) {
- EXPECT_TRUE(false) << "Unhandled exception.";
- }
-
- HTTPNoCallback.finish();
-}
diff --git a/test/storage/http_retry_network_status.cpp b/test/storage/http_retry_network_status.cpp
deleted file mode 100644
index 94a2bcdc4d..0000000000
--- a/test/storage/http_retry_network_status.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/storage/network_status.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/timer.hpp>
-
-// Test for https://github.com/mapbox/mapbox-gl-native/issues/2123
-//
-// A request is made. While the request is in progress, the network status changes. This should
-// trigger an immediate retry of all requests that are not in progress. This test makes sure that
-// we don't accidentally double-trigger the request.
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPNetworkStatusChange)) {
- SCOPED_TEST(HTTPNetworkStatusChange)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/delayed" };
-
- // This request takes 200 milliseconds to answer.
- std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
- req.reset();
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Response", *res.data);
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- loop.stop();
- HTTPNetworkStatusChange.finish();
- });
-
- // After 50 milliseconds, we're going to trigger a NetworkStatus change.
- util::Timer reachableTimer;
- reachableTimer.start(Milliseconds(50), Duration::zero(), [] () {
- mbgl::NetworkStatus::Reachable();
- });
-
- loop.run();
-}
-
-// Tests that a change in network status preempts requests that failed due to connection or
-// reachability issues.
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPNetworkStatusChangePreempt)) {
- SCOPED_TEST(HTTPNetworkStatusChangePreempt)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- const auto start = Clock::now();
-
- const Resource resource{ Resource::Unknown, "http://127.0.0.1:3001/test" };
- std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
- static int counter = 0;
- const auto duration = std::chrono::duration<const double>(Clock::now() - start).count();
- if (counter == 0) {
- EXPECT_GT(0.2, duration) << "Response came in too late";
- } else if (counter == 1) {
- EXPECT_LT(0.39, duration) << "Preempted retry triggered too early";
- EXPECT_GT(0.6, duration) << "Preempted retry triggered too late";
- } else if (counter > 1) {
- FAIL() << "Retried too often";
- }
- ASSERT_NE(nullptr, res.error);
- EXPECT_EQ(Response::Error::Reason::Connection, res.error->reason);
- ASSERT_FALSE(res.data.get());
- EXPECT_FALSE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
-
- if (counter++ == 1) {
- req.reset();
- loop.stop();
- HTTPNetworkStatusChangePreempt.finish();
- }
- });
-
- // After 400 milliseconds, we're going to trigger a NetworkStatus change.
- util::Timer reachableTimer;
- reachableTimer.start(Milliseconds(400), Duration::zero(), [] () {
- mbgl::NetworkStatus::Reachable();
- });
-
- loop.run();
-}
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPNetworkStatusOnlineOffline)) {
- SCOPED_TEST(HTTPNetworkStatusOnlineOffline)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" };
-
- EXPECT_EQ(NetworkStatus::Get(), NetworkStatus::Status::Online) << "Default status should be Online";
- NetworkStatus::Set(NetworkStatus::Status::Offline);
-
- util::Timer onlineTimer;
- onlineTimer.start(Milliseconds(100), Duration::zero(), [&] () {
- NetworkStatus::Set(NetworkStatus::Status::Online);
- });
-
- std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
- req.reset();
-
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
-
- EXPECT_EQ(NetworkStatus::Get(), NetworkStatus::Status::Online) << "Triggered before set back to Online";
-
- loop.stop();
- HTTPNetworkStatusOnlineOffline.finish();
- });
-
- loop.run();
-}
diff --git a/test/storage/http_timeout.cpp b/test/storage/http_timeout.cpp
deleted file mode 100644
index 42c7f39f56..0000000000
--- a/test/storage/http_timeout.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "storage.hpp"
-
-#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/storage/network_status.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-TEST_F(Storage, TEST_REQUIRES_SERVER(HTTPTimeout)) {
- SCOPED_TEST(HTTPTimeout)
-
- using namespace mbgl;
-
- util::RunLoop loop;
- OnlineFileSource fs;
-
- int counter = 0;
-
- const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test?cachecontrol=max-age=1" };
- std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
- counter++;
- EXPECT_EQ(nullptr, res.error);
- ASSERT_TRUE(res.data.get());
- EXPECT_EQ("Hello World!", *res.data);
- EXPECT_TRUE(bool(res.expires));
- EXPECT_FALSE(bool(res.modified));
- EXPECT_FALSE(bool(res.etag));
- if (counter == 4) {
- req.reset();
- loop.stop();
- HTTPTimeout.finish();
- }
- });
-
- loop.run();
-
- EXPECT_EQ(4, counter);
-}
diff --git a/test/storage/online_file_source.cpp b/test/storage/online_file_source.cpp
new file mode 100644
index 0000000000..dced95c196
--- /dev/null
+++ b/test/storage/online_file_source.cpp
@@ -0,0 +1,361 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/storage/online_file_source.hpp>
+#include <mbgl/storage/network_status.hpp>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/timer.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace mbgl;
+
+TEST(OnlineFileSource, Cancel) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ fs.request({ Resource::Unknown, "http://127.0.0.1:3000/test" }, [&](Response) {
+ ADD_FAILURE() << "Callback should not be called";
+ });
+
+ loop.runOnce();
+}
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(CancelMultiple)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" };
+
+ std::unique_ptr<AsyncRequest> req2 = fs.request(resource, [&](Response) {
+ ADD_FAILURE() << "Callback should not be called";
+ });
+ std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
+ req.reset();
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Hello World!", *res.data);
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+ req2.reset();
+
+ loop.run();
+}
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(TemporaryError)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ const auto start = Clock::now();
+
+ auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/temporary-error" }, [&](Response res) {
+ static int counter = 0;
+ switch (counter++) {
+ case 0: {
+ const auto duration = std::chrono::duration<const double>(Clock::now() - start).count();
+ EXPECT_GT(0.2, duration) << "Initial error request took too long";
+ ASSERT_NE(nullptr, res.error);
+ EXPECT_EQ(Response::Error::Reason::Server, res.error->reason);
+ EXPECT_EQ("HTTP status code 500", res.error->message);
+ ASSERT_FALSE(bool(res.data));
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ } break;
+ case 1: {
+ const auto duration = std::chrono::duration<const double>(Clock::now() - start).count();
+ EXPECT_LT(0.99, duration) << "Backoff timer didn't wait 1 second";
+ EXPECT_GT(1.2, duration) << "Backoff timer fired too late";
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Hello World!", *res.data);
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ } break;
+ }
+ });
+
+ loop.run();
+}
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(ConnectionError)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ const auto start = Clock::now();
+
+ std::unique_ptr<AsyncRequest> req = fs.request({ Resource::Unknown, "http://127.0.0.1:3001/" }, [&](Response res) {
+ static int counter = 0;
+ static int wait = 0;
+ const auto duration = std::chrono::duration<const double>(Clock::now() - start).count();
+ EXPECT_LT(wait - 0.01, duration) << "Backoff timer didn't wait 1 second";
+ EXPECT_GT(wait + 0.2, duration) << "Backoff timer fired too late";
+ ASSERT_NE(nullptr, res.error);
+ EXPECT_EQ(Response::Error::Reason::Connection, res.error->reason);
+ ASSERT_FALSE(res.data.get());
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+
+ if (counter == 2) {
+ req.reset();
+ loop.stop();
+ }
+ wait += (1 << counter);
+ counter++;
+ });
+
+ loop.run();
+}
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(Timeout)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ int counter = 0;
+
+ const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test?cachecontrol=max-age=1" };
+ std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
+ counter++;
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Hello World!", *res.data);
+ EXPECT_TRUE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ if (counter == 4) {
+ req.reset();
+ loop.stop();
+ }
+ });
+
+ loop.run();
+
+ EXPECT_EQ(4, counter);
+}
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RetryDelayOnExpiredTile)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ int counter = 0;
+
+ const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test?expires=10000" };
+ std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
+ counter++;
+ EXPECT_EQ(nullptr, res.error);
+ EXPECT_GT(SystemClock::now(), res.expires);
+ });
+
+ util::Timer timer;
+ timer.start(Milliseconds(500), Duration::zero(), [&] () {
+ loop.stop();
+ });
+
+ loop.run();
+
+ EXPECT_EQ(1, counter);
+}
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RetryOnClockSkew)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ int counter = 0;
+
+ const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/clockskew" };
+ std::unique_ptr<AsyncRequest> req1 = fs.request(resource, [&](Response res) {
+ switch (counter++) {
+ case 0: {
+ EXPECT_EQ(nullptr, res.error);
+ EXPECT_GT(SystemClock::now(), res.expires);
+ } break;
+ case 1: {
+ EXPECT_EQ(nullptr, res.error);
+
+ auto now = SystemClock::now();
+ EXPECT_LT(now + Seconds(40), res.expires) << "Expiration not interpolated to 60s";
+ EXPECT_GT(now + Seconds(80), res.expires) << "Expiration not interpolated to 60s";
+
+ loop.stop();
+ } break;
+ }
+ });
+
+ loop.run();
+}
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RespectPriorExpires)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ // Very long expiration time, should never arrive.
+ Resource resource1{ Resource::Unknown, "http://127.0.0.1:3000/test" };
+ resource1.priorExpires = SystemClock::now() + Seconds(100000);
+
+ std::unique_ptr<AsyncRequest> req1 = fs.request(resource1, [&](Response) {
+ FAIL() << "Should never be called";
+ });
+
+ // No expiration time, should be requested immediately.
+ Resource resource2{ Resource::Unknown, "http://127.0.0.1:3000/test" };
+
+ std::unique_ptr<AsyncRequest> req2 = fs.request(resource2, [&](Response) {
+ loop.stop();
+ });
+
+ // Very long expiration time, should never arrive.
+ Resource resource3{ Resource::Unknown, "http://127.0.0.1:3000/test" };
+ resource3.priorExpires = SystemClock::now() + Seconds(100000);
+
+ std::unique_ptr<AsyncRequest> req3 = fs.request(resource3, [&](Response) {
+ FAIL() << "Should never be called";
+ });
+
+ loop.run();
+}
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(Load)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ const int concurrency = 50;
+ const int max = 10000;
+ int number = 1;
+
+ std::unique_ptr<AsyncRequest> 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);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ(std::string("Request ") + std::to_string(current), *res.data);
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+
+ if (number <= max) {
+ req(i);
+ } else if (current == max) {
+ loop.stop();
+ }
+ });
+ };
+
+ for (int i = 0; i < concurrency; i++) {
+ req(i);
+ }
+
+ loop.run();
+}
+
+// Test for https://github.com/mapbox/mapbox-gl-native/issues/2123
+//
+// A request is made. While the request is in progress, the network status changes. This should
+// trigger an immediate retry of all requests that are not in progress. This test makes sure that
+// we don't accidentally double-trigger the request.
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(NetworkStatusChange)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/delayed" };
+
+ // This request takes 200 milliseconds to answer.
+ std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
+ req.reset();
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Response", *res.data);
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ // After 50 milliseconds, we're going to trigger a NetworkStatus change.
+ util::Timer reachableTimer;
+ reachableTimer.start(Milliseconds(50), Duration::zero(), [] () {
+ mbgl::NetworkStatus::Reachable();
+ });
+
+ loop.run();
+}
+
+// Tests that a change in network status preempts requests that failed due to connection or
+// reachability issues.
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(NetworkStatusChangePreempt)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ const auto start = Clock::now();
+
+ const Resource resource{ Resource::Unknown, "http://127.0.0.1:3001/test" };
+ std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
+ static int counter = 0;
+ const auto duration = std::chrono::duration<const double>(Clock::now() - start).count();
+ if (counter == 0) {
+ EXPECT_GT(0.2, duration) << "Response came in too late";
+ } else if (counter == 1) {
+ EXPECT_LT(0.39, duration) << "Preempted retry triggered too early";
+ EXPECT_GT(0.6, duration) << "Preempted retry triggered too late";
+ } else if (counter > 1) {
+ FAIL() << "Retried too often";
+ }
+ ASSERT_NE(nullptr, res.error);
+ EXPECT_EQ(Response::Error::Reason::Connection, res.error->reason);
+ ASSERT_FALSE(res.data.get());
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+
+ if (counter++ == 1) {
+ req.reset();
+ loop.stop();
+ }
+ });
+
+ // After 400 milliseconds, we're going to trigger a NetworkStatus change.
+ util::Timer reachableTimer;
+ reachableTimer.start(Milliseconds(400), Duration::zero(), [] () {
+ mbgl::NetworkStatus::Reachable();
+ });
+
+ loop.run();
+}
+
+TEST(OnlineFileSource, TEST_REQUIRES_SERVER(NetworkStatusOnlineOffline)) {
+ util::RunLoop loop;
+ OnlineFileSource fs;
+
+ const Resource resource { Resource::Unknown, "http://127.0.0.1:3000/test" };
+
+ EXPECT_EQ(NetworkStatus::Get(), NetworkStatus::Status::Online) << "Default status should be Online";
+ NetworkStatus::Set(NetworkStatus::Status::Offline);
+
+ util::Timer onlineTimer;
+ onlineTimer.start(Milliseconds(100), Duration::zero(), [&] () {
+ NetworkStatus::Set(NetworkStatus::Status::Online);
+ });
+
+ std::unique_ptr<AsyncRequest> req = fs.request(resource, [&](Response res) {
+ req.reset();
+
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+
+ EXPECT_EQ(NetworkStatus::Get(), NetworkStatus::Status::Online) << "Triggered before set back to Online";
+
+ loop.stop();
+ });
+
+ loop.run();
+}
diff --git a/test/storage/storage.cpp b/test/storage/storage.cpp
deleted file mode 100644
index d9a414beb7..0000000000
--- a/test/storage/storage.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "storage.hpp"
-
-std::unique_ptr<mbgl::test::Server> Storage::server;
-
-void Storage::SetUpTestCase() {
-#if TEST_HAS_SERVER
- server = std::make_unique<mbgl::test::Server>("test/storage/server.js");
-#endif
-}
-
-void Storage::TearDownTestCase() {
- server.reset();
-}
diff --git a/test/storage/storage.hpp b/test/storage/storage.hpp
deleted file mode 100644
index e7cd960546..0000000000
--- a/test/storage/storage.hpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef MBGL_TEST_STORAGE_STORAGE
-#define MBGL_TEST_STORAGE_STORAGE
-
-#include <mbgl/test/util.hpp>
-#include <mbgl/storage/response.hpp>
-#include <memory>
-
-class Storage : public testing::Test {
-public:
- static void SetUpTestCase();
- static void TearDownTestCase();
-
-protected:
- static std::unique_ptr<mbgl::test::Server> server;
-};
-
-#endif
diff --git a/test/test.gypi b/test/test.gypi
index 6b3b43bd0c..b8b61ebf9c 100644
--- a/test/test.gypi
+++ b/test/test.gypi
@@ -45,24 +45,14 @@
'map/tile.cpp',
'map/transform.cpp',
- 'storage/storage.hpp',
- 'storage/storage.cpp',
- 'storage/default_file_source.cpp',
'storage/offline.cpp',
'storage/offline_database.cpp',
'storage/offline_download.cpp',
'storage/asset_file_source.cpp',
+ 'storage/default_file_source.cpp',
+ 'storage/http_file_source.cpp',
+ 'storage/online_file_source.cpp',
'storage/headers.cpp',
- 'storage/http_cancel.cpp',
- 'storage/http_error.cpp',
- 'storage/http_expires.cpp',
- 'storage/http_header_parsing.cpp',
- 'storage/http_issue_1369.cpp',
- 'storage/http_load.cpp',
- 'storage/http_other_loop.cpp',
- 'storage/http_retry_network_status.cpp',
- 'storage/http_reading.cpp',
- 'storage/http_timeout.cpp',
'storage/resource.cpp',
'style/glyph_store.cpp',