1c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca// Use of this source code is governed by a BSD-style license that can be
3c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca// found in the LICENSE file.
4c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
5c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "base/file_util.h"
6c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "base/message_loop/message_loop.h"
7c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "base/strings/string_number_conversions.h"
8c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "base/test/test_file_util.h"
9c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "content/browser/browser_thread_impl.h"
10c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "content/browser/byte_stream.h"
11c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "content/browser/download/download_create_info.h"
12c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "content/browser/download/download_file_impl.h"
13c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "content/browser/download/download_request_handle.h"
14c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "content/public/browser/download_destination_observer.h"
15c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "content/public/browser/download_interrupt_reasons.h"
16c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "content/public/browser/download_manager.h"
17c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "content/public/test/mock_download_manager.h"
18c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "net/base/file_stream.h"
19c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "net/base/mock_file_stream.h"
20c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "net/base/net_errors.h"
21c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "testing/gmock/include/gmock/gmock.h"
22c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca#include "testing/gtest/include/gtest/gtest.h"
23c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
24c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecausing ::testing::_;
25c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecausing ::testing::AnyNumber;
26c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecausing ::testing::DoAll;
27c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecausing ::testing::InSequence;
28c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecausing ::testing::Return;
29c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecausing ::testing::SetArgPointee;
30c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecausing ::testing::StrictMock;
31c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
328244d6e5adfcc668676e3783ac6ce53e8dcc2a88José Fonsecanamespace content {
33c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecanamespace {
34c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
35c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecaclass MockByteStreamReader : public ByteStreamReader {
36b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca public:
37c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  MockByteStreamReader() {}
38c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  ~MockByteStreamReader() {}
39c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
40138428badea350a20f5afc652a4fa1850e1ec653José Fonseca  // ByteStream functions
41c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  MOCK_METHOD2(Read, ByteStreamReader::StreamState(
42c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca      scoped_refptr<net::IOBuffer>*, size_t*));
43c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  MOCK_CONST_METHOD0(GetStatus, int());
44c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
45c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca};
46c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
47c87fab0008453567b45dd5e5eb7dd5d026990071José Fonsecaclass MockDownloadDestinationObserver : public DownloadDestinationObserver {
48c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca public:
49c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  MOCK_METHOD3(DestinationUpdate, void(int64, int64, const std::string&));
50c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  MOCK_METHOD1(DestinationError, void(DownloadInterruptReason));
51c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  MOCK_METHOD1(DestinationCompleted, void(const std::string&));
52c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
53c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  // Doesn't override any methods in the base class.  Used to make sure
54c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  // that the last DestinationUpdate before a Destination{Completed,Error}
55c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  // had the right values.
56c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  MOCK_METHOD3(CurrentUpdateStatus,
57c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca               void(int64, int64, const std::string&));
58b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca};
59c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
60c87fab0008453567b45dd5e5eb7dd5d026990071José FonsecaMATCHER(IsNullCallback, "") { return (arg.is_null()); }
6199f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca
6299f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca}  // namespace
6399f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca
6499f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonsecaclass DownloadFileTest : public testing::Test {
65c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca public:
66c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
67c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  static const char* kTestData1;
68c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  static const char* kTestData2;
69138428badea350a20f5afc652a4fa1850e1ec653José Fonseca  static const char* kTestData3;
70c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  static const char* kDataHash;
71c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  static const uint32 kDummyDownloadId;
72c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  static const int kDummyChildId;
73c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  static const int kDummyRequestId;
74c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
75b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca  DownloadFileTest() :
76c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca      observer_(new StrictMock<MockDownloadDestinationObserver>),
77c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca      observer_factory_(observer_.get()),
78c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca      input_stream_(NULL),
79c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca      bytes_(-1),
80c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca      bytes_per_sec_(-1),
81c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca      hash_state_("xyzzy"),
82c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca      ui_thread_(BrowserThread::UI, &loop_),
83c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca      file_thread_(BrowserThread::FILE, &loop_) {
84c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  }
85c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
86c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  virtual ~DownloadFileTest() {
87c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  }
88c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
89c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  void SetUpdateDownloadInfo(int64 bytes, int64 bytes_per_sec,
90c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca                             const std::string& hash_state) {
91c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    bytes_ = bytes;
92c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    bytes_per_sec_ = bytes_per_sec;
93c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    hash_state_ = hash_state;
94c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  }
95c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
96c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  void ConfirmUpdateDownloadInfo() {
97c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_);
98c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  }
99c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
100c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  virtual void SetUp() {
101c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
102c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca        .Times(AnyNumber())
103c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca        .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
104c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  }
105c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
106c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  // Mock calls to this function are forwarded here.
107c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  void RegisterCallback(base::Closure sink_callback) {
108c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    sink_callback_ = sink_callback;
109c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  }
110c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
111c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  void SetInterruptReasonCallback(bool* was_called,
112c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca                                  DownloadInterruptReason* reason_p,
113b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca                                  DownloadInterruptReason reason) {
114c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    *was_called = true;
115c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    *reason_p = reason;
116c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  }
117c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
118c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca  bool CreateDownloadFile(int offset, bool calculate_hash) {
119c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    // There can be only one.
120c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    DCHECK(!download_file_.get());
12199f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca
12299f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca    input_stream_ = new StrictMock<MockByteStreamReader>();
12399f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca
124c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    // TODO: Need to actually create a function that'll set the variables
125c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    // based on the inputs from the callback.
126c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    EXPECT_CALL(*input_stream_, RegisterCallback(_))
127c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca        .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
128c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca        .RetiresOnSaturation();
129c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
130c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
131c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    download_file_.reset(
132c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca        new DownloadFileImpl(save_info.Pass(),
133c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca                             base::FilePath(),
134c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca                             GURL(),  // Source
135c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca                             GURL(),  // Referrer
136c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca                             calculate_hash,
137b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca                             scoped_ptr<ByteStreamReader>(input_stream_),
138c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca                             net::BoundNetLog(),
139c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca                             observer_factory_.GetWeakPtr()));
140c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    download_file_->SetClientGuid(
141c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca        "12345678-ABCD-1234-DCBA-123456789ABC");
142c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
143c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    EXPECT_CALL(*input_stream_, Read(_, _))
144c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca        .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
145c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca        .RetiresOnSaturation();
146c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca
147c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
148c87fab0008453567b45dd5e5eb7dd5d026990071José Fonseca    bool called = false;
149138428badea350a20f5afc652a4fa1850e1ec653José Fonseca    DownloadInterruptReason result;
150138428badea350a20f5afc652a4fa1850e1ec653José Fonseca    download_file_->Initialize(base::Bind(
151138428badea350a20f5afc652a4fa1850e1ec653José Fonseca        &DownloadFileTest::SetInterruptReasonCallback,
152b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca        weak_ptr_factory.GetWeakPtr(), &called, &result));
153138428badea350a20f5afc652a4fa1850e1ec653José Fonseca    loop_.RunUntilIdle();
154138428badea350a20f5afc652a4fa1850e1ec653José Fonseca    EXPECT_TRUE(called);
155138428badea350a20f5afc652a4fa1850e1ec653José Fonseca
156138428badea350a20f5afc652a4fa1850e1ec653José Fonseca    ::testing::Mock::VerifyAndClearExpectations(input_stream_);
157138428badea350a20f5afc652a4fa1850e1ec653José Fonseca    return result == DOWNLOAD_INTERRUPT_REASON_NONE;
158138428badea350a20f5afc652a4fa1850e1ec653José Fonseca  }
159b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca
160138428badea350a20f5afc652a4fa1850e1ec653José Fonseca  void DestroyDownloadFile(int offset) {
161138428badea350a20f5afc652a4fa1850e1ec653José Fonseca    EXPECT_FALSE(download_file_->InProgress());
16299f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca
16399f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca    // Make sure the data has been properly written to disk.
16499f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca    std::string disk_data;
16599f11f653012e8e18502cb0f5cce3cd1e0643c23José Fonseca    EXPECT_TRUE(base::ReadFileToString(download_file_->FullPath(), &disk_data));
166138428badea350a20f5afc652a4fa1850e1ec653José Fonseca    EXPECT_EQ(expected_data_, disk_data);
1679493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonseca
1689493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonseca    // Make sure the Browser and File threads outlive the DownloadFile
169e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul    // to satisfy thread checks inside it.
170e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul    download_file_.reset();
171e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul  }
172e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul
173080c40ab32b2abd6d8381b4a0cc143d36a1652b2José Fonseca  // Setup the stream to do be a data append; don't actually trigger
174e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul  // the callback or do verifications.
175e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul  void SetupDataAppend(const char **data_chunks, size_t num_chunks,
176e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul                       ::testing::Sequence s) {
177e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul    DCHECK(input_stream_);
178e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul    for (size_t i = 0; i < num_chunks; i++) {
179e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul      const char *source_data = data_chunks[i];
180e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul      size_t length = strlen(source_data);
181e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul      scoped_refptr<net::IOBuffer> data = new net::IOBuffer(length);
182e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul      memcpy(data->data(), source_data, length);
183e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul      EXPECT_CALL(*input_stream_, Read(_, _))
184e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul          .InSequence(s)
185e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul          .WillOnce(DoAll(SetArgPointee<0>(data),
186e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul                          SetArgPointee<1>(length),
187e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul                          Return(ByteStreamReader::STREAM_HAS_DATA)))
188e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul          .RetiresOnSaturation();
189e288796c92bb7d75cd6dfee968804c6230ef38d7Brian Paul      expected_data_ += source_data;
19038110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul    }
19138110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul  }
19238110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul
19338110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul  void VerifyStreamAndSize() {
19438110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul    ::testing::Mock::VerifyAndClearExpectations(input_stream_);
19538110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul    int64 size;
19638110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul    EXPECT_TRUE(base::GetFileSize(download_file_->FullPath(), &size));
19738110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul    EXPECT_EQ(expected_data_.size(), static_cast<size_t>(size));
19838110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul  }
19938110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul
20038110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul  // TODO(rdsmith): Manage full percentage issues properly.
20138110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul  void AppendDataToFile(const char **data_chunks, size_t num_chunks) {
20238110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul    ::testing::Sequence s1;
20338110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul    SetupDataAppend(data_chunks, num_chunks, s1);
20438110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul    EXPECT_CALL(*input_stream_, Read(_, _))
20538110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul        .InSequence(s1)
20638110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul        .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
20738110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul        .RetiresOnSaturation();
20838110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul    sink_callback_.Run();
209b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca    VerifyStreamAndSize();
210b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca  }
2110c2ea2433833d5eda8a4fefe1412bf0ea40b14bfJosé Fonseca
2124458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca  void SetupFinishStream(DownloadInterruptReason interrupt_reason,
213b4835ea03d64261da5a892f9590c9977b06920e8José Fonseca                       ::testing::Sequence s) {
2144458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca    EXPECT_CALL(*input_stream_, Read(_, _))
2154458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca        .InSequence(s)
2164458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca        .WillOnce(Return(ByteStreamReader::STREAM_COMPLETE))
21738110fd1c3a6c57d1ff089d546a3456ca1a78da8Brian Paul        .RetiresOnSaturation();
2184458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca    EXPECT_CALL(*input_stream_, GetStatus())
2194458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca        .InSequence(s)
2204458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca        .WillOnce(Return(interrupt_reason))
2214458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca        .RetiresOnSaturation();
2224458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca    EXPECT_CALL(*input_stream_, RegisterCallback(_))
2234458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca        .RetiresOnSaturation();
2244458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca  }
2254458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca
2264458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca  void FinishStream(DownloadInterruptReason interrupt_reason,
2274458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca                    bool check_observer) {
2284458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca    ::testing::Sequence s1;
2294458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca    SetupFinishStream(interrupt_reason, s1);
2304458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca    sink_callback_.Run();
2314458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca    VerifyStreamAndSize();
2324458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca    if (check_observer) {
2334458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca      EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
2344458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca      loop_.RunUntilIdle();
2354458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca      ::testing::Mock::VerifyAndClearExpectations(observer_.get());
2364458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca      EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
2374458695bdafb13eba639d986e2f20953f0f7445cJosé Fonseca          .Times(AnyNumber())
2380c2ea2433833d5eda8a4fefe1412bf0ea40b14bfJosé Fonseca          .WillRepeatedly(Invoke(this,
2390c2ea2433833d5eda8a4fefe1412bf0ea40b14bfJosé Fonseca                                 &DownloadFileTest::SetUpdateDownloadInfo));
2400c2ea2433833d5eda8a4fefe1412bf0ea40b14bfJosé Fonseca    }
2413dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul  }
2423dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul
2433dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul  DownloadInterruptReason RenameAndUniquify(
2443dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul      const base::FilePath& full_path,
2453dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul      base::FilePath* result_path_p) {
2463dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
2473dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
2483dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    bool callback_was_called(false);
2493dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    base::FilePath result_path;
2503dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul
2513dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    download_file_->RenameAndUniquify(
2523dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul        full_path, base::Bind(&DownloadFileTest::SetRenameResult,
2533dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul                              weak_ptr_factory.GetWeakPtr(),
2543dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul                              &callback_was_called,
2553dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul                              &result_reason, result_path_p));
2563dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    loop_.RunUntilIdle();
2573dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul
2583dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    EXPECT_TRUE(callback_was_called);
2593dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    return result_reason;
2603dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul  }
2613dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul
2623dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul  DownloadInterruptReason RenameAndAnnotate(
2633dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul      const base::FilePath& full_path,
2643dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul      base::FilePath* result_path_p) {
2653dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
2663dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
2673dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    bool callback_was_called(false);
2683dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    base::FilePath result_path;
2693dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul
2703dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    download_file_->RenameAndAnnotate(
2713dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul        full_path, base::Bind(&DownloadFileTest::SetRenameResult,
2723dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul                              weak_ptr_factory.GetWeakPtr(),
2733dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul                              &callback_was_called,
2743dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul                              &result_reason, result_path_p));
2753dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    loop_.RunUntilIdle();
2763dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul
2773dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul    EXPECT_TRUE(callback_was_called);
278fcf532ce6f4812d3cc0d3a0697c965fa354dd697Brian Paul    return result_reason;
2793dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul  }
2803dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul
281fcf532ce6f4812d3cc0d3a0697c965fa354dd697Brian Paul protected:
2823dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul  scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_;
2833dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul  base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_;
2843dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul
2853dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul  // DownloadFile instance we are testing.
2863dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul  scoped_ptr<DownloadFile> download_file_;
2873dcb25364fc3b8570dfe240e5b1e6fa278bf0911Brian Paul
28845d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  // Stream for sending data into the download file.
28945d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  // Owned by download_file_; will be alive for lifetime of download_file_.
29045d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  StrictMock<MockByteStreamReader>* input_stream_;
29145d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul
29245d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  // Sink callback data for stream.
29345d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  base::Closure sink_callback_;
29445d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul
29545d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  // Latest update sent to the observer.
29645d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  int64 bytes_;
29745d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  int64 bytes_per_sec_;
29845d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  std::string hash_state_;
29945d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul
30045d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  base::MessageLoop loop_;
30145d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul
30245d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul private:
30345d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  void SetRenameResult(bool* called_p,
30445d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul                       DownloadInterruptReason* reason_p,
30545d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul                       base::FilePath* result_path_p,
30645d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul                       DownloadInterruptReason reason,
30745d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul                       const base::FilePath& result_path) {
30845d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul    if (called_p)
30945d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul      *called_p = true;
31045d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul    if (reason_p)
31145d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul      *reason_p = reason;
31245d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul    if (result_path_p)
31345d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul      *result_path_p = result_path;
31445d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  }
31545d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul
31645d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  // UI thread.
31745d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  BrowserThreadImpl ui_thread_;
31845d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  // File thread to satisfy debug checks in DownloadFile.
31945d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  BrowserThreadImpl file_thread_;
32045d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul
32145d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  // Keep track of what data should be saved to the disk file.
32245d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul  std::string expected_data_;
32345d6289fab1aa012f265e5b51a10c2a07c85679bBrian Paul};
3249493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonseca
3259493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonsecaconst char* DownloadFileTest::kTestData1 =
3269493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonseca    "Let's write some data to the file!\n";
327b4835ea03d64261da5a892f9590c9977b06920e8José Fonsecaconst char* DownloadFileTest::kTestData2 = "Writing more data.\n";
3289493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonsecaconst char* DownloadFileTest::kTestData3 = "Final line.";
3299493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonsecaconst char* DownloadFileTest::kDataHash =
3309493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonseca    "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8";
3319493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonseca
3329493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonsecaconst uint32 DownloadFileTest::kDummyDownloadId = 23;
3339493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonsecaconst int DownloadFileTest::kDummyChildId = 3;
3349493260fdcef4a8238b9d9a9dc3e753dd89810feJosé Fonsecaconst int DownloadFileTest::kDummyRequestId = 67;
335
336// Rename the file before any data is downloaded, after some has, after it all
337// has, and after it's closed.
338TEST_F(DownloadFileTest, RenameFileFinal) {
339  ASSERT_TRUE(CreateDownloadFile(0, true));
340  base::FilePath initial_path(download_file_->FullPath());
341  EXPECT_TRUE(base::PathExists(initial_path));
342  base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
343  base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2"));
344  base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3"));
345  base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4"));
346  base::FilePath path_5(initial_path.InsertBeforeExtensionASCII("_5"));
347  base::FilePath output_path;
348
349  // Rename the file before downloading any data.
350  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
351            RenameAndUniquify(path_1, &output_path));
352  base::FilePath renamed_path = download_file_->FullPath();
353  EXPECT_EQ(path_1, renamed_path);
354  EXPECT_EQ(path_1, output_path);
355
356  // Check the files.
357  EXPECT_FALSE(base::PathExists(initial_path));
358  EXPECT_TRUE(base::PathExists(path_1));
359
360  // Download the data.
361  const char* chunks1[] = { kTestData1, kTestData2 };
362  AppendDataToFile(chunks1, 2);
363
364  // Rename the file after downloading some data.
365  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
366            RenameAndUniquify(path_2, &output_path));
367  renamed_path = download_file_->FullPath();
368  EXPECT_EQ(path_2, renamed_path);
369  EXPECT_EQ(path_2, output_path);
370
371  // Check the files.
372  EXPECT_FALSE(base::PathExists(path_1));
373  EXPECT_TRUE(base::PathExists(path_2));
374
375  const char* chunks2[] = { kTestData3 };
376  AppendDataToFile(chunks2, 1);
377
378  // Rename the file after downloading all the data.
379  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
380            RenameAndUniquify(path_3, &output_path));
381  renamed_path = download_file_->FullPath();
382  EXPECT_EQ(path_3, renamed_path);
383  EXPECT_EQ(path_3, output_path);
384
385  // Check the files.
386  EXPECT_FALSE(base::PathExists(path_2));
387  EXPECT_TRUE(base::PathExists(path_3));
388
389  // Should not be able to get the hash until the file is closed.
390  std::string hash;
391  EXPECT_FALSE(download_file_->GetHash(&hash));
392  FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
393  loop_.RunUntilIdle();
394
395  // Rename the file after downloading all the data and closing the file.
396  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
397            RenameAndUniquify(path_4, &output_path));
398  renamed_path = download_file_->FullPath();
399  EXPECT_EQ(path_4, renamed_path);
400  EXPECT_EQ(path_4, output_path);
401
402  // Check the files.
403  EXPECT_FALSE(base::PathExists(path_3));
404  EXPECT_TRUE(base::PathExists(path_4));
405
406  // Check the hash.
407  EXPECT_TRUE(download_file_->GetHash(&hash));
408  EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
409
410  // Check that a rename with overwrite to an existing file succeeds.
411  std::string file_contents;
412  ASSERT_FALSE(base::PathExists(path_5));
413  static const char file_data[] = "xyzzy";
414  ASSERT_EQ(static_cast<int>(sizeof(file_data) - 1),
415            base::WriteFile(path_5, file_data, sizeof(file_data) - 1));
416  ASSERT_TRUE(base::PathExists(path_5));
417  EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents));
418  EXPECT_EQ(std::string(file_data), file_contents);
419
420  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
421            RenameAndAnnotate(path_5, &output_path));
422  EXPECT_EQ(path_5, output_path);
423
424  file_contents = "";
425  EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents));
426  EXPECT_NE(std::string(file_data), file_contents);
427
428  DestroyDownloadFile(0);
429}
430
431// Test to make sure the rename uniquifies if we aren't overwriting
432// and there's a file where we're aiming.
433TEST_F(DownloadFileTest, RenameUniquifies) {
434  ASSERT_TRUE(CreateDownloadFile(0, true));
435  base::FilePath initial_path(download_file_->FullPath());
436  EXPECT_TRUE(base::PathExists(initial_path));
437  base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
438  base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)"));
439
440  ASSERT_FALSE(base::PathExists(path_1));
441  static const char file_data[] = "xyzzy";
442  ASSERT_EQ(static_cast<int>(sizeof(file_data)),
443            base::WriteFile(path_1, file_data, sizeof(file_data)));
444  ASSERT_TRUE(base::PathExists(path_1));
445
446  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL));
447  EXPECT_TRUE(base::PathExists(path_1_suffixed));
448
449  FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
450  loop_.RunUntilIdle();
451  DestroyDownloadFile(0);
452}
453
454// Test to make sure we get the proper error on failure.
455TEST_F(DownloadFileTest, RenameError) {
456  ASSERT_TRUE(CreateDownloadFile(0, true));
457  base::FilePath initial_path(download_file_->FullPath());
458
459  // Create a subdirectory.
460  base::FilePath tempdir(
461      initial_path.DirName().Append(FILE_PATH_LITERAL("tempdir")));
462  ASSERT_TRUE(base::CreateDirectory(tempdir));
463  base::FilePath target_path(tempdir.Append(initial_path.BaseName()));
464
465  // Targets
466  base::FilePath target_path_suffixed(
467      target_path.InsertBeforeExtensionASCII(" (1)"));
468  ASSERT_FALSE(base::PathExists(target_path));
469  ASSERT_FALSE(base::PathExists(target_path_suffixed));
470
471  // Make the directory unwritable and try to rename within it.
472  {
473    file_util::PermissionRestorer restorer(tempdir);
474    ASSERT_TRUE(file_util::MakeFileUnwritable(tempdir));
475
476    // Expect nulling out of further processing.
477    EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback()));
478    EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
479              RenameAndAnnotate(target_path, NULL));
480    EXPECT_FALSE(base::PathExists(target_path_suffixed));
481  }
482
483  FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
484  loop_.RunUntilIdle();
485  DestroyDownloadFile(0);
486}
487
488// Various tests of the StreamActive method.
489TEST_F(DownloadFileTest, StreamEmptySuccess) {
490  ASSERT_TRUE(CreateDownloadFile(0, true));
491  base::FilePath initial_path(download_file_->FullPath());
492  EXPECT_TRUE(base::PathExists(initial_path));
493
494  // Test that calling the sink_callback_ on an empty stream shouldn't
495  // do anything.
496  AppendDataToFile(NULL, 0);
497
498  // Finish the download this way and make sure we see it on the
499  // observer.
500  EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
501  FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, false);
502  loop_.RunUntilIdle();
503
504  DestroyDownloadFile(0);
505}
506
507TEST_F(DownloadFileTest, StreamEmptyError) {
508  ASSERT_TRUE(CreateDownloadFile(0, true));
509  base::FilePath initial_path(download_file_->FullPath());
510  EXPECT_TRUE(base::PathExists(initial_path));
511
512  // Finish the download in error and make sure we see it on the
513  // observer.
514  EXPECT_CALL(*(observer_.get()),
515              DestinationError(
516                  DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
517      .WillOnce(InvokeWithoutArgs(
518          this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
519
520  // If this next EXPECT_CALL fails flakily, it's probably a real failure.
521  // We'll be getting a stream of UpdateDownload calls from the timer, and
522  // the last one may have the correct information even if the failure
523  // doesn't produce an update, as the timer update may have triggered at the
524  // same time.
525  EXPECT_CALL(*(observer_.get()), CurrentUpdateStatus(0, _, _));
526
527  FinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false);
528
529  loop_.RunUntilIdle();
530
531  DestroyDownloadFile(0);
532}
533
534TEST_F(DownloadFileTest, StreamNonEmptySuccess) {
535  ASSERT_TRUE(CreateDownloadFile(0, true));
536  base::FilePath initial_path(download_file_->FullPath());
537  EXPECT_TRUE(base::PathExists(initial_path));
538
539  const char* chunks1[] = { kTestData1, kTestData2 };
540  ::testing::Sequence s1;
541  SetupDataAppend(chunks1, 2, s1);
542  SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, s1);
543  EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
544  sink_callback_.Run();
545  VerifyStreamAndSize();
546  loop_.RunUntilIdle();
547  DestroyDownloadFile(0);
548}
549
550TEST_F(DownloadFileTest, StreamNonEmptyError) {
551  ASSERT_TRUE(CreateDownloadFile(0, true));
552  base::FilePath initial_path(download_file_->FullPath());
553  EXPECT_TRUE(base::PathExists(initial_path));
554
555  const char* chunks1[] = { kTestData1, kTestData2 };
556  ::testing::Sequence s1;
557  SetupDataAppend(chunks1, 2, s1);
558  SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, s1);
559
560  EXPECT_CALL(*(observer_.get()),
561              DestinationError(
562                  DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
563      .WillOnce(InvokeWithoutArgs(
564          this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
565
566  // If this next EXPECT_CALL fails flakily, it's probably a real failure.
567  // We'll be getting a stream of UpdateDownload calls from the timer, and
568  // the last one may have the correct information even if the failure
569  // doesn't produce an update, as the timer update may have triggered at the
570  // same time.
571  EXPECT_CALL(*(observer_.get()),
572              CurrentUpdateStatus(strlen(kTestData1) + strlen(kTestData2),
573                                  _, _));
574
575  sink_callback_.Run();
576  loop_.RunUntilIdle();
577  VerifyStreamAndSize();
578  DestroyDownloadFile(0);
579}
580
581// Send some data, wait 3/4s of a second, run the message loop, and
582// confirm the values the observer received are correct.
583TEST_F(DownloadFileTest, ConfirmUpdate) {
584  CreateDownloadFile(0, true);
585
586  const char* chunks1[] = { kTestData1, kTestData2 };
587  AppendDataToFile(chunks1, 2);
588
589  // Run the message loops for 750ms and check for results.
590  loop_.PostDelayedTask(FROM_HERE,
591                        base::MessageLoop::QuitClosure(),
592                        base::TimeDelta::FromMilliseconds(750));
593  loop_.Run();
594
595  EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)),
596            bytes_);
597  EXPECT_EQ(download_file_->GetHashState(), hash_state_);
598
599  FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
600  DestroyDownloadFile(0);
601}
602
603}  // namespace content
604