mirror of
https://github.com/vicliu624/trail-mate.git
synced 2026-10-23 05:32:18 +00:00
Align UI storage event runtime contracts
This commit is contained in:
1 parent
f055d36fd5
commit
b2d19334af
11 files changed
+2291
-61
No files matched your search
@@ -40,6 +40,39 @@ class FakeUiEffectSink final : public sys::runtime::IUiEffectSink
|
||||
sys::runtime::RuntimeUiEffect last_effect{};
|
||||
};
|
||||
|
||||
class FakeBusAdapter final : public sys::runtime::IBusAdapter
|
||||
{
|
||||
public:
|
||||
bool acquire_ok = true;
|
||||
uint32_t now_ms = 100;
|
||||
uint32_t last_timeout_ms = 0;
|
||||
int acquire_count = 0;
|
||||
int release_count = 0;
|
||||
|
||||
bool tryAcquire(uint32_t timeout_ms) override
|
||||
{
|
||||
last_timeout_ms = timeout_ms;
|
||||
++acquire_count;
|
||||
now_ms += timeout_ms;
|
||||
return acquire_ok;
|
||||
}
|
||||
|
||||
void release() override
|
||||
{
|
||||
++release_count;
|
||||
}
|
||||
|
||||
uint32_t nowMs() const override
|
||||
{
|
||||
return now_ms;
|
||||
}
|
||||
|
||||
uint32_t owner() const override
|
||||
{
|
||||
return 77;
|
||||
}
|
||||
};
|
||||
|
||||
void test_priority_pop_order()
|
||||
{
|
||||
sys::runtime::FixedCommandQueue<4> queue;
|
||||
@@ -223,6 +256,45 @@ void test_event_to_ui_effect_bridge()
|
||||
assert(out.event_id == event.event_id);
|
||||
}
|
||||
|
||||
void test_storage_bus_arbiter_uses_policy_timeout()
|
||||
{
|
||||
FakeBusAdapter adapter;
|
||||
sys::runtime::DefaultBusPolicyStrategy policy;
|
||||
sys::runtime::StorageBusArbiter arbiter(adapter, policy);
|
||||
|
||||
sys::runtime::BusAcquireRequest request{};
|
||||
request.resource = 3;
|
||||
request.command_id = 9;
|
||||
request.policy = sys::runtime::BusAccessPolicy::InteractiveWorkerBounded;
|
||||
|
||||
const sys::runtime::BusAcquireResult result = arbiter.acquire(request);
|
||||
assert(result.status == sys::runtime::BusAcquireStatus::Acquired);
|
||||
assert(result.token.valid);
|
||||
assert(result.token.owner == 9);
|
||||
assert(adapter.last_timeout_ms == 2);
|
||||
assert(result.diagnostics.owner == 77);
|
||||
|
||||
arbiter.release(result.token);
|
||||
assert(adapter.release_count == 1);
|
||||
}
|
||||
|
||||
void test_storage_bus_arbiter_reports_degraded_after_timeouts()
|
||||
{
|
||||
FakeBusAdapter adapter;
|
||||
adapter.acquire_ok = false;
|
||||
sys::runtime::DefaultBusPolicyStrategy policy;
|
||||
sys::runtime::StorageBusArbiter arbiter(adapter, policy);
|
||||
|
||||
sys::runtime::BusAcquireRequest request{};
|
||||
request.policy = sys::runtime::BusAccessPolicy::BackgroundWorkerBounded;
|
||||
|
||||
assert(arbiter.acquire(request).status == sys::runtime::BusAcquireStatus::TimedOut);
|
||||
assert(arbiter.health().status == sys::runtime::StorageHealthStatus::Slow);
|
||||
assert(arbiter.acquire(request).status == sys::runtime::BusAcquireStatus::TimedOut);
|
||||
assert(arbiter.acquire(request).status == sys::runtime::BusAcquireStatus::TimedOut);
|
||||
assert(arbiter.health().status == sys::runtime::StorageHealthStatus::Degraded);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
@@ -234,5 +306,7 @@ int main()
|
||||
test_runtime_facade_submit_tick();
|
||||
test_runtime_facade_dedupe_cancel_policy();
|
||||
test_event_to_ui_effect_bridge();
|
||||
test_storage_bus_arbiter_uses_policy_timeout();
|
||||
test_storage_bus_arbiter_reports_degraded_after_timeouts();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
#include "gps/track_runtime.h"
|
||||
#include "sys/feedback_runtime.h"
|
||||
#include "sys/persistence_runtime.h"
|
||||
#include "sys/runtime_harness.h"
|
||||
#include "ui_map_runtime/map_tiles/map_tile_async_runtime.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class MapCommandSink final : public ui::map_tiles::IMapTileCommandSink
|
||||
{
|
||||
public:
|
||||
bool enqueue(const ui::map_tiles::LoadTileCommand& command) override
|
||||
{
|
||||
if (count >= 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
commands[count++] = command;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t cancelGeneration(uint32_t generation) override
|
||||
{
|
||||
std::size_t removed = 0;
|
||||
ui::map_tiles::LoadTileCommand kept[4]{};
|
||||
std::size_t kept_count = 0;
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (commands[i].runtime.generation == generation)
|
||||
{
|
||||
++removed;
|
||||
}
|
||||
else
|
||||
{
|
||||
kept[kept_count++] = commands[i];
|
||||
}
|
||||
}
|
||||
for (std::size_t i = 0; i < kept_count; ++i)
|
||||
{
|
||||
commands[i] = kept[i];
|
||||
}
|
||||
count = kept_count;
|
||||
return removed;
|
||||
}
|
||||
|
||||
ui::map_tiles::LoadTileCommand commands[4]{};
|
||||
std::size_t count = 0;
|
||||
};
|
||||
|
||||
class MapUiSink final : public ui::map_tiles::IMapTileUiSink
|
||||
{
|
||||
public:
|
||||
bool applyTile(const ui::map_tiles::MapTileEvent& event) override
|
||||
{
|
||||
last = event;
|
||||
++count;
|
||||
return true;
|
||||
}
|
||||
|
||||
ui::map_tiles::MapTileEvent last{};
|
||||
std::size_t count = 0;
|
||||
};
|
||||
|
||||
class TrackEvents final : public gps::runtime::ITrackEventSink
|
||||
{
|
||||
public:
|
||||
bool publish(const gps::runtime::TrackEvent& event) override
|
||||
{
|
||||
if (count >= 8)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
events[count++] = event;
|
||||
return true;
|
||||
}
|
||||
|
||||
gps::runtime::TrackEvent events[8]{};
|
||||
std::size_t count = 0;
|
||||
};
|
||||
|
||||
class TrackFiles final : public gps::runtime::ITrackFileAdapter
|
||||
{
|
||||
public:
|
||||
bool open(uint32_t track_id) override
|
||||
{
|
||||
active_track = track_id;
|
||||
++open_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool append(uint32_t track_id,
|
||||
const gps::runtime::TrackPoint* points,
|
||||
std::size_t count) override
|
||||
{
|
||||
assert(track_id == active_track);
|
||||
assert(points != nullptr || count == 0);
|
||||
appended += count;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool flush(uint32_t track_id) override
|
||||
{
|
||||
assert(track_id == active_track);
|
||||
++flush_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool close(uint32_t track_id) override
|
||||
{
|
||||
assert(track_id == active_track);
|
||||
++close_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t list(uint32_t* track_ids, std::size_t capacity) override
|
||||
{
|
||||
if (track_ids && capacity > 0)
|
||||
{
|
||||
track_ids[0] = active_track;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t active_track = 0;
|
||||
std::size_t appended = 0;
|
||||
std::size_t open_count = 0;
|
||||
std::size_t flush_count = 0;
|
||||
std::size_t close_count = 0;
|
||||
};
|
||||
|
||||
ui::map_tiles::MapTileRef tileRef()
|
||||
{
|
||||
ui::map_tiles::MapTileRef ref{};
|
||||
ref.layer = ui::map_tiles::MapTileLayer::Osm;
|
||||
ref.z = 12;
|
||||
ref.x = 100;
|
||||
ref.y = 200;
|
||||
return ref;
|
||||
}
|
||||
|
||||
void test_map_tile_runtime_contract()
|
||||
{
|
||||
MapCommandSink commands;
|
||||
ui::map_tiles::MapTileAsyncRuntime async(commands);
|
||||
ui::map_tiles::MapTileStateMachine states;
|
||||
MapUiSink ui;
|
||||
ui::map_tiles::MapTileRuntime runtime(async, states, &ui);
|
||||
|
||||
ui::map_tiles::MapViewportPlan plan{};
|
||||
plan.generation = 7;
|
||||
plan.tile_count = 1;
|
||||
plan.tiles[0] = tileRef();
|
||||
assert(runtime.requestVisibleTiles(plan, 10) == 1);
|
||||
assert(commands.count == 1);
|
||||
|
||||
ui::map_tiles::MapTileEvent ready{};
|
||||
ready.kind = ui::map_tiles::MapTileEventKind::Ready;
|
||||
ready.generation = 7;
|
||||
ready.tile = tileRef();
|
||||
ui::map_tiles::MapTileRenderQueue render_queue;
|
||||
assert(runtime.handle(ready, render_queue));
|
||||
assert(ui.count == 1);
|
||||
assert(runtime.snapshot().ready_count == 1);
|
||||
}
|
||||
|
||||
void test_persistence_runtime_contract()
|
||||
{
|
||||
sys::runtime::RuntimeHarness harness;
|
||||
sys::runtime::DirtyStoreRegistry<4> registry;
|
||||
sys::runtime::DefaultPersistencePolicy policy;
|
||||
sys::runtime::PersistenceWorker worker(harness.storage(),
|
||||
harness.storage(),
|
||||
harness.bus(),
|
||||
harness.events(),
|
||||
policy);
|
||||
sys::runtime::PersistenceRuntime<4> runtime(registry,
|
||||
worker,
|
||||
harness.events(),
|
||||
policy);
|
||||
|
||||
assert(runtime.markDirty("nodes", 0));
|
||||
runtime.tick(100);
|
||||
assert(harness.storage().writeCount() == 0);
|
||||
runtime.tick(150);
|
||||
assert(harness.storage().writeCount() == 1);
|
||||
assert(harness.bus().acquireCount() == 1);
|
||||
assert(harness.events().persistenceCount() >= 3);
|
||||
}
|
||||
|
||||
void test_feedback_runtime_contract()
|
||||
{
|
||||
sys::runtime::RuntimeHarness harness;
|
||||
sys::runtime::FeedbackQueue<4> queue;
|
||||
sys::runtime::DefaultFeedbackPolicy policy;
|
||||
sys::runtime::FeedbackRuntime<4> runtime(queue,
|
||||
policy,
|
||||
harness.feedbackPresenter(),
|
||||
harness.events());
|
||||
|
||||
sys::runtime::NoticeIntent sent{};
|
||||
sent.category = sys::runtime::NoticeCategory::ChatDelivery;
|
||||
sent.severity = sys::runtime::NoticeSeverity::Success;
|
||||
sys::runtime::setNoticeMessage(sent, "Sent");
|
||||
sent.dedupe_key = 42;
|
||||
sent.created_at_ms = 10;
|
||||
assert(runtime.post(sent));
|
||||
assert(runtime.post(sent));
|
||||
assert(runtime.drainToUi(20) == 1);
|
||||
assert(harness.feedbackPresenter().captured() == 1);
|
||||
assert(harness.feedbackPresenter().capturedNotice(0).duration_ms == 1400);
|
||||
}
|
||||
|
||||
void test_track_runtime_contract()
|
||||
{
|
||||
sys::runtime::RuntimeHarness harness;
|
||||
TrackFiles files;
|
||||
TrackEvents events;
|
||||
gps::runtime::DefaultTrackFlushPolicy policy;
|
||||
gps::runtime::TrackStorageWorker worker(files, harness.bus(), events, policy);
|
||||
gps::runtime::TrackPointBuffer<8> points;
|
||||
gps::runtime::TrackStateMachine states;
|
||||
gps::runtime::TrackRuntime<8> runtime(points, states, policy, worker, events);
|
||||
|
||||
assert(runtime.startNewTrack(123, 0));
|
||||
runtime.tick(1);
|
||||
assert(events.count == 1);
|
||||
runtime.handle(events.events[0]);
|
||||
assert(states.state() == gps::runtime::TrackRecorderStatus::Recording);
|
||||
|
||||
gps::runtime::TrackPoint point{};
|
||||
point.latitude = 1.0;
|
||||
point.longitude = 2.0;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
point.timestamp_ms = static_cast<uint32_t>(i);
|
||||
assert(runtime.appendPoint(point, 10 + static_cast<uint32_t>(i)));
|
||||
}
|
||||
runtime.tick(30);
|
||||
assert(files.appended == 8);
|
||||
assert(files.flush_count == 1);
|
||||
}
|
||||
|
||||
void test_runtime_harness_keeps_ui_drain_separate()
|
||||
{
|
||||
sys::runtime::RuntimeHarness harness;
|
||||
harness.advance(5);
|
||||
harness.ui().assertNoBlockingCalls();
|
||||
assert(harness.drainUi() == 0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
test_map_tile_runtime_contract();
|
||||
test_persistence_runtime_contract();
|
||||
test_feedback_runtime_contract();
|
||||
test_track_runtime_contract();
|
||||
test_runtime_harness_keeps_ui_drain_separate();
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user