Skip to content

Commit

Permalink
mobile: Add C++ stream callback integration tests (envoyproxy#34149)
Browse files Browse the repository at this point in the history
Risk Level: low (tests only)
Testing: integration tests
Docs Changes: n/a
Release Notes: n/a
Platform Specific Features: n/a

Signed-off-by: Fredy Wijaya <[email protected]>
  • Loading branch information
fredyw authored May 14, 2024
1 parent e0a54c0 commit 4cafd35
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 12 deletions.
42 changes: 42 additions & 0 deletions mobile/test/cc/integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,48 @@ envoy_cc_test(
],
)

envoy_cc_test(
name = "receive_headers_test",
srcs = ["receive_headers_test.cc"],
repository = "@envoy",
deps = [
"//library/cc:engine_builder_lib",
"//library/common:engine_types_lib",
"//library/common/http:header_utility_lib",
"//test/common/integration:engine_with_test_server",
"//test/common/integration:test_server_lib",
"@envoy_build_config//:test_extensions",
],
)

envoy_cc_test(
name = "receive_data_test",
srcs = ["receive_data_test.cc"],
repository = "@envoy",
deps = [
"//library/cc:engine_builder_lib",
"//library/common:engine_types_lib",
"//library/common/http:header_utility_lib",
"//test/common/integration:engine_with_test_server",
"//test/common/integration:test_server_lib",
"@envoy_build_config//:test_extensions",
],
)

envoy_cc_test(
name = "receive_trailers_test",
srcs = ["receive_trailers_test.cc"],
repository = "@envoy",
deps = [
"//library/cc:engine_builder_lib",
"//library/common:engine_types_lib",
"//library/common/http:header_utility_lib",
"//test/common/integration:engine_with_test_server",
"//test/common/integration:test_server_lib",
"@envoy_build_config//:test_extensions",
],
)

envoy_cc_test(
name = "lifetimes_test",
srcs = ["lifetimes_test.cc"],
Expand Down
67 changes: 67 additions & 0 deletions mobile/test/cc/integration/receive_data_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "test/common/integration/engine_with_test_server.h"
#include "test/common/integration/test_server.h"

#include "absl/synchronization/notification.h"
#include "gtest/gtest.h"
#include "library/cc/engine_builder.h"
#include "library/common/engine_types.h"
#include "library/common/http/header_utility.h"

namespace Envoy {

TEST(ReceiveDataTest, Success) {
absl::Notification engine_running;
Platform::EngineBuilder engine_builder;
engine_builder.enforceTrustChainVerification(false)
.setLogLevel(Logger::Logger::debug)
.setOnEngineRunning([&]() { engine_running.Notify(); });
EngineWithTestServer engine_with_test_server(engine_builder, TestServerType::HTTP2_WITH_TLS,
/* headers= */ {}, /* body= */ "hello world",
/* trailers= */ {});
engine_running.WaitForNotification();

bool on_data_was_called = false;
std::string actual_status_code;
bool actual_end_stream;
std::string actual_response_body;
absl::Notification stream_complete;
EnvoyStreamCallbacks stream_callbacks;
stream_callbacks.on_headers_ = [&](const Http::ResponseHeaderMap& headers, bool end_stream,
envoy_stream_intel) {
actual_status_code = headers.getStatusValue();
actual_end_stream = end_stream;
};
stream_callbacks.on_data_ = [&](const Buffer::Instance& buffer, uint64_t length, bool end_stream,
envoy_stream_intel) {
on_data_was_called = true;
actual_end_stream = end_stream;
actual_response_body += absl::string_view(buffer.toString().data(), length);
};
stream_callbacks.on_complete_ = [&](envoy_stream_intel, envoy_final_stream_intel) {
stream_complete.Notify();
};
stream_callbacks.on_error_ = [&](EnvoyError, envoy_stream_intel, envoy_final_stream_intel) {
stream_complete.Notify();
};
stream_callbacks.on_cancel_ = [&](envoy_stream_intel, envoy_final_stream_intel) {
stream_complete.Notify();
};
auto stream_prototype = engine_with_test_server.engine()->streamClient()->newStreamPrototype();
Platform::StreamSharedPtr stream = stream_prototype->start(std::move(stream_callbacks));

auto headers = Http::Utility::createRequestHeaderMapPtr();
headers->addCopy(Http::LowerCaseString(":method"), "GET");
headers->addCopy(Http::LowerCaseString(":scheme"), "https");
headers->addCopy(Http::LowerCaseString(":authority"),
engine_with_test_server.testServer().getAddress());
headers->addCopy(Http::LowerCaseString(":path"), "/");
stream->sendHeaders(std::move(headers), true);
stream_complete.WaitForNotification();

EXPECT_TRUE(on_data_was_called);
EXPECT_EQ(actual_status_code, "200");
EXPECT_TRUE(actual_end_stream);
EXPECT_EQ(actual_response_body, "hello world");
}

} // namespace Envoy
64 changes: 64 additions & 0 deletions mobile/test/cc/integration/receive_headers_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include "test/common/integration/engine_with_test_server.h"
#include "test/common/integration/test_server.h"

#include "absl/synchronization/notification.h"
#include "gtest/gtest.h"
#include "library/cc/engine_builder.h"
#include "library/common/engine_types.h"
#include "library/common/http/header_utility.h"

namespace Envoy {

TEST(ReceiveHeadersTest, Success) {
absl::Notification engine_running;
Platform::EngineBuilder engine_builder;
engine_builder.enforceTrustChainVerification(false)
.setLogLevel(Logger::Logger::debug)
.setOnEngineRunning([&]() { engine_running.Notify(); });
EngineWithTestServer engine_with_test_server(engine_builder, TestServerType::HTTP2_WITH_TLS,
{{"foo", "bar"}});
engine_running.WaitForNotification();

bool on_headers_was_called = false;
std::string actual_status_code;
bool actual_end_stream;
absl::Notification stream_complete;
EnvoyStreamCallbacks stream_callbacks;
stream_callbacks.on_headers_ = [&](const Http::ResponseHeaderMap& headers, bool end_stream,
envoy_stream_intel) {
on_headers_was_called = true;
actual_status_code = headers.getStatusValue();
EXPECT_EQ("bar", headers.get(Http::LowerCaseString("foo"))[0]->value().getStringView());
actual_end_stream = end_stream;
};
stream_callbacks.on_data_ = [&](const Buffer::Instance&, uint64_t /* length */, bool end_stream,
envoy_stream_intel) { actual_end_stream = end_stream; };
stream_callbacks.on_complete_ = [&](envoy_stream_intel, envoy_final_stream_intel) {
stream_complete.Notify();
};
stream_callbacks.on_error_ = [&](EnvoyError, envoy_stream_intel, envoy_final_stream_intel) {
stream_complete.Notify();
};
stream_callbacks.on_cancel_ = [&](envoy_stream_intel, envoy_final_stream_intel) {
stream_complete.Notify();
};
auto stream_prototype = engine_with_test_server.engine()->streamClient()->newStreamPrototype();
Platform::StreamSharedPtr stream = stream_prototype->start(std::move(stream_callbacks));

auto headers = Http::Utility::createRequestHeaderMapPtr();
headers->addCopy(Http::LowerCaseString(":method"), "GET");
headers->addCopy(Http::LowerCaseString(":scheme"), "https");
headers->addCopy(Http::LowerCaseString(":authority"),
engine_with_test_server.testServer().getAddress());
headers->addCopy(Http::LowerCaseString(":path"), "/");
stream->sendHeaders(std::move(headers), true);
stream->sendData(std::make_unique<Buffer::OwnedImpl>("request body"));
stream->close(std::make_unique<Buffer::OwnedImpl>("request body"));
stream_complete.WaitForNotification();

EXPECT_TRUE(on_headers_was_called);
EXPECT_EQ(actual_status_code, "200");
EXPECT_TRUE(actual_end_stream);
}

} // namespace Envoy
62 changes: 62 additions & 0 deletions mobile/test/cc/integration/receive_trailers_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "test/common/integration/engine_with_test_server.h"
#include "test/common/integration/test_server.h"

#include "absl/synchronization/notification.h"
#include "gtest/gtest.h"
#include "library/cc/engine_builder.h"
#include "library/common/engine_types.h"
#include "library/common/http/header_utility.h"

namespace Envoy {

TEST(ReceiveTrailersTest, Success) {
absl::Notification engine_running;
Platform::EngineBuilder engine_builder;
engine_builder.enforceTrustChainVerification(false)
.setLogLevel(Logger::Logger::debug)
.setOnEngineRunning([&]() { engine_running.Notify(); });
EngineWithTestServer engine_with_test_server(engine_builder, TestServerType::HTTP2_WITH_TLS,
/* headers= */ {},
/* body= */ "", /* trailers= */ {{"foo", "bar"}});
engine_running.WaitForNotification();

bool on_trailers_was_called = false;
std::string actual_status_code;
absl::Notification stream_complete;
EnvoyStreamCallbacks stream_callbacks;
stream_callbacks.on_headers_ = [&](const Http::ResponseHeaderMap& headers, bool /* end_stream */,
envoy_stream_intel) {
actual_status_code = headers.getStatusValue();
};
stream_callbacks.on_trailers_ = [&](const Http::ResponseTrailerMap& trailers,
envoy_stream_intel) {
on_trailers_was_called = true;
EXPECT_EQ("bar", trailers.get(Http::LowerCaseString("foo"))[0]->value().getStringView());
};
stream_callbacks.on_complete_ = [&](envoy_stream_intel, envoy_final_stream_intel) {
stream_complete.Notify();
};
stream_callbacks.on_error_ = [&](EnvoyError, envoy_stream_intel, envoy_final_stream_intel) {
stream_complete.Notify();
};
stream_callbacks.on_cancel_ = [&](envoy_stream_intel, envoy_final_stream_intel) {
stream_complete.Notify();
};
auto stream_prototype = engine_with_test_server.engine()->streamClient()->newStreamPrototype();
Platform::StreamSharedPtr stream = stream_prototype->start(std::move(stream_callbacks));

auto headers = Http::Utility::createRequestHeaderMapPtr();
headers->addCopy(Http::LowerCaseString(":method"), "GET");
headers->addCopy(Http::LowerCaseString(":scheme"), "https");
headers->addCopy(Http::LowerCaseString(":authority"),
engine_with_test_server.testServer().getAddress());
headers->addCopy(Http::LowerCaseString(":path"), "/");
stream->sendHeaders(std::move(headers), true);

stream_complete.WaitForNotification();

EXPECT_TRUE(on_trailers_was_called);
EXPECT_EQ(actual_status_code, "200");
}

} // namespace Envoy
6 changes: 3 additions & 3 deletions mobile/test/cc/integration/send_trailers_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ TEST(SendTrailersTest, Success) {
.addNativeFilter("envoy.filters.http.assertion", std::string(ASSERTION_FILTER_TEXT_PROTO))
#endif
.setOnEngineRunning([&]() { engine_running.Notify(); });
EngineWithTestServer engine_with_test_server(engine_builder, TestServerType::HTTP2_WITH_TLS);
EngineWithTestServer engine_with_test_server(engine_builder, TestServerType::HTTP2_WITH_TLS,
/* headers= */ {}, /* body= */ "body",
/* trailers= */ {{"trailer-key", "trailer-value"}});
engine_running.WaitForNotification();

engine_with_test_server.testServer().setResponse({}, "body", {{"trailer-key", "trailer-value"}});

std::string actual_status_code;
std::string actual_trailer_value;
absl::Notification stream_complete;
Expand Down
7 changes: 5 additions & 2 deletions mobile/test/common/integration/engine_with_test_server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

namespace Envoy {

EngineWithTestServer::EngineWithTestServer(Platform::EngineBuilder& engine_builder,
TestServerType type) {
EngineWithTestServer::EngineWithTestServer(
Platform::EngineBuilder& engine_builder, TestServerType type,
const absl::flat_hash_map<std::string, std::string>& headers, absl::string_view body,
const absl::flat_hash_map<std::string, std::string>& trailers) {
test_server_.start(type);
test_server_.setResponse(headers, body, trailers);
engine_ = engine_builder.build();
}

Expand Down
5 changes: 4 additions & 1 deletion mobile/test/common/integration/engine_with_test_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ namespace Envoy {
*/
class EngineWithTestServer {
public:
EngineWithTestServer(Platform::EngineBuilder& engine_builder, TestServerType type);
EngineWithTestServer(Platform::EngineBuilder& engine_builder, TestServerType type,
const absl::flat_hash_map<std::string, std::string>& headers = {},
absl::string_view body = "",
const absl::flat_hash_map<std::string, std::string>& trailers = {});
~EngineWithTestServer();

/** Returns the reference of `Engine` created. */
Expand Down
6 changes: 3 additions & 3 deletions mobile/test/common/integration/test_server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -458,17 +458,17 @@ void TestServer::shutdown() {
test_server_.reset();
}

std::string TestServer::getAddress() {
std::string TestServer::getAddress() const {
ASSERT(upstream_);
return upstream_->localAddress()->asString();
}

std::string TestServer::getIpAddress() {
std::string TestServer::getIpAddress() const {
ASSERT(upstream_);
return upstream_->localAddress()->ip()->addressAsString();
}

int TestServer::getPort() {
int TestServer::getPort() const {
ASSERT(upstream_ || test_server_);
if (upstream_) {
return upstream_->localAddress()->ip()->port();
Expand Down
6 changes: 3 additions & 3 deletions mobile/test/common/integration/test_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ class TestServer : public ListenerHooks {
void shutdown();

/** Gets the server address. The server address is a combination of IP address and port number. */
std::string getAddress();
std::string getAddress() const;

/** Gets the server IP address. */
std::string getIpAddress();
std::string getIpAddress() const;

/** Returns the server port number. */
int getPort();
int getPort() const;

/**
* Sets headers and data for the test server to return on all future requests.
Expand Down

0 comments on commit 4cafd35

Please sign in to comment.