Backed out changeset 1b14354719c0 (bug 1895254) for causing bustages on NavigationTra...
[gecko.git] / uriloader / preload / gtest / TestFetchPreloader.cpp
blob9f0614f84aafba81eb02896301a7dbe6422f400d
1 #include "gtest/gtest.h"
3 #include "mozilla/CORSMode.h"
4 #include "mozilla/dom/XMLDocument.h"
5 #include "mozilla/dom/ReferrerPolicyBinding.h"
6 #include "mozilla/FetchPreloader.h"
7 #include "mozilla/gtest/MozAssertions.h"
8 #include "mozilla/Maybe.h"
9 #include "mozilla/PreloadHashKey.h"
10 #include "mozilla/SpinEventLoopUntil.h"
11 #include "nsNetUtil.h"
12 #include "nsIChannel.h"
13 #include "nsIStreamListener.h"
14 #include "nsISupportsPriority.h"
15 #include "nsThreadUtils.h"
16 #include "nsStringStream.h"
18 namespace {
20 auto const ERROR_CANCEL = NS_ERROR_ABORT;
21 auto const ERROR_ONSTOP = NS_ERROR_NET_INTERRUPT;
22 auto const ERROR_THROW = NS_ERROR_FAILURE;
24 class FakeChannel : public nsIChannel {
25 public:
26 NS_DECL_ISUPPORTS
27 NS_DECL_NSICHANNEL
28 NS_DECL_NSIREQUEST
30 nsresult Start() { return mListener->OnStartRequest(this); }
31 nsresult Data(const nsACString& aData) {
32 if (NS_FAILED(mStatus)) {
33 return mStatus;
35 nsCOMPtr<nsIInputStream> is;
36 NS_NewCStringInputStream(getter_AddRefs(is), aData);
37 return mListener->OnDataAvailable(this, is, 0, aData.Length());
39 nsresult Stop(nsresult status) {
40 if (NS_SUCCEEDED(mStatus)) {
41 mStatus = status;
43 mListener->OnStopRequest(this, mStatus);
44 mListener = nullptr;
45 return mStatus;
48 private:
49 virtual ~FakeChannel() = default;
50 bool mIsPending = false;
51 bool mCanceled = false;
52 nsresult mStatus = NS_OK;
53 nsCOMPtr<nsIStreamListener> mListener;
56 NS_IMPL_ISUPPORTS(FakeChannel, nsIChannel, nsIRequest)
58 NS_IMETHODIMP FakeChannel::GetName(nsACString& result) { return NS_OK; }
59 NS_IMETHODIMP FakeChannel::IsPending(bool* result) {
60 *result = mIsPending;
61 return NS_OK;
63 NS_IMETHODIMP FakeChannel::GetStatus(nsresult* status) {
64 *status = mStatus;
65 return NS_OK;
67 NS_IMETHODIMP FakeChannel::SetCanceledReason(const nsACString& aReason) {
68 return SetCanceledReasonImpl(aReason);
70 NS_IMETHODIMP FakeChannel::GetCanceledReason(nsACString& aReason) {
71 return GetCanceledReasonImpl(aReason);
73 NS_IMETHODIMP FakeChannel::CancelWithReason(nsresult aStatus,
74 const nsACString& aReason) {
75 return CancelWithReasonImpl(aStatus, aReason);
77 NS_IMETHODIMP FakeChannel::Cancel(nsresult status) {
78 if (!mCanceled) {
79 mCanceled = true;
80 mStatus = status;
82 return NS_OK;
84 NS_IMETHODIMP FakeChannel::Suspend() { return NS_OK; }
85 NS_IMETHODIMP FakeChannel::Resume() { return NS_OK; }
86 NS_IMETHODIMP FakeChannel::GetLoadFlags(nsLoadFlags* aLoadFlags) {
87 *aLoadFlags = 0;
88 return NS_OK;
90 NS_IMETHODIMP FakeChannel::SetLoadFlags(nsLoadFlags aLoadFlags) {
91 return NS_OK;
93 NS_IMETHODIMP FakeChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
94 return NS_ERROR_NOT_IMPLEMENTED;
96 NS_IMETHODIMP FakeChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
97 return NS_ERROR_NOT_IMPLEMENTED;
99 NS_IMETHODIMP FakeChannel::GetLoadGroup(nsILoadGroup** aLoadGroup) {
100 return NS_OK;
102 NS_IMETHODIMP FakeChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) {
103 return NS_OK;
105 NS_IMETHODIMP FakeChannel::GetOriginalURI(nsIURI** aURI) { return NS_OK; }
106 NS_IMETHODIMP FakeChannel::SetOriginalURI(nsIURI* aURI) { return NS_OK; }
107 NS_IMETHODIMP FakeChannel::GetURI(nsIURI** aURI) { return NS_OK; }
108 NS_IMETHODIMP FakeChannel::GetOwner(nsISupports** aOwner) { return NS_OK; }
109 NS_IMETHODIMP FakeChannel::SetOwner(nsISupports* aOwner) { return NS_OK; }
110 NS_IMETHODIMP FakeChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) { return NS_OK; }
111 NS_IMETHODIMP FakeChannel::GetLoadInfo(nsILoadInfo** aLoadInfo) {
112 return NS_OK;
114 NS_IMETHODIMP FakeChannel::GetIsDocument(bool* aIsDocument) {
115 *aIsDocument = false;
116 return NS_OK;
118 NS_IMETHODIMP FakeChannel::GetNotificationCallbacks(
119 nsIInterfaceRequestor** aCallbacks) {
120 return NS_OK;
122 NS_IMETHODIMP FakeChannel::SetNotificationCallbacks(
123 nsIInterfaceRequestor* aCallbacks) {
124 return NS_OK;
126 NS_IMETHODIMP FakeChannel::GetSecurityInfo(
127 nsITransportSecurityInfo** aSecurityInfo) {
128 return NS_OK;
130 NS_IMETHODIMP FakeChannel::GetContentType(nsACString& aContentType) {
131 return NS_OK;
133 NS_IMETHODIMP FakeChannel::SetContentType(const nsACString& aContentType) {
134 return NS_OK;
136 NS_IMETHODIMP FakeChannel::GetContentCharset(nsACString& aContentCharset) {
137 return NS_OK;
139 NS_IMETHODIMP FakeChannel::SetContentCharset(
140 const nsACString& aContentCharset) {
141 return NS_OK;
143 NS_IMETHODIMP FakeChannel::GetContentDisposition(
144 uint32_t* aContentDisposition) {
145 return NS_OK;
147 NS_IMETHODIMP FakeChannel::SetContentDisposition(uint32_t aContentDisposition) {
148 return NS_OK;
150 NS_IMETHODIMP FakeChannel::GetContentDispositionFilename(
151 nsAString& aContentDispositionFilename) {
152 return NS_OK;
154 NS_IMETHODIMP FakeChannel::SetContentDispositionFilename(
155 const nsAString& aContentDispositionFilename) {
156 return NS_OK;
158 NS_IMETHODIMP FakeChannel::GetContentDispositionHeader(
159 nsACString& aContentDispositionHeader) {
160 return NS_ERROR_NOT_AVAILABLE;
162 NS_IMETHODIMP FakeChannel::GetContentLength(int64_t* aContentLength) {
163 return NS_OK;
165 NS_IMETHODIMP FakeChannel::SetContentLength(int64_t aContentLength) {
166 return NS_OK;
168 NS_IMETHODIMP FakeChannel::GetCanceled(bool* aCanceled) {
169 *aCanceled = mCanceled;
170 return NS_OK;
172 NS_IMETHODIMP FakeChannel::Open(nsIInputStream** aStream) {
173 return NS_ERROR_NOT_IMPLEMENTED;
175 NS_IMETHODIMP
176 FakeChannel::AsyncOpen(nsIStreamListener* aListener) {
177 mIsPending = true;
178 mListener = aListener;
179 return NS_OK;
182 class FakePreloader : public mozilla::FetchPreloader {
183 public:
184 explicit FakePreloader(FakeChannel* aChannel) : mDrivingChannel(aChannel) {}
186 private:
187 RefPtr<FakeChannel> mDrivingChannel;
189 virtual nsresult CreateChannel(
190 nsIChannel** aChannel, nsIURI* aURI, const mozilla::CORSMode aCORSMode,
191 const mozilla::dom::ReferrerPolicy& aReferrerPolicy,
192 mozilla::dom::Document* aDocument, nsILoadGroup* aLoadGroup,
193 nsIInterfaceRequestor* aCallbacks, uint64_t aHttpChannelId,
194 int32_t aSupportsPriorityValue) override {
195 mDrivingChannel.forget(aChannel);
196 return NS_OK;
200 class FakeListener : public nsIStreamListener {
201 NS_DECL_ISUPPORTS
202 NS_DECL_NSIREQUESTOBSERVER
203 NS_DECL_NSISTREAMLISTENER
205 enum { Never, OnStart, OnData, OnStop } mCancelIn = Never;
207 nsresult mOnStartResult = NS_OK;
208 nsresult mOnDataResult = NS_OK;
209 nsresult mOnStopResult = NS_OK;
211 bool mOnStart = false;
212 nsCString mOnData;
213 mozilla::Maybe<nsresult> mOnStop;
215 private:
216 virtual ~FakeListener() = default;
219 NS_IMPL_ISUPPORTS(FakeListener, nsIStreamListener, nsIRequestObserver)
221 NS_IMETHODIMP FakeListener::OnStartRequest(nsIRequest* request) {
222 EXPECT_FALSE(mOnStart);
223 mOnStart = true;
225 if (mCancelIn == OnStart) {
226 request->Cancel(ERROR_CANCEL);
229 return mOnStartResult;
231 NS_IMETHODIMP FakeListener::OnDataAvailable(nsIRequest* request,
232 nsIInputStream* input,
233 uint64_t offset, uint32_t count) {
234 nsAutoCString data;
235 data.SetLength(count);
237 uint32_t read;
238 input->Read(data.BeginWriting(), count, &read);
239 mOnData += data;
241 if (mCancelIn == OnData) {
242 request->Cancel(ERROR_CANCEL);
245 return mOnDataResult;
247 NS_IMETHODIMP FakeListener::OnStopRequest(nsIRequest* request,
248 nsresult status) {
249 EXPECT_FALSE(mOnStop);
250 mOnStop.emplace(status);
252 if (mCancelIn == OnStop) {
253 request->Cancel(ERROR_CANCEL);
256 return mOnStopResult;
259 bool eventInProgress = true;
261 void Await() {
262 MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil(
263 "uriloader:TestFetchPreloader:Await"_ns, [&]() {
264 bool yield = !eventInProgress;
265 eventInProgress = true; // Just for convenience
266 return yield;
267 }));
270 // WinBase.h defines this.
271 #undef Yield
272 void Yield() { eventInProgress = false; }
274 } // namespace
276 // ****************************************************************************
277 // Test body
278 // ****************************************************************************
280 // Caching with all good results (data + NS_OK)
281 TEST(TestFetchPreloader, CacheNoneBeforeConsume)
283 nsCOMPtr<nsIURI> uri;
284 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
285 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
287 RefPtr<FakeChannel> channel = new FakeChannel();
288 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
289 RefPtr<mozilla::dom::Document> doc;
290 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
292 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
293 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
294 0, nsISupportsPriority::PRIORITY_NORMAL)));
296 RefPtr<FakeListener> listener = new FakeListener();
297 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
298 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
300 EXPECT_NS_SUCCEEDED(channel->Start());
301 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
302 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
303 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
304 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
306 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
307 EXPECT_TRUE(listener->mOnStart);
308 EXPECT_TRUE(listener->mOnData.EqualsLiteral("onetwothree"));
309 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == NS_OK);
311 Yield();
312 }));
314 Await();
316 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
319 TEST(TestFetchPreloader, CacheStartBeforeConsume)
321 nsCOMPtr<nsIURI> uri;
322 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
323 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
325 RefPtr<FakeChannel> channel = new FakeChannel();
326 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
327 RefPtr<mozilla::dom::Document> doc;
328 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
330 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
331 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
332 0, nsISupportsPriority::PRIORITY_NORMAL)));
334 EXPECT_NS_SUCCEEDED(channel->Start());
336 RefPtr<FakeListener> listener = new FakeListener();
337 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
338 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
340 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
341 EXPECT_TRUE(listener->mOnStart);
343 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
344 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
345 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
346 EXPECT_TRUE(listener->mOnData.EqualsLiteral("onetwothree"));
348 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
349 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == NS_OK);
351 Yield();
352 }));
354 Await();
356 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
359 TEST(TestFetchPreloader, CachePartOfDataBeforeConsume)
361 nsCOMPtr<nsIURI> uri;
362 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
363 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
365 RefPtr<FakeChannel> channel = new FakeChannel();
366 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
367 RefPtr<mozilla::dom::Document> doc;
368 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
370 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
371 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
372 0, nsISupportsPriority::PRIORITY_NORMAL)));
374 EXPECT_NS_SUCCEEDED(channel->Start());
375 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
376 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
378 RefPtr<FakeListener> listener = new FakeListener();
379 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
380 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
382 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
383 EXPECT_TRUE(listener->mOnStart);
385 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
386 EXPECT_TRUE(listener->mOnData.EqualsLiteral("onetwothree"));
388 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
389 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == NS_OK);
391 Yield();
392 }));
394 Await();
396 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
399 TEST(TestFetchPreloader, CacheAllDataBeforeConsume)
401 nsCOMPtr<nsIURI> uri;
402 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
403 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
405 RefPtr<FakeChannel> channel = new FakeChannel();
406 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
407 RefPtr<mozilla::dom::Document> doc;
408 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
410 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
411 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
412 0, nsISupportsPriority::PRIORITY_NORMAL)));
414 EXPECT_NS_SUCCEEDED(channel->Start());
415 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
416 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
417 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
419 // Request consumation of the preload...
420 RefPtr<FakeListener> listener = new FakeListener();
421 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
422 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
424 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
425 EXPECT_TRUE(listener->mOnStart);
426 EXPECT_TRUE(listener->mOnData.EqualsLiteral("onetwothree"));
428 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
429 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == NS_OK);
431 Yield();
432 }));
434 Await();
436 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
439 TEST(TestFetchPreloader, CacheAllBeforeConsume)
441 nsCOMPtr<nsIURI> uri;
442 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
443 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
445 RefPtr<FakeChannel> channel = new FakeChannel();
446 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
447 RefPtr<mozilla::dom::Document> doc;
448 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
450 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
451 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
452 0, nsISupportsPriority::PRIORITY_NORMAL)));
454 EXPECT_NS_SUCCEEDED(channel->Start());
455 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
456 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
457 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
458 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
460 RefPtr<FakeListener> listener = new FakeListener();
461 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
462 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
464 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
465 EXPECT_TRUE(listener->mOnStart);
466 EXPECT_TRUE(listener->mOnData.EqualsLiteral("onetwothree"));
467 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == NS_OK);
469 Yield();
470 }));
472 Await();
474 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
477 // Get data before the channel fails
478 TEST(TestFetchPreloader, CacheAllBeforeConsumeWithChannelError)
480 nsCOMPtr<nsIURI> uri;
481 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
482 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
484 RefPtr<FakeChannel> channel = new FakeChannel();
485 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
486 RefPtr<mozilla::dom::Document> doc;
487 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
489 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
490 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
491 0, nsISupportsPriority::PRIORITY_NORMAL)));
493 EXPECT_NS_SUCCEEDED(channel->Start());
494 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
495 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
496 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
497 EXPECT_NS_FAILED(channel->Stop(ERROR_ONSTOP));
499 RefPtr<FakeListener> listener = new FakeListener();
500 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
501 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
503 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
504 EXPECT_TRUE(listener->mOnStart);
505 EXPECT_TRUE(listener->mOnData.EqualsLiteral("onetwothree"));
506 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_ONSTOP);
508 Yield();
509 }));
511 Await();
513 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
516 // Cancel the channel between caching and consuming
517 TEST(TestFetchPreloader, CacheAllBeforeConsumeWithChannelCancel)
519 nsCOMPtr<nsIURI> uri;
520 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
521 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
523 RefPtr<FakeChannel> channel = new FakeChannel();
524 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
525 RefPtr<mozilla::dom::Document> doc;
526 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
528 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
529 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
530 0, nsISupportsPriority::PRIORITY_NORMAL)));
532 EXPECT_NS_SUCCEEDED(channel->Start());
533 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
534 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
535 channel->Cancel(ERROR_CANCEL);
536 EXPECT_NS_FAILED(channel->Stop(ERROR_CANCEL));
538 RefPtr<FakeListener> listener = new FakeListener();
539 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
540 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
542 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
543 EXPECT_TRUE(listener->mOnStart);
544 // XXX - This is hard to solve; the data is there but we won't deliver it.
545 // This is a bit different case than e.g. a network error. We want to
546 // deliver some data in that case. Cancellation probably happens because of
547 // navigation or a demand to not consume the channel anyway.
548 EXPECT_TRUE(listener->mOnData.IsEmpty());
549 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_CANCEL);
551 Yield();
552 }));
554 Await();
556 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
559 // Let the listener throw while data is already cached
560 TEST(TestFetchPreloader, CacheAllBeforeConsumeThrowFromOnStartRequest)
562 nsCOMPtr<nsIURI> uri;
563 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
564 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
566 RefPtr<FakeChannel> channel = new FakeChannel();
567 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
568 RefPtr<mozilla::dom::Document> doc;
569 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
571 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
572 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
573 0, nsISupportsPriority::PRIORITY_NORMAL)));
575 EXPECT_NS_SUCCEEDED(channel->Start());
576 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
577 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
578 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
579 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
581 RefPtr<FakeListener> listener = new FakeListener();
582 listener->mOnStartResult = ERROR_THROW;
584 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
585 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
587 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
588 EXPECT_TRUE(listener->mOnStart);
589 EXPECT_TRUE(listener->mOnData.IsEmpty());
590 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_THROW);
592 Yield();
593 }));
595 Await();
597 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
600 TEST(TestFetchPreloader, CacheAllBeforeConsumeThrowFromOnDataAvailable)
602 nsCOMPtr<nsIURI> uri;
603 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
604 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
606 RefPtr<FakeChannel> channel = new FakeChannel();
607 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
608 RefPtr<mozilla::dom::Document> doc;
609 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
611 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
612 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
613 0, nsISupportsPriority::PRIORITY_NORMAL)));
615 EXPECT_NS_SUCCEEDED(channel->Start());
616 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
617 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
618 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
619 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
621 RefPtr<FakeListener> listener = new FakeListener();
622 listener->mOnDataResult = ERROR_THROW;
624 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
625 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
627 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
628 EXPECT_TRUE(listener->mOnStart);
629 EXPECT_TRUE(listener->mOnData.EqualsLiteral("one"));
630 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_THROW);
632 Yield();
633 }));
635 Await();
637 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
640 TEST(TestFetchPreloader, CacheAllBeforeConsumeThrowFromOnStopRequest)
642 nsCOMPtr<nsIURI> uri;
643 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
644 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
646 RefPtr<FakeChannel> channel = new FakeChannel();
647 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
648 RefPtr<mozilla::dom::Document> doc;
649 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
651 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
652 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
653 0, nsISupportsPriority::PRIORITY_NORMAL)));
655 EXPECT_NS_SUCCEEDED(channel->Start());
656 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
657 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
658 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
659 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
661 RefPtr<FakeListener> listener = new FakeListener();
662 listener->mOnStopResult = ERROR_THROW;
664 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
665 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
667 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
668 EXPECT_TRUE(listener->mOnStart);
669 EXPECT_TRUE(listener->mOnData.EqualsLiteral("onetwothree"));
670 // Throwing from OnStopRequest is generally ignored.
671 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == NS_OK);
673 Yield();
674 }));
676 Await();
678 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
681 // Cancel the channel in various callbacks
682 TEST(TestFetchPreloader, CacheAllBeforeConsumeCancelInOnStartRequest)
684 nsCOMPtr<nsIURI> uri;
685 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
686 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
688 RefPtr<FakeChannel> channel = new FakeChannel();
689 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
690 RefPtr<mozilla::dom::Document> doc;
691 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
693 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
694 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
695 0, nsISupportsPriority::PRIORITY_NORMAL)));
697 EXPECT_NS_SUCCEEDED(channel->Start());
698 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
699 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
700 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
701 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
703 RefPtr<FakeListener> listener = new FakeListener();
704 listener->mCancelIn = FakeListener::OnStart;
705 // check that throwing from OnStartRequest doesn't affect the cancellation
706 // status.
707 listener->mOnStartResult = ERROR_THROW;
709 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
710 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
712 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
713 EXPECT_TRUE(listener->mOnStart);
714 EXPECT_TRUE(listener->mOnData.IsEmpty());
715 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_CANCEL);
717 Yield();
718 }));
720 Await();
722 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
725 TEST(TestFetchPreloader, CacheAllBeforeConsumeCancelInOnDataAvailable)
727 nsCOMPtr<nsIURI> uri;
728 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
729 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
731 RefPtr<FakeChannel> channel = new FakeChannel();
732 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
733 RefPtr<mozilla::dom::Document> doc;
734 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
736 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
737 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
738 0, nsISupportsPriority::PRIORITY_NORMAL)));
740 EXPECT_NS_SUCCEEDED(channel->Start());
741 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
742 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
743 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
744 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
746 RefPtr<FakeListener> listener = new FakeListener();
747 listener->mCancelIn = FakeListener::OnData;
748 // check that throwing from OnStartRequest doesn't affect the cancellation
749 // status.
750 listener->mOnDataResult = ERROR_THROW;
752 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
753 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
755 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
756 EXPECT_TRUE(listener->mOnStart);
757 EXPECT_TRUE(listener->mOnData.EqualsLiteral("one"));
758 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_CANCEL);
760 Yield();
761 }));
763 Await();
765 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
768 // Corner cases
769 TEST(TestFetchPreloader, CachePartlyBeforeConsumeCancelInOnDataAvailable)
771 nsCOMPtr<nsIURI> uri;
772 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
773 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
775 RefPtr<FakeChannel> channel = new FakeChannel();
776 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
777 RefPtr<mozilla::dom::Document> doc;
778 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
780 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
781 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
782 0, nsISupportsPriority::PRIORITY_NORMAL)));
784 EXPECT_NS_SUCCEEDED(channel->Start());
785 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
786 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
788 RefPtr<FakeListener> listener = new FakeListener();
789 listener->mCancelIn = FakeListener::OnData;
791 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
792 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
794 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
795 EXPECT_NS_FAILED(channel->Data("three"_ns));
796 EXPECT_NS_FAILED(channel->Stop(NS_OK));
798 EXPECT_TRUE(listener->mOnStart);
799 EXPECT_TRUE(listener->mOnData.EqualsLiteral("one"));
800 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_CANCEL);
802 Yield();
803 }));
805 Await();
807 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
810 TEST(TestFetchPreloader, CachePartlyBeforeConsumeCancelInOnStartRequestAndRace)
812 nsCOMPtr<nsIURI> uri;
813 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
814 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
816 RefPtr<FakeChannel> channel = new FakeChannel();
817 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
818 RefPtr<mozilla::dom::Document> doc;
819 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
821 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
822 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
823 0, nsISupportsPriority::PRIORITY_NORMAL)));
825 EXPECT_NS_SUCCEEDED(channel->Start());
826 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
827 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
829 // This has to simulate a possibiilty when stream listener notifications from
830 // the channel are already pending in the queue while AsyncConsume is called.
831 // At this moment the listener has not been notified yet.
832 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
833 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
834 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
835 }));
837 RefPtr<FakeListener> listener = new FakeListener();
838 listener->mCancelIn = FakeListener::OnStart;
840 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
841 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
843 // Check listener's been fed properly. Expected is to NOT get any data and
844 // propagate the cancellation code and not being called duplicated
845 // OnStopRequest.
846 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
847 EXPECT_TRUE(listener->mOnStart);
848 EXPECT_TRUE(listener->mOnData.IsEmpty());
849 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_CANCEL);
851 Yield();
852 }));
854 Await();
856 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
859 TEST(TestFetchPreloader, CachePartlyBeforeConsumeCancelInOnDataAvailableAndRace)
861 nsCOMPtr<nsIURI> uri;
862 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
863 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
865 RefPtr<FakeChannel> channel = new FakeChannel();
866 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
867 RefPtr<mozilla::dom::Document> doc;
868 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
870 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
871 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
872 0, nsISupportsPriority::PRIORITY_NORMAL)));
874 EXPECT_NS_SUCCEEDED(channel->Start());
875 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
876 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
878 // This has to simulate a possibiilty when stream listener notifications from
879 // the channel are already pending in the queue while AsyncConsume is called.
880 // At this moment the listener has not been notified yet.
881 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
882 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
883 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
884 }));
886 RefPtr<FakeListener> listener = new FakeListener();
887 listener->mCancelIn = FakeListener::OnData;
889 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
890 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
892 // Check listener's been fed properly. Expected is to NOT get anything after
893 // the first OnData and propagate the cancellation code and not being called
894 // duplicated OnStopRequest.
895 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
896 EXPECT_TRUE(listener->mOnStart);
897 EXPECT_TRUE(listener->mOnData.EqualsLiteral("one"));
898 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_CANCEL);
900 Yield();
901 }));
903 Await();
905 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
908 TEST(TestFetchPreloader, CachePartlyBeforeConsumeThrowFromOnStartRequestAndRace)
910 nsCOMPtr<nsIURI> uri;
911 NS_NewURI(getter_AddRefs(uri), "https://example.com"_ns);
912 auto key = mozilla::PreloadHashKey::CreateAsFetch(uri, mozilla::CORS_NONE);
914 RefPtr<FakeChannel> channel = new FakeChannel();
915 RefPtr<FakePreloader> preloader = new FakePreloader(channel);
916 RefPtr<mozilla::dom::Document> doc;
917 NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
919 EXPECT_TRUE(NS_SUCCEEDED(preloader->OpenChannel(
920 key, uri, mozilla::CORS_NONE, mozilla::dom::ReferrerPolicy::_empty, doc,
921 0, nsISupportsPriority::PRIORITY_NORMAL)));
923 EXPECT_NS_SUCCEEDED(channel->Start());
924 EXPECT_NS_SUCCEEDED(channel->Data("one"_ns));
925 EXPECT_NS_SUCCEEDED(channel->Data("two"_ns));
927 // This has to simulate a possibiilty when stream listener notifications from
928 // the channel are already pending in the queue while AsyncConsume is called.
929 // At this moment the listener has not been notified yet.
930 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
931 EXPECT_NS_SUCCEEDED(channel->Data("three"_ns));
932 EXPECT_NS_SUCCEEDED(channel->Stop(NS_OK));
933 }));
935 RefPtr<FakeListener> listener = new FakeListener();
936 listener->mOnStartResult = ERROR_THROW;
938 EXPECT_NS_SUCCEEDED(preloader->AsyncConsume(listener));
939 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));
941 // Check listener's been fed properly. Expected is to NOT get any data and
942 // propagate the throwing code and not being called duplicated OnStopRequest.
943 NS_DispatchToMainThread(NS_NewRunnableFunction("test", [&]() {
944 EXPECT_TRUE(listener->mOnStart);
945 EXPECT_TRUE(listener->mOnData.IsEmpty());
946 EXPECT_TRUE(listener->mOnStop && *listener->mOnStop == ERROR_THROW);
948 Yield();
949 }));
951 Await();
953 EXPECT_FALSE(NS_SUCCEEDED(preloader->AsyncConsume(listener)));