This commit is contained in:
2026-08-12 13:46:53 +08:00
parent 898a58b554
commit d7cf626c25
22 changed files with 1639 additions and 292 deletions
+107 -13
View File
@@ -172,6 +172,17 @@ TEST(RenderiveWebBridge, DecodesOnlyEventMessages) {
ASSERT_TRUE(observe.has_value());
EXPECT_EQ(std::get<Gallery_Request>(*observe).kind, Gallery_Request_Kind::Observe);
const auto refresh = Web_Event_Adapter::decode(
R"({"category":"event","type":"gallery_refresh"})");
ASSERT_TRUE(refresh.has_value());
EXPECT_EQ(std::get<Gallery_Request>(*refresh).kind, Gallery_Request_Kind::Refresh);
const auto reset_monitoring = Web_Event_Adapter::decode(
R"({"category":"event","type":"gallery_reset_monitoring"})");
ASSERT_TRUE(reset_monitoring.has_value());
EXPECT_EQ(std::get<Gallery_Request>(*reset_monitoring).kind,
Gallery_Request_Kind::Reset_Monitoring);
const auto bounded = Web_Event_Adapter::decode(
R"({"category":"event","type":"resize","width":1e100,"height":-1e100})");
ASSERT_TRUE(bounded.has_value());
@@ -232,7 +243,7 @@ TEST(RenderiveWebGallery, AdminiveCatalogCoversEveryControlCaseAndThreeModes) {
TEST(RenderiveWebGallery, CatalogOwnsDashboardFieldsAndDynamicBehavior) {
const nlohmann::json catalog = parse_json(Gallery_Protocol::catalog_json());
const auto& dashboard = catalog.at("dashboard");
EXPECT_EQ(dashboard.at("performance").at("fields").size(), 22U);
EXPECT_EQ(dashboard.at("performance").at("fields").size(), 33U);
EXPECT_EQ(dashboard.at("limits").at("fields").size(), 4U);
EXPECT_EQ(dashboard.at("observer").at("sections").size(), 4U);
std::set<std::string> client_sources;
@@ -243,9 +254,12 @@ TEST(RenderiveWebGallery, CatalogOwnsDashboardFieldsAndDynamicBehavior) {
client_sources.insert(source);
}
}
constexpr std::array<std::string_view, 14> client_fields{
"display_interval_latest_ms", "display_interval_ms", "display_interval_p95_ms",
"display_jitter_ms", "frame_round_trip_ms", "transport_fps", "presentation_fps",
constexpr std::array<std::string_view, 20> client_fields{
"display_interval_latest_ms", "display_interval_ms", "display_interval_average_ms",
"display_interval_p95_ms", "display_interval_p99_ms", "display_interval_deviation_ms",
"frame_round_trip_ms", "frame_round_trip_average_ms", "frame_round_trip_p95_ms",
"frame_round_trip_p99_ms", "frame_round_trip_deviation_ms",
"transport_fps", "presentation_fps",
"websocket_buffered_bytes", "overwritten_pixel_frames", "changed_pixel_frames",
"duplicate_pixel_frames", "frame_request_timeout_count", "last_pixel_receive_age_ms",
"last_pixel_change_age_ms"
@@ -393,6 +407,76 @@ TEST(RenderiveWebGallery, AdminiveResourcesPatchTheRealRenderableState) {
EXPECT_EQ(foreign.at("type"), "error");
}
TEST(RenderiveWebGallery, ExposesEachRenderableObserverAndStableTaskTopology) {
Gallery_Plot_Session session;
const auto opened = response_json(session.handle(gallery_request(
Gallery_Request_Kind::Open, open_message("spectrum", "manual"))));
ASSERT_EQ(opened.at("type"), "case_state");
const auto& observers = opened.at("controls").at("observers");
const auto& graph = opened.at("controls").at("task_graph");
ASSERT_EQ(observers.size(), graph.at("nodes").size());
EXPECT_GE(observers.size(), 7U);
for (const std::string_view target : {"frequency_axis", "value_axis", "spectrum"}) {
const auto found = std::find_if(observers.begin(), observers.end(),
[target](const auto& resource) {
return resource.at("target").template get<std::string>() == target;
});
ASSERT_NE(found, observers.end()) << target;
EXPECT_EQ(found->at("descriptor").at("label"), "渲染对象观察器");
EXPECT_EQ(found->at("descriptor").at("fields").at(0)
.at("presentation").at("label"),
"最近状态事件");
EXPECT_EQ(found->at("data").at("event"), "Render_Completed");
EXPECT_GT(found->at("data").at("publish_count").get<std::uint64_t>(), 0U);
EXPECT_GT(found->at("data").at("successful_render_count")
.get<std::uint64_t>(), 0U);
EXPECT_GT(found->at("data").at("task_execution_count")
.get<std::uint64_t>(), 0U);
}
ASSERT_TRUE(graph.at("topology_id").is_string());
EXPECT_FALSE(graph.at("topology_id").get<std::string>().empty());
EXPECT_FALSE(graph.at("nodes").empty());
EXPECT_FALSE(graph.at("edges").empty());
ASSERT_EQ(graph.at("renderables").size(), 3U);
const auto spectrum_graph = std::find_if(
graph.at("renderables").begin(), graph.at("renderables").end(),
[](const auto& resource) { return resource.at("target") == "spectrum"; });
ASSERT_NE(spectrum_graph, graph.at("renderables").end());
EXPECT_FALSE(spectrum_graph->at("graph").at("nodes").empty());
const auto observed = response_json(session.handle(gallery_request(
Gallery_Request_Kind::Observe,
R"({"category":"event","type":"gallery_observe"})")));
ASSERT_EQ(observed.at("type"), "observer_state");
EXPECT_EQ(observed.at("telemetry").at("renderable_observers").size(),
graph.at("nodes").size());
EXPECT_FALSE(observed.at("telemetry").contains("task_graph"));
const auto refreshed = response_json(session.handle(gallery_request(
Gallery_Request_Kind::Refresh,
R"({"category":"event","type":"gallery_refresh"})")));
ASSERT_EQ(refreshed.at("type"), "refresh_state");
EXPECT_EQ(refreshed.at("controls").at("observers").size(),
graph.at("nodes").size());
EXPECT_EQ(refreshed.at("notice"), "观察数据已手动刷新");
const auto reset = response_json(session.handle(gallery_request(
Gallery_Request_Kind::Reset_Monitoring,
R"({"category":"event","type":"gallery_reset_monitoring"})")));
ASSERT_EQ(reset.at("type"), "refresh_state");
EXPECT_EQ(reset.at("notice"), "监测滑动窗口已重置");
EXPECT_EQ(reset.at("telemetry").at("performance").at("render_sample_count"), 0);
EXPECT_EQ(reset.at("telemetry").at("performance").at("pixel_encode_sample_count"), 0);
for (const auto& observer : reset.at("telemetry").at("renderable_observers")) {
EXPECT_EQ(observer.at("data").at("successful_render_count"), 0);
EXPECT_EQ(observer.at("data").at("task_execution_count"), 0);
EXPECT_EQ(observer.at("data").at("render_duration_sample_count"), 0);
EXPECT_EQ(observer.at("data").at("task_duration_sample_count"), 0);
}
}
TEST(RenderiveWebGallery, PartitionControlRebuildsTheObservedTaskGraph) {
Gallery_Plot_Session session;
ASSERT_EQ(response_json(session.handle(gallery_request(
@@ -406,10 +490,11 @@ TEST(RenderiveWebGallery, PartitionControlRebuildsTheObservedTaskGraph) {
return invoke_action(session, "mode_render").at("telemetry").at("kernel_observer");
};
ASSERT_EQ(patch_controls(session,
{{"partition_mode", "Fixed"}, {"partition_count", 1}},
"spectrum").at("type"),
"case_state");
const auto single_state = patch_controls(
session, {{"partition_mode", "Fixed"}, {"partition_count", 1}}, "spectrum");
ASSERT_EQ(single_state.at("type"), "case_state");
const std::string single_topology = single_state.at("controls").at("task_graph")
.at("topology_id");
const auto single = render();
EXPECT_EQ(single.at("task_execution_state"), "Completed");
EXPECT_EQ(single.at("task_completed_node_count"),
@@ -417,8 +502,11 @@ TEST(RenderiveWebGallery, PartitionControlRebuildsTheObservedTaskGraph) {
EXPECT_EQ(single.at("task_running_node_count"), 0);
EXPECT_EQ(single.at("task_pending_node_count"), 0);
ASSERT_EQ(patch_controls(session, {{"partition_count", 4}}, "spectrum").at("type"),
"case_state");
const auto partitioned_state = patch_controls(
session, {{"partition_count", 4}}, "spectrum");
ASSERT_EQ(partitioned_state.at("type"), "case_state");
EXPECT_NE(partitioned_state.at("controls").at("task_graph").at("topology_id"),
single_topology);
const auto partitioned = render();
EXPECT_EQ(partitioned.at("task_graph_node_count").get<std::size_t>(),
single.at("task_graph_node_count").get<std::size_t>() + 3U);
@@ -1170,7 +1258,7 @@ TEST(RenderiveWebGallery, ConsumerFeedbackSourcesCanBeSelectedIndependentlyAndMa
}).at("type"), "case_state");
auto observed = response_json(session.handle(gallery_request(
Gallery_Request_Kind::Observe,
R"({"category":"event","type":"gallery_observe","client_metrics":{"transport_fps":25,"presentation_fps":60,"websocket_buffered_bytes":0,"changed_pixel_frames":1,"duplicate_pixel_frames":0,"frame_request_timeout_count":0,"frame_round_trip_ms":5,"display_interval_ms":16,"display_interval_latest_ms":16,"display_interval_p95_ms":17,"display_jitter_ms":1,"overwritten_pixel_frames":0,"last_pixel_receive_age_ms":1,"last_pixel_change_age_ms":1}})")));
R"({"category":"event","type":"gallery_observe","client_metrics":{"transport_fps":25,"presentation_fps":60,"websocket_buffered_bytes":0,"changed_pixel_frames":1,"duplicate_pixel_frames":0,"frame_request_timeout_count":0,"frame_round_trip_ms":5,"frame_round_trip_average_ms":4.8,"frame_round_trip_deviation_ms":0.2,"frame_round_trip_p95_ms":5.1,"frame_round_trip_p99_ms":5.3,"display_interval_ms":16,"display_interval_average_ms":16.2,"display_interval_latest_ms":16,"display_interval_p95_ms":17,"display_interval_p99_ms":18,"display_interval_deviation_ms":0.5,"overwritten_pixel_frames":0,"last_pixel_receive_age_ms":1,"last_pixel_change_age_ms":1}})")));
auto observer = observed.at("telemetry").at("kernel_observer");
auto feedback = observed.at("telemetry").at("consumer_feedback");
EXPECT_EQ(feedback.at("source"), "pixel");
@@ -1289,7 +1377,7 @@ TEST(RenderiveWebGallery, ProductionLowLatencySessionRendersWithoutPixelPulls) {
}));
const auto observed = session.handle(gallery_request(
Gallery_Request_Kind::Observe,
R"({"category":"event","type":"gallery_observe","client_metrics":{"transport_fps":120,"presentation_fps":60,"websocket_buffered_bytes":0,"changed_pixel_frames":17,"duplicate_pixel_frames":3,"frame_request_timeout_count":2,"frame_round_trip_ms":4.5,"display_interval_ms":16.7,"display_interval_latest_ms":16.9,"display_interval_p95_ms":17.4,"display_jitter_ms":0.7,"overwritten_pixel_frames":5,"last_pixel_receive_age_ms":8.5,"last_pixel_change_age_ms":12.5}})"));
R"({"category":"event","type":"gallery_observe","client_metrics":{"transport_fps":120,"presentation_fps":60,"websocket_buffered_bytes":0,"changed_pixel_frames":17,"duplicate_pixel_frames":3,"frame_request_timeout_count":2,"frame_round_trip_ms":4.5,"frame_round_trip_average_ms":4.2,"frame_round_trip_deviation_ms":0.3,"frame_round_trip_p95_ms":5.1,"frame_round_trip_p99_ms":5.4,"display_interval_ms":16.7,"display_interval_average_ms":16.8,"display_interval_latest_ms":16.9,"display_interval_p95_ms":17.4,"display_interval_p99_ms":18.2,"display_interval_deviation_ms":0.7,"overwritten_pixel_frames":5,"last_pixel_receive_age_ms":8.5,"last_pixel_change_age_ms":12.5}})"));
ASSERT_TRUE(observed.has_value());
const auto telemetry = parse_json(observed->payload).at("telemetry");
const auto& performance = telemetry.at("performance");
@@ -1308,10 +1396,16 @@ TEST(RenderiveWebGallery, ProductionLowLatencySessionRendersWithoutPixelPulls) {
EXPECT_EQ(telemetry.at("client_performance").at("duplicate_pixel_frames"), 3);
EXPECT_EQ(telemetry.at("client_performance").at("frame_request_timeout_count"), 2);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("frame_round_trip_ms"), 4.5);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("frame_round_trip_average_ms"), 4.2);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("frame_round_trip_deviation_ms"), 0.3);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("frame_round_trip_p95_ms"), 5.1);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("frame_round_trip_p99_ms"), 5.4);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("display_interval_ms"), 16.7);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("display_interval_average_ms"), 16.8);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("display_interval_latest_ms"), 16.9);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("display_interval_p95_ms"), 17.4);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("display_jitter_ms"), 0.7);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("display_interval_p99_ms"), 18.2);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("display_interval_deviation_ms"), 0.7);
EXPECT_EQ(telemetry.at("client_performance").at("overwritten_pixel_frames"), 5);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("last_pixel_receive_age_ms"), 8.5);
EXPECT_DOUBLE_EQ(telemetry.at("client_performance").at("last_pixel_change_age_ms"), 12.5);