Browse Source

Additional waypoint methods, update mock, update tests

pull/860/head
philon- 9 months ago
parent
commit
092b90b989
  1. 9
      packages/web/src/core/stores/deviceStore/deviceStore.mock.ts
  2. 39
      packages/web/src/core/stores/deviceStore/deviceStore.test.ts
  3. 112
      packages/web/src/core/stores/deviceStore/index.ts

9
packages/web/src/core/stores/deviceStore/deviceStore.mock.ts

@ -45,8 +45,13 @@ export const mockDeviceStore: Device = {
deleteMessages: false,
managedMode: false,
clientNotification: false,
resetNodeDb: false,
clearAllStores: false,
factoryResetConfig: false,
factoryResetDevice: false,
},
clientNotifications: [],
neighborInfo: new Map(),
setStatus: vi.fn(),
setConfig: vi.fn(),
@ -67,6 +72,8 @@ export const mockDeviceStore: Device = {
setPendingSettingsChanges: vi.fn(),
addChannel: vi.fn(),
addWaypoint: vi.fn(),
removeWaypoint: vi.fn(),
getWaypoint: vi.fn(),
addConnection: vi.fn(),
addTraceRoute: vi.fn(),
addMetadata: vi.fn(),
@ -81,4 +88,6 @@ export const mockDeviceStore: Device = {
getClientNotification: vi.fn(),
getAllUnreadCount: vi.fn().mockReturnValue(0),
getUnreadCount: vi.fn().mockReturnValue(0),
getNeighborInfo: vi.fn(),
addNeighborInfo: vi.fn(),
};

39
packages/web/src/core/stores/deviceStore/deviceStore.test.ts

@ -349,19 +349,16 @@ describe("DeviceStore – traceroutes & waypoints retention + merge on setHardwa
// Old device with myNodeNum=777 and some waypoints (one expired)
const oldDevice = state.addDevice(1);
oldDevice.connection = { sendWaypoint: vi.fn() } as any;
oldDevice.setHardware(makeHardware(777));
oldDevice.addWaypoint(
makeWaypoint(1, Date.parse("2024-12-31T23:59:59Z")),
makeWaypoint(1, Date.parse("2024-12-31T23:59:59Z")), // This is expired, will not be added
0,
0,
new Date(),
); // expired
oldDevice.addWaypoint(
makeWaypoint(2, Date.parse("2028-01-01T00:00:00Z")),
0,
0,
new Date(),
); // ok
oldDevice.addWaypoint(makeWaypoint(2, 0), 0, 0, new Date()); // no expire
oldDevice.addWaypoint(
makeWaypoint(3, Date.parse("2026-01-01T00:00:00Z")),
0,
@ -380,12 +377,12 @@ describe("DeviceStore – traceroutes & waypoints retention + merge on setHardwa
);
const wps = useDeviceStore.getState().devices.get(1)!.waypoints;
expect(wps.length).toBe(3);
expect(wps.length).toBe(2);
expect(wps.find((w) => w.id === 2)?.expire).toBe(
Date.parse("2027-01-01T00:00:00Z"),
);
// Retention: push 102 total waypoints -> capped at 100. Oldest (id=1,2) evicted
// Retention: push 102 total waypoints -> capped at 100. Oldest evicted
for (let i = 3; i <= 102; i++) {
oldDevice.addWaypoint(makeWaypoint(i), 0, 0, new Date());
}
@ -394,24 +391,32 @@ describe("DeviceStore – traceroutes & waypoints retention + merge on setHardwa
100,
);
// Remove waypoint
oldDevice.removeWaypoint(102, false);
expect(oldDevice.connection?.sendWaypoint).not.toHaveBeenCalled();
await oldDevice.removeWaypoint(101, true); // toMesh=true
expect(oldDevice.connection?.sendWaypoint).toHaveBeenCalled();
expect(useDeviceStore.getState().devices.get(1)!.waypoints.length).toBe(98);
// New device shares myNodeNum; setHardware should:
// - move traceroutes from old device
// - copy waypoints minus expired
// - delete old device entry
const newDev = state.addDevice(2);
newDev.setHardware(makeHardware(777));
const newDevice = state.addDevice(2);
newDevice.setHardware(makeHardware(777));
expect(state.getDevice(1)).toBeUndefined();
expect(state.getDevice(2)).toBeDefined();
// traceroutes moved:
expect(state.getDevice(2)!.traceroutes.size).toBeGreaterThan(0);
expect(state.getDevice(2)!.traceroutes.size).toBe(2);
// expired waypoint removed, last non-expired retained:
const newWps = state.getDevice(2)!.waypoints;
expect(newWps.find((w) => w.id === 1)).toBeUndefined();
expect(newWps.find((w) => w.id === 2)).toBeUndefined();
expect(newWps.find((w) => w.id === 3)).toBeTruthy();
// Getter for waypoint by id works
expect(newDevice.getWaypoint(1)).toBeUndefined();
expect(newDevice.getWaypoint(2)).toBeUndefined();
expect(newDevice.getWaypoint(3)).toBeTruthy();
vi.useRealTimers();
});

112
packages/web/src/core/stores/deviceStore/index.ts

@ -89,6 +89,8 @@ export interface Device extends DeviceData {
from: number,
rxTime: Date,
) => void;
removeWaypoint: (waypointId: number, toMesh: boolean) => Promise<void>;
getWaypoint: (waypointId: number) => WaypointWithMetadata | undefined;
addConnection: (connection: MeshDevice) => void;
addTraceRoute: (
traceroute: Types.PacketMetadata<Protobuf.Mesh.RouteDiscovery>,
@ -566,32 +568,102 @@ function deviceFactory(
set(
produce<PrivateDeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
const index = device.waypoints.findIndex(
(wp) => wp.id === waypoint.id,
);
if (index !== -1) {
const created =
device.waypoints[index]?.metadata.created ?? new Date();
const updatedWaypoint = {
...waypoint,
metadata: { created, updated: rxTime, from, channel },
};
device.waypoints[index] = updatedWaypoint;
} else {
device.waypoints.push({
...waypoint,
metadata: { created: rxTime, from, channel },
});
if (!device) {
return undefined;
}
const index = device.waypoints.findIndex(
(wp) => wp.id === waypoint.id,
);
if (index !== -1) {
const created =
device.waypoints[index]?.metadata.created ?? new Date();
const updatedWaypoint = {
...waypoint,
metadata: { created, updated: rxTime, from, channel },
};
// Remove existing waypoint
device.waypoints.splice(index, 1);
// Push new if no expiry or not expired
if (waypoint.expire === 0 || waypoint.expire > Date.now()) {
device.waypoints.push(updatedWaypoint);
}
} else if (
// only add if set to never expire or not already expired
waypoint.expire === 0 ||
(waypoint.expire !== 0 && waypoint.expire < Date.now())
) {
device.waypoints.push({
...waypoint,
metadata: { created: rxTime, from, channel },
});
}
// Enforce retention limit
evictOldestEntries(device.waypoints, WAYPOINT_RETENTION_NUM);
}),
);
},
removeWaypoint: async (waypointId: number, toMesh: boolean) => {
const device = get().devices.get(id);
if (!device) {
return;
}
const waypoint = device.waypoints.find((wp) => wp.id === waypointId);
if (!waypoint) {
return;
}
// Enforce retention limit
evictOldestEntries(device.waypoints, WAYPOINT_RETENTION_NUM);
if (toMesh) {
if (!device.connection) {
return;
}
const waypointToBroadcast = create(Protobuf.Mesh.WaypointSchema, {
id: waypoint.id, // Bare minimum to delete a waypoint
lockedTo: 0,
name: "",
description: "",
icon: 0,
expire: 1,
});
await device.connection.sendWaypoint(
waypointToBroadcast,
"broadcast",
waypoint.metadata.channel,
);
}
// Remove from store
set(
produce<PrivateDeviceState>((draft) => {
const device = draft.devices.get(id);
if (!device) {
return;
}
const idx = device.waypoints.findIndex(
(waypoint) => waypoint.id === waypointId,
);
if (idx >= 0) {
device.waypoints.splice(idx, 1);
}
}),
);
},
getWaypoint: (waypointId: number) => {
const device = get().devices.get(id);
if (!device) {
return;
}
return device.waypoints.find((waypoint) => waypoint.id === waypointId);
},
setActiveNode: (node) => {
set(
produce<PrivateDeviceState>((draft) => {

Loading…
Cancel
Save