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