blob: 2040de836bccf308b1f490adceff1a221ae0c924 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/async/cpp/task.h>
#include "garnet/bin/cobalt/utils/fuchsia_http_client.h"
#include "gtest/gtest.h"
#include "lib/gtest/test_with_loop.h"
#include "lib/network_wrapper/fake_network_wrapper.h"
namespace cobalt {
namespace utils {
using clearcut::HTTPRequest;
using clearcut::HTTPResponse;
using network_wrapper::FakeNetworkWrapper;
using tensorflow_statusor::StatusOr;
class FuchsiaHTTPClientTest : public ::gtest::TestWithLoop {
public:
FuchsiaHTTPClientTest()
: ::gtest::TestWithLoop(),
network_wrapper_(dispatcher()),
delete_after_post_(false),
http_client_(new FuchsiaHTTPClient(&network_wrapper_, dispatcher())) {}
void PrepareResponse(const std::string& body, uint32_t status_code = 200) {
network_wrapper_.SetStringResponse(body, status_code);
}
void PrepareResponse(zx::socket body, uint32_t status_code = 200) {
network_wrapper_.SetSocketResponse(std::move(body), status_code);
}
template <class Rep, class Period>
bool WaitForPostFor(const std::chrono::duration<Rep, Period>& duration) {
std::unique_lock<std::mutex> lock(mutex_);
if (post_sent_) {
return true;
}
return post_sent_cv_.wait_for(lock, duration,
[this] { return post_sent_; });
}
std::future<StatusOr<HTTPResponse>> PostString(const std::string& body) {
auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(1);
auto future = std::async(std::launch::async, [this, body, deadline] {
HTTPRequest request;
request.url = "http://www.test.com";
request.body = body;
auto post_future = http_client_->Post(request, deadline);
if (delete_after_post_) {
delete_after_post_ = false;
http_client_.reset(nullptr);
}
{
std::unique_lock<std::mutex> lock(mutex_);
post_sent_ = true;
}
post_sent_cv_.notify_one();
return post_future.get();
});
// Wait up to 1 second for the post to be sent.
EXPECT_TRUE(WaitForPostFor(std::chrono::seconds(1)));
return future;
}
void DeleteHttpClientAfterPost() { delete_after_post_ = true; }
private:
FakeNetworkWrapper network_wrapper_;
bool delete_after_post_;
std::unique_ptr<FuchsiaHTTPClient> http_client_;
std::mutex mutex_;
bool post_sent_;
std::condition_variable post_sent_cv_;
};
TEST_F(FuchsiaHTTPClientTest, MakePostAndGet) {
PrepareResponse("Response");
auto response_future = PostString("Request");
RunLoopFor(zx::sec(5));
EXPECT_EQ(response_future.wait_for(std::chrono::milliseconds(1)),
std::future_status::ready);
auto response_or = response_future.get();
EXPECT_TRUE(response_or.ok());
auto response = response_or.ConsumeValueOrDie();
EXPECT_EQ(response.response, "Response");
}
TEST_F(FuchsiaHTTPClientTest, TestTimeout) {
auto response_future = PostString("Request");
RunLoopFor(zx::msec(100));
EXPECT_NE(std::future_status::ready,
response_future.wait_for(std::chrono::milliseconds(1)));
RunLoopFor(zx::sec(1));
EXPECT_EQ(std::future_status::ready,
response_future.wait_for(std::chrono::milliseconds(1)));
auto response_or = response_future.get();
ASSERT_FALSE(response_or.ok());
EXPECT_EQ(response_or.status().error_code(),
util::StatusCode::DEADLINE_EXCEEDED);
}
TEST_F(FuchsiaHTTPClientTest, WaitAfterRelease) {
zx::socket socket_in, socket_out;
ASSERT_EQ(zx::socket::create(0u, &socket_in, &socket_out), ZX_OK);
PrepareResponse(std::move(socket_in));
DeleteHttpClientAfterPost();
auto response_future = PostString("Request");
const char message[] = "Response";
for (const char* it = message; *it; ++it) {
RunLoopUntilIdle();
size_t bytes_written;
socket_out.write(0u, it, 1, &bytes_written);
EXPECT_EQ(1u, bytes_written);
EXPECT_NE(std::future_status::ready,
response_future.wait_for(std::chrono::milliseconds(1)));
}
socket_out.reset();
RunLoopUntilIdle();
ASSERT_EQ(std::future_status::ready,
response_future.wait_for(std::chrono::milliseconds(1)));
auto response_or = response_future.get();
EXPECT_TRUE(response_or.ok());
auto response = response_or.ConsumeValueOrDie();
EXPECT_EQ(response.response, "Response");
}
} // namespace utils
} // namespace cobalt