1 // Copyright 2018 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 "chrome/chrome_cleaner/http/mock_http_agent_factory.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <memory>
11 #include <string>
12 #include <vector>
13
14 #include "base/check.h"
15 #include "chrome/chrome_cleaner/http/http_agent.h"
16 #include "chrome/chrome_cleaner/http/http_agent_factory.h"
17 #include "chrome/chrome_cleaner/http/http_response.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace chrome_cleaner {
21
22 namespace {
23
24 // Class that provides a response based on how the MockHttpAgentConfig is
25 // configured.
26 class MockHttpResponse : public chrome_cleaner::HttpResponse {
27 public:
MockHttpResponse(MockHttpAgentConfig * config)28 explicit MockHttpResponse(MockHttpAgentConfig* config) : config_(config) {
29 DCHECK(config);
30 }
31
32 ~MockHttpResponse() override = default;
33
34 // chrome_cleaner::HttpResponse:
GetStatusCode(uint16_t * status_code)35 bool GetStatusCode(uint16_t* status_code) override {
36 if (config_->GetCurrentCalls().get_status_code_succeeds) {
37 *status_code = static_cast<uint16_t>(
38 config_->GetCurrentCalls().get_status_code_result);
39 }
40 return config_->GetCurrentCalls().get_status_code_succeeds;
41 }
42
GetContentLength(bool * has_content_length,uint32_t * content_length)43 bool GetContentLength(bool* has_content_length,
44 uint32_t* content_length) override {
45 ADD_FAILURE() << "This method should not be called.";
46 return false;
47 }
48
GetContentType(bool * has_content_type,std::wstring * content_type)49 bool GetContentType(bool* has_content_type,
50 std::wstring* content_type) override {
51 ADD_FAILURE() << "This method should not be called.";
52 return false;
53 }
54
HasData(bool * has_data)55 bool HasData(bool* has_data) override {
56 if (config_->GetCurrentCalls().has_data_succeeds)
57 *has_data = !config_->GetCurrentCalls().read_data_result.empty();
58 return config_->GetCurrentCalls().has_data_succeeds;
59 }
60
ReadData(char * buffer,uint32_t * count)61 bool ReadData(char* buffer, uint32_t* count) override {
62 MockHttpAgentConfig::Calls& calls = config_->GetCurrentCalls();
63
64 bool succeeds = calls.read_data_succeeds_by_default;
65 if (!calls.read_data_success_sequence.empty()) {
66 succeeds = calls.read_data_success_sequence[0];
67 calls.read_data_success_sequence.erase(
68 calls.read_data_success_sequence.begin());
69 }
70
71 if (succeeds)
72 config_->ReadData(buffer, count);
73 return succeeds;
74 }
75
76 private:
77 MockHttpAgentConfig* config_{nullptr};
78
79 DISALLOW_COPY_AND_ASSIGN(MockHttpResponse);
80 };
81
82 // Class that acts as an HttpAgent based on how the MockHttpAgentConfig is
83 // configured.
84 class MockHttpAgent : public chrome_cleaner::HttpAgent {
85 public:
MockHttpAgent(MockHttpAgentConfig * config)86 explicit MockHttpAgent(MockHttpAgentConfig* config) : config_(config) {
87 DCHECK(config);
88 }
89
90 ~MockHttpAgent() override = default;
91
92 // chrome_cleaner::HttpAgent:
Post(const std::wstring & host,uint16_t port,const std::wstring & path,bool secure,const std::wstring & extra_headers,const std::string & body,const net::NetworkTrafficAnnotationTag &)93 std::unique_ptr<chrome_cleaner::HttpResponse> Post(
94 const std::wstring& host,
95 uint16_t port,
96 const std::wstring& path,
97 bool secure,
98 const std::wstring& extra_headers,
99 const std::string& body,
100 const net::NetworkTrafficAnnotationTag& /*traffic_annotation*/) override {
101 const bool post_succeeds = config_->GetCurrentCalls().request_succeeds;
102 MockHttpAgentConfig::RequestData post_data;
103 post_data.host = host;
104 post_data.port = port;
105 post_data.path = path;
106 post_data.secure = secure;
107 post_data.extra_headers = extra_headers;
108 post_data.body = body;
109 config_->AddRequestData(post_data);
110
111 if (post_succeeds)
112 return std::make_unique<MockHttpResponse>(config_);
113 return std::unique_ptr<MockHttpResponse>();
114 }
115
116 // chrome_cleaner::HttpAgent:
Get(const std::wstring & host,uint16_t port,const std::wstring & path,bool secure,const std::wstring & extra_headers,const net::NetworkTrafficAnnotationTag &)117 std::unique_ptr<chrome_cleaner::HttpResponse> Get(
118 const std::wstring& host,
119 uint16_t port,
120 const std::wstring& path,
121 bool secure,
122 const std::wstring& extra_headers,
123 const net::NetworkTrafficAnnotationTag& /*traffic_annotation*/) override {
124 const bool get_succeeds = config_->GetCurrentCalls().request_succeeds;
125 MockHttpAgentConfig::RequestData get_data;
126 get_data.host = host;
127 get_data.port = port;
128 get_data.path = path;
129 get_data.secure = secure;
130 get_data.extra_headers = extra_headers;
131 config_->AddRequestData(get_data);
132
133 if (get_succeeds)
134 return std::make_unique<MockHttpResponse>(config_);
135 return std::unique_ptr<MockHttpResponse>();
136 }
137
138 private:
139 MockHttpAgentConfig* config_{nullptr};
140
141 DISALLOW_COPY_AND_ASSIGN(MockHttpAgent);
142 };
143
144 } // namespace
145
Calls(HttpStatus status)146 MockHttpAgentConfig::Calls::Calls(HttpStatus status)
147 : get_status_code_result(status) {}
148
149 MockHttpAgentConfig::Calls::Calls(const Calls& other) = default;
150
151 MockHttpAgentConfig::Calls::~Calls() = default;
152
153 MockHttpAgentConfig::Calls& MockHttpAgentConfig::Calls::operator=(
154 const MockHttpAgentConfig::Calls& other) = default;
155
156 MockHttpAgentConfig::RequestData::RequestData() = default;
157
158 MockHttpAgentConfig::RequestData::RequestData(const RequestData& other) =
159 default;
160
161 MockHttpAgentConfig::RequestData::~RequestData() = default;
162
163 MockHttpAgentConfig::RequestData& MockHttpAgentConfig::RequestData::operator=(
164 const MockHttpAgentConfig::RequestData& other) = default;
165
166 MockHttpAgentConfig::MockHttpAgentConfig() = default;
167
168 MockHttpAgentConfig::~MockHttpAgentConfig() = default;
169
AddCalls(const Calls & calls)170 size_t MockHttpAgentConfig::AddCalls(const Calls& calls) {
171 calls_.push_back(calls);
172 return calls_.size() - 1;
173 }
174
GetCurrentCalls()175 MockHttpAgentConfig::Calls& MockHttpAgentConfig::GetCurrentCalls() {
176 if (current_index_ >= calls_.size()) {
177 static Calls default_calls(HttpStatus::kOk);
178 ADD_FAILURE() << "Did not expect more than " << calls_.size() << " tries";
179 return default_calls;
180 }
181 return calls_[current_index_];
182 }
183
ReadData(char * buffer,uint32_t * count)184 void MockHttpAgentConfig::ReadData(char* buffer, uint32_t* count) {
185 if (current_index_ >= calls_.size()) {
186 ADD_FAILURE() << "Reading data for an unexpected call";
187 *count = 0;
188 return;
189 }
190 Calls& calls = calls_[current_index_];
191 *count =
192 std::min(*count, static_cast<uint32_t>(calls.read_data_result.size()));
193 memcpy(buffer, calls.read_data_result.c_str(), *count);
194 calls.read_data_result = calls.read_data_result.substr(*count);
195 }
196
AddRequestData(const RequestData & request_data)197 void MockHttpAgentConfig::AddRequestData(const RequestData& request_data) {
198 ASSERT_EQ(request_data_.size(), current_index_)
199 << "MockHttpAgentConfig does not support creating multiple agents "
200 << "without calling Post or Get on each before creating the next one. "
201 << "Suggest adding support to MockHttpAgentConfig for that if necessary, "
202 << "or updating your code to avoid this.";
203 request_data_.push_back(request_data);
204 }
205
MockHttpAgentFactory(MockHttpAgentConfig * config)206 MockHttpAgentFactory::MockHttpAgentFactory(MockHttpAgentConfig* config)
207 : config_(config) {
208 DCHECK(config);
209 }
210
211 std::unique_ptr<chrome_cleaner::HttpAgent>
CreateHttpAgent() const212 MockHttpAgentFactory::CreateHttpAgent() const {
213 // Set the configuration index to the next one (one per HttpAgent).
214 if (config_->current_index_ == MockHttpAgentConfig::kInvalidIndex)
215 config_->current_index_ = 0;
216 else
217 ++config_->current_index_;
218
219 return std::make_unique<MockHttpAgent>(config_);
220 }
221
222 } // namespace chrome_cleaner
223