1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/child/fileapi/webfilewriter_base.h"
6
7#include "base/logging.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/message_loop/message_loop.h"
10#include "base/strings/utf_string_conversions.h"
11#include "testing/gtest/include/gtest/gtest.h"
12#include "third_party/WebKit/public/platform/WebFileError.h"
13#include "third_party/WebKit/public/platform/WebFileWriterClient.h"
14#include "third_party/WebKit/public/platform/WebURL.h"
15#include "url/gurl.h"
16
17namespace content {
18
19namespace {
20
21// We use particular offsets to trigger particular behaviors
22// in the TestableFileWriter.
23const int kNoOffset = -1;
24const int kBasicFileTruncate_Offset = 1;
25const int kErrorFileTruncate_Offset = 2;
26const int kCancelFileTruncate_Offset = 3;
27const int kCancelFailedTruncate_Offset = 4;
28const int kBasicFileWrite_Offset = 1;
29const int kErrorFileWrite_Offset = 2;
30const int kMultiFileWrite_Offset = 3;
31const int kCancelFileWriteBeforeCompletion_Offset = 4;
32const int kCancelFileWriteAfterCompletion_Offset = 5;
33
34GURL mock_path_as_gurl() {
35  return GURL("MockPath");
36}
37
38}  // namespace
39
40class TestableFileWriter : public WebFileWriterBase {
41 public:
42  explicit TestableFileWriter(blink::WebFileWriterClient* client)
43      : WebFileWriterBase(mock_path_as_gurl(), client) {
44    reset();
45  }
46
47  void reset() {
48    received_truncate_ = false;
49    received_truncate_path_ = GURL();
50    received_truncate_offset_ = kNoOffset;
51    received_write_ = false;
52    received_write_path_ = GURL();
53    received_write_offset_ = kNoOffset;
54    received_write_blob_uuid_ = std::string();
55    received_cancel_ = false;
56  }
57
58  bool received_truncate_;
59  GURL received_truncate_path_;
60  int64 received_truncate_offset_;
61  bool received_write_;
62  GURL received_write_path_;
63  std::string received_write_blob_uuid_;
64  int64 received_write_offset_;
65  bool received_cancel_;
66
67 protected:
68  virtual void DoTruncate(const GURL& path, int64 offset) OVERRIDE {
69    received_truncate_ = true;
70    received_truncate_path_ = path;
71    received_truncate_offset_ = offset;
72
73    if (offset == kBasicFileTruncate_Offset) {
74      DidSucceed();
75    } else if (offset == kErrorFileTruncate_Offset) {
76      DidFail(base::File::FILE_ERROR_NOT_FOUND);
77    } else if (offset == kCancelFileTruncate_Offset) {
78      cancel();
79      DidSucceed();  // truncate completion
80      DidSucceed();  // cancel completion
81    } else if (offset == kCancelFailedTruncate_Offset) {
82      cancel();
83      DidFail(base::File::FILE_ERROR_NOT_FOUND);  // truncate completion
84      DidSucceed();  // cancel completion
85    } else {
86      FAIL();
87    }
88  }
89
90  virtual void DoWrite(
91        const GURL& path, const std::string& blob_uuid,
92        int64 offset) OVERRIDE {
93    received_write_ = true;
94    received_write_path_ = path;
95    received_write_offset_ = offset;
96    received_write_blob_uuid_ = blob_uuid;
97
98    if (offset == kBasicFileWrite_Offset) {
99      DidWrite(1, true);
100    } else if (offset == kErrorFileWrite_Offset) {
101      DidFail(base::File::FILE_ERROR_NOT_FOUND);
102    } else if (offset == kMultiFileWrite_Offset) {
103      DidWrite(1, false);
104      DidWrite(1, false);
105      DidWrite(1, true);
106    } else if (offset == kCancelFileWriteBeforeCompletion_Offset) {
107      DidWrite(1, false);
108      cancel();
109      DidWrite(1, false);
110      DidWrite(1, false);
111      DidFail(base::File::FILE_ERROR_FAILED);  // write completion
112      DidSucceed();  // cancel completion
113    } else if (offset == kCancelFileWriteAfterCompletion_Offset) {
114      DidWrite(1, false);
115      cancel();
116      DidWrite(1, false);
117      DidWrite(1, false);
118      DidWrite(1, true);  // write completion
119      DidFail(base::File::FILE_ERROR_FAILED);  // cancel completion
120    } else {
121      FAIL();
122    }
123  }
124
125  virtual void DoCancel() OVERRIDE {
126    received_cancel_ = true;
127  }
128};
129
130class FileWriterTest : public testing::Test,
131                       public blink::WebFileWriterClient {
132 public:
133  FileWriterTest() {
134    reset();
135  }
136
137  blink::WebFileWriter* writer() {
138    return testable_writer_.get();
139  }
140
141  // WebFileWriterClient overrides
142  virtual void didWrite(long long bytes, bool complete) {
143    EXPECT_FALSE(received_did_write_complete_);
144    ++received_did_write_count_;
145    received_did_write_bytes_total_ += bytes;
146    if (complete)
147      received_did_write_complete_ = true;
148
149    if (delete_in_client_callback_)
150      testable_writer_.reset(NULL);
151  }
152
153  virtual void didTruncate() {
154    EXPECT_FALSE(received_did_truncate_);
155    received_did_truncate_ = true;
156    if (delete_in_client_callback_)
157      testable_writer_.reset(NULL);
158  }
159
160  virtual void didFail(blink::WebFileError error) {
161    EXPECT_FALSE(received_did_fail_);
162    received_did_fail_ = true;
163    fail_error_received_ = error;
164    if (delete_in_client_callback_)
165      testable_writer_.reset(NULL);
166  }
167
168 protected:
169  void reset() {
170    testable_writer_.reset(new TestableFileWriter(this));
171    delete_in_client_callback_ = false;
172    received_did_write_count_ = 0;
173    received_did_write_bytes_total_ = 0;
174    received_did_write_complete_ = false;
175    received_did_truncate_ = false;
176    received_did_fail_ = false;
177    fail_error_received_ = static_cast<blink::WebFileError>(0);
178  }
179
180  scoped_ptr<TestableFileWriter> testable_writer_;
181  bool delete_in_client_callback_;
182
183  // Observed WebFileWriterClient artifacts.
184  int received_did_write_count_;
185  long long received_did_write_bytes_total_;
186  bool received_did_write_complete_;
187  bool received_did_truncate_;
188  bool received_did_fail_;
189  blink::WebFileError fail_error_received_;
190
191  DISALLOW_COPY_AND_ASSIGN(FileWriterTest);
192};
193
194TEST_F(FileWriterTest, BasicFileWrite) {
195  // Call the webkit facing api.
196  const std::string kBlobId("1234");
197  writer()->write(kBasicFileWrite_Offset,
198                  blink::WebString::fromUTF8(kBlobId));
199
200  // Check that the derived class gets called correctly.
201  EXPECT_TRUE(testable_writer_->received_write_);
202  EXPECT_EQ(testable_writer_->received_write_path_,
203            mock_path_as_gurl());
204  EXPECT_EQ(kBasicFileWrite_Offset,
205            testable_writer_->received_write_offset_);
206  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
207  EXPECT_FALSE(testable_writer_->received_truncate_);
208  EXPECT_FALSE(testable_writer_->received_cancel_);
209
210  // Check that the client gets called correctly.
211  EXPECT_EQ(1, received_did_write_count_);
212  EXPECT_TRUE(received_did_write_complete_);
213  EXPECT_EQ(1, received_did_write_bytes_total_);
214  EXPECT_FALSE(received_did_truncate_);
215  EXPECT_FALSE(received_did_fail_);
216}
217
218TEST_F(FileWriterTest, BasicFileTruncate) {
219  // Call the webkit facing api.
220  writer()->truncate(kBasicFileTruncate_Offset);
221
222  // Check that the derived class gets called correctly.
223  EXPECT_TRUE(testable_writer_->received_truncate_);
224  EXPECT_EQ(mock_path_as_gurl(),
225            testable_writer_->received_truncate_path_);
226  EXPECT_EQ(kBasicFileTruncate_Offset,
227            testable_writer_->received_truncate_offset_);
228  EXPECT_FALSE(testable_writer_->received_write_);
229  EXPECT_FALSE(testable_writer_->received_cancel_);
230
231  // Check that the client gets called correctly.
232  EXPECT_TRUE(received_did_truncate_);
233  EXPECT_EQ(0, received_did_write_count_);
234  EXPECT_FALSE(received_did_fail_);
235}
236
237TEST_F(FileWriterTest, ErrorFileWrite) {
238  // Call the webkit facing api.
239  const std::string kBlobId("1234");
240  writer()->write(kErrorFileWrite_Offset,
241                  blink::WebString::fromUTF8(kBlobId));
242
243  // Check that the derived class gets called correctly.
244  EXPECT_TRUE(testable_writer_->received_write_);
245  EXPECT_EQ(testable_writer_->received_write_path_,
246            mock_path_as_gurl());
247  EXPECT_EQ(kErrorFileWrite_Offset,
248            testable_writer_->received_write_offset_);
249  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
250  EXPECT_FALSE(testable_writer_->received_truncate_);
251  EXPECT_FALSE(testable_writer_->received_cancel_);
252
253  // Check that the client gets called correctly.
254  EXPECT_TRUE(received_did_fail_);
255  EXPECT_EQ(blink::WebFileErrorNotFound, fail_error_received_);
256  EXPECT_EQ(0, received_did_write_count_);
257  EXPECT_FALSE(received_did_truncate_);
258}
259
260TEST_F(FileWriterTest, ErrorFileTruncate) {
261  // Call the webkit facing api.
262  writer()->truncate(kErrorFileTruncate_Offset);
263
264  // Check that the derived class gets called correctly.
265  EXPECT_TRUE(testable_writer_->received_truncate_);
266  EXPECT_EQ(mock_path_as_gurl(),
267            testable_writer_->received_truncate_path_);
268  EXPECT_EQ(kErrorFileTruncate_Offset,
269            testable_writer_->received_truncate_offset_);
270  EXPECT_FALSE(testable_writer_->received_write_);
271  EXPECT_FALSE(testable_writer_->received_cancel_);
272
273  // Check that the client gets called correctly.
274  EXPECT_TRUE(received_did_fail_);
275  EXPECT_EQ(blink::WebFileErrorNotFound, fail_error_received_);
276  EXPECT_FALSE(received_did_truncate_);
277  EXPECT_EQ(0, received_did_write_count_);
278}
279
280TEST_F(FileWriterTest, MultiFileWrite) {
281  // Call the webkit facing api.
282  const std::string kBlobId("1234");
283  writer()->write(kMultiFileWrite_Offset,
284                  blink::WebString::fromUTF8(kBlobId));
285
286  // Check that the derived class gets called correctly.
287  EXPECT_TRUE(testable_writer_->received_write_);
288  EXPECT_EQ(testable_writer_->received_write_path_,
289            mock_path_as_gurl());
290  EXPECT_EQ(kMultiFileWrite_Offset,
291            testable_writer_->received_write_offset_);
292  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
293  EXPECT_FALSE(testable_writer_->received_truncate_);
294  EXPECT_FALSE(testable_writer_->received_cancel_);
295
296  // Check that the client gets called correctly.
297  EXPECT_EQ(3, received_did_write_count_);
298  EXPECT_TRUE(received_did_write_complete_);
299  EXPECT_EQ(3, received_did_write_bytes_total_);
300  EXPECT_FALSE(received_did_truncate_);
301  EXPECT_FALSE(received_did_fail_);
302}
303
304TEST_F(FileWriterTest, CancelFileWriteBeforeCompletion) {
305  // Call the webkit facing api.
306  const std::string kBlobId("1234");
307  writer()->write(kCancelFileWriteBeforeCompletion_Offset,
308                  blink::WebString::fromUTF8(kBlobId));
309
310  // Check that the derived class gets called correctly.
311  EXPECT_TRUE(testable_writer_->received_write_);
312  EXPECT_EQ(testable_writer_->received_write_path_,
313            mock_path_as_gurl());
314  EXPECT_EQ(kCancelFileWriteBeforeCompletion_Offset,
315            testable_writer_->received_write_offset_);
316  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
317  EXPECT_TRUE(testable_writer_->received_cancel_);
318  EXPECT_FALSE(testable_writer_->received_truncate_);
319
320  // Check that the client gets called correctly.
321  EXPECT_TRUE(received_did_fail_);
322  EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_);
323  EXPECT_EQ(1, received_did_write_count_);
324  EXPECT_FALSE(received_did_write_complete_);
325  EXPECT_EQ(1, received_did_write_bytes_total_);
326  EXPECT_FALSE(received_did_truncate_);
327}
328
329TEST_F(FileWriterTest, CancelFileWriteAfterCompletion) {
330  // Call the webkit facing api.
331  const std::string kBlobId("1234");
332  writer()->write(kCancelFileWriteAfterCompletion_Offset,
333                  blink::WebString::fromUTF8(kBlobId));
334
335  // Check that the derived class gets called correctly.
336  EXPECT_TRUE(testable_writer_->received_write_);
337  EXPECT_EQ(testable_writer_->received_write_path_,
338            mock_path_as_gurl());
339  EXPECT_EQ(kCancelFileWriteAfterCompletion_Offset,
340            testable_writer_->received_write_offset_);
341  EXPECT_EQ(kBlobId, testable_writer_->received_write_blob_uuid_);
342  EXPECT_TRUE(testable_writer_->received_cancel_);
343  EXPECT_FALSE(testable_writer_->received_truncate_);
344
345  // Check that the client gets called correctly.
346  EXPECT_TRUE(received_did_fail_);
347  EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_);
348  EXPECT_EQ(1, received_did_write_count_);
349  EXPECT_FALSE(received_did_write_complete_);
350  EXPECT_EQ(1, received_did_write_bytes_total_);
351  EXPECT_FALSE(received_did_truncate_);
352}
353
354TEST_F(FileWriterTest, CancelFileTruncate) {
355  // Call the webkit facing api.
356  writer()->truncate(kCancelFileTruncate_Offset);
357
358  // Check that the derived class gets called correctly.
359  EXPECT_TRUE(testable_writer_->received_truncate_);
360  EXPECT_EQ(mock_path_as_gurl(),
361            testable_writer_->received_truncate_path_);
362  EXPECT_EQ(kCancelFileTruncate_Offset,
363            testable_writer_->received_truncate_offset_);
364  EXPECT_TRUE(testable_writer_->received_cancel_);
365  EXPECT_FALSE(testable_writer_->received_write_);
366
367  // Check that the client gets called correctly.
368  EXPECT_TRUE(received_did_fail_);
369  EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_);
370  EXPECT_FALSE(received_did_truncate_);
371  EXPECT_EQ(0, received_did_write_count_);
372}
373
374TEST_F(FileWriterTest, CancelFailedTruncate) {
375  // Call the webkit facing api.
376  writer()->truncate(kCancelFailedTruncate_Offset);
377
378  // Check that the derived class gets called correctly.
379  EXPECT_TRUE(testable_writer_->received_truncate_);
380  EXPECT_EQ(mock_path_as_gurl(),
381            testable_writer_->received_truncate_path_);
382  EXPECT_EQ(kCancelFailedTruncate_Offset,
383            testable_writer_->received_truncate_offset_);
384  EXPECT_TRUE(testable_writer_->received_cancel_);
385  EXPECT_FALSE(testable_writer_->received_write_);
386
387  // Check that the client gets called correctly.
388  EXPECT_TRUE(received_did_fail_);
389  EXPECT_EQ(blink::WebFileErrorAbort, fail_error_received_);
390  EXPECT_FALSE(received_did_truncate_);
391  EXPECT_EQ(0, received_did_write_count_);
392}
393
394TEST_F(FileWriterTest, DeleteInCompletionCallbacks) {
395  const std::string kBlobId("1234");
396  delete_in_client_callback_ = true;
397  writer()->write(kBasicFileWrite_Offset,
398                  blink::WebString::fromUTF8(kBlobId));
399  EXPECT_FALSE(testable_writer_.get());
400
401  reset();
402  delete_in_client_callback_ = true;
403  writer()->truncate(kBasicFileTruncate_Offset);
404  EXPECT_FALSE(testable_writer_.get());
405
406  reset();
407  delete_in_client_callback_ = true;
408  writer()->write(kErrorFileWrite_Offset,
409                  blink::WebString::fromUTF8(kBlobId));
410  EXPECT_FALSE(testable_writer_.get());
411
412  reset();
413  delete_in_client_callback_ = true;
414  writer()->truncate(kErrorFileTruncate_Offset);
415  EXPECT_FALSE(testable_writer_.get());
416
417  // Not crashing counts as passing.
418}
419
420}  // namespace content
421