OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/offline_pages/core/prefetch/generate_page_bundle_request.h" | |
6 | |
7 #include "base/test/mock_callback.h" | |
8 #include "components/offline_pages/core/prefetch/prefetch_request_test_base.h" | |
9 #include "components/offline_pages/core/prefetch/prefetch_types.h" | |
10 #include "components/offline_pages/core/prefetch/proto/offline_pages.pb.h" | |
11 #include "components/offline_pages/core/prefetch/proto/operation.pb.h" | |
12 #include "net/http/http_status_code.h" | |
13 #include "net/url_request/url_request_status.h" | |
14 #include "testing/gmock/include/gmock/gmock.h" | |
15 #include "url/gurl.h" | |
16 | |
17 using testing::_; | |
18 using testing::DoAll; | |
19 using testing::Eq; | |
20 using testing::SaveArg; | |
21 | |
22 namespace offline_pages { | |
23 | |
24 namespace { | |
25 const char kPageBundleTypeURL[] = "type.googleapis.com/test.PageBundle"; | |
26 const char kTestURL[] = "http://example.com"; | |
27 const char kTestURL2[] = "http://example.com/2"; | |
28 const char kTestURL3[] = "http://example.com/3"; | |
29 const char kTestURL4[] = "http://example.com/4"; | |
30 const char kTestUserAgent[] = "Test User Agent"; | |
31 const char kTestGCMID[] = "Test GCM ID"; | |
32 const int kTestMaxBundleSize = 100000; | |
33 const char kTestBodyName[] = "body_name"; | |
34 const int64_t kTestBodyLength = 12345678LL; | |
35 } // namespace | |
36 | |
37 class OperationBuilder { | |
38 public: | |
39 virtual ~OperationBuilder() {} | |
40 | |
41 // Builds the opereation with an Any value and returns it in binary serialized | |
42 // format. | |
43 virtual std::string BuildFromAny(const std::string& any_type_url, | |
44 const std::string& any_value) = 0; | |
45 | |
46 // Builds the opereation with with an Any value filled with page bundle data | |
47 // and returns it in binary serialized format. | |
48 std::string BuildFromPageBundle(const proto::PageBundle& bundle) { | |
49 std::string bundle_data; | |
50 EXPECT_TRUE(bundle.SerializeToString(&bundle_data)); | |
51 return BuildFromAny(kPageBundleTypeURL, bundle_data); | |
52 } | |
53 }; | |
54 | |
55 class DoneOperationBuilder : public OperationBuilder { | |
dewittj
2017/05/11 21:51:48
Are there any textproto decoders in Chrome? It mig
jianli
2017/05/11 23:07:27
I don't find one.
| |
56 public: | |
57 ~DoneOperationBuilder() override {} | |
58 | |
59 std::string BuildFromAny(const std::string& any_type_url, | |
60 const std::string& any_value) override { | |
61 proto::Operation operation; | |
62 operation.set_done(true); | |
dewittj
2017/05/11 21:51:48
These two builders only differ in one line. Can t
jianli
2017/05/11 23:07:28
Done.
| |
63 proto::Any* response = operation.mutable_response(); | |
64 response->set_type_url(any_type_url); | |
65 response->set_value(any_value); | |
66 std::string data; | |
67 EXPECT_TRUE(operation.SerializeToString(&data)); | |
68 return data; | |
69 } | |
70 }; | |
71 | |
72 class PendingOperationBuilder : public OperationBuilder { | |
73 public: | |
74 ~PendingOperationBuilder() override {} | |
75 | |
76 std::string BuildFromAny(const std::string& any_type_url, | |
77 const std::string& any_value) override { | |
78 proto::Operation operation; | |
79 operation.set_done(false); | |
80 proto::Any* response = operation.mutable_metadata(); | |
81 response->set_type_url(any_type_url); | |
82 response->set_value(any_value); | |
83 std::string data; | |
84 EXPECT_TRUE(operation.SerializeToString(&data)); | |
85 return data; | |
86 } | |
87 }; | |
88 | |
89 class GeneratePageBundleRequestTest : public PrefetchRequestTestBase { | |
90 public: | |
91 // Sends GeneratePageBundleRequest for single page with |page_url| and | |
92 // gets back the data in |http_response|. | |
93 PrefetchRequestStatus GeneratePage(const std::string& page_url, | |
94 const std::string& http_response); | |
95 | |
96 // Sends GeneratePageBundleRequest for multiple pages and gets back the data | |
97 // in |http_response|. | |
98 PrefetchRequestStatus GenerateMultiplePages( | |
99 const std::vector<std::string>& page_urls, | |
100 const std::string& http_response); | |
101 | |
102 const std::vector<RenderPageInfo>& pages() const { return pages_; } | |
103 | |
104 private: | |
105 std::vector<RenderPageInfo> pages_; | |
106 }; | |
107 | |
108 PrefetchRequestStatus GeneratePageBundleRequestTest::GeneratePage( | |
109 const std::string& page_url, | |
110 const std::string& http_response) { | |
111 std::vector<std::string> page_urls; | |
112 page_urls.push_back(page_url); | |
113 return GenerateMultiplePages(page_urls, http_response); | |
114 } | |
115 | |
116 PrefetchRequestStatus GeneratePageBundleRequestTest::GenerateMultiplePages( | |
117 const std::vector<std::string>& page_urls, | |
118 const std::string& http_response) { | |
119 base::MockCallback<GeneratePageBundleRequest::FinishedCallback> callback; | |
120 std::unique_ptr<GeneratePageBundleRequest> fetcher( | |
121 new GeneratePageBundleRequest(kTestUserAgent, kTestGCMID, | |
122 kTestMaxBundleSize, page_urls, | |
123 request_context(), callback.Get())); | |
124 | |
125 PrefetchRequestStatus status; | |
126 pages_.clear(); | |
127 EXPECT_CALL(callback, Run(_, _)) | |
128 .WillOnce(DoAll(SaveArg<0>(&status), SaveArg<1>(&pages_))); | |
129 RespondWithData(http_response); | |
130 | |
131 return status; | |
132 } | |
133 | |
134 TEST_F(GeneratePageBundleRequestTest, FailedToParse) { | |
135 EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
136 GeneratePage(kTestURL, "Some data")); | |
137 EXPECT_TRUE(pages().empty()); | |
138 } | |
139 | |
140 TEST_F(GeneratePageBundleRequestTest, NoResultInDoneOperation) { | |
141 proto::Operation operation; | |
142 operation.set_done(true); | |
143 std::string data; | |
144 EXPECT_TRUE(operation.SerializeToString(&data)); | |
145 EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
146 GeneratePage(kTestURL, data)); | |
147 EXPECT_TRUE(pages().empty()); | |
148 } | |
149 | |
150 TEST_F(GeneratePageBundleRequestTest, ErrorCodeInDoneOperation) { | |
151 proto::Operation operation; | |
152 operation.set_done(true); | |
153 operation.mutable_error()->set_code(1); | |
154 std::string data; | |
155 EXPECT_TRUE(operation.SerializeToString(&data)); | |
156 EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
157 GeneratePage(kTestURL, data)); | |
158 EXPECT_TRUE(pages().empty()); | |
159 } | |
160 | |
161 template <typename T> | |
162 class GeneratePageBundleRequestOperationTest | |
163 : public GeneratePageBundleRequestTest { | |
164 public: | |
165 std::string BuildFromAny(const std::string& any_type_url, | |
166 const std::string& any_value) { | |
167 return builder_.BuildFromAny(any_type_url, any_value); | |
168 } | |
169 | |
170 std::string BuildFromPageBundle(const proto::PageBundle& bundle) { | |
171 return builder_.BuildFromPageBundle(bundle); | |
172 } | |
173 | |
174 private: | |
175 T builder_; | |
176 }; | |
177 | |
178 typedef testing::Types<DoneOperationBuilder, PendingOperationBuilder> MyTypes; | |
179 TYPED_TEST_CASE(GeneratePageBundleRequestOperationTest, MyTypes); | |
180 | |
181 TYPED_TEST(GeneratePageBundleRequestOperationTest, InvalidTypeUrl) { | |
182 EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
183 this->GeneratePage(kTestURL, this->BuildFromAny("foo", ""))); | |
184 EXPECT_TRUE(this->pages().empty()); | |
185 } | |
186 | |
187 TYPED_TEST(GeneratePageBundleRequestOperationTest, InvalidValue) { | |
188 EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
189 this->GeneratePage(kTestURL, | |
190 this->BuildFromAny(kPageBundleTypeURL, "foo"))); | |
191 EXPECT_TRUE(this->pages().empty()); | |
192 } | |
193 | |
194 TYPED_TEST(GeneratePageBundleRequestOperationTest, EmptyPageBundle) { | |
195 proto::PageBundle bundle; | |
196 EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
197 this->GeneratePage(kTestURL, this->BuildFromPageBundle(bundle))); | |
198 EXPECT_TRUE(this->pages().empty()); | |
199 } | |
200 | |
201 TYPED_TEST(GeneratePageBundleRequestOperationTest, EmptyArchive) { | |
202 proto::PageBundle bundle; | |
203 bundle.add_archives(); | |
204 EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
205 this->GeneratePage(kTestURL, this->BuildFromPageBundle(bundle))); | |
206 EXPECT_TRUE(this->pages().empty()); | |
207 } | |
208 | |
209 TYPED_TEST(GeneratePageBundleRequestOperationTest, NoPageInfo) { | |
210 proto::PageBundle bundle; | |
211 proto::Archive* archive = bundle.add_archives(); | |
212 archive->set_body_name(kTestBodyName); | |
213 archive->set_body_length(kTestBodyLength); | |
214 EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
215 this->GeneratePage(kTestURL, this->BuildFromPageBundle(bundle))); | |
216 EXPECT_TRUE(this->pages().empty()); | |
217 } | |
218 | |
219 TYPED_TEST(GeneratePageBundleRequestOperationTest, MissingPageInfoUrl) { | |
220 proto::PageBundle bundle; | |
221 proto::Archive* archive = bundle.add_archives(); | |
222 proto::PageInfo* page_info = archive->add_page_infos(); | |
223 page_info->set_redirect_url(kTestURL); | |
224 EXPECT_EQ(PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF, | |
225 this->GeneratePage(kTestURL, this->BuildFromPageBundle(bundle))); | |
226 EXPECT_TRUE(this->pages().empty()); | |
227 } | |
228 | |
229 TYPED_TEST(GeneratePageBundleRequestOperationTest, SinglePage) { | |
230 proto::PageBundle bundle; | |
231 proto::Archive* archive = bundle.add_archives(); | |
232 archive->set_body_name(kTestBodyName); | |
233 archive->set_body_length(kTestBodyLength); | |
234 proto::PageInfo* page_info = archive->add_page_infos(); | |
235 page_info->set_url(kTestURL); | |
236 page_info->set_redirect_url(kTestURL2); | |
237 page_info->mutable_status()->set_code(proto::OK); | |
238 page_info->set_transformation(proto::NO_TRANSFORMATION); | |
239 int64_t ms_since_epoch = base::Time::Now().ToJavaTime(); | |
240 page_info->mutable_render_time()->set_seconds(ms_since_epoch / 1000); | |
241 page_info->mutable_render_time()->set_nanos((ms_since_epoch % 1000) * | |
242 1000000); | |
243 EXPECT_EQ(PrefetchRequestStatus::SUCCESS, | |
244 this->GeneratePage(kTestURL, this->BuildFromPageBundle(bundle))); | |
245 ASSERT_EQ(1u, this->pages().size()); | |
246 EXPECT_EQ(kTestURL, this->pages().back().url); | |
247 EXPECT_EQ(kTestURL2, this->pages().back().redirect_url); | |
248 EXPECT_EQ(RenderStatus::RENDERED, this->pages().back().status); | |
249 EXPECT_EQ(kTestBodyName, this->pages().back().body_name); | |
250 EXPECT_EQ(kTestBodyLength, this->pages().back().body_length); | |
251 EXPECT_EQ(ms_since_epoch, this->pages().back().render_time.ToJavaTime()); | |
252 } | |
253 | |
254 TYPED_TEST(GeneratePageBundleRequestOperationTest, MultiplePages) { | |
255 proto::PageBundle bundle; | |
256 | |
257 // Adds a page that is still being rendered. | |
258 proto::Archive* archive = bundle.add_archives(); | |
259 proto::PageInfo* page_info = archive->add_page_infos(); | |
260 page_info->set_url(kTestURL); | |
261 page_info->mutable_status()->set_code(proto::NOT_FOUND); | |
262 | |
263 // Adds a page that failed to render due to bundle size limits. | |
264 archive = bundle.add_archives(); | |
265 page_info = archive->add_page_infos(); | |
266 page_info->set_url(kTestURL2); | |
267 page_info->mutable_status()->set_code(proto::FAILED_PRECONDITION); | |
268 | |
269 // Adds a page that failed to render for any other reason. | |
270 archive = bundle.add_archives(); | |
271 page_info = archive->add_page_infos(); | |
272 page_info->set_url(kTestURL3); | |
273 page_info->mutable_status()->set_code(proto::UNKNOWN); | |
274 | |
275 // Adds a page that was rendered successfully. | |
276 archive = bundle.add_archives(); | |
277 archive->set_body_name(kTestBodyName); | |
278 archive->set_body_length(kTestBodyLength); | |
279 page_info = archive->add_page_infos(); | |
280 page_info->set_url(kTestURL4); | |
281 page_info->mutable_status()->set_code(proto::OK); | |
282 page_info->set_transformation(proto::NO_TRANSFORMATION); | |
283 int64_t ms_since_epoch = base::Time::Now().ToJavaTime(); | |
284 page_info->mutable_render_time()->set_seconds(ms_since_epoch / 1000); | |
285 page_info->mutable_render_time()->set_nanos((ms_since_epoch % 1000) * | |
286 1000000); | |
287 | |
288 std::vector<std::string> page_urls = {kTestURL, kTestURL2, kTestURL3}; | |
289 EXPECT_EQ(PrefetchRequestStatus::SUCCESS, | |
290 this->GenerateMultiplePages(page_urls, | |
291 this->BuildFromPageBundle(bundle))); | |
292 ASSERT_EQ(4u, this->pages().size()); | |
293 EXPECT_EQ(kTestURL, this->pages().at(0).url); | |
294 EXPECT_EQ(RenderStatus::PENDING, this->pages().at(0).status); | |
295 EXPECT_EQ(kTestURL2, this->pages().at(1).url); | |
296 EXPECT_EQ(RenderStatus::EXCEEDED_LIMIT, this->pages().at(1).status); | |
297 EXPECT_EQ(kTestURL3, this->pages().at(2).url); | |
298 EXPECT_EQ(RenderStatus::FAILED, this->pages().at(2).status); | |
299 EXPECT_EQ(kTestURL4, this->pages().at(3).url); | |
300 EXPECT_EQ(RenderStatus::RENDERED, this->pages().at(3).status); | |
301 EXPECT_EQ(kTestBodyName, this->pages().at(3).body_name); | |
302 EXPECT_EQ(kTestBodyLength, this->pages().at(3).body_length); | |
303 EXPECT_EQ(ms_since_epoch, this->pages().at(3).render_time.ToJavaTime()); | |
304 } | |
305 | |
306 } // namespace offline_pages | |
OLD | NEW |