blob: 06f70ff67cec590f96e3c0e638926984e962cf42 [file] [log] [blame]
// Copyright 2017 The Chromium 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 "components/offline_pages/core/prefetch/tasks/generate_page_bundle_task.h"
#include <utility>
#include "base/logging.h"
#include "base/test/mock_callback.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
#include "components/offline_pages/core/offline_clock.h"
#include "components/offline_pages/core/prefetch/prefetch_item.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
#include "components/offline_pages/core/prefetch/tasks/prefetch_task_test_base.h"
#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/test_prefetch_gcm_handler.h"
#include "components/offline_pages/task/task.h"
#include "services/network/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::Contains;
using testing::HasSubstr;
using testing::Not;
namespace offline_pages {
// All tests cases here only validate the request data and check for general
// http response. The tests for the Operation proto data returned in the http
// response are covered in PrefetchRequestOperationResponseTest.
class GeneratePageBundleTaskTest : public PrefetchTaskTestBase {
public:
GeneratePageBundleTaskTest() = default;
~GeneratePageBundleTaskTest() override = default;
TestPrefetchGCMHandler* gcm_handler() { return &gcm_handler_; }
TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
private:
TestPrefetchGCMHandler gcm_handler_;
TestPrefetchDispatcher dispatcher_;
};
TEST_F(GeneratePageBundleTaskTest, StoreFailure) {
store_util()->SimulateInitializationError();
base::MockCallback<PrefetchRequestFinishedCallback> callback;
RunTask(std::make_unique<GeneratePageBundleTask>(
dispatcher(), store(), gcm_handler(), prefetch_request_factory(),
callback.Get()));
EXPECT_EQ(0, dispatcher()->generate_page_bundle_requested);
}
TEST_F(GeneratePageBundleTaskTest, EmptyTask) {
base::MockCallback<PrefetchRequestFinishedCallback> callback;
RunTask(std::make_unique<GeneratePageBundleTask>(
dispatcher(), store(), gcm_handler(), prefetch_request_factory(),
callback.Get()));
EXPECT_FALSE(prefetch_request_factory()->HasOutstandingRequests());
auto requested_urls = prefetch_request_factory()->GetAllUrlsRequested();
EXPECT_TRUE(requested_urls->empty());
EXPECT_EQ(0, dispatcher()->generate_page_bundle_requested);
}
TEST_F(GeneratePageBundleTaskTest, TaskMakesNetworkRequest) {
base::MockCallback<PrefetchRequestFinishedCallback> request_callback;
base::SimpleTestClock clock;
// This item will be sent with the bundle request.
PrefetchItem item1 =
item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST);
item1.freshness_time = clock.Now();
item1.creation_time = item1.freshness_time;
EXPECT_TRUE(store_util()->InsertPrefetchItem(item1));
clock.Advance(base::TimeDelta::FromSeconds(1));
// This item will also be sent with the bundle request but being the freshest
// it will come first in the list.
PrefetchItem item2 =
item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST);
item1.freshness_time = clock.Now();
item1.creation_time = item1.freshness_time;
item2.generate_bundle_attempts = 1;
EXPECT_TRUE(store_util()->InsertPrefetchItem(item2));
EXPECT_NE(item1.offline_id, item2.offline_id);
// This item should be unaffected by the task.
PrefetchItem item3 =
item_generator()->CreateItem(PrefetchItemState::FINISHED);
EXPECT_TRUE(store_util()->InsertPrefetchItem(item3));
EXPECT_NE(item3.offline_id, item1.offline_id);
EXPECT_NE(item3.offline_id, item2.offline_id);
EXPECT_EQ(3, store_util()->CountPrefetchItems());
clock.Advance(base::TimeDelta::FromHours(1));
GeneratePageBundleTask task(dispatcher(), store(), gcm_handler(),
prefetch_request_factory(),
request_callback.Get());
SetOfflineClockForTesting(&clock);
RunTask(&task);
// Note: even though the requested URLs checked further below are in undefined
// order (due to use of std::set) their order of requesting is known: latest
// creation dates should come first. But as these ids are stored in a
// std::vector we can rely on the order being correct.
EXPECT_EQ(1, dispatcher()->generate_page_bundle_requested);
EXPECT_EQ(2u, dispatcher()->ids_from_generate_page_bundle_requested->size());
EXPECT_EQ(std::make_pair(item1.offline_id, item1.client_id),
dispatcher()->ids_from_generate_page_bundle_requested->at(1));
EXPECT_EQ(std::make_pair(item2.offline_id, item2.client_id),
dispatcher()->ids_from_generate_page_bundle_requested->at(0));
std::unique_ptr<std::set<std::string>> requested_urls =
prefetch_request_factory()->GetAllUrlsRequested();
EXPECT_EQ(2u, requested_urls->size());
EXPECT_THAT(*requested_urls, Contains(item1.url.spec()));
EXPECT_THAT(*requested_urls, Contains(item2.url.spec()));
EXPECT_THAT(*requested_urls, Not(Contains(item3.url.spec())));
std::string upload_data =
network::GetUploadData(GetPendingRequest(0 /*index*/)->request);
EXPECT_THAT(upload_data, HasSubstr(MockPrefetchItemGenerator::kUrlPrefix));
EXPECT_EQ(3, store_util()->CountPrefetchItems());
std::unique_ptr<PrefetchItem> updated_item1 =
store_util()->GetPrefetchItem(item1.offline_id);
std::unique_ptr<PrefetchItem> updated_item2 =
store_util()->GetPrefetchItem(item2.offline_id);
ASSERT_TRUE(updated_item1);
ASSERT_TRUE(updated_item2);
EXPECT_EQ(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE, updated_item1->state);
EXPECT_EQ(1, updated_item1->generate_bundle_attempts);
// Item #1 should have had it's freshness date updated during the task
// execution.
EXPECT_EQ(clock.Now(), updated_item1->freshness_time);
EXPECT_EQ(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE, updated_item2->state);
EXPECT_EQ(2, updated_item2->generate_bundle_attempts);
// As item #2 has already an attempt to GPB it should not have its
// freshness_time updated.
EXPECT_EQ(item2.freshness_time, updated_item2->freshness_time);
}
} // namespace offline_pages