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 "chrome/browser/local_discovery/privet_url_fetcher.h"
6#include "net/url_request/test_url_fetcher_factory.h"
7#include "net/url_request/url_request_test_util.h"
8#include "testing/gmock/include/gmock/gmock.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11using testing::StrictMock;
12
13namespace local_discovery {
14
15namespace {
16
17const char kSamplePrivetURL[] =
18    "http://10.0.0.8:7676/privet/register?action=start";
19const char kSamplePrivetToken[] = "MyToken";
20const char kEmptyPrivetToken[] = "\"\"";
21
22const char kSampleParsableJSON[] = "{ \"hello\" : 2 }";
23const char kSampleUnparsableJSON[] = "{ \"hello\" : }";
24const char kSampleJSONWithError[] = "{ \"error\" : \"unittest_example\" }";
25
26class MockPrivetURLFetcherDelegate : public PrivetURLFetcher::Delegate {
27 public:
28  MockPrivetURLFetcherDelegate() : raw_mode_(false) {
29  }
30
31  virtual ~MockPrivetURLFetcherDelegate() {
32  }
33
34  virtual void OnError(PrivetURLFetcher* fetcher,
35                       PrivetURLFetcher::ErrorType error) OVERRIDE {
36    OnErrorInternal(error);
37  }
38
39  MOCK_METHOD1(OnErrorInternal, void(PrivetURLFetcher::ErrorType error));
40
41  virtual void OnParsedJson(PrivetURLFetcher* fetcher,
42                            const base::DictionaryValue& value,
43                            bool has_error) OVERRIDE {
44    saved_value_.reset(value.DeepCopy());
45    OnParsedJsonInternal(has_error);
46  }
47
48  MOCK_METHOD1(OnParsedJsonInternal, void(bool has_error));
49
50  virtual void OnNeedPrivetToken(
51      PrivetURLFetcher* fetcher,
52      const PrivetURLFetcher::TokenCallback& callback) {
53  }
54
55  bool OnRawData(PrivetURLFetcher* fetcher,
56                 bool response_is_file,
57                 const std::string& data,
58                 const base::FilePath& response_file) {
59    if (!raw_mode_) return false;
60
61    if (response_is_file) {
62      EXPECT_TRUE(response_file != base::FilePath());
63      OnFileInternal();
64    } else {
65      OnRawDataInternal(data);
66    }
67
68    return true;
69  }
70
71  MOCK_METHOD1(OnRawDataInternal, void(std::string data));
72
73  MOCK_METHOD0(OnFileInternal, void());
74
75  const base::DictionaryValue* saved_value() { return saved_value_.get(); }
76
77  void SetRawMode(bool raw_mode) {
78    raw_mode_ = raw_mode;
79  }
80
81  std::string GetAuthToken() { return "MyAuthToken"; }
82
83 private:
84  scoped_ptr<base::DictionaryValue> saved_value_;
85  bool raw_mode_;
86};
87
88class PrivetURLFetcherTest : public ::testing::Test {
89 public:
90  PrivetURLFetcherTest() {
91    request_context_= new net::TestURLRequestContextGetter(
92        base::MessageLoopProxy::current());
93    privet_urlfetcher_.reset(new PrivetURLFetcher(
94        GURL(kSamplePrivetURL),
95        net::URLFetcher::POST,
96        request_context_.get(),
97        &delegate_));
98
99    PrivetURLFetcher::SetTokenForHost(GURL(kSamplePrivetURL).GetOrigin().spec(),
100                                      kSamplePrivetToken);
101  }
102  virtual ~PrivetURLFetcherTest() {
103  }
104
105  void RunFor(base::TimeDelta time_period) {
106    base::CancelableCallback<void()> callback(base::Bind(
107        &PrivetURLFetcherTest::Stop, base::Unretained(this)));
108    base::MessageLoop::current()->PostDelayedTask(
109        FROM_HERE, callback.callback(), time_period);
110
111    base::MessageLoop::current()->Run();
112    callback.Cancel();
113  }
114
115  void Stop() {
116    base::MessageLoop::current()->Quit();
117  }
118
119 protected:
120  base::MessageLoop loop_;
121  scoped_refptr<net::TestURLRequestContextGetter> request_context_;
122  net::TestURLFetcherFactory fetcher_factory_;
123  scoped_ptr<PrivetURLFetcher> privet_urlfetcher_;
124  StrictMock<MockPrivetURLFetcherDelegate> delegate_;
125};
126
127TEST_F(PrivetURLFetcherTest, FetchSuccess) {
128  privet_urlfetcher_->Start();
129  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
130  ASSERT_TRUE(fetcher != NULL);
131  fetcher->SetResponseString(kSampleParsableJSON);
132  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
133                                            net::OK));
134  fetcher->set_response_code(200);
135
136  EXPECT_CALL(delegate_, OnParsedJsonInternal(false));
137  fetcher->delegate()->OnURLFetchComplete(fetcher);
138
139  const base::DictionaryValue* value = delegate_.saved_value();
140  int hello_value;
141  ASSERT_TRUE(value != NULL);
142  ASSERT_TRUE(value->GetInteger("hello", &hello_value));
143  EXPECT_EQ(2, hello_value);
144}
145
146TEST_F(PrivetURLFetcherTest, HTTP503Retry) {
147  privet_urlfetcher_->Start();
148  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
149  ASSERT_TRUE(fetcher != NULL);
150  fetcher->SetResponseString(kSampleParsableJSON);
151  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
152                                            net::OK));
153  fetcher->set_response_code(503);
154
155  fetcher->delegate()->OnURLFetchComplete(fetcher);
156
157  RunFor(base::TimeDelta::FromSeconds(7));
158  fetcher = fetcher_factory_.GetFetcherByID(0);
159
160  ASSERT_TRUE(fetcher != NULL);
161  fetcher->SetResponseString(kSampleParsableJSON);
162  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
163                                            net::OK));
164  fetcher->set_response_code(200);
165
166  EXPECT_CALL(delegate_, OnParsedJsonInternal(false));
167  fetcher->delegate()->OnURLFetchComplete(fetcher);
168}
169
170TEST_F(PrivetURLFetcherTest, ResponseCodeError) {
171  privet_urlfetcher_->Start();
172  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
173  ASSERT_TRUE(fetcher != NULL);
174  fetcher->SetResponseString(kSampleParsableJSON);
175  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
176                                            net::OK));
177  fetcher->set_response_code(404);
178
179  EXPECT_CALL(delegate_,
180              OnErrorInternal(PrivetURLFetcher::RESPONSE_CODE_ERROR));
181  fetcher->delegate()->OnURLFetchComplete(fetcher);
182}
183
184TEST_F(PrivetURLFetcherTest, JsonParseError) {
185  privet_urlfetcher_->Start();
186  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
187  ASSERT_TRUE(fetcher != NULL);
188  fetcher->SetResponseString(kSampleUnparsableJSON);
189  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
190                                            net::OK));
191  fetcher->set_response_code(200);
192
193  EXPECT_CALL(delegate_,
194              OnErrorInternal(PrivetURLFetcher::JSON_PARSE_ERROR));
195  fetcher->delegate()->OnURLFetchComplete(fetcher);
196}
197
198TEST_F(PrivetURLFetcherTest, Header) {
199  privet_urlfetcher_->Start();
200  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
201  ASSERT_TRUE(fetcher != NULL);
202  net::HttpRequestHeaders headers;
203  fetcher->GetExtraRequestHeaders(&headers);
204
205  std::string header_token;
206  ASSERT_TRUE(headers.GetHeader("X-Privet-Token", &header_token));
207  EXPECT_EQ(kSamplePrivetToken, header_token);
208}
209
210TEST_F(PrivetURLFetcherTest, Header2) {
211  PrivetURLFetcher::SetTokenForHost(GURL(kSamplePrivetURL).GetOrigin().spec(),
212                                    "");
213
214  privet_urlfetcher_->SendEmptyPrivetToken();
215  privet_urlfetcher_->Start();
216
217  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
218  ASSERT_TRUE(fetcher != NULL);
219  net::HttpRequestHeaders headers;
220  fetcher->GetExtraRequestHeaders(&headers);
221
222  std::string header_token;
223  ASSERT_TRUE(headers.GetHeader("X-Privet-Token", &header_token));
224  EXPECT_EQ(kEmptyPrivetToken, header_token);
225}
226
227TEST_F(PrivetURLFetcherTest, AlwaysSendEmpty) {
228  PrivetURLFetcher::SetTokenForHost(GURL(kSamplePrivetURL).GetOrigin().spec(),
229                                    "SampleToken");
230
231  privet_urlfetcher_->SendEmptyPrivetToken();
232  privet_urlfetcher_->Start();
233
234  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
235  ASSERT_TRUE(fetcher != NULL);
236  net::HttpRequestHeaders headers;
237  fetcher->GetExtraRequestHeaders(&headers);
238
239  std::string header_token;
240  ASSERT_TRUE(headers.GetHeader("X-Privet-Token", &header_token));
241  EXPECT_EQ(kEmptyPrivetToken, header_token);
242}
243
244TEST_F(PrivetURLFetcherTest, FetchHasError) {
245  privet_urlfetcher_->Start();
246  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
247  ASSERT_TRUE(fetcher != NULL);
248  fetcher->SetResponseString(kSampleJSONWithError);
249  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
250                                            net::OK));
251  fetcher->set_response_code(200);
252
253  EXPECT_CALL(delegate_, OnParsedJsonInternal(true));
254  fetcher->delegate()->OnURLFetchComplete(fetcher);
255}
256
257TEST_F(PrivetURLFetcherTest, FetcherRawData) {
258  delegate_.SetRawMode(true);
259  privet_urlfetcher_->Start();
260  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
261  ASSERT_TRUE(fetcher != NULL);
262  fetcher->SetResponseString(kSampleJSONWithError);
263  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
264                                            net::OK));
265  fetcher->set_response_code(200);
266
267  EXPECT_CALL(delegate_, OnRawDataInternal(kSampleJSONWithError));
268  fetcher->delegate()->OnURLFetchComplete(fetcher);
269}
270
271TEST_F(PrivetURLFetcherTest, RangeRequest) {
272  delegate_.SetRawMode(true);
273  privet_urlfetcher_->SetByteRange(200, 300);
274  privet_urlfetcher_->Start();
275  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
276  ASSERT_TRUE(fetcher != NULL);
277  net::HttpRequestHeaders headers;
278  fetcher->GetExtraRequestHeaders(&headers);
279
280  std::string header_range;
281  ASSERT_TRUE(headers.GetHeader("Range", &header_range));
282  EXPECT_EQ("bytes=200-300", header_range);
283}
284
285TEST_F(PrivetURLFetcherTest, FetcherToFile) {
286  delegate_.SetRawMode(true);
287  privet_urlfetcher_->SaveResponseToFile();
288  privet_urlfetcher_->Start();
289  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
290  ASSERT_TRUE(fetcher != NULL);
291  fetcher->SetResponseFilePath(
292      base::FilePath(FILE_PATH_LITERAL("sample/file")));
293  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
294                                            net::OK));
295  fetcher->set_response_code(200);
296
297  EXPECT_CALL(delegate_, OnFileInternal());
298  fetcher->delegate()->OnURLFetchComplete(fetcher);
299}
300
301TEST_F(PrivetURLFetcherTest, V3Mode) {
302  delegate_.SetRawMode(true);
303  privet_urlfetcher_->V3Mode();
304  privet_urlfetcher_->Start();
305  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
306  ASSERT_TRUE(fetcher != NULL);
307  fetcher->SetResponseFilePath(
308      base::FilePath(FILE_PATH_LITERAL("sample/file")));
309  net::HttpRequestHeaders headers;
310  fetcher->GetExtraRequestHeaders(&headers);
311
312  std::string header_token;
313  ASSERT_FALSE(headers.GetHeader("X-Privet-Token", &header_token));
314  ASSERT_TRUE(headers.GetHeader("X-Privet-Auth", &header_token));
315  ASSERT_EQ("MyAuthToken", header_token);
316}
317
318}  // namespace
319
320}  // namespace local_discovery
321