// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/payments/content/payment_manifest_downloader.h"

#include <memory>
#include <optional>
#include <utility>

#include "base/functional/bind.h"
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/payments/core/const_csp_checker.h"
#include "components/payments/core/error_logger.h"
#include "components/payments/core/features.h"
#include "content/public/browser/weak_document_ptr.h"
#include "content/public/test/test_renderer_host.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace payments {
namespace {

using testing::_;

static constexpr char kNoContent[] = "";
static constexpr char kNoError[] = "";
static constexpr std::nullopt_t kNoLinkHeader = std::nullopt;
static constexpr char kEmptyLinkHeader[] = "";
static constexpr char kNoResponseBody[] = "";

}  // namespace

class PaymentManifestDownloaderTestBase
    : public content::RenderViewHostTestHarness {
 public:
  enum class Headers {
    kSend,
    kOmit,
  };

  PaymentManifestDownloaderTestBase()
      : test_url_("https://bobpay.test"),
        shared_url_loader_factory_(
            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                &test_factory_)),
        const_csp_checker_(std::make_unique<ConstCSPChecker>(/*allow=*/true)) {}

  void InitDownloader() {
    mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_rfh;
    test_factory_.Clone(url_loader_factory_rfh.BindNewPipeAndPassReceiver());
    downloader_ = std::make_unique<PaymentManifestDownloader>(
        std::make_unique<ErrorLogger>(), const_csp_checker_->GetWeakPtr(),
        shared_url_loader_factory_, std::move(url_loader_factory_rfh),
        main_rfh()->GetWeakDocumentPtr());
  }

  MOCK_METHOD3(OnManifestDownload,
               void(const GURL& unused_url_after_redirects,
                    const std::string& content,
                    const std::string& error_message));

  void ServerResponse(int response_code,
                      Headers send_headers,
                      std::optional<std::string> link_header,
                      const std::string& response_body,
                      int net_error) {
    scoped_refptr<net::HttpResponseHeaders> headers;
    if (send_headers == Headers::kSend) {
      headers = base::MakeRefCounted<net::HttpResponseHeaders>(std::string());
      headers->ReplaceStatusLine(
          base::StringPrintf("HTTP/1.1 %d %s", response_code,
                             net::GetHttpReasonPhrase(response_code)));

      if (link_header.has_value()) {
        headers->SetHeader("Link", *link_header);
      }
    }

    downloader_->OnURLLoaderCompleteInternal(
        downloader_->GetLoaderForTesting(),
        downloader_->GetLoaderOriginalURLForTesting(), response_body, headers,
        net_error);
  }

  void ServerResponse(int response_code,
                      const std::string& response_body,
                      int net_error) {
    ServerResponse(response_code, Headers::kSend, /*link_header=*/std::nullopt,
                   response_body, net_error);
  }

  void ServerRedirect(int redirect_code, const GURL& new_url) {
    net::RedirectInfo redirect_info;
    redirect_info.status_code = redirect_code;
    redirect_info.new_url = new_url;
    std::vector<std::string> to_be_removed_headers;
    // This is irrelevant.
    GURL url_before_redirect;

    downloader_->OnURLLoaderRedirect(
        downloader_->GetLoaderForTesting(), url_before_redirect, redirect_info,
        network::mojom::URLResponseHead(), &to_be_removed_headers);
  }

  GURL GetOriginalURL() {
    return downloader_->GetLoaderOriginalURLForTesting();
  }

 protected:
  GURL test_url_;
  network::TestURLLoaderFactory test_factory_;
  scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
  std::unique_ptr<ConstCSPChecker> const_csp_checker_;
  std::unique_ptr<PaymentManifestDownloader> downloader_;
};

class PaymentMethodManifestDownloaderTest
    : public PaymentManifestDownloaderTestBase {
 public:
  PaymentMethodManifestDownloaderTest() = default;

  void SetUp() override {
    PaymentManifestDownloaderTestBase::SetUp();
    InitDownloader();
    downloader_->DownloadPaymentMethodManifest(
        url::Origin::Create(GURL("https://chromium.org")), test_url_,
        base::BindOnce(&PaymentMethodManifestDownloaderTest::OnManifestDownload,
                       base::Unretained(this)));
  }
};

TEST_F(PaymentMethodManifestDownloaderTest, FirstHttpResponse404IsFailure) {
  EXPECT_CALL(*this, OnManifestDownload(
                         _, kNoContent,
                         "Unable to download payment manifest "
                         "\"https://bobpay.test/\". HTTP 404 Not Found."));

  ServerResponse(404, Headers::kSend, kNoLinkHeader, kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       NoHttpHeadersAndEmptyResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kOmit, kNoLinkHeader, kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       NoHttpHeadersButWithResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kOmit, kNoLinkHeader, "response body", net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       EmptyHttpHeaderAndEmptyResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, kNoLinkHeader, kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       EmptyHttpHeaderButWithResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, kNoLinkHeader, "response content",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       EmptyHttpLinkHeaderWithoutResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, kEmptyLinkHeader, kNoResponseBody,
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       EmptyHttpLinkHeaderButWithResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, kEmptyLinkHeader, "response body",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       NoRelInHttpLinkHeaderAndNoResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, "<manifest.json>", kNoResponseBody,
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       NoRelInHttpLinkHeaderButWithResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, "<manifest.json>", "response body",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       NoUrlInHttpLinkHeaderAndNoResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, "rel=payment-method-manifest",
                 kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       NoUrlInHttpLinkHeaderButWithResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, "rel=payment-method-manifest",
                 "response body", net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       NoManifestRellInHttpLinkHeaderAndNoResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, "<manifest.json>; rel=web-app-manifest",
                 kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       NoManifestRellInHttpLinkHeaderButWithResponseBodyIsFailure) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "No \"Link: rel=payment-method-manifest\" HTTP header found "
                  "at \"https://bobpay.test/\"."));

  ServerResponse(200, Headers::kSend, "<manifest.json>; rel=web-app-manifest",
                 "response body", net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest, SecondHttpResponse404IsFailure) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(
      *this, OnManifestDownload(
                 _, kNoContent,
                 "Unable to download payment manifest "
                 "\"https://bobpay.test/manifest.json\". HTTP 404 Not Found."));

  ServerResponse(404, Headers::kSend, kNoLinkHeader, kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest, EmptySecondResponseIsFailure) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this,
              OnManifestDownload(_, kNoContent,
                                 "No content found in payment manifest "
                                 "\"https://bobpay.test/manifest.json\"."));

  ServerResponse(200, Headers::kSend, kNoLinkHeader, kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       SecondResponseWithoutHeadersButWithContentIsSuccess) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this, OnManifestDownload(_, "response content", kNoError));

  ServerResponse(200, Headers::kOmit, kNoLinkHeader, "response content",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       SecondResponseWithoutContentIsFailure) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this,
              OnManifestDownload(_, kNoContent,
                                 "No content found in payment manifest "
                                 "\"https://bobpay.test/manifest.json\"."));

  ServerResponse(200, Headers::kOmit, kNoLinkHeader, kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest, NonEmptySecondResponseIsSuccess) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));

  ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       InsufficientResourcesInHttpLinkFailure) {
  EXPECT_CALL(
      *this, OnManifestDownload(
                 _, kNoContent,
                 "Unable to download payment manifest "
                 "\"https://bobpay.test/\". ERR_INSUFFICIENT_RESOURCES (-12)"));

  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::ERR_INSUFFICIENT_RESOURCES);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       InsufficientResourcesAfterHttpLinkFailure) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this,
              OnManifestDownload(_, kNoContent,
                                 "Unable to download payment manifest "
                                 "\"https://bobpay.test/manifest.json\". "
                                 "ERR_INSUFFICIENT_RESOURCES (-12)"));

  ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content",
                 net::ERR_INSUFFICIENT_RESOURCES);
}

TEST_F(PaymentMethodManifestDownloaderTest, FirstResponseCode204IsSuccess) {
  ServerResponse(204, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));

  ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest, SecondResponseCode204IsFailure) {
  ServerResponse(204, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(
      *this,
      OnManifestDownload(
          _, kNoContent,
          "Unable to download payment manifest "
          "\"https://bobpay.test/manifest.json\". HTTP 204 No Content."));

  ServerResponse(204, Headers::kSend, kNoLinkHeader, "manifest content",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       SecondResponseWithLinkHeaderAndNoContentIsFailure) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this,
              OnManifestDownload(_, kNoContent,
                                 "No content found in payment manifest "
                                 "\"https://bobpay.test/manifest.json\"."));

  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       SecondResponseWithLinkHeaderAndWithContentReturnsTheContent) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));

  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 "manifest content", net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest, RelativeHttpHeaderLinkUrl) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_EQ("https://bobpay.test/manifest.json", GetOriginalURL());
}

TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpsHeaderLinkUrl) {
  ServerResponse(200, Headers::kSend,
                 "<https://bobpay.test/manifest.json>; "
                 "rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_EQ("https://bobpay.test/manifest.json", GetOriginalURL());
}

TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpHeaderLinkUrl) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "\"http://bobpay.test/manifest.json\" is not a valid payment "
                  "manifest "
                  "URL with HTTPS scheme (or HTTP scheme for localhost)."));

  ServerResponse(
      200, Headers::kSend,
      "<http://bobpay.test/manifest.json>; rel=payment-method-manifest",
      kNoResponseBody, net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest, 300IsUnsupportedRedirect) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "HTTP status code 300 \"Multiple Choices\" not allowed for "
                  "payment method manifest \"https://bobpay.test/\"."));

  ServerRedirect(300, GURL("https://pay.bobpay.test"));
}

TEST_F(PaymentMethodManifestDownloaderTest, 301And302AreSupportedRedirects) {
  ServerRedirect(301, GURL("https://pay.bobpay.test"));

  EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.test"));

  ServerRedirect(302, GURL("https://newpay.bobpay.test"));

  EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.test"));

  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));

  ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest,
       CannotRedirectAfterFollowingLinkHeader) {
  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this, OnManifestDownload(
                         _, kNoContent,
                         "Unable to download the payment manifest because "
                         "reached the maximum number of redirects."));

  ServerRedirect(301, GURL("https://pay.bobpay.test"));
}

TEST_F(PaymentMethodManifestDownloaderTest, 302And303AreSupportedRedirects) {
  ServerRedirect(302, GURL("https://pay.bobpay.test"));

  EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.test"));

  ServerRedirect(303, GURL("https://newpay.bobpay.test"));

  EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.test"));

  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));

  ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest, 304IsUnsupportedRedirect) {
  EXPECT_CALL(*this,
              OnManifestDownload(
                  _, kNoContent,
                  "HTTP status code 304 \"Not Modified\" not allowed for "
                  "payment method manifest \"https://bobpay.test/\"."));

  ServerRedirect(304, GURL("https://pay.bobpay.test"));
}

TEST_F(PaymentMethodManifestDownloaderTest, 305IsUnsupportedRedirect) {
  EXPECT_CALL(*this, OnManifestDownload(
                         _, kNoContent,
                         "HTTP status code 305 \"Use Proxy\" not allowed for "
                         "payment method manifest \"https://bobpay.test/\"."));

  ServerRedirect(305, GURL("https://pay.bobpay.test"));
}

TEST_F(PaymentMethodManifestDownloaderTest, 307And308AreSupportedRedirects) {
  ServerRedirect(307, GURL("https://pay.bobpay.test"));

  EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.test"));

  ServerRedirect(308, GURL("https://newpay.bobpay.test"));

  EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.test"));

  ServerResponse(200, Headers::kSend,
                 "<manifest.json>; rel=payment-method-manifest",
                 kNoResponseBody, net::OK);

  EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));

  ServerResponse(200, Headers::kSend, kNoLinkHeader, "manifest content",
                 net::OK);
}

TEST_F(PaymentMethodManifestDownloaderTest, NoMoreThanThreeRedirects) {
  ServerRedirect(301, GURL("https://pay.bobpay.test"));

  EXPECT_EQ(GetOriginalURL(), GURL("https://pay.bobpay.test"));

  ServerRedirect(302, GURL("https://oldpay.bobpay.test"));

  EXPECT_EQ(GetOriginalURL(), GURL("https://oldpay.bobpay.test"));

  ServerRedirect(308, GURL("https://newpay.bobpay.test"));

  EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.test"));

  EXPECT_CALL(*this, OnManifestDownload(
                         _, kNoContent,
                         "Unable to download the payment manifest because "
                         "reached the maximum number of redirects."));

  ServerRedirect(308, GURL("https://newpay.bobpay.test"));
}

TEST_F(PaymentMethodManifestDownloaderTest, InvalidRedirectUrlIsFailure) {
  EXPECT_CALL(*this, OnManifestDownload(
                         _, kNoContent,
                         "\"\" is not a valid payment manifest URL with HTTPS "
                         "scheme (or HTTP scheme for localhost)."));

  ServerRedirect(308, GURL("pay.bobpay.test"));
}

TEST_F(PaymentMethodManifestDownloaderTest, NotAllowCrossSiteRedirects) {
  EXPECT_CALL(
      *this,
      OnManifestDownload(
          _, kNoContent,
          "Cross-site redirect from \"https://bobpay.test/\" to "
          "\"https://alicepay.test/\" not allowed for payment manifests."));

  ServerRedirect(301, GURL("https://alicepay.test"));
}

class WebAppManifestDownloaderTest : public PaymentManifestDownloaderTestBase {
 public:
  WebAppManifestDownloaderTest() = default;

  void SetUp() override {
    PaymentManifestDownloaderTestBase::SetUp();
    InitDownloader();
    downloader_->DownloadWebAppManifest(
        url::Origin::Create(test_url_), test_url_,
        base::BindOnce(&WebAppManifestDownloaderTest::OnManifestDownload,
                       base::Unretained(this)));
  }
};

TEST_F(WebAppManifestDownloaderTest, HttpGetResponse404IsFailure) {
  EXPECT_CALL(*this, OnManifestDownload(
                         _, kNoContent,
                         "Unable to download payment manifest "
                         "\"https://bobpay.test/\". HTTP 404 Not Found."));

  ServerResponse(404, kNoResponseBody, net::OK);
}

TEST_F(WebAppManifestDownloaderTest, EmptyHttpGetResponseIsFailure) {
  EXPECT_CALL(
      *this,
      OnManifestDownload(
          _, kNoContent,
          "No content found in payment manifest \"https://bobpay.test/\"."));

  ServerResponse(200, kNoResponseBody, net::OK);
}

TEST_F(WebAppManifestDownloaderTest, NonEmptyHttpGetResponseIsSuccess) {
  EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError));

  ServerResponse(200, "manifest content", net::OK);
}

TEST_F(WebAppManifestDownloaderTest, InsufficientResourcesFailure) {
  EXPECT_CALL(
      *this, OnManifestDownload(
                 _, kNoContent,
                 "Unable to download payment manifest "
                 "\"https://bobpay.test/\". ERR_INSUFFICIENT_RESOURCES (-12)"));

  ServerResponse(200, "manifest content", net::ERR_INSUFFICIENT_RESOURCES);
}

using PaymentManifestDownloaderCSPTest = PaymentManifestDownloaderTestBase;

// Download fails when CSP checker is gone, e.g., during shutdown.
TEST_F(PaymentManifestDownloaderCSPTest,
       PaymentMethodManifestCSPCheckerMissing) {
  InitDownloader();
  const_csp_checker_.reset();

  EXPECT_CALL(
      *this,
      OnManifestDownload(
          _, kNoContent,
          "Unable to download payment manifest \"https://bobpay.test/\"."));

  downloader_->DownloadPaymentMethodManifest(
      url::Origin::Create(GURL("https://chromium.org")), test_url_,
      base::BindOnce(&PaymentManifestDownloaderCSPTest::OnManifestDownload,
                     base::Unretained(this)));
}

// Download fails when CSP checker is gone, e.g., during shutdown.
TEST_F(PaymentManifestDownloaderCSPTest, WebAppManifestCSPCheckerMissing) {
  InitDownloader();
  const_csp_checker_.reset();

  EXPECT_CALL(
      *this,
      OnManifestDownload(
          _, kNoContent,
          "Unable to download payment manifest \"https://bobpay.test/\"."));

  downloader_->DownloadWebAppManifest(
      url::Origin::Create(test_url_), test_url_,
      base::BindOnce(&PaymentManifestDownloaderCSPTest::OnManifestDownload,
                     base::Unretained(this)));
}

// Download fails when CSP checker denies it.
TEST_F(PaymentManifestDownloaderCSPTest, PaymentMethodManifestCSPDenied) {
  const_csp_checker_ = std::make_unique<ConstCSPChecker>(/*allow=*/false);
  InitDownloader();

  EXPECT_CALL(*this, OnManifestDownload(
                         _, kNoContent,
                         "Content Security Policy denied the download of "
                         "payment manifest \"https://bobpay.test/\"."));

  downloader_->DownloadPaymentMethodManifest(
      url::Origin::Create(GURL("https://chromium.org")), test_url_,
      base::BindOnce(&PaymentManifestDownloaderCSPTest::OnManifestDownload,
                     base::Unretained(this)));
}

// Download fails when CSP checker denies it.
TEST_F(PaymentManifestDownloaderCSPTest, WebAppManifestCSPDenied) {
  const_csp_checker_ = std::make_unique<ConstCSPChecker>(/*allow=*/false);
  InitDownloader();

  EXPECT_CALL(*this, OnManifestDownload(
                         _, kNoContent,
                         "Content Security Policy denied the download of "
                         "payment manifest \"https://bobpay.test/\"."));

  downloader_->DownloadWebAppManifest(
      url::Origin::Create(test_url_), test_url_,
      base::BindOnce(&PaymentManifestDownloaderCSPTest::OnManifestDownload,
                     base::Unretained(this)));
}

}  // namespace payments
