// 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.
#import <memory>
#import "base/functional/bind.h"
#import "base/run_loop.h"
#import "base/strings/utf_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "ios/web/public/download/download_controller.h"
#import "ios/web/public/download/download_task.h"
#import "ios/web/public/test/download_task_test_util.h"
#import "ios/web/public/test/fakes/fake_download_controller_delegate.h"
#import "ios/web/public/test/navigation_test_util.h"
#import "ios/web/public/test/web_test_with_web_state.h"
#import "ios/web/public/web_client.h"
#import "net/http/http_request_headers.h"
#import "net/test/embedded_test_server/embedded_test_server.h"
#import "net/test/embedded_test_server/http_request.h"
#import "net/test/embedded_test_server/http_response.h"
#import "testing/gtest_mac.h"
using base::test::ios::WaitUntilConditionOrTimeout;
using base::test::ios::kWaitForDownloadTimeout;
using base::test::ios::kWaitForPageLoadTimeout;
namespace web {
namespace {
const char kContentDisposition[] = "attachment; filename=download.test";
const char kMimeType[] = "application/vnd.test";
const char kContent[] = "testdata";
// Returns HTTP response which causes WebState to start the download.
std::unique_ptr<net::test_server::HttpResponse> GetDownloadResponse(
const net::test_server::HttpRequest& request) {
auto result = std::make_unique<net::test_server::BasicHttpResponse>();
std::string user_agent =
request.headers.at(net::HttpRequestHeaders::kUserAgent);
if (user_agent == GetWebClient()->GetUserAgent(UserAgentType::MOBILE)) {
result->set_code(net::HTTP_OK);
result->set_content(kContent);
result->AddCustomHeader("Content-Type", kMimeType);
result->AddCustomHeader("Content-Disposition", kContentDisposition);
}
return result;
}
} // namespace
// Test fixture for DownloadController, DownloadControllerDelegate and
// DownloadTask integration tests.
class DownloadTest : public WebTestWithWebState {
protected:
DownloadTest() = default;
void SetUp() override {
WebTestWithWebState::SetUp();
delegate_ =
std::make_unique<FakeDownloadControllerDelegate>(download_controller());
server_.RegisterRequestHandler(base::BindRepeating(&GetDownloadResponse));
}
DownloadController* download_controller() {
return DownloadController::FromBrowserState(GetBrowserState());
}
protected:
net::EmbeddedTestServer server_;
std::unique_ptr<FakeDownloadControllerDelegate> delegate_;
};
// Tests sucessfull download flow.
TEST_F(DownloadTest, SuccessfulDownload) {
// Load download URL.
ASSERT_TRUE(server_.Start());
GURL url(server_.GetURL("/"));
test::LoadUrl(web_state(), url);
// Wait until download task is created.
ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForDownloadTimeout, ^{
return !delegate_->alive_download_tasks().empty();
}));
ASSERT_EQ(1U, delegate_->alive_download_tasks().size());
// Verify the initial state of the download task.
DownloadTask* task = delegate_->alive_download_tasks()[0].second.get();
ASSERT_TRUE(task);
EXPECT_TRUE(task->GetIdentifier());
EXPECT_EQ(url, task->GetOriginalUrl());
EXPECT_FALSE(task->IsDone());
EXPECT_EQ(0, task->GetErrorCode());
EXPECT_EQ(static_cast<int64_t>(strlen(kContent)), task->GetTotalBytes());
EXPECT_EQ(-1, task->GetPercentComplete());
EXPECT_EQ(kContentDisposition, task->GetContentDisposition());
EXPECT_EQ(kMimeType, task->GetMimeType());
EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("download.test")),
task->GenerateFileName());
// Start the download task and wait for completion.
{
web::test::WaitDownloadTaskDone observer(task);
task->Start(base::FilePath());
observer.Wait();
}
// Verify the completed state of the download task.
EXPECT_EQ(0, task->GetErrorCode());
EXPECT_EQ(static_cast<int64_t>(strlen(kContent)), task->GetTotalBytes());
EXPECT_EQ(100, task->GetPercentComplete());
EXPECT_EQ(200, task->GetHttpCode());
EXPECT_NSEQ(@(kContent),
[[NSString alloc]
initWithData:web::test::GetDownloadTaskResponseData(task)
encoding:NSUTF8StringEncoding]);
}
} // namespace web