• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium OS 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 <brillo/http/http_request.h>
6 
7 #include <string>
8 
9 #include <base/callback.h>
10 #include <brillo/bind_lambda.h>
11 #include <brillo/http/mock_connection.h>
12 #include <brillo/http/mock_transport.h>
13 #include <brillo/mime_utils.h>
14 #include <brillo/streams/mock_stream.h>
15 #include <gmock/gmock.h>
16 #include <gtest/gtest.h>
17 
18 using testing::DoAll;
19 using testing::Invoke;
20 using testing::Return;
21 using testing::SetArgPointee;
22 using testing::Unused;
23 using testing::WithArg;
24 using testing::_;
25 
26 namespace brillo {
27 namespace http {
28 
29 MATCHER_P(ContainsStringData, str, "") {
30   if (arg->GetSize() != str.size())
31     return false;
32 
33   std::string data;
34   char buf[100];
35   size_t read = 0;
36   while (arg->ReadBlocking(buf, sizeof(buf), &read, nullptr) && read > 0) {
37     data.append(buf, read);
38   }
39   return data == str;
40 }
41 
42 class HttpRequestTest : public testing::Test {
43  public:
SetUp()44   void SetUp() override {
45     transport_ = std::make_shared<MockTransport>();
46     connection_ = std::make_shared<MockConnection>(transport_);
47   }
48 
TearDown()49   void TearDown() override {
50     // Having shared pointers to mock objects (some of methods in these tests
51     // return shared pointers to connection and transport) could cause the
52     // test expectations to hold on to the mock object without releasing them
53     // at the end of a test, causing Mock's object leak detection to erroneously
54     // detect mock object "leaks". Verify and clear the expectations manually
55     // and explicitly to ensure the shared pointer refcounters are not
56     // preventing the mocks to be destroyed at the end of each test.
57     testing::Mock::VerifyAndClearExpectations(connection_.get());
58     connection_.reset();
59     testing::Mock::VerifyAndClearExpectations(transport_.get());
60     transport_.reset();
61   }
62 
63  protected:
64   std::shared_ptr<MockTransport> transport_;
65   std::shared_ptr<MockConnection> connection_;
66 };
67 
TEST_F(HttpRequestTest,Defaults)68 TEST_F(HttpRequestTest, Defaults) {
69   Request request{"http://www.foo.bar", request_type::kPost, transport_};
70   EXPECT_TRUE(request.GetContentType().empty());
71   EXPECT_TRUE(request.GetReferer().empty());
72   EXPECT_TRUE(request.GetUserAgent().empty());
73   EXPECT_EQ("*/*", request.GetAccept());
74   EXPECT_EQ("http://www.foo.bar", request.GetRequestURL());
75   EXPECT_EQ(request_type::kPost, request.GetRequestMethod());
76 
77   Request request2{"http://www.foo.bar/baz", request_type::kGet, transport_};
78   EXPECT_EQ("http://www.foo.bar/baz", request2.GetRequestURL());
79   EXPECT_EQ(request_type::kGet, request2.GetRequestMethod());
80 }
81 
TEST_F(HttpRequestTest,ContentType)82 TEST_F(HttpRequestTest, ContentType) {
83   Request request{"http://www.foo.bar", request_type::kPost, transport_};
84   request.SetContentType(mime::image::kJpeg);
85   EXPECT_EQ(mime::image::kJpeg, request.GetContentType());
86 }
87 
TEST_F(HttpRequestTest,Referer)88 TEST_F(HttpRequestTest, Referer) {
89   Request request{"http://www.foo.bar", request_type::kPost, transport_};
90   request.SetReferer("http://www.foo.bar/baz");
91   EXPECT_EQ("http://www.foo.bar/baz", request.GetReferer());
92 }
93 
TEST_F(HttpRequestTest,UserAgent)94 TEST_F(HttpRequestTest, UserAgent) {
95   Request request{"http://www.foo.bar", request_type::kPost, transport_};
96   request.SetUserAgent("FooBar Browser");
97   EXPECT_EQ("FooBar Browser", request.GetUserAgent());
98 }
99 
TEST_F(HttpRequestTest,Accept)100 TEST_F(HttpRequestTest, Accept) {
101   Request request{"http://www.foo.bar", request_type::kPost, transport_};
102   request.SetAccept("text/*, text/html, text/html;level=1, */*");
103   EXPECT_EQ("text/*, text/html, text/html;level=1, */*", request.GetAccept());
104 }
105 
TEST_F(HttpRequestTest,GetResponseAndBlock)106 TEST_F(HttpRequestTest, GetResponseAndBlock) {
107   Request request{"http://www.foo.bar", request_type::kPost, transport_};
108   request.SetUserAgent("FooBar Browser");
109   request.SetReferer("http://www.foo.bar/baz");
110   request.SetAccept("text/*, text/html, text/html;level=1, */*");
111   request.AddHeader(request_header::kAcceptEncoding, "compress, gzip");
112   request.AddHeaders({
113       {request_header::kAcceptLanguage, "da, en-gb;q=0.8, en;q=0.7"},
114       {request_header::kConnection, "close"},
115   });
116   request.AddRange(-10);
117   request.AddRange(100, 200);
118   request.AddRange(300);
119   std::string req_body{"Foo bar baz"};
120   request.AddHeader(request_header::kContentType, mime::text::kPlain);
121 
122   EXPECT_CALL(*transport_, CreateConnection(
123       "http://www.foo.bar",
124       request_type::kPost,
125       HeaderList{
126         {request_header::kAcceptEncoding, "compress, gzip"},
127         {request_header::kAcceptLanguage, "da, en-gb;q=0.8, en;q=0.7"},
128         {request_header::kConnection, "close"},
129         {request_header::kContentType, mime::text::kPlain},
130         {request_header::kRange, "bytes=-10,100-200,300-"},
131         {request_header::kAccept, "text/*, text/html, text/html;level=1, */*"},
132       },
133       "FooBar Browser",
134       "http://www.foo.bar/baz",
135       nullptr)).WillOnce(Return(connection_));
136 
137   EXPECT_CALL(*connection_, MockSetRequestData(ContainsStringData(req_body), _))
138       .WillOnce(Return(true));
139 
140   EXPECT_TRUE(
141       request.AddRequestBody(req_body.data(), req_body.size(), nullptr));
142 
143   EXPECT_CALL(*connection_, FinishRequest(_)).WillOnce(Return(true));
144   auto resp = request.GetResponseAndBlock(nullptr);
145   EXPECT_NE(nullptr, resp.get());
146 }
147 
TEST_F(HttpRequestTest,GetResponse)148 TEST_F(HttpRequestTest, GetResponse) {
149   Request request{"http://foo.bar", request_type::kGet, transport_};
150 
151   std::string resp_data{"FooBar response body"};
152   auto read_data =
153       [&resp_data](void* buffer, Unused, size_t* read, Unused) -> bool {
154     memcpy(buffer, resp_data.data(), resp_data.size());
155     *read = resp_data.size();
156     return true;
157   };
158 
159   auto success_callback = [](decltype(this) test,
160                              const std::string& resp_data,
161                              RequestID request_id,
162                              std::unique_ptr<Response> resp) {
163     EXPECT_EQ(23, request_id);
164     EXPECT_CALL(*test->connection_, GetResponseStatusCode())
165         .WillOnce(Return(status_code::Partial));
166     EXPECT_EQ(status_code::Partial, resp->GetStatusCode());
167 
168     EXPECT_CALL(*test->connection_, GetResponseStatusText())
169         .WillOnce(Return("Partial completion"));
170     EXPECT_EQ("Partial completion", resp->GetStatusText());
171 
172     EXPECT_CALL(*test->connection_,
173                 GetResponseHeader(response_header::kContentType))
174         .WillOnce(Return(mime::text::kHtml));
175     EXPECT_EQ(mime::text::kHtml, resp->GetContentType());
176 
177     EXPECT_EQ(resp_data, resp->ExtractDataAsString());
178   };
179 
180   auto finish_request_async =
181       [this, &read_data](const SuccessCallback& success_callback) {
182     std::unique_ptr<MockStream> mock_stream{new MockStream};
183     EXPECT_CALL(*mock_stream, ReadBlocking(_, _, _, _))
184         .WillOnce(Invoke(read_data))
185         .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
186 
187     EXPECT_CALL(*connection_, MockExtractDataStream(_))
188       .WillOnce(Return(mock_stream.release()));
189     std::unique_ptr<Response> resp{new Response{connection_}};
190     success_callback.Run(23, std::move(resp));
191   };
192 
193   EXPECT_CALL(
194       *transport_,
195       CreateConnection("http://foo.bar", request_type::kGet, _, "", "", _))
196       .WillOnce(Return(connection_));
197 
198   EXPECT_CALL(*connection_, FinishRequestAsync(_, _))
199       .WillOnce(DoAll(WithArg<0>(Invoke(finish_request_async)), Return(23)));
200 
201   EXPECT_EQ(
202       23,
203       request.GetResponse(
204           base::Bind(success_callback, base::Unretained(this), resp_data), {}));
205 }
206 
207 }  // namespace http
208 }  // namespace brillo
209