aggregation_test.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #include "opentelemetry/sdk/metrics/aggregation/aggregation.h"
  4. #include <gtest/gtest.h>
  5. #include <stdint.h>
  6. #include <limits>
  7. #include <string>
  8. #include <vector>
  9. #include "opentelemetry/nostd/variant.h"
  10. #include "opentelemetry/sdk/metrics/aggregation/aggregation_config.h"
  11. #include "opentelemetry/sdk/metrics/aggregation/base2_exponential_histogram_aggregation.h"
  12. #include "opentelemetry/sdk/metrics/aggregation/default_aggregation.h"
  13. #include "opentelemetry/sdk/metrics/aggregation/histogram_aggregation.h"
  14. #include "opentelemetry/sdk/metrics/aggregation/lastvalue_aggregation.h"
  15. #include "opentelemetry/sdk/metrics/aggregation/sum_aggregation.h"
  16. #include "opentelemetry/sdk/metrics/data/circular_buffer.h"
  17. #include "opentelemetry/sdk/metrics/data/point_data.h"
  18. #include "opentelemetry/sdk/metrics/instruments.h"
  19. using namespace opentelemetry::sdk::metrics;
  20. namespace nostd = opentelemetry::nostd;
  21. TEST(Aggregation, LongSumAggregation)
  22. {
  23. LongSumAggregation aggr(true);
  24. auto data = aggr.ToPoint();
  25. ASSERT_TRUE(nostd::holds_alternative<SumPointData>(data));
  26. auto sum_data = nostd::get<SumPointData>(data);
  27. ASSERT_TRUE(nostd::holds_alternative<int64_t>(sum_data.value_));
  28. EXPECT_EQ(nostd::get<int64_t>(sum_data.value_), 0);
  29. aggr.Aggregate(static_cast<int64_t>(12), {});
  30. aggr.Aggregate(static_cast<int64_t>(0), {});
  31. sum_data = nostd::get<SumPointData>(aggr.ToPoint());
  32. EXPECT_EQ(nostd::get<int64_t>(sum_data.value_), 12);
  33. }
  34. TEST(Aggregation, DoubleSumAggregation)
  35. {
  36. DoubleSumAggregation aggr(true);
  37. auto data = aggr.ToPoint();
  38. ASSERT_TRUE(nostd::holds_alternative<SumPointData>(data));
  39. auto sum_data = nostd::get<SumPointData>(data);
  40. ASSERT_TRUE(nostd::holds_alternative<double>(sum_data.value_));
  41. EXPECT_EQ(nostd::get<double>(sum_data.value_), 0);
  42. aggr.Aggregate(12.0, {});
  43. aggr.Aggregate(1.0, {});
  44. sum_data = nostd::get<SumPointData>(aggr.ToPoint());
  45. EXPECT_EQ(nostd::get<double>(sum_data.value_), 13.0);
  46. }
  47. TEST(Aggregation, LongLastValueAggregation)
  48. {
  49. LongLastValueAggregation aggr;
  50. auto data = aggr.ToPoint();
  51. ASSERT_TRUE(nostd::holds_alternative<LastValuePointData>(data));
  52. auto lastvalue_data = nostd::get<LastValuePointData>(data);
  53. ASSERT_TRUE(nostd::holds_alternative<int64_t>(lastvalue_data.value_));
  54. EXPECT_EQ(lastvalue_data.is_lastvalue_valid_, false);
  55. aggr.Aggregate(static_cast<int64_t>(12), {});
  56. aggr.Aggregate(static_cast<int64_t>(1), {});
  57. lastvalue_data = nostd::get<LastValuePointData>(aggr.ToPoint());
  58. EXPECT_EQ(nostd::get<int64_t>(lastvalue_data.value_), 1.0);
  59. }
  60. TEST(Aggregation, DoubleLastValueAggregation)
  61. {
  62. DoubleLastValueAggregation aggr;
  63. auto data = aggr.ToPoint();
  64. ASSERT_TRUE(nostd::holds_alternative<LastValuePointData>(data));
  65. auto lastvalue_data = nostd::get<LastValuePointData>(data);
  66. ASSERT_TRUE(nostd::holds_alternative<double>(lastvalue_data.value_));
  67. EXPECT_EQ(lastvalue_data.is_lastvalue_valid_, false);
  68. aggr.Aggregate(12.0, {});
  69. aggr.Aggregate(1.0, {});
  70. lastvalue_data = nostd::get<LastValuePointData>(aggr.ToPoint());
  71. EXPECT_EQ(nostd::get<double>(lastvalue_data.value_), 1.0);
  72. }
  73. TEST(Aggregation, LongHistogramAggregation)
  74. {
  75. LongHistogramAggregation aggr;
  76. auto data = aggr.ToPoint();
  77. ASSERT_TRUE(nostd::holds_alternative<HistogramPointData>(data));
  78. auto histogram_data = nostd::get<HistogramPointData>(data);
  79. ASSERT_TRUE(nostd::holds_alternative<int64_t>(histogram_data.sum_));
  80. EXPECT_EQ(nostd::get<int64_t>(histogram_data.sum_), 0);
  81. EXPECT_EQ(histogram_data.count_, 0);
  82. aggr.Aggregate(static_cast<int64_t>(12), {}); // lies in third bucket
  83. aggr.Aggregate(static_cast<int64_t>(100), {}); // lies in sixth bucket
  84. histogram_data = nostd::get<HistogramPointData>(aggr.ToPoint());
  85. EXPECT_EQ(nostd::get<int64_t>(histogram_data.min_), 12);
  86. EXPECT_EQ(nostd::get<int64_t>(histogram_data.max_), 100);
  87. EXPECT_EQ(nostd::get<int64_t>(histogram_data.sum_), 112);
  88. EXPECT_EQ(histogram_data.count_, 2);
  89. EXPECT_EQ(histogram_data.counts_[3], 1);
  90. EXPECT_EQ(histogram_data.counts_[6], 1);
  91. aggr.Aggregate(static_cast<int64_t>(13), {}); // lies in third bucket
  92. aggr.Aggregate(static_cast<int64_t>(252), {}); // lies in eight bucket
  93. histogram_data = nostd::get<HistogramPointData>(aggr.ToPoint());
  94. EXPECT_EQ(histogram_data.count_, 4);
  95. EXPECT_EQ(histogram_data.counts_[3], 2);
  96. EXPECT_EQ(histogram_data.counts_[8], 1);
  97. EXPECT_EQ(nostd::get<int64_t>(histogram_data.min_), 12);
  98. EXPECT_EQ(nostd::get<int64_t>(histogram_data.max_), 252);
  99. // Merge
  100. LongHistogramAggregation aggr1;
  101. aggr1.Aggregate(static_cast<int64_t>(1), {});
  102. aggr1.Aggregate(static_cast<int64_t>(11), {});
  103. aggr1.Aggregate(static_cast<int64_t>(26), {});
  104. LongHistogramAggregation aggr2;
  105. aggr2.Aggregate(static_cast<int64_t>(2), {});
  106. aggr2.Aggregate(static_cast<int64_t>(3), {});
  107. aggr2.Aggregate(static_cast<int64_t>(13), {});
  108. aggr2.Aggregate(static_cast<int64_t>(28), {});
  109. aggr2.Aggregate(static_cast<int64_t>(105), {});
  110. auto aggr3 = aggr1.Merge(aggr2);
  111. histogram_data = nostd::get<HistogramPointData>(aggr3->ToPoint());
  112. EXPECT_EQ(histogram_data.count_, 8); // 3 each from aggr1 and aggr2
  113. EXPECT_EQ(histogram_data.counts_[1], 3); // 1, 2, 3
  114. EXPECT_EQ(histogram_data.counts_[3], 2); // 11, 13
  115. EXPECT_EQ(histogram_data.counts_[4], 2); // 25, 28
  116. EXPECT_EQ(histogram_data.counts_[7], 1); // 105
  117. EXPECT_EQ(nostd::get<int64_t>(histogram_data.min_), 1);
  118. EXPECT_EQ(nostd::get<int64_t>(histogram_data.max_), 105);
  119. // Diff
  120. auto aggr4 = aggr1.Diff(aggr2);
  121. histogram_data = nostd::get<HistogramPointData>(aggr4->ToPoint());
  122. EXPECT_EQ(histogram_data.count_, 2); // aggr2:5 - aggr1:3
  123. EXPECT_EQ(histogram_data.counts_[1], 1); // aggr2(2, 3) - aggr1(1)
  124. EXPECT_EQ(histogram_data.counts_[3], 0); // aggr2(13) - aggr1(11)
  125. EXPECT_EQ(histogram_data.counts_[4], 0); // aggr2(28) - aggr1(25)
  126. EXPECT_EQ(histogram_data.counts_[7], 1); // aggr2(105) - aggr1(0)
  127. }
  128. TEST(Aggregation, LongHistogramAggregationBoundaries)
  129. {
  130. std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregationConfig> aggregation_config{
  131. new opentelemetry::sdk::metrics::HistogramAggregationConfig};
  132. std::vector<double> user_boundaries = {0.0, 50.0, 100.0, 250.0, 500.0,
  133. 750.0, 1000.0, 2500.0, 5000.0, 10000.0};
  134. aggregation_config->boundaries_ = user_boundaries;
  135. LongHistogramAggregation aggr{aggregation_config.get()};
  136. auto data = aggr.ToPoint();
  137. ASSERT_TRUE(nostd::holds_alternative<HistogramPointData>(data));
  138. auto histogram_data = nostd::get<HistogramPointData>(data);
  139. EXPECT_EQ(histogram_data.boundaries_, user_boundaries);
  140. }
  141. TEST(Aggregation, DoubleHistogramAggregationBoundaries)
  142. {
  143. std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregationConfig> aggregation_config{
  144. new opentelemetry::sdk::metrics::HistogramAggregationConfig};
  145. std::vector<double> user_boundaries = {0.0, 50.0, 100.0, 250.0, 500.0,
  146. 750.0, 1000.0, 2500.0, 5000.0, 10000.0};
  147. aggregation_config->boundaries_ = user_boundaries;
  148. DoubleHistogramAggregation aggr{aggregation_config.get()};
  149. auto data = aggr.ToPoint();
  150. ASSERT_TRUE(nostd::holds_alternative<HistogramPointData>(data));
  151. auto histogram_data = nostd::get<HistogramPointData>(data);
  152. EXPECT_EQ(histogram_data.boundaries_, user_boundaries);
  153. }
  154. TEST(Aggregation, DoubleHistogramAggregation)
  155. {
  156. DoubleHistogramAggregation aggr;
  157. auto data = aggr.ToPoint();
  158. ASSERT_TRUE(nostd::holds_alternative<HistogramPointData>(data));
  159. auto histogram_data = nostd::get<HistogramPointData>(data);
  160. ASSERT_TRUE(nostd::holds_alternative<double>(histogram_data.sum_));
  161. EXPECT_EQ(nostd::get<double>(histogram_data.sum_), 0);
  162. EXPECT_EQ(histogram_data.count_, 0);
  163. aggr.Aggregate(12.0, {}); // lies in third bucket
  164. aggr.Aggregate(100.0, {}); // lies in sixth bucket
  165. histogram_data = nostd::get<HistogramPointData>(aggr.ToPoint());
  166. EXPECT_EQ(nostd::get<double>(histogram_data.sum_), 112);
  167. EXPECT_EQ(histogram_data.count_, 2);
  168. EXPECT_EQ(histogram_data.counts_[3], 1);
  169. EXPECT_EQ(histogram_data.counts_[6], 1);
  170. EXPECT_EQ(nostd::get<double>(histogram_data.min_), 12);
  171. EXPECT_EQ(nostd::get<double>(histogram_data.max_), 100);
  172. aggr.Aggregate(13.0, {}); // lies in third bucket
  173. aggr.Aggregate(252.0, {}); // lies in eight bucket
  174. histogram_data = nostd::get<HistogramPointData>(aggr.ToPoint());
  175. EXPECT_EQ(histogram_data.count_, 4);
  176. EXPECT_EQ(histogram_data.counts_[3], 2);
  177. EXPECT_EQ(histogram_data.counts_[8], 1);
  178. EXPECT_EQ(nostd::get<double>(histogram_data.sum_), 377);
  179. EXPECT_EQ(nostd::get<double>(histogram_data.min_), 12);
  180. EXPECT_EQ(nostd::get<double>(histogram_data.max_), 252);
  181. // Merge
  182. DoubleHistogramAggregation aggr1;
  183. aggr1.Aggregate(1.0, {});
  184. aggr1.Aggregate(11.0, {});
  185. aggr1.Aggregate(25.1, {});
  186. DoubleHistogramAggregation aggr2;
  187. aggr2.Aggregate(2.0, {});
  188. aggr2.Aggregate(3.0, {});
  189. aggr2.Aggregate(13.0, {});
  190. aggr2.Aggregate(28.1, {});
  191. aggr2.Aggregate(105.0, {});
  192. auto aggr3 = aggr1.Merge(aggr2);
  193. histogram_data = nostd::get<HistogramPointData>(aggr3->ToPoint());
  194. EXPECT_EQ(histogram_data.count_, 8); // 3 each from aggr1 and aggr2
  195. EXPECT_EQ(histogram_data.counts_[1], 3); // 1.0, 2.0, 3.0
  196. EXPECT_EQ(histogram_data.counts_[3], 2); // 11.0, 13.0
  197. EXPECT_EQ(histogram_data.counts_[4], 2); // 25.1, 28.1
  198. EXPECT_EQ(histogram_data.counts_[7], 1); // 105.0
  199. EXPECT_EQ(nostd::get<double>(histogram_data.min_), 1);
  200. EXPECT_EQ(nostd::get<double>(histogram_data.max_), 105);
  201. // Diff
  202. auto aggr4 = aggr1.Diff(aggr2);
  203. histogram_data = nostd::get<HistogramPointData>(aggr4->ToPoint());
  204. EXPECT_EQ(histogram_data.count_, 2); // aggr2:5 - aggr1:3
  205. EXPECT_EQ(histogram_data.counts_[1], 1); // aggr2(2.0, 3.0) - aggr1(1.0)
  206. EXPECT_EQ(histogram_data.counts_[3], 0); // aggr2(13.0) - aggr1(11.0)
  207. EXPECT_EQ(histogram_data.counts_[4], 0); // aggr2(28.1) - aggr1(25.1)
  208. EXPECT_EQ(histogram_data.counts_[7], 1); // aggr2(105.0) - aggr1(0)
  209. }
  210. TEST(Aggregation, Base2ExponentialHistogramAggregation)
  211. {
  212. // Low res histo
  213. auto SCALE0 = 0;
  214. auto MAX_BUCKETS0 = 7;
  215. Base2ExponentialHistogramAggregationConfig scale0_config;
  216. scale0_config.max_scale_ = SCALE0;
  217. scale0_config.max_buckets_ = MAX_BUCKETS0;
  218. scale0_config.record_min_max_ = true;
  219. Base2ExponentialHistogramAggregation scale0_aggr(&scale0_config);
  220. auto point = scale0_aggr.ToPoint();
  221. ASSERT_TRUE(nostd::holds_alternative<Base2ExponentialHistogramPointData>(point));
  222. auto histo_point = nostd::get<Base2ExponentialHistogramPointData>(point);
  223. EXPECT_EQ(histo_point.count_, 0);
  224. EXPECT_EQ(histo_point.sum_, 0.0);
  225. EXPECT_EQ(histo_point.zero_count_, 0);
  226. EXPECT_EQ(histo_point.min_, (std::numeric_limits<double>::max)());
  227. EXPECT_EQ(histo_point.max_, (std::numeric_limits<double>::min)());
  228. EXPECT_EQ(histo_point.scale_, SCALE0);
  229. EXPECT_EQ(histo_point.max_buckets_, MAX_BUCKETS0);
  230. ASSERT_TRUE(histo_point.positive_buckets_ != nullptr);
  231. ASSERT_TRUE(histo_point.negative_buckets_ != nullptr);
  232. ASSERT_TRUE(histo_point.positive_buckets_->Empty());
  233. ASSERT_TRUE(histo_point.negative_buckets_->Empty());
  234. // Create a new aggreagte based in point data
  235. {
  236. auto point_data = histo_point;
  237. Base2ExponentialHistogramAggregation scale0_aggr2(point_data);
  238. scale0_aggr2.Aggregate(0.0, {});
  239. auto histo_point2 = nostd::get<Base2ExponentialHistogramPointData>(point);
  240. EXPECT_EQ(histo_point2.count_, 0);
  241. EXPECT_EQ(histo_point2.sum_, 0.0);
  242. EXPECT_EQ(histo_point2.zero_count_, 0);
  243. EXPECT_EQ(histo_point2.min_, (std::numeric_limits<double>::max)());
  244. EXPECT_EQ(histo_point2.max_, (std::numeric_limits<double>::min)());
  245. EXPECT_EQ(histo_point2.scale_, SCALE0);
  246. EXPECT_EQ(histo_point2.max_buckets_, MAX_BUCKETS0);
  247. ASSERT_TRUE(histo_point2.positive_buckets_->Empty());
  248. ASSERT_TRUE(histo_point2.negative_buckets_->Empty());
  249. }
  250. // zero point
  251. scale0_aggr.Aggregate(static_cast<int64_t>(0.0), {});
  252. histo_point = nostd::get<Base2ExponentialHistogramPointData>(scale0_aggr.ToPoint());
  253. EXPECT_EQ(histo_point.count_, 1);
  254. EXPECT_EQ(histo_point.zero_count_, 1);
  255. // Two recordings in the same bucket (bucket 1 at scale 0)
  256. scale0_aggr.Aggregate(3.0, {});
  257. scale0_aggr.Aggregate(3.5, {});
  258. histo_point = nostd::get<Base2ExponentialHistogramPointData>(scale0_aggr.ToPoint());
  259. EXPECT_EQ(histo_point.count_, 3);
  260. EXPECT_EQ(histo_point.sum_, 6.5);
  261. EXPECT_EQ(histo_point.min_, 0.0);
  262. EXPECT_EQ(histo_point.max_, 3.5);
  263. ASSERT_TRUE(histo_point.positive_buckets_ != nullptr);
  264. ASSERT_TRUE(histo_point.negative_buckets_ != nullptr);
  265. ASSERT_FALSE(histo_point.positive_buckets_->Empty());
  266. auto start_index = histo_point.positive_buckets_->StartIndex();
  267. auto end_index = histo_point.positive_buckets_->EndIndex();
  268. EXPECT_EQ(start_index, 1);
  269. EXPECT_EQ(end_index, 1);
  270. EXPECT_EQ(histo_point.positive_buckets_->Get(start_index), 2);
  271. // Recording in a different bucket (bucket -2 at scale 0)
  272. scale0_aggr.Aggregate(-0.3, {});
  273. histo_point = nostd::get<Base2ExponentialHistogramPointData>(scale0_aggr.ToPoint());
  274. EXPECT_EQ(histo_point.count_, 4);
  275. EXPECT_EQ(histo_point.sum_, 6.2);
  276. EXPECT_EQ(histo_point.min_, -0.3);
  277. EXPECT_EQ(histo_point.max_, 3.5);
  278. ASSERT_TRUE(histo_point.positive_buckets_ != nullptr);
  279. ASSERT_TRUE(histo_point.negative_buckets_ != nullptr);
  280. EXPECT_EQ(histo_point.negative_buckets_->Get(-2), 1);
  281. EXPECT_EQ(histo_point.positive_buckets_->Get(1), 2);
  282. Base2ExponentialHistogramAggregationConfig scale1_config;
  283. scale1_config.max_scale_ = 1;
  284. scale1_config.max_buckets_ = 14;
  285. scale1_config.record_min_max_ = true;
  286. Base2ExponentialHistogramAggregation scale1_aggr(&scale1_config);
  287. scale1_aggr.Aggregate(0.0, {});
  288. scale1_aggr.Aggregate(3.0, {});
  289. scale1_aggr.Aggregate(3.5, {});
  290. scale1_aggr.Aggregate(0.3, {});
  291. auto scale1_point = nostd::get<Base2ExponentialHistogramPointData>(scale1_aggr.ToPoint());
  292. EXPECT_EQ(scale1_point.count_, 4);
  293. EXPECT_EQ(scale1_point.sum_, 6.8);
  294. EXPECT_EQ(scale1_point.zero_count_, 1);
  295. EXPECT_EQ(scale1_point.min_, 0.0);
  296. EXPECT_EQ(scale1_point.max_, 3.5);
  297. // Merge test
  298. auto merged = scale0_aggr.Merge(scale1_aggr);
  299. auto merged_point = nostd::get<Base2ExponentialHistogramPointData>(merged->ToPoint());
  300. EXPECT_EQ(merged_point.count_, 8);
  301. EXPECT_EQ(merged_point.sum_, 13.0);
  302. EXPECT_EQ(merged_point.zero_count_, 2);
  303. EXPECT_EQ(merged_point.min_, -0.3);
  304. EXPECT_EQ(merged_point.max_, 3.5);
  305. EXPECT_EQ(merged_point.scale_, 0);
  306. ASSERT_TRUE(merged_point.positive_buckets_ != nullptr);
  307. ASSERT_TRUE(merged_point.negative_buckets_ != nullptr);
  308. EXPECT_EQ(merged_point.positive_buckets_->Get(1), 4);
  309. EXPECT_EQ(merged_point.negative_buckets_->Get(-2), 1);
  310. EXPECT_EQ(merged_point.positive_buckets_->Get(2), 0);
  311. // Diff test
  312. Base2ExponentialHistogramAggregation scale2_aggr(&scale1_config);
  313. Base2ExponentialHistogramAggregation scale3_aggr(&scale1_config);
  314. scale2_aggr.Aggregate(2.0, {});
  315. scale2_aggr.Aggregate(4.0, {});
  316. scale2_aggr.Aggregate(2.5, {});
  317. scale3_aggr.Aggregate(2.0, {});
  318. scale3_aggr.Aggregate(2.3, {});
  319. scale3_aggr.Aggregate(2.5, {});
  320. scale3_aggr.Aggregate(4.0, {});
  321. auto diffd = scale2_aggr.Diff(scale3_aggr);
  322. auto diffd_point = nostd::get<Base2ExponentialHistogramPointData>(diffd->ToPoint());
  323. EXPECT_EQ(diffd_point.count_, 1);
  324. EXPECT_NEAR(diffd_point.sum_, 2.3, 1e-9);
  325. EXPECT_EQ(diffd_point.zero_count_, 0);
  326. EXPECT_EQ(diffd_point.scale_, 1);
  327. ASSERT_TRUE(diffd_point.positive_buckets_ != nullptr);
  328. ASSERT_TRUE(diffd_point.negative_buckets_ != nullptr);
  329. EXPECT_EQ(diffd_point.positive_buckets_->Get(2), 1);
  330. }
  331. TEST(Aggregation, Base2ExponentialHistogramAggregationMerge)
  332. {
  333. Base2ExponentialHistogramAggregationConfig config;
  334. config.max_scale_ = 10;
  335. config.max_buckets_ = 100;
  336. config.record_min_max_ = true;
  337. Base2ExponentialHistogramAggregation aggr(&config);
  338. int expected_count = 0;
  339. double expected_sum = 0.0;
  340. // Aggregate some small values
  341. for (int i = 1; i < 10; ++i)
  342. {
  343. expected_count++;
  344. const double value = i * 1e-12;
  345. expected_sum += value;
  346. aggr.Aggregate(value);
  347. }
  348. const auto aggr_point = nostd::get<Base2ExponentialHistogramPointData>(aggr.ToPoint());
  349. ASSERT_EQ(aggr_point.count_, expected_count);
  350. ASSERT_DOUBLE_EQ(aggr_point.sum_, expected_sum);
  351. ASSERT_EQ(aggr_point.zero_count_, 0);
  352. ASSERT_GT(aggr_point.scale_, -10);
  353. ASSERT_EQ(aggr_point.max_buckets_, config.max_buckets_);
  354. auto test_merge = [](const std::unique_ptr<Aggregation> &merged_aggr, int expected_count,
  355. double expected_sum, int expected_zero_count, int expected_scale,
  356. int expected_max_buckets) {
  357. auto merged_point = nostd::get<Base2ExponentialHistogramPointData>(merged_aggr->ToPoint());
  358. EXPECT_EQ(merged_point.count_, expected_count);
  359. EXPECT_DOUBLE_EQ(merged_point.sum_, expected_sum);
  360. EXPECT_EQ(merged_point.zero_count_, expected_zero_count);
  361. EXPECT_EQ(merged_point.scale_, expected_scale);
  362. EXPECT_EQ(merged_point.max_buckets_, expected_max_buckets);
  363. };
  364. // default aggregation merge
  365. {
  366. InstrumentDescriptor descriptor;
  367. descriptor.type_ = InstrumentType::kHistogram;
  368. descriptor.unit_ = "unit";
  369. descriptor.name_ = "histogram";
  370. descriptor.description_ = "a histogram";
  371. descriptor.value_type_ = InstrumentValueType::kDouble;
  372. auto default_aggr = DefaultAggregation::CreateAggregation(
  373. AggregationType::kBase2ExponentialHistogram, descriptor);
  374. auto default_point = nostd::get<Base2ExponentialHistogramPointData>(default_aggr->ToPoint());
  375. const int expected_scale =
  376. aggr_point.scale_ < default_point.scale_ ? aggr_point.scale_ : default_point.scale_;
  377. const int expected_max_buckets = aggr_point.max_buckets_ < default_point.max_buckets_
  378. ? aggr_point.max_buckets_
  379. : default_point.max_buckets_;
  380. const int expected_zero_count = 0;
  381. auto merged_from_default = aggr.Merge(*default_aggr);
  382. test_merge(merged_from_default, expected_count, expected_sum, expected_zero_count,
  383. expected_scale, expected_max_buckets);
  384. auto merged_to_default = default_aggr->Merge(aggr);
  385. test_merge(merged_to_default, expected_count, expected_sum, expected_zero_count, expected_scale,
  386. expected_max_buckets);
  387. }
  388. // zero count aggregation merge (Zero is a special case and does not increment the buckets)
  389. {
  390. Base2ExponentialHistogramAggregation zero_aggr(&config);
  391. zero_aggr.Aggregate(0.0);
  392. const auto zero_point = nostd::get<Base2ExponentialHistogramPointData>(zero_aggr.ToPoint());
  393. const int expected_scale =
  394. aggr_point.scale_ < zero_point.scale_ ? aggr_point.scale_ : zero_point.scale_;
  395. const int expected_max_buckets = aggr_point.max_buckets_ < zero_point.max_buckets_
  396. ? aggr_point.max_buckets_
  397. : zero_point.max_buckets_;
  398. const int expected_zero_count = 1;
  399. auto merged_from_zero = aggr.Merge(zero_aggr);
  400. test_merge(merged_from_zero, expected_count + 1, expected_sum, expected_zero_count,
  401. expected_scale, expected_max_buckets);
  402. auto merged_to_zero = zero_aggr.Merge(aggr);
  403. test_merge(merged_to_zero, expected_count + 1, expected_sum, expected_zero_count,
  404. expected_scale, expected_max_buckets);
  405. }
  406. }