-
Notifications
You must be signed in to change notification settings - Fork 440
/
otlp_grpc_exporter_test.cc
363 lines (309 loc) · 13.1 KB
/
otlp_grpc_exporter_test.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENTELEMETRY_STL_VERSION
// Unfortunately as of 04/27/2021 the fix is NOT in the vcpkg snapshot of Google Test.
// Remove above `#ifdef` once the GMock fix for C++20 is in the mainline.
//
// Please refer to this GitHub issue for additional details:
// https://github.com/google/googletest/issues/2914
// https://github.com/google/googletest/commit/61f010d703b32de9bfb20ab90ece38ab2f25977f
//
// If we compile using Visual Studio 2019 with `c++latest` (C++20) without the GMock fix,
// then the compilation here fails in `gmock-actions.h` from:
// .\tools\vcpkg\installed\x64-windows\include\gmock\gmock-actions.h(819):
// error C2653: 'result_of': is not a class or namespace name
//
// That is because `std::result_of` has been removed in C++20.
# include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h"
# include "opentelemetry/exporters/otlp/protobuf_include_prefix.h"
// Problematic code that pulls in Gmock and breaks with vs2019/c++latest :
# include "opentelemetry/proto/collector/trace/v1/trace_service_mock.grpc.pb.h"
# include "opentelemetry/exporters/otlp/protobuf_include_suffix.h"
# include "opentelemetry/sdk/trace/simple_processor.h"
# include "opentelemetry/sdk/trace/tracer_provider.h"
# include "opentelemetry/trace/provider.h"
# include <grpcpp/grpcpp.h>
# include <gtest/gtest.h>
# if defined(_MSC_VER)
# include "opentelemetry/sdk/common/env_variables.h"
using opentelemetry::sdk::common::setenv;
using opentelemetry::sdk::common::unsetenv;
# endif
using namespace testing;
OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace otlp
{
namespace
{
class OtlpMockTraceServiceStub : public proto::collector::trace::v1::MockTraceServiceStub
{
public:
// Some old toolchains can only use gRPC 1.33 and it's experimental.
# if defined(GRPC_CPP_VERSION_MAJOR) && \
(GRPC_CPP_VERSION_MAJOR * 1000 + GRPC_CPP_VERSION_MINOR) >= 1039
using async_interface_base =
proto::collector::trace::v1::TraceService::StubInterface::async_interface;
# else
using async_interface_base =
proto::collector::trace::v1::TraceService::StubInterface::experimental_async_interface;
# endif
OtlpMockTraceServiceStub() : async_interface_(this) {}
class async_interface : public async_interface_base
{
public:
async_interface(OtlpMockTraceServiceStub *owner) : stub_(owner) {}
virtual ~async_interface() {}
void Export(
::grpc::ClientContext *context,
const ::opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest *request,
::opentelemetry::proto::collector::trace::v1::ExportTraceServiceResponse *response,
std::function<void(::grpc::Status)> callback) override
{
stub_->last_async_status_ = stub_->Export(context, *request, response);
callback(stub_->last_async_status_);
}
// Some old toolchains can only use gRPC 1.33 and it's experimental.
# if defined(GRPC_CPP_VERSION_MAJOR) && \
(GRPC_CPP_VERSION_MAJOR * 1000 + GRPC_CPP_VERSION_MINOR) >= 1039 || \
defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)
void Export(
::grpc::ClientContext * /*context*/,
const ::opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest * /*request*/,
::opentelemetry::proto::collector::trace::v1::ExportTraceServiceResponse * /*response*/,
::grpc::ClientUnaryReactor * /*reactor*/) override
{}
# else
void Export(
::grpc::ClientContext * /*context*/,
const ::opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest * /*request*/,
::opentelemetry::proto::collector::trace::v1::ExportTraceServiceResponse * /*response*/,
::grpc::experimental::ClientUnaryReactor * /*reactor*/)
{}
# endif
private:
OtlpMockTraceServiceStub *stub_;
};
async_interface_base *async() { return &async_interface_; }
async_interface_base *experimental_async() { return &async_interface_; }
::grpc::Status GetLastAsyncStatus() const noexcept { return last_async_status_; }
private:
::grpc::Status last_async_status_;
async_interface async_interface_;
};
} // namespace
class OtlpGrpcExporterTestPeer : public ::testing::Test
{
public:
std::unique_ptr<sdk::trace::SpanExporter> GetExporter(
std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> &stub_interface)
{
return std::unique_ptr<sdk::trace::SpanExporter>(
new OtlpGrpcExporter(std::move(stub_interface)));
}
// Get the options associated with the given exporter.
const OtlpGrpcExporterOptions &GetOptions(std::unique_ptr<OtlpGrpcExporter> &exporter)
{
return exporter->options_;
}
};
TEST_F(OtlpGrpcExporterTestPeer, ShutdownTest)
{
auto mock_stub = new OtlpMockTraceServiceStub();
std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> stub_interface(
mock_stub);
auto exporter = GetExporter(stub_interface);
auto recordable_1 = exporter->MakeRecordable();
recordable_1->SetName("Test span 1");
auto recordable_2 = exporter->MakeRecordable();
recordable_2->SetName("Test span 2");
// exporter shuold not be shutdown by default
nostd::span<std::unique_ptr<sdk::trace::Recordable>> batch_1(&recordable_1, 1);
EXPECT_CALL(*mock_stub, Export(_, _, _)).Times(Exactly(1)).WillOnce(Return(grpc::Status::OK));
auto result = exporter->Export(batch_1);
exporter->ForceFlush();
EXPECT_EQ(sdk::common::ExportResult::kSuccess, result);
exporter->Shutdown();
nostd::span<std::unique_ptr<sdk::trace::Recordable>> batch_2(&recordable_2, 1);
result = exporter->Export(batch_2);
EXPECT_EQ(sdk::common::ExportResult::kFailure, result);
}
// Call Export() directly
TEST_F(OtlpGrpcExporterTestPeer, ExportUnitTest)
{
auto mock_stub = new OtlpMockTraceServiceStub();
std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> stub_interface(
mock_stub);
auto exporter = GetExporter(stub_interface);
auto recordable_1 = exporter->MakeRecordable();
recordable_1->SetName("Test span 1");
auto recordable_2 = exporter->MakeRecordable();
recordable_2->SetName("Test span 2");
// Test successful RPC
nostd::span<std::unique_ptr<sdk::trace::Recordable>> batch_1(&recordable_1, 1);
EXPECT_CALL(*mock_stub, Export(_, _, _)).Times(Exactly(1)).WillOnce(Return(grpc::Status::OK));
auto result = exporter->Export(batch_1);
EXPECT_EQ(sdk::common::ExportResult::kSuccess, result);
// Test failed RPC
nostd::span<std::unique_ptr<sdk::trace::Recordable>> batch_2(&recordable_2, 1);
EXPECT_CALL(*mock_stub, Export(_, _, _))
.Times(Exactly(1))
.WillOnce(Return(grpc::Status::CANCELLED));
result = exporter->Export(batch_2);
exporter->ForceFlush();
# if defined(ENABLE_ASYNC_EXPORT)
EXPECT_EQ(sdk::common::ExportResult::kSuccess, result);
EXPECT_FALSE(mock_stub->GetLastAsyncStatus().ok());
# else
EXPECT_EQ(sdk::common::ExportResult::kFailure, result);
# endif
}
// Create spans, let processor call Export()
TEST_F(OtlpGrpcExporterTestPeer, ExportIntegrationTest)
{
auto mock_stub = new OtlpMockTraceServiceStub();
std::unique_ptr<proto::collector::trace::v1::TraceService::StubInterface> stub_interface(
mock_stub);
auto exporter = GetExporter(stub_interface);
auto processor = std::unique_ptr<sdk::trace::SpanProcessor>(
new sdk::trace::SimpleSpanProcessor(std::move(exporter)));
auto provider = nostd::shared_ptr<trace::TracerProvider>(
new sdk::trace::TracerProvider(std::move(processor)));
auto tracer = provider->GetTracer("test");
EXPECT_CALL(*mock_stub, Export(_, _, _))
.Times(AtLeast(1))
.WillRepeatedly(Return(grpc::Status::OK));
auto parent_span = tracer->StartSpan("Test parent span");
auto child_span = tracer->StartSpan("Test child span");
child_span->End();
parent_span->End();
}
// Test exporter configuration options
TEST_F(OtlpGrpcExporterTestPeer, ConfigTest)
{
OtlpGrpcExporterOptions opts;
opts.endpoint = "localhost:45454";
std::unique_ptr<OtlpGrpcExporter> exporter(new OtlpGrpcExporter(opts));
EXPECT_EQ(GetOptions(exporter).endpoint, "localhost:45454");
}
// Test exporter configuration options with use_ssl_credentials
TEST_F(OtlpGrpcExporterTestPeer, ConfigSslCredentialsTest)
{
std::string cacert_str = "--begin and end fake cert--";
OtlpGrpcExporterOptions opts;
opts.use_ssl_credentials = true;
opts.ssl_credentials_cacert_as_string = cacert_str;
std::unique_ptr<OtlpGrpcExporter> exporter(new OtlpGrpcExporter(opts));
EXPECT_EQ(GetOptions(exporter).ssl_credentials_cacert_as_string, cacert_str);
EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true);
}
# ifndef NO_GETENV
// Test exporter configuration options with use_ssl_credentials
TEST_F(OtlpGrpcExporterTestPeer, ConfigFromEnv)
{
const std::string cacert_str = "--begin and end fake cert--";
setenv("OTEL_EXPORTER_OTLP_CERTIFICATE_STRING", cacert_str.c_str(), 1);
setenv("OTEL_EXPORTER_OTLP_SSL_ENABLE", "True", 1);
const std::string endpoint = "https://localhost:9999";
setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1);
setenv("OTEL_EXPORTER_OTLP_TIMEOUT", "20050ms", 1);
setenv("OTEL_EXPORTER_OTLP_HEADERS", "k1=v1,k2=v2", 1);
setenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS", "k1=v3,k1=v4", 1);
std::unique_ptr<OtlpGrpcExporter> exporter(new OtlpGrpcExporter());
EXPECT_EQ(GetOptions(exporter).ssl_credentials_cacert_as_string, cacert_str);
EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true);
EXPECT_EQ(GetOptions(exporter).endpoint, endpoint);
EXPECT_EQ(GetOptions(exporter).timeout.count(),
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::milliseconds{20050})
.count());
EXPECT_EQ(GetOptions(exporter).metadata.size(), 3);
{
// Test k2
auto range = GetOptions(exporter).metadata.equal_range("k2");
EXPECT_TRUE(range.first != range.second);
EXPECT_EQ(range.first->second, std::string("v2"));
++range.first;
EXPECT_TRUE(range.first == range.second);
}
{
// Test k1
auto range = GetOptions(exporter).metadata.equal_range("k1");
EXPECT_TRUE(range.first != range.second);
EXPECT_EQ(range.first->second, std::string("v3"));
++range.first;
EXPECT_EQ(range.first->second, std::string("v4"));
++range.first;
EXPECT_TRUE(range.first == range.second);
}
unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT");
unsetenv("OTEL_EXPORTER_OTLP_CERTIFICATE_STRING");
unsetenv("OTEL_EXPORTER_OTLP_SSL_ENABLE");
unsetenv("OTEL_EXPORTER_OTLP_TIMEOUT");
unsetenv("OTEL_EXPORTER_OTLP_HEADERS");
unsetenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS");
}
# endif
# ifndef NO_GETENV
// Test exporter configuration options with use_ssl_credentials
TEST_F(OtlpGrpcExporterTestPeer, ConfigHttpsSecureFromEnv)
{
// https takes precedence over insecure
const std::string endpoint = "https://localhost:9999";
setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1);
setenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE", "true", 1);
std::unique_ptr<OtlpGrpcExporter> exporter(new OtlpGrpcExporter());
EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true);
EXPECT_EQ(GetOptions(exporter).endpoint, endpoint);
unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT");
unsetenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE");
}
# endif
# ifndef NO_GETENV
// Test exporter configuration options with use_ssl_credentials
TEST_F(OtlpGrpcExporterTestPeer, ConfigHttpInsecureFromEnv)
{
// http takes precedence over secure
const std::string endpoint = "http://localhost:9999";
setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1);
setenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE", "false", 1);
std::unique_ptr<OtlpGrpcExporter> exporter(new OtlpGrpcExporter());
EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, false);
EXPECT_EQ(GetOptions(exporter).endpoint, endpoint);
unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT");
unsetenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE");
}
# endif
# ifndef NO_GETENV
// Test exporter configuration options with use_ssl_credentials
TEST_F(OtlpGrpcExporterTestPeer, ConfigUnknownSecureFromEnv)
{
const std::string endpoint = "localhost:9999";
setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1);
setenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE", "false", 1);
std::unique_ptr<OtlpGrpcExporter> exporter(new OtlpGrpcExporter());
EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, true);
EXPECT_EQ(GetOptions(exporter).endpoint, endpoint);
unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT");
unsetenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE");
}
# endif
# ifndef NO_GETENV
// Test exporter configuration options with use_ssl_credentials
TEST_F(OtlpGrpcExporterTestPeer, ConfigUnknownInsecureFromEnv)
{
const std::string endpoint = "localhost:9999";
setenv("OTEL_EXPORTER_OTLP_ENDPOINT", endpoint.c_str(), 1);
setenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE", "true", 1);
std::unique_ptr<OtlpGrpcExporter> exporter(new OtlpGrpcExporter());
EXPECT_EQ(GetOptions(exporter).use_ssl_credentials, false);
EXPECT_EQ(GetOptions(exporter).endpoint, endpoint);
unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT");
unsetenv("OTEL_EXPORTER_OTLP_TRACES_INSECURE");
}
# endif
} // namespace otlp
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif /* OPENTELEMETRY_STL_VERSION */