// Pure Metric JSON (de)serialization (no Libp2pModuleImpl, links without libp2p.so). #include #include #include using json = nlohmann::json; LOGOS_TEST(metric_from_json_basic_fields) { const auto j = json::parse(R"({ "name": "libp2p_peers", "type": "gauge", "help": "Number of connected peers", "labels": [], "value": 3, "timestamp": 0 })"); const auto m = j.get(); LOGOS_ASSERT_TRUE(m.name == "libp2p_peers"); LOGOS_ASSERT_TRUE(m.type == "gauge"); LOGOS_ASSERT_TRUE(m.help == "Number of connected peers"); LOGOS_ASSERT_EQ(m.value, 3.0); LOGOS_ASSERT_TRUE(m.labels.empty()); LOGOS_ASSERT_EQ(m.timestamp, 0); } LOGOS_TEST(metric_from_json_flattens_label_pair_array) { // cbind emits labels as a sequence of {name,value} pairs, but openmetrics- // module's renderer wants a flat {key:value} object. Verify the flattening. const auto j = json::parse(R"({ "name": "libp2p_open_streams", "type": "gauge", "help": "", "labels": [ {"name": "dir", "value": "in"}, {"name": "proto", "value": "ping"} ], "value": 4, "timestamp": 0 })"); const auto m = j.get(); LOGOS_ASSERT_EQ(m.labels.size(), 2u); LOGOS_ASSERT_TRUE(m.labels.at("dir") == "in"); LOGOS_ASSERT_TRUE(m.labels.at("proto") == "ping"); } LOGOS_TEST(metric_from_json_handles_missing_labels) { const auto j = json::parse(R"({ "name": "x", "type": "gauge", "help": "", "value": 0 })"); const auto m = j.get(); LOGOS_ASSERT_TRUE(m.labels.empty()); LOGOS_ASSERT_EQ(m.timestamp, 0); } LOGOS_TEST(metric_from_json_records_timestamp) { const auto j = json::parse(R"({ "name": "x", "type": "gauge", "help": "", "labels": [], "value": 1, "timestamp": 1700000000000 })"); const auto m = j.get(); LOGOS_ASSERT_EQ(m.timestamp, 1700000000000); } LOGOS_TEST(metric_to_json_emits_labels_as_object) { // openmetrics_format.cpp:82 requires labels.is_object(); round-trip must // produce that shape, not the inbound array-of-pairs. Metric m; m.name = "libp2p_peers"; m.type = "gauge"; m.help = "Number of connected peers"; m.labels = {{"dir", "in"}}; m.value = 7; const json j = m; LOGOS_ASSERT_TRUE(j["labels"].is_object()); LOGOS_ASSERT_TRUE(j["labels"]["dir"].get() == "in"); LOGOS_ASSERT_FALSE(j.contains("timestamp")); } LOGOS_TEST(metric_to_json_keeps_nonzero_timestamp) { Metric m; m.name = "x"; m.type = "gauge"; m.timestamp = 1700000000000; const json j = m; LOGOS_ASSERT_TRUE(j.contains("timestamp")); LOGOS_ASSERT_EQ(j["timestamp"].get(), 1700000000000); } LOGOS_TEST(metric_array_round_trips_through_payload_shape) { // End-to-end: take a cbind-shaped JSON array, parse it to vector, // wrap it as payload["metrics"], and check the result matches what // openmetrics-module expects as input. const auto in = json::parse(R"([ {"name":"libp2p_peers","type":"gauge","help":"peers", "labels":[],"value":2,"timestamp":0}, {"name":"libp2p_failed_dials_total","type":"counter","help":"fails", "labels":[{"name":"err","value":"timeout"}],"value":9,"timestamp":0} ])"); const auto series = in.get>(); json payload; payload["metrics"] = series; LOGOS_ASSERT_EQ(payload["metrics"].size(), 2u); LOGOS_ASSERT_TRUE(payload["metrics"][1]["labels"].is_object()); LOGOS_ASSERT_TRUE( payload["metrics"][1]["labels"]["err"].get() == "timeout"); }