phase 2 progress
This commit is contained in:
@@ -67,6 +67,18 @@ void TestRuntimeEventPayloadTypes()
|
||||
Expect(RuntimeEventPayloadType(persistence) == RuntimeEventType::RuntimePersistenceRequested, "runtime persistence payload maps to persistence event type");
|
||||
Expect(persistence.debounceAllowed, "runtime persistence payload carries debounce policy");
|
||||
|
||||
FileChangeDetectedEvent fileChange;
|
||||
fileChange.path = "PollRuntimeStoreChanges";
|
||||
fileChange.shaderPackageCandidate = true;
|
||||
Expect(RuntimeEventPayloadType(fileChange) == RuntimeEventType::FileChangeDetected, "file change payload maps to file change event type");
|
||||
Expect(fileChange.shaderPackageCandidate, "file change payload carries shader package candidate flag");
|
||||
|
||||
ManualReloadRequestedEvent manualReload;
|
||||
manualReload.preserveFeedbackState = true;
|
||||
manualReload.reason = "RequestShaderReload";
|
||||
Expect(RuntimeEventPayloadType(manualReload) == RuntimeEventType::ManualReloadRequested, "manual reload payload maps to manual reload event type");
|
||||
Expect(manualReload.preserveFeedbackState, "manual reload payload carries feedback preservation policy");
|
||||
|
||||
ShaderBuildEvent preparedBuild;
|
||||
preparedBuild.phase = RuntimeEventShaderBuildPhase::Prepared;
|
||||
preparedBuild.inputWidth = 1920;
|
||||
@@ -234,12 +246,89 @@ void TestRuntimeEventDispatcher()
|
||||
Expect(!dispatcher.Publish(mismatched), "dispatcher rejects mismatched event type and payload");
|
||||
|
||||
RuntimeEventDispatcher tinyDispatcher(1);
|
||||
Expect(tinyDispatcher.PublishPayload(broadcast, "test"), "tiny dispatcher accepts first event");
|
||||
Expect(!tinyDispatcher.PublishPayload(broadcast, "test"), "tiny dispatcher rejects event when queue is full");
|
||||
RuntimeMutationEvent acceptedMutation;
|
||||
acceptedMutation.accepted = true;
|
||||
Expect(tinyDispatcher.PublishPayload(acceptedMutation, "test"), "tiny dispatcher accepts first FIFO event");
|
||||
Expect(!tinyDispatcher.PublishPayload(acceptedMutation, "test"), "tiny dispatcher rejects FIFO event when queue is full");
|
||||
RuntimeEventQueueMetrics metrics = tinyDispatcher.GetQueueMetrics();
|
||||
Expect(metrics.droppedCount == 1, "dispatcher exposes queue drop metrics");
|
||||
}
|
||||
|
||||
void TestRuntimeEventDispatcherCoalescing()
|
||||
{
|
||||
RuntimeEventDispatcher dispatcher(4);
|
||||
std::string seenReason;
|
||||
std::string seenShaderMessage;
|
||||
double seenTimingValue = 0.0;
|
||||
int broadcastHandlerCount = 0;
|
||||
int shaderHandlerCount = 0;
|
||||
int timingHandlerCount = 0;
|
||||
|
||||
dispatcher.Subscribe(RuntimeEventType::RuntimeStateBroadcastRequested, [&](const RuntimeEvent& event) {
|
||||
const auto* payload = std::get_if<RuntimeStateBroadcastRequestedEvent>(&event.payload);
|
||||
if (payload)
|
||||
seenReason = payload->reason;
|
||||
++broadcastHandlerCount;
|
||||
});
|
||||
dispatcher.Subscribe(RuntimeEventType::ShaderBuildRequested, [&](const RuntimeEvent& event) {
|
||||
const auto* payload = std::get_if<ShaderBuildEvent>(&event.payload);
|
||||
if (payload)
|
||||
seenShaderMessage = payload->message;
|
||||
++shaderHandlerCount;
|
||||
});
|
||||
dispatcher.Subscribe(RuntimeEventType::TimingSampleRecorded, [&](const RuntimeEvent& event) {
|
||||
const auto* payload = std::get_if<TimingSampleRecordedEvent>(&event.payload);
|
||||
if (payload)
|
||||
seenTimingValue = payload->value;
|
||||
++timingHandlerCount;
|
||||
});
|
||||
|
||||
RuntimeStateBroadcastRequestedEvent first;
|
||||
first.reason = "parameter";
|
||||
RuntimeStateBroadcastRequestedEvent second;
|
||||
second.reason = "reload";
|
||||
|
||||
Expect(dispatcher.PublishPayload(first, "RuntimeCoordinator"), "dispatcher accepts first coalescable event");
|
||||
Expect(dispatcher.PublishPayload(second, "RuntimeCoordinator"), "dispatcher coalesces second matching event");
|
||||
RuntimeEventQueueMetrics queuedMetrics = dispatcher.GetQueueMetrics();
|
||||
Expect(queuedMetrics.depth == 1, "dispatcher reports coalesced event depth");
|
||||
Expect(queuedMetrics.coalescedCount == 1, "dispatcher reports coalesced event count");
|
||||
|
||||
RuntimeEventDispatchResult result = dispatcher.DispatchPending();
|
||||
Expect(result.dispatchedEvents == 1, "dispatcher dispatches one coalesced event");
|
||||
Expect(broadcastHandlerCount == 1, "dispatcher invokes handler once for coalesced event");
|
||||
Expect(seenReason == "reload", "dispatcher dispatches latest coalesced payload");
|
||||
|
||||
ShaderBuildEvent shaderFirst;
|
||||
shaderFirst.phase = RuntimeEventShaderBuildPhase::Requested;
|
||||
shaderFirst.inputWidth = 1920;
|
||||
shaderFirst.inputHeight = 1080;
|
||||
shaderFirst.preserveFeedbackState = true;
|
||||
shaderFirst.message = "first";
|
||||
ShaderBuildEvent shaderSecond = shaderFirst;
|
||||
shaderSecond.message = "second";
|
||||
Expect(dispatcher.PublishPayload(shaderFirst, "RuntimeCoordinator"), "dispatcher accepts first shader build request");
|
||||
Expect(dispatcher.PublishPayload(shaderSecond, "RuntimeCoordinator"), "dispatcher coalesces matching shader build request");
|
||||
result = dispatcher.DispatchPending();
|
||||
Expect(result.dispatchedEvents == 1, "dispatcher dispatches one coalesced shader build request");
|
||||
Expect(shaderHandlerCount == 1, "dispatcher invokes shader handler once for matching coalesced request");
|
||||
Expect(seenShaderMessage == "second", "dispatcher dispatches latest shader build request payload");
|
||||
|
||||
TimingSampleRecordedEvent timingFirst;
|
||||
timingFirst.subsystem = "RuntimeEventDispatcher";
|
||||
timingFirst.metric = "dispatchDuration";
|
||||
timingFirst.value = 1.0;
|
||||
timingFirst.unit = "ms";
|
||||
TimingSampleRecordedEvent timingSecond = timingFirst;
|
||||
timingSecond.value = 2.0;
|
||||
Expect(dispatcher.PublishPayload(timingFirst, "HealthTelemetry"), "dispatcher accepts first timing sample");
|
||||
Expect(dispatcher.PublishPayload(timingSecond, "HealthTelemetry"), "dispatcher coalesces matching timing sample");
|
||||
result = dispatcher.DispatchPending();
|
||||
Expect(result.dispatchedEvents == 1, "dispatcher dispatches one coalesced timing sample");
|
||||
Expect(timingHandlerCount == 1, "dispatcher invokes timing handler once for matching coalesced sample");
|
||||
Expect(seenTimingValue == 2.0, "dispatcher dispatches latest timing sample payload");
|
||||
}
|
||||
|
||||
void TestRuntimeEventCoalescingQueue()
|
||||
{
|
||||
RuntimeEventCoalescingQueue queue(2);
|
||||
@@ -401,6 +490,124 @@ void TestAcceptedMutationFollowUps()
|
||||
Expect(persistencePayload && persistencePayload->reason == "SetLayerShader", "persistence follow-up preserves mutation action reason");
|
||||
}
|
||||
|
||||
void TestAppLevelBroadcastAndBuildCoalescing()
|
||||
{
|
||||
RuntimeEventTestHarness harness;
|
||||
|
||||
RuntimeMutationEvent firstMutation;
|
||||
firstMutation.action = "SetLayerShader";
|
||||
firstMutation.accepted = true;
|
||||
firstMutation.runtimeStateChanged = true;
|
||||
firstMutation.runtimeStateBroadcastRequired = true;
|
||||
firstMutation.shaderBuildRequested = true;
|
||||
|
||||
RuntimeMutationEvent secondMutation = firstMutation;
|
||||
secondMutation.action = "LoadStackPreset";
|
||||
|
||||
RuntimeStateBroadcastRequestedEvent firstBroadcast;
|
||||
firstBroadcast.reason = "SetLayerShader";
|
||||
RuntimeStateBroadcastRequestedEvent secondBroadcast;
|
||||
secondBroadcast.reason = "LoadStackPreset";
|
||||
|
||||
ShaderBuildEvent firstBuild;
|
||||
firstBuild.phase = RuntimeEventShaderBuildPhase::Requested;
|
||||
firstBuild.inputWidth = 1920;
|
||||
firstBuild.inputHeight = 1080;
|
||||
firstBuild.preserveFeedbackState = false;
|
||||
firstBuild.message = "first build request";
|
||||
ShaderBuildEvent secondBuild = firstBuild;
|
||||
secondBuild.message = "second build request";
|
||||
|
||||
Expect(harness.Publish(firstMutation, "RuntimeCoordinator"), "first accepted mutation fact publishes");
|
||||
Expect(harness.Publish(firstBroadcast, "RuntimeUpdateController"), "first broadcast request publishes through app dispatcher");
|
||||
Expect(harness.Publish(firstBuild, "RuntimeCoordinator"), "first shader build request publishes through app dispatcher");
|
||||
Expect(harness.Publish(secondMutation, "RuntimeCoordinator"), "second accepted mutation fact publishes");
|
||||
Expect(harness.Publish(secondBroadcast, "RuntimeUpdateController"), "second broadcast request coalesces through app dispatcher");
|
||||
Expect(harness.Publish(secondBuild, "RuntimeCoordinator"), "second shader build request coalesces through app dispatcher");
|
||||
|
||||
RuntimeEventQueueMetrics metrics = harness.Dispatcher().GetQueueMetrics();
|
||||
Expect(metrics.depth == 4, "app dispatcher keeps FIFO facts plus coalesced broadcast/build requests");
|
||||
Expect(metrics.coalescedCount == 2, "app dispatcher reports broadcast and build coalescing");
|
||||
|
||||
RuntimeEventDispatchResult result = harness.DispatchPending();
|
||||
Expect(result.dispatchedEvents == 4, "app dispatcher dispatches FIFO facts plus one broadcast and one build request");
|
||||
Expect(harness.SeenCount(RuntimeEventType::RuntimeMutationAccepted) == 2, "app dispatcher preserves every accepted mutation fact");
|
||||
Expect(harness.SeenCount(RuntimeEventType::RuntimeStateBroadcastRequested) == 1, "app dispatcher coalesces broadcast requests");
|
||||
Expect(harness.SeenCount(RuntimeEventType::ShaderBuildRequested) == 1, "app dispatcher coalesces matching shader build requests");
|
||||
|
||||
const RuntimeEvent* broadcastEvent = harness.LastSeen(RuntimeEventType::RuntimeStateBroadcastRequested);
|
||||
const auto* broadcastPayload = broadcastEvent ? std::get_if<RuntimeStateBroadcastRequestedEvent>(&broadcastEvent->payload) : nullptr;
|
||||
Expect(broadcastPayload && broadcastPayload->reason == "LoadStackPreset", "app dispatcher dispatches latest broadcast request");
|
||||
|
||||
const RuntimeEvent* buildEvent = harness.LastSeen(RuntimeEventType::ShaderBuildRequested);
|
||||
const auto* buildPayload = buildEvent ? std::get_if<ShaderBuildEvent>(&buildEvent->payload) : nullptr;
|
||||
Expect(buildPayload && buildPayload->message == "second build request", "app dispatcher dispatches latest shader build request");
|
||||
}
|
||||
|
||||
void TestManualReloadBridgeEvents()
|
||||
{
|
||||
RuntimeEventTestHarness harness;
|
||||
|
||||
ManualReloadRequestedEvent manualReload;
|
||||
manualReload.preserveFeedbackState = true;
|
||||
manualReload.reason = "RequestShaderReload";
|
||||
|
||||
RuntimeReloadRequestedEvent runtimeReload;
|
||||
runtimeReload.preserveFeedbackState = true;
|
||||
runtimeReload.reason = "RequestShaderReload";
|
||||
|
||||
ShaderBuildEvent shaderBuild;
|
||||
shaderBuild.phase = RuntimeEventShaderBuildPhase::Requested;
|
||||
shaderBuild.preserveFeedbackState = true;
|
||||
shaderBuild.message = "Shader rebuild queued.";
|
||||
|
||||
Expect(harness.Publish(manualReload, "RuntimeCoordinator"), "manual reload ingress event publishes");
|
||||
Expect(harness.Publish(runtimeReload, "RuntimeCoordinator"), "manual reload bridge publishes runtime reload request");
|
||||
Expect(harness.Publish(shaderBuild, "RuntimeCoordinator"), "manual reload bridge publishes shader build request");
|
||||
|
||||
RuntimeEventDispatchResult result = harness.DispatchPending();
|
||||
Expect(result.dispatchedEvents == 3, "manual reload bridge dispatches ingress and follow-up events");
|
||||
Expect(harness.SeenCount(RuntimeEventType::ManualReloadRequested) == 1, "manual reload ingress event is observed");
|
||||
Expect(harness.SeenCount(RuntimeEventType::RuntimeReloadRequested) == 1, "manual reload runtime reload follow-up is observed");
|
||||
Expect(harness.SeenCount(RuntimeEventType::ShaderBuildRequested) == 1, "manual reload shader build follow-up is observed");
|
||||
|
||||
const RuntimeEvent* reloadEvent = harness.LastSeen(RuntimeEventType::RuntimeReloadRequested);
|
||||
const auto* reloadPayload = reloadEvent ? std::get_if<RuntimeReloadRequestedEvent>(&reloadEvent->payload) : nullptr;
|
||||
Expect(reloadPayload && reloadPayload->preserveFeedbackState, "manual reload bridge preserves feedback policy in runtime reload event");
|
||||
}
|
||||
|
||||
void TestFileReloadBridgeEvents()
|
||||
{
|
||||
RuntimeEventTestHarness harness;
|
||||
|
||||
FileChangeDetectedEvent fileChange;
|
||||
fileChange.path = "PollRuntimeStoreChanges";
|
||||
fileChange.shaderPackageCandidate = true;
|
||||
|
||||
RuntimeReloadRequestedEvent runtimeReload;
|
||||
runtimeReload.preserveFeedbackState = false;
|
||||
runtimeReload.reason = "PollRuntimeStoreChanges";
|
||||
|
||||
ShaderBuildEvent shaderBuild;
|
||||
shaderBuild.phase = RuntimeEventShaderBuildPhase::Requested;
|
||||
shaderBuild.preserveFeedbackState = false;
|
||||
shaderBuild.message = "Shader rebuild queued.";
|
||||
|
||||
Expect(harness.Publish(fileChange, "RuntimeCoordinator"), "file change ingress event publishes");
|
||||
Expect(harness.Publish(runtimeReload, "RuntimeCoordinator"), "file change bridge publishes runtime reload request");
|
||||
Expect(harness.Publish(shaderBuild, "RuntimeCoordinator"), "file change bridge publishes shader build request");
|
||||
|
||||
RuntimeEventDispatchResult result = harness.DispatchPending();
|
||||
Expect(result.dispatchedEvents == 3, "file reload bridge dispatches ingress and follow-up events");
|
||||
Expect(harness.SeenCount(RuntimeEventType::FileChangeDetected) == 1, "file change ingress event is observed");
|
||||
Expect(harness.SeenCount(RuntimeEventType::RuntimeReloadRequested) == 1, "file reload runtime reload follow-up is observed");
|
||||
Expect(harness.SeenCount(RuntimeEventType::ShaderBuildRequested) == 1, "file reload shader build follow-up is observed");
|
||||
|
||||
const RuntimeEvent* fileEvent = harness.LastSeen(RuntimeEventType::FileChangeDetected);
|
||||
const auto* filePayload = fileEvent ? std::get_if<FileChangeDetectedEvent>(&fileEvent->payload) : nullptr;
|
||||
Expect(filePayload && filePayload->shaderPackageCandidate, "file reload bridge marks shader package candidate changes");
|
||||
}
|
||||
|
||||
void TestRejectedMutationHasNoDownstreamFollowUps()
|
||||
{
|
||||
RuntimeEventTestHarness harness;
|
||||
@@ -487,10 +694,14 @@ int main()
|
||||
TestRuntimeEventEnvelope();
|
||||
TestRuntimeEventQueue();
|
||||
TestRuntimeEventDispatcher();
|
||||
TestRuntimeEventDispatcherCoalescing();
|
||||
TestRuntimeEventCoalescingQueue();
|
||||
TestRuntimeEventCoalescingCustomKey();
|
||||
TestRuntimeEventTestHarness();
|
||||
TestAcceptedMutationFollowUps();
|
||||
TestAppLevelBroadcastAndBuildCoalescing();
|
||||
TestManualReloadBridgeEvents();
|
||||
TestFileReloadBridgeEvents();
|
||||
TestRejectedMutationHasNoDownstreamFollowUps();
|
||||
TestShaderBuildGenerationEventMatching();
|
||||
TestHandlerFailureCanBecomeTelemetryEvent();
|
||||
|
||||
Reference in New Issue
Block a user