Skip to content

Commit 6f6ddb0

Browse files
committed
improved testing
1 parent 600a6ec commit 6f6ddb0

3 files changed

Lines changed: 343 additions & 94 deletions

File tree

google/cloud/bigtable/internal/directpath_diagnostics.cc

Lines changed: 95 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -77,72 +77,103 @@ std::string ToString(DiagnosticFailureReason reason) {
7777
#ifndef _WIN32
7878
namespace {
7979

80-
bool CanConnectTcp(std::string const& host, std::uint16_t port,
81-
std::chrono::milliseconds timeout) {
82-
int const sock = socket(AF_INET, SOCK_STREAM, 0);
83-
if (sock < 0) return false;
84-
85-
std::int64_t const total_usec =
86-
std::chrono::duration_cast<std::chrono::microseconds>(timeout).count();
87-
struct timeval tv;
88-
tv.tv_sec = static_cast<time_t>(total_usec / 1000000);
89-
tv.tv_usec = static_cast<suseconds_t>(total_usec % 1000000);
90-
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
91-
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
92-
93-
struct sockaddr_in addr;
94-
std::memset(&addr, 0, sizeof(addr));
95-
addr.sin_family = AF_INET;
96-
addr.sin_port = htons(port);
97-
inet_pton(AF_INET, host.c_str(), &addr.sin_addr);
98-
99-
int const res =
100-
connect(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
101-
close(sock);
102-
return res == 0;
103-
}
104-
105-
DiagnosticFailureReason CheckLoopbackConfiguration() {
106-
struct ifaddrs* ifaddr = nullptr;
107-
if (getifaddrs(&ifaddr) == -1) return DiagnosticFailureReason::kUnknown;
108-
109-
bool has_ipv4_lo = false;
110-
bool has_ipv6_lo = false;
80+
class DefaultDirectPathNetworkSystem : public DirectPathNetworkSystem {
81+
public:
82+
bool CanConnectTcp(std::string const& host, std::uint16_t port,
83+
std::chrono::milliseconds timeout) override {
84+
int const sock = socket(AF_INET, SOCK_STREAM, 0);
85+
if (sock < 0) return false;
86+
87+
std::int64_t const total_usec =
88+
std::chrono::duration_cast<std::chrono::microseconds>(timeout).count();
89+
struct timeval tv;
90+
tv.tv_sec = static_cast<time_t>(total_usec / 1000000);
91+
tv.tv_usec = static_cast<suseconds_t>(total_usec % 1000000);
92+
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
93+
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
94+
95+
struct sockaddr_in addr;
96+
std::memset(&addr, 0, sizeof(addr));
97+
addr.sin_family = AF_INET;
98+
addr.sin_port = htons(port);
99+
inet_pton(AF_INET, host.c_str(), &addr.sin_addr);
100+
101+
int const res =
102+
connect(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
103+
close(sock);
104+
return res == 0;
105+
}
111106

112-
for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
113-
if (ifa->ifa_addr == nullptr) continue;
114-
if (std::string(ifa->ifa_name) == "lo") {
115-
if (ifa->ifa_addr->sa_family == AF_INET) {
116-
has_ipv4_lo = true;
117-
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
118-
has_ipv6_lo = true;
107+
DiagnosticFailureReason CheckLoopbackConfiguration() override {
108+
struct ifaddrs* ifaddr = nullptr;
109+
if (getifaddrs(&ifaddr) == -1) return DiagnosticFailureReason::kUnknown;
110+
111+
bool has_ipv4_lo = false;
112+
bool has_ipv6_lo = false;
113+
114+
for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
115+
if (ifa->ifa_addr == nullptr) continue;
116+
if (std::string(ifa->ifa_name) == "lo") {
117+
if (ifa->ifa_addr->sa_family == AF_INET) {
118+
has_ipv4_lo = true;
119+
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
120+
has_ipv6_lo = true;
121+
}
119122
}
120123
}
121-
}
122-
freeifaddrs(ifaddr);
124+
freeifaddrs(ifaddr);
123125

124-
if (!has_ipv4_lo && !has_ipv6_lo) {
125-
return DiagnosticFailureReason::kLoopbackMisconfigured;
126+
if (!has_ipv4_lo && !has_ipv6_lo) {
127+
return DiagnosticFailureReason::kLoopbackMisconfigured;
128+
}
129+
if (!has_ipv4_lo) {
130+
return DiagnosticFailureReason::kLoopbackMisconfiguredIpv4;
131+
}
132+
if (!has_ipv6_lo) {
133+
return DiagnosticFailureReason::kLoopbackMisconfiguredIpv6;
134+
}
135+
return DiagnosticFailureReason::kUnknown;
126136
}
127-
if (!has_ipv4_lo) {
128-
return DiagnosticFailureReason::kLoopbackMisconfiguredIpv4;
137+
};
138+
139+
} // namespace
140+
141+
std::shared_ptr<DirectPathNetworkSystem> MakeDefaultDirectPathNetworkSystem() {
142+
return std::make_shared<DefaultDirectPathNetworkSystem>();
143+
}
144+
145+
#else
146+
147+
namespace {
148+
149+
class DefaultDirectPathNetworkSystem : public DirectPathNetworkSystem {
150+
public:
151+
bool CanConnectTcp(std::string const&, std::uint16_t,
152+
std::chrono::milliseconds) override {
153+
return false;
129154
}
130-
if (!has_ipv6_lo) {
131-
return DiagnosticFailureReason::kLoopbackMisconfiguredIpv6;
155+
DiagnosticFailureReason CheckLoopbackConfiguration() override {
156+
return DiagnosticFailureReason::kUnknown;
132157
}
133-
return DiagnosticFailureReason::kUnknown;
134-
}
158+
};
135159

136160
} // namespace
161+
162+
std::shared_ptr<DirectPathNetworkSystem> MakeDefaultDirectPathNetworkSystem() {
163+
return std::make_shared<DefaultDirectPathNetworkSystem>();
164+
}
137165
#endif
138166

139167
DiagnosticFailureReason DirectPathDiagnostics::RunDiagnostics(
140168
Options const& options) {
141-
return RunDiagnostics(options, internal::MakeGcpDetector());
169+
return RunDiagnostics(options, internal::MakeGcpDetector(),
170+
MakeDefaultDirectPathNetworkSystem(), "169.254.169.254",
171+
80);
142172
}
143173

144174
DiagnosticFailureReason DirectPathDiagnostics::RunDiagnostics(
145175
Options const& options, std::shared_ptr<internal::GcpDetector> detector,
176+
std::shared_ptr<DirectPathNetworkSystem> network_system,
146177
std::string const& metadata_host, std::uint16_t metadata_port) {
147178
// Step 1: Check platform (GCP VM)
148179
if (detector == nullptr) {
@@ -152,43 +183,46 @@ DiagnosticFailureReason DirectPathDiagnostics::RunDiagnostics(
152183
return DiagnosticFailureReason::kNotInGcp;
153184
}
154185

155-
#ifdef _WIN32
156-
return DiagnosticFailureReason::kUnknown;
157-
#else
186+
if (network_system == nullptr) {
187+
network_system = MakeDefaultDirectPathNetworkSystem();
188+
}
189+
158190
// Step 2: Metadata server reachability
159191
std::chrono::milliseconds timeout =
160192
options.get<bigtable::experimental::DirectPathDiagnosticsTimeoutOption>();
161193
if (timeout <= std::chrono::milliseconds::zero()) {
162194
timeout = std::chrono::milliseconds(500);
163195
}
164196

165-
if (!CanConnectTcp(metadata_host, metadata_port, timeout)) {
197+
if (!network_system->CanConnectTcp(metadata_host, metadata_port, timeout)) {
166198
return DiagnosticFailureReason::kMetadataUnreachable;
167199
}
168200

169201
// Step 3 & 4: Loopback configuration check
170-
DiagnosticFailureReason const lo_result = CheckLoopbackConfiguration();
202+
DiagnosticFailureReason const lo_result =
203+
network_system->CheckLoopbackConfiguration();
171204
if (lo_result != DiagnosticFailureReason::kUnknown) {
172205
return lo_result;
173206
}
174207

175208
// Step 5: Route resolution or fallback
176209
return DiagnosticFailureReason::kUnknown;
177-
#endif
178210
}
179211

180212
#ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
181213
void DirectPathDiagnostics::RunAsync(
182214
CompletionQueue cq, Options const& options,
183215
std::shared_ptr<DirectAccessCompatibility> direct_access_compatibility) {
184216
RunAsync(std::move(cq), options, std::move(direct_access_compatibility),
185-
internal::MakeGcpDetector());
217+
internal::MakeGcpDetector(), MakeDefaultDirectPathNetworkSystem(),
218+
"169.254.169.254", 80);
186219
}
187220

188221
void DirectPathDiagnostics::RunAsync(
189222
CompletionQueue cq, Options const& options,
190223
std::shared_ptr<DirectAccessCompatibility> direct_access_compatibility,
191224
std::shared_ptr<internal::GcpDetector> detector,
225+
std::shared_ptr<DirectPathNetworkSystem> network_system,
192226
std::string const& metadata_host, std::uint16_t metadata_port) {
193227
std::chrono::milliseconds timeout =
194228
options.get<bigtable::experimental::DirectPathDiagnosticsTimeoutOption>();
@@ -199,10 +233,12 @@ void DirectPathDiagnostics::RunAsync(
199233
cq.RunAsync([options,
200234
direct_access_compatibility =
201235
std::move(direct_access_compatibility),
202-
detector = std::move(detector), metadata_host, metadata_port]() {
236+
detector = std::move(detector),
237+
network_system = std::move(network_system), metadata_host,
238+
metadata_port]() {
203239
DiagnosticFailureReason const reason =
204-
DirectPathDiagnostics::RunDiagnostics(options, detector, metadata_host,
205-
metadata_port);
240+
DirectPathDiagnostics::RunDiagnostics(options, detector, network_system,
241+
metadata_host, metadata_port);
206242
if (direct_access_compatibility != nullptr) {
207243
direct_access_compatibility->Record(
208244
opentelemetry::context::RuntimeContext::GetCurrent(), 0,

google/cloud/bigtable/internal/directpath_diagnostics.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "google/cloud/bigtable/internal/client_schema_metrics.h"
2525
#endif
2626
#include "google/cloud/internal/detect_gcp.h"
27+
#include <chrono>
2728
#include <cstdint>
2829
#include <memory>
2930
#include <string>
@@ -53,28 +54,42 @@ enum class DiagnosticFailureReason {
5354

5455
std::string ToString(DiagnosticFailureReason reason);
5556

57+
/**
58+
* Interface for OS-specific networking and system operations used by
59+
* DirectPath diagnostics.
60+
*/
61+
class DirectPathNetworkSystem {
62+
public:
63+
virtual ~DirectPathNetworkSystem() = default;
64+
virtual bool CanConnectTcp(std::string const& host, std::uint16_t port,
65+
std::chrono::milliseconds timeout) = 0;
66+
virtual DiagnosticFailureReason CheckLoopbackConfiguration() = 0;
67+
};
68+
69+
std::shared_ptr<DirectPathNetworkSystem> MakeDefaultDirectPathNetworkSystem();
70+
5671
class DirectPathDiagnostics {
5772
public:
5873
static DiagnosticFailureReason RunDiagnostics(Options const& options);
5974

6075
/// For testing only.
6176
static DiagnosticFailureReason RunDiagnostics(
6277
Options const& options, std::shared_ptr<internal::GcpDetector> detector,
63-
std::string const& metadata_host = "169.254.169.254",
64-
std::uint16_t metadata_port = 80);
78+
std::shared_ptr<DirectPathNetworkSystem> network_system,
79+
std::string const& metadata_host, std::uint16_t metadata_port);
6580

6681
#ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
6782
static void RunAsync(CompletionQueue cq, Options const& options,
6883
std::shared_ptr<DirectAccessCompatibility>
6984
direct_access_compatibility = nullptr);
7085

7186
/// For testing only.
72-
static void RunAsync(CompletionQueue cq, Options const& options,
73-
std::shared_ptr<DirectAccessCompatibility>
74-
direct_access_compatibility,
75-
std::shared_ptr<internal::GcpDetector> detector,
76-
std::string const& metadata_host = "169.254.169.254",
77-
std::uint16_t metadata_port = 80);
87+
static void RunAsync(
88+
CompletionQueue cq, Options const& options,
89+
std::shared_ptr<DirectAccessCompatibility> direct_access_compatibility,
90+
std::shared_ptr<internal::GcpDetector> detector,
91+
std::shared_ptr<DirectPathNetworkSystem> network_system,
92+
std::string const& metadata_host, std::uint16_t metadata_port);
7893
#endif
7994
};
8095

0 commit comments

Comments
 (0)