1 /* 2 * Copyright 2021 Google LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #ifndef FCP_CLIENT_HTTP_TESTING_TEST_HELPERS_H_ 17 #define FCP_CLIENT_HTTP_TESTING_TEST_HELPERS_H_ 18 19 #include <functional> 20 #include <memory> 21 #include <string> 22 #include <utility> 23 #include <vector> 24 25 #include "google/longrunning/operations.pb.h" 26 #include "gmock/gmock.h" 27 #include "gtest/gtest.h" 28 #include "absl/base/attributes.h" 29 #include "absl/status/status.h" 30 #include "absl/status/statusor.h" 31 #include "fcp/base/monitoring.h" 32 #include "fcp/client/http/http_client.h" 33 34 namespace fcp { 35 namespace client { 36 namespace http { 37 38 // A simple `HttpResponse` implementation consisting of a code, headers (which 39 // are returned via the `HttpResponse` interface methods), and an optional 40 // in-memory response body which `MockableHttpClient` can use to return the data 41 // via the `HttpRequestCallback::OnResponseBody` method. 42 class FakeHttpResponse : public HttpResponse { 43 public: FakeHttpResponse(int code,HeaderList headers)44 FakeHttpResponse(int code, HeaderList headers) 45 : code_(code), headers_(headers), body_("") {} FakeHttpResponse(int code,HeaderList headers,std::string body)46 FakeHttpResponse(int code, HeaderList headers, std::string body) 47 : code_(code), headers_(headers), body_(body) {} 48 code()49 int code() const override { return code_; } headers()50 const HeaderList& headers() const override { return headers_; } body()51 const std::string& body() const { return body_; } 52 53 private: 54 const int code_; 55 const HeaderList headers_; 56 const std::string body_; 57 }; 58 59 // A simplified version of the `HttpClient` interface for use in tests. Enables 60 // easy use with gMock via the simplified `PerformSingleRequest` interface. 61 class MockableHttpClient : public HttpClient { 62 public: 63 // A simple container holding all important properties of an incoming 64 // `HttpRequest`. This is the parameter type passed to `PerformSingleRequest`, 65 // and because it is a simple struct (as opposed to `HttpRequest`, which uses 66 // a number of methods that are hard to mock such as `HttpRequest::ReadBody`) 67 // it makes it easy to use gMock matchers to match against parts or all of the 68 // request's properties. 69 struct SimpleHttpRequest { 70 const std::string uri; 71 const HttpRequest::Method method; 72 const HeaderList headers; 73 const std::string body; 74 }; 75 76 MockableHttpClient() = default; 77 78 ABSL_MUST_USE_RESULT std::unique_ptr<HttpRequestHandle> EnqueueRequest( 79 std::unique_ptr<HttpRequest> request) override; 80 81 absl::Status PerformRequests( 82 std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>> requests) 83 override; 84 85 // Implement this method (e.g. using gMock's MOCK_METHOD) for a simple way to 86 // mock a single request. See `MockHttpClient` below. 87 virtual absl::StatusOr<FakeHttpResponse> PerformSingleRequest( 88 SimpleHttpRequest request) = 0; 89 90 // Registers a callback that will be called when any request receives a 91 // `HttpRequestHandle::Cancel` call. SetCancellationListener(std::function<void ()> listener)92 virtual void SetCancellationListener(std::function<void()> listener) { 93 cancellation_listener_ = listener; 94 } 95 96 // Returns the (fake) number of bytes that the mock client has sent/received. 97 // This number will match the sum of all `HttpRequestHandle`'s 98 // `TotalSentReceivedBytes()` methods after they were processed by the mock 99 // client. TotalSentReceivedBytes()100 virtual HttpRequestHandle::SentReceivedBytes TotalSentReceivedBytes() { 101 return sent_received_bytes_; 102 } 103 104 private: 105 std::function<void()> cancellation_listener_ = []() {}; 106 107 // A running (fake) tally of the number of bytes that have been 108 // downloaded/uploaded so far. 109 HttpRequestHandle::SentReceivedBytes sent_received_bytes_; 110 }; 111 112 // A convenient to use mock HttpClient implementation. 113 class MockHttpClient : public MockableHttpClient { 114 public: 115 MockHttpClient() = default; 116 117 MOCK_METHOD(absl::StatusOr<FakeHttpResponse>, PerformSingleRequest, 118 (SimpleHttpRequest request), (override)); 119 }; 120 121 ::testing::Matcher<MockableHttpClient::SimpleHttpRequest> 122 SimpleHttpRequestMatcher( 123 const ::testing::Matcher<std::string>& uri_matcher, 124 const ::testing::Matcher<HttpRequest::Method>& method_matcher, 125 const ::testing::Matcher<HeaderList>& headers_matcher, 126 const ::testing::Matcher<std::string>& body_matcher); 127 128 // A mock request callback. 129 class MockHttpRequestCallback : public HttpRequestCallback { 130 public: 131 explicit MockHttpRequestCallback() = default; 132 ~MockHttpRequestCallback() override = default; 133 MOCK_METHOD(absl::Status, OnResponseStarted, 134 (const HttpRequest& request, const HttpResponse& response), 135 (override)); 136 137 MOCK_METHOD(void, OnResponseError, 138 (const HttpRequest& request, const absl::Status& error), 139 (override)); 140 141 MOCK_METHOD(absl::Status, OnResponseBody, 142 (const HttpRequest& request, const HttpResponse& response, 143 absl::string_view data), 144 (override)); 145 146 MOCK_METHOD(void, OnResponseBodyError, 147 (const HttpRequest& request, const HttpResponse& response, 148 const absl::Status& error), 149 (override)); 150 151 MOCK_METHOD(void, OnResponseCompleted, 152 (const HttpRequest& request, const HttpResponse& response), 153 (override)); 154 }; 155 156 // Creates a 'pending' `Operation`. 157 ::google::longrunning::Operation CreatePendingOperation( 158 absl::string_view operation_name); 159 160 // Creates a 'done' `Operation`, packing the given message into an `Any`. 161 ::google::longrunning::Operation CreateDoneOperation( 162 absl::string_view operation_name, const google::protobuf::Message& inner_result); 163 164 // Creates an `Operation` with the specified error information. 165 ::google::longrunning::Operation CreateErrorOperation( 166 absl::string_view operation_name, const absl::StatusCode error_code, 167 absl::string_view error_message); 168 169 } // namespace http 170 } // namespace client 171 } // namespace fcp 172 173 #endif // FCP_CLIENT_HTTP_TESTING_TEST_HELPERS_H_ 174