Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
test_opentelemetry_adapter.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5
6#include <gtest/gtest.h>
8// Note: distributed_tracer.h does not exist in include directory
9// #include <kcenon/monitoring/tracing/distributed_tracer.h>
11#include <thread>
12#include <chrono>
13
14using namespace kcenon::monitoring;
15
16class OpenTelemetryAdapterTest : public ::testing::Test {
17protected:
18 void SetUp() override {
19 resource = create_service_resource("test_service", "1.0.0", "test_namespace");
21 }
22
23 void TearDown() override {
25 compatibility_layer->shutdown();
26 }
27 }
28
30 std::unique_ptr<opentelemetry_compatibility_layer> compatibility_layer;
31};
32
33TEST_F(OpenTelemetryAdapterTest, ResourceCreation) {
34 EXPECT_EQ(resource.type, otel_resource_type::service);
35
36 auto service_name = resource.get_attribute("service.name");
37 ASSERT_TRUE(service_name.is_ok());
38 EXPECT_EQ(service_name.value(), "test_service");
39
40 auto service_version = resource.get_attribute("service.version");
41 ASSERT_TRUE(service_version.is_ok());
42 EXPECT_EQ(service_version.value(), "1.0.0");
43
44 auto service_namespace = resource.get_attribute("service.namespace");
45 ASSERT_TRUE(service_namespace.is_ok());
46 EXPECT_EQ(service_namespace.value(), "test_namespace");
47
48 auto sdk_name = resource.get_attribute("telemetry.sdk.name");
49 ASSERT_TRUE(sdk_name.is_ok());
50 EXPECT_EQ(sdk_name.value(), "monitoring_system");
51}
52
53TEST_F(OpenTelemetryAdapterTest, AttributeOperations) {
54 otel_attribute attr("test.key", "test.value");
55 EXPECT_EQ(attr.key, "test.key");
56 EXPECT_EQ(attr.value, "test.value");
57
58 otel_attribute attr2("test.key", "test.value");
59 EXPECT_EQ(attr, attr2);
60
61 otel_attribute attr3("different.key", "test.value");
62 EXPECT_NE(attr, attr3);
63}
64
65TEST_F(OpenTelemetryAdapterTest, SpanContextCreation) {
66 otel_span_context context("trace123", "span456");
67 EXPECT_EQ(context.trace_id, "trace123");
68 EXPECT_EQ(context.span_id, "span456");
69 EXPECT_TRUE(context.is_valid);
70 EXPECT_FALSE(context.is_remote);
71
72 otel_span_context invalid_context;
73 EXPECT_FALSE(invalid_context.is_valid);
74}
75
76TEST_F(OpenTelemetryAdapterTest, SpanDataOperations) {
77 otel_span_data span;
78 span.name = "test_operation";
79 span.kind = otel_span_kind::server;
80 span.status_code = otel_status_code::ok;
81 span.start_time = std::chrono::system_clock::now();
82
83 EXPECT_FALSE(span.is_ended());
84 EXPECT_EQ(span.duration().count(), 0);
85
86 std::this_thread::sleep_for(std::chrono::milliseconds(1));
87 span.end_time = std::chrono::system_clock::now();
88
89 EXPECT_TRUE(span.is_ended());
90 EXPECT_GT(span.duration().count(), 0);
91
92 span.add_attribute("http.method", "GET");
93 span.add_event("request_started");
94
95 EXPECT_EQ(span.attributes.size(), 1);
96 EXPECT_EQ(span.events.size(), 1);
97 EXPECT_EQ(span.attributes[0].key, "http.method");
98 EXPECT_EQ(span.attributes[0].value, "GET");
99}
100
101TEST_F(OpenTelemetryAdapterTest, MetricDataOperations) {
103 metric.name = "cpu_usage";
104 metric.description = "CPU usage percentage";
105 metric.unit = "percent";
106 metric.value = 75.5;
107 metric.timestamp = std::chrono::system_clock::now();
108
109 metric.add_attribute("host.name", "server01");
110 metric.add_attribute("service.name", "web_server");
111
112 EXPECT_EQ(metric.name, "cpu_usage");
113 EXPECT_EQ(metric.value, 75.5);
114 EXPECT_EQ(metric.attributes.size(), 2);
115 EXPECT_EQ(metric.attributes[0].key, "host.name");
116 EXPECT_EQ(metric.attributes[0].value, "server01");
117}
118
119TEST_F(OpenTelemetryAdapterTest, TracerAdapterSpanConversion) {
120 opentelemetry_tracer_adapter adapter(resource);
121
122 trace_span internal_span;
123 internal_span.operation_name = "database_query";
124 internal_span.trace_id = "trace123";
125 internal_span.span_id = "span456";
126 internal_span.parent_span_id = "parent789";
127 internal_span.start_time = std::chrono::system_clock::now();
128 internal_span.end_time = internal_span.start_time + std::chrono::milliseconds(100);
129 internal_span.tags["span.kind"] = "client";
130 internal_span.tags["db.statement"] = "SELECT * FROM users";
131 internal_span.tags["error"] = "false";
132
133 auto result = adapter.convert_span(internal_span);
134 ASSERT_TRUE(result.is_ok());
135
136 const auto& otel_span = result.value();
137 EXPECT_EQ(otel_span.name, "database_query");
138 EXPECT_EQ(otel_span.context.trace_id, "trace123");
139 EXPECT_EQ(otel_span.context.span_id, "span456");
140 EXPECT_EQ(otel_span.parent_context.span_id, "parent789");
141 EXPECT_EQ(otel_span.kind, otel_span_kind::client);
142 EXPECT_EQ(otel_span.status_code, otel_status_code::ok);
143 EXPECT_EQ(otel_span.attributes.size(), 1);
144
145 // Find db.statement attribute
146 bool found_db_statement = false;
147 for (const auto& attr : otel_span.attributes) {
148 if (attr.key == "db.statement" && attr.value == "SELECT * FROM users") {
149 found_db_statement = true;
150 break;
151 }
152 }
153 EXPECT_TRUE(found_db_statement);
154}
155
156TEST_F(OpenTelemetryAdapterTest, TracerAdapterErrorSpanConversion) {
157 opentelemetry_tracer_adapter adapter(resource);
158
159 trace_span error_span;
160 error_span.operation_name = "failed_operation";
161 error_span.trace_id = "trace123";
162 error_span.span_id = "span456";
163 error_span.start_time = std::chrono::system_clock::now();
164 error_span.end_time = error_span.start_time + std::chrono::milliseconds(50);
165 error_span.tags["error"] = "true";
166 error_span.tags["error.message"] = "Connection timeout";
167
168 auto result = adapter.convert_span(error_span);
169 ASSERT_TRUE(result.is_ok());
170
171 const auto& otel_span = result.value();
172 EXPECT_EQ(otel_span.status_code, otel_status_code::error);
173 EXPECT_EQ(otel_span.status_message, "Connection timeout");
174}
175
176TEST_F(OpenTelemetryAdapterTest, TracerAdapterMultipleSpans) {
177 opentelemetry_tracer_adapter adapter(resource);
178
179 std::vector<trace_span> spans;
180 for (int i = 0; i < 3; ++i) {
181 trace_span span;
182 span.operation_name = "operation_" + std::to_string(i);
183 span.trace_id = "trace123";
184 span.span_id = "span" + std::to_string(i);
185 span.start_time = std::chrono::system_clock::now();
186 span.end_time = span.start_time + std::chrono::milliseconds(10);
187 spans.push_back(span);
188 }
189
190 auto result = adapter.convert_spans(spans);
191 ASSERT_TRUE(result.is_ok());
192
193 const auto& otel_spans = result.value();
194 EXPECT_EQ(otel_spans.size(), 3);
195
196 for (size_t i = 0; i < otel_spans.size(); ++i) {
197 EXPECT_EQ(otel_spans[i].name, "operation_" + std::to_string(i));
198 EXPECT_EQ(otel_spans[i].context.span_id, "span" + std::to_string(i));
199 }
200}
201
202TEST_F(OpenTelemetryAdapterTest, MetricsAdapterConversion) {
203 opentelemetry_metrics_adapter adapter(resource);
204
205 monitoring_data data("test_component");
206 data.add_metric("cpu_usage", 75.5);
207 data.add_metric("memory_usage", 1024.0);
208 data.add_tag("environment", "production");
209 data.add_tag("region", "us-west-2");
210
211 auto result = adapter.convert_monitoring_data(data);
212 ASSERT_TRUE(result.is_ok());
213
214 const auto& otel_metrics = result.value();
215 EXPECT_EQ(otel_metrics.size(), 2);
216
217 // Find CPU usage metric
218 bool found_cpu = false;
219 for (const auto& metric : otel_metrics) {
220 if (metric.name == "cpu_usage") {
221 EXPECT_EQ(metric.value, 75.5);
222 found_cpu = true;
223
224 // Check attributes include tags
225 bool found_env = false;
226 for (const auto& attr : metric.attributes) {
227 if (attr.key == "environment" && attr.value == "production") {
228 found_env = true;
229 break;
230 }
231 }
232 EXPECT_TRUE(found_env);
233 }
234 }
235 EXPECT_TRUE(found_cpu);
236}
237
238TEST_F(OpenTelemetryAdapterTest, CompatibilityLayerInitialization) {
239 EXPECT_TRUE(compatibility_layer);
240
241 auto init_result = compatibility_layer->initialize();
242 EXPECT_TRUE(init_result.is_ok());
243
244 // Double initialization should fail
245 auto double_init = compatibility_layer->initialize();
246 EXPECT_TRUE(double_init.is_err());
247 EXPECT_EQ(double_init.error().code, static_cast<int>(monitoring_error_code::already_exists));
248
249 auto shutdown_result = compatibility_layer->shutdown();
250 EXPECT_TRUE(shutdown_result.is_ok());
251}
252
253TEST_F(OpenTelemetryAdapterTest, CompatibilityLayerSpanExport) {
254 auto init_result = compatibility_layer->initialize();
255 ASSERT_TRUE(init_result.is_ok());
256
257 std::vector<trace_span> spans;
258 trace_span span;
259 span.operation_name = "test_operation";
260 span.trace_id = "trace123";
261 span.span_id = "span456";
262 span.start_time = std::chrono::system_clock::now();
263 span.end_time = span.start_time + std::chrono::milliseconds(10);
264 spans.push_back(span);
265
266 auto export_result = compatibility_layer->export_spans(spans);
267 EXPECT_TRUE(export_result.is_ok());
268
269 auto stats = compatibility_layer->get_stats();
270 EXPECT_EQ(stats.pending_spans, 1);
271 EXPECT_EQ(stats.pending_metrics, 0);
272
273 auto flush_result = compatibility_layer->flush();
274 EXPECT_TRUE(flush_result.is_ok());
275
276 stats = compatibility_layer->get_stats();
277 EXPECT_EQ(stats.pending_spans, 0);
278}
279
280TEST_F(OpenTelemetryAdapterTest, CompatibilityLayerMetricExport) {
281 auto init_result = compatibility_layer->initialize();
282 ASSERT_TRUE(init_result.is_ok());
283
284 monitoring_data data("test_component");
285 data.add_metric("test_metric", 42.0);
286 data.add_tag("test_tag", "test_value");
287
288 auto export_result = compatibility_layer->export_metrics(data);
289 EXPECT_TRUE(export_result.is_ok());
290
291 auto stats = compatibility_layer->get_stats();
292 EXPECT_EQ(stats.pending_metrics, 1);
293 EXPECT_EQ(stats.pending_spans, 0);
294
295 auto flush_result = compatibility_layer->flush();
296 EXPECT_TRUE(flush_result.is_ok());
297
298 stats = compatibility_layer->get_stats();
299 EXPECT_EQ(stats.pending_metrics, 0);
300}
301
302TEST_F(OpenTelemetryAdapterTest, CompatibilityLayerUninitializedExport) {
303 std::vector<trace_span> spans;
304 trace_span span;
305 spans.push_back(span);
306
307 auto export_result = compatibility_layer->export_spans(spans);
308 EXPECT_TRUE(export_result.is_err());
309 EXPECT_EQ(export_result.error().code, static_cast<int>(monitoring_error_code::invalid_state));
310
311 monitoring_data data("test");
312 auto metrics_export_result = compatibility_layer->export_metrics(data);
313 EXPECT_TRUE(metrics_export_result.is_err());
314 EXPECT_EQ(metrics_export_result.error().code, static_cast<int>(monitoring_error_code::invalid_state));
315}
316
317TEST_F(OpenTelemetryAdapterTest, CompatibilityLayerResourceAccess) {
318 const auto& layer_resource = compatibility_layer->get_resource();
319 EXPECT_EQ(layer_resource.type, otel_resource_type::service);
320
321 auto service_name = layer_resource.get_attribute("service.name");
322 EXPECT_TRUE(service_name.is_ok());
323 EXPECT_EQ(service_name.value(), "test_service");
324}
325
326TEST_F(OpenTelemetryAdapterTest, ExporterConfigValidation) {
328 valid_config.endpoint = "http://localhost:4317";
329 valid_config.protocol = "grpc";
330 valid_config.timeout = std::chrono::milliseconds(5000);
331 valid_config.max_batch_size = 100;
332
333 auto validation = valid_config.validate();
334 EXPECT_TRUE(validation.is_ok());
335
336 // Test invalid endpoint
337 opentelemetry_exporter_config invalid_endpoint;
338 invalid_endpoint.endpoint = "";
339 auto endpoint_validation = invalid_endpoint.validate();
340 EXPECT_TRUE(endpoint_validation.is_err());
341 EXPECT_EQ(endpoint_validation.error().code, static_cast<int>(monitoring_error_code::invalid_configuration));
342
343 // Test invalid protocol
344 opentelemetry_exporter_config invalid_protocol;
345 invalid_protocol.protocol = "invalid";
346 auto protocol_validation = invalid_protocol.validate();
347 EXPECT_TRUE(protocol_validation.is_err());
348
349 // Test invalid timeout
350 opentelemetry_exporter_config invalid_timeout;
351 invalid_timeout.timeout = std::chrono::milliseconds(0);
352 auto timeout_validation = invalid_timeout.validate();
353 EXPECT_TRUE(timeout_validation.is_err());
354
355 // Test invalid batch size
356 opentelemetry_exporter_config invalid_batch;
357 invalid_batch.max_batch_size = 0;
358 auto batch_validation = invalid_batch.validate();
359 EXPECT_TRUE(batch_validation.is_err());
360}
361
363 // Test service resource creation
364 auto service_resource = create_service_resource("my_service", "2.0.0", "production");
365 EXPECT_EQ(service_resource.type, otel_resource_type::service);
366
367 auto name = service_resource.get_attribute("service.name");
368 EXPECT_TRUE(name.is_ok());
369 EXPECT_EQ(name.value(), "my_service");
370
371 auto version = service_resource.get_attribute("service.version");
372 EXPECT_TRUE(version.is_ok());
373 EXPECT_EQ(version.value(), "2.0.0");
374
375 // Test compatibility layer factory functions
376 auto layer1 = create_opentelemetry_compatibility_layer(service_resource);
377 EXPECT_TRUE(layer1 != nullptr);
378
379 auto layer2 = create_opentelemetry_compatibility_layer("test_service", "1.0.0");
380 EXPECT_TRUE(layer2 != nullptr);
381
382 const auto& layer2_resource = layer2->get_resource();
383 auto layer2_name = layer2_resource.get_attribute("service.name");
384 EXPECT_TRUE(layer2_name.is_ok());
385 EXPECT_EQ(layer2_name.value(), "test_service");
386}
std::unique_ptr< opentelemetry_compatibility_layer > compatibility_layer
Adapter for converting monitoring system metrics to OpenTelemetry format.
common::Result< std::vector< otel_metric_data > > convert_monitoring_data(const monitoring_data &data)
Convert monitoring data to OpenTelemetry metric data.
Adapter for converting monitoring system traces to OpenTelemetry format.
common::Result< otel_span_data > convert_span(const trace_span &span)
Convert internal span to OpenTelemetry span data.
common::Result< std::vector< otel_span_data > > convert_spans(const std::vector< trace_span > &spans)
Convert multiple spans to OpenTelemetry format.
Core monitoring system interface definitions.
std::unique_ptr< opentelemetry_compatibility_layer > create_opentelemetry_compatibility_layer(const otel_resource &resource)
Create OpenTelemetry compatibility layer.
otel_resource create_service_resource(const std::string &service_name, const std::string &service_version="1.0.0", const std::string &service_namespace="")
Create OpenTelemetry resource with service information.
OpenTelemetry compatibility layer for monitoring system integration.
Basic metric structure for interface compatibility.
std::chrono::system_clock::time_point timestamp
std::variant< double, int64_t, std::string > value
Container for monitoring metrics from a component.
void add_metric(const std::string &key, double value)
Add a numeric metric.
void add_tag(const std::string &key, const std::string &value)
Add a tag (string metadata)
Configuration for OpenTelemetry exporters.
OpenTelemetry attribute representation.
OpenTelemetry metric data representation.
OpenTelemetry resource representation.
OpenTelemetry span data representation.
std::chrono::microseconds duration() const
std::chrono::system_clock::time_point start_time
void add_attribute(const std::string &key, const std::string &value)
std::vector< otel_attribute > attributes
std::chrono::system_clock::time_point end_time
void add_event(const std::string &event)
Trace span representing a unit of work in distributed tracing.
std::unordered_map< std::string, std::string > tags
std::chrono::system_clock::time_point end_time
std::chrono::system_clock::time_point start_time
TEST_F(OpenTelemetryAdapterTest, ResourceCreation)