summaryrefslogtreecommitdiffstats
path: root/content/test/test_file_error_injector.h
blob: f5f4978c2c64cf04a10a98674b10a14dcb0c331d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_TEST_TEST_FILE_ERROR_INJECTOR_H_
#define CONTENT_TEST_TEST_FILE_ERROR_INJECTOR_H_
#pragma once

#include <map>
#include <string>

#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/net_errors.h"

class GURL;

namespace content {

class DownloadId;
class DownloadFileWithErrorsFactory;

// Test helper for injecting errors into download file operations.
// All errors for a download must be injected before it starts.
// This class needs to be |RefCountedThreadSafe| because the implementation
// is referenced by other classes that live past the time when the user is
// nominally done with it.  These classes are internal to content/.
//
// NOTE: No more than one download with the same URL can be in progress at
// the same time.  You can have multiple simultaneous downloads as long as the
// URLs are different, as the URLs are used as keys to get information about
// the download.
//
// Example:
//
// FileErrorInfo a = { url1, ... };
// FileErrorInfo b = { url2, ... };
//
// scoped_refptr<TestFileErrorInjector> injector =
//     TestFileErrorInjector::Create();
//
// injector->AddError(a);
// injector->AddError(b);
// injector->InjectErrors();
//
// download_manager->DownloadUrl(url1, ...);
// download_manager->DownloadUrl(url2, ...);
// ... wait for downloads to finish or get an injected error ...
class TestFileErrorInjector
    : public base::RefCountedThreadSafe<TestFileErrorInjector> {
 public:
  enum FileOperationCode {
    FILE_OPERATION_INITIALIZE,
    FILE_OPERATION_WRITE,
    FILE_OPERATION_RENAME
  };

  // Structure that encapsulates the information needed to inject a file error.
  struct FileErrorInfo {
    std::string url;  // Full URL of the download.  Identifies the download.
    FileOperationCode code;  // Operation to affect.
    int operation_instance;  // 0-based count of operation calls, for each code.
    net::Error net_error;  // Error to inject.
  };

  typedef std::map<std::string, FileErrorInfo> ErrorMap;

  // Creates an instance.  May only be called once.
  // Lives until all callbacks (in the implementation) are complete and the
  // creator goes out of scope.
  static scoped_refptr<TestFileErrorInjector> Create();

  // Adds an error.
  // Must be called before |InjectErrors()| for a particular download file.
  // It is an error to call |AddError()| more than once for the same file
  // (URL), unless you call |ClearErrors()| in between them.
  bool AddError(const FileErrorInfo& error_info);

  // Clears all errors.
  // Only affects files created after the next call to InjectErrors().
  void ClearErrors();

  // Injects the errors such that new download files will be affected.
  // The download system must already be initialized before calling this.
  // Multiple calls are allowed, but only useful if the errors have changed.
  // Replaces the injected error list.
  bool InjectErrors();

  // Tells how many files are currently open.
  size_t CurrentFileCount() const;

  // Tells how many files have ever been open (since construction or the
  // last call to |ClearFoundFiles()|).
  size_t TotalFileCount() const;

  // Returns whether or not a file matching |url| has been created.
  bool HadFile(const GURL& url) const;

  // Gets the download ID associated with the file matching |url|.
  const content::DownloadId GetId(const GURL& url) const;

  // Resets the found file list.
  void ClearFoundFiles();

  static std::string DebugString(FileOperationCode code);

 private:
  friend class base::RefCountedThreadSafe<TestFileErrorInjector>;

  typedef std::map<GURL, content::DownloadId> FileMap;

  TestFileErrorInjector();

  virtual ~TestFileErrorInjector();

  void AddFactory(scoped_ptr<DownloadFileWithErrorsFactory> factory);

  void InjectErrorsOnFileThread(ErrorMap map,
                                DownloadFileWithErrorsFactory* factory);

  // Callbacks from the download file, to record lifetimes.
  // These may be called on any thread.
  void RecordDownloadFileConstruction(const GURL& url, content::DownloadId id);
  void RecordDownloadFileDestruction(const GURL& url);

  // These run on the UI thread.
  void DownloadFileCreated(GURL url, content::DownloadId id);
  void DestroyingDownloadFile(GURL url);

  // All the data is used on the UI thread.
  // Our injected error list, mapped by URL.  One per file.
  ErrorMap injected_errors_;

  // Keep track of active DownloadFiles.
  FileMap files_;

  // Keep track of found DownloadFiles.
  FileMap found_files_;

  // The factory we created.  May outlive this class.
  DownloadFileWithErrorsFactory* created_factory_;

  DISALLOW_COPY_AND_ASSIGN(TestFileErrorInjector);
};

}  // namespace content

#endif  // CONTENT_TEST_TEST_FILE_ERROR_INJECTOR_H_