Refactor ConsoleAPIStorage event handling and add tests for ring buffer behavior

This commit is contained in:
wuggy 2026-09-07 13:27:39 -07:00
commit 810e55b503
6 changed files with 137 additions and 14 deletions

View file

@ -94,13 +94,24 @@ ConsoleAPIStorageService.prototype = {
getEvents: function CS_getEvents(aId)
{
if (aId != null) {
return (_consoleStorage.get(aId) || []).slice(0);
let storage = _consoleStorage.get(aId);
if (!storage) {
return [];
}
let { events, next } = storage;
return next === 0 ? events.slice() :
events.slice(next).concat(events.slice(0, next));
}
let result = [];
for (let [id, events] of _consoleStorage) {
result.push.apply(result, events);
for (let { events, next } of _consoleStorage.values()) {
for (let i = next; i < events.length; i++) {
result.push(events[i]);
}
for (let i = 0; i < next; i++) {
result.push(events[i]);
}
}
return result.sort(function(a, b) {
@ -122,16 +133,21 @@ ConsoleAPIStorageService.prototype = {
*/
recordEvent: function CS_recordEvent(aId, aOuterId, aEvent)
{
if (!_consoleStorage.has(aId)) {
_consoleStorage.set(aId, []);
let storage = _consoleStorage.get(aId);
if (!storage) {
storage = { events: [], next: 0 };
_consoleStorage.set(aId, storage);
}
let storage = _consoleStorage.get(aId);
storage.push(aEvent);
// truncate
if (storage.length > STORAGE_MAX_EVENTS) {
storage.shift();
// Overwrite the oldest event once full, without moving the other entries.
// Advance before notifying observers, which may read or reenter storage.
if (storage.events.length < STORAGE_MAX_EVENTS) {
storage.events.push(aEvent);
} else {
storage.events[storage.next] = aEvent;
if (++storage.next === STORAGE_MAX_EVENTS) {
storage.next = 0;
}
}
Services.obs.notifyObservers(aEvent, "console-api-log-event", aOuterId);

View file

@ -40,5 +40,6 @@ LOCAL_INCLUDES += [
MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
MOCHITEST_CHROME_MANIFESTS += [ 'tests/chrome.ini' ]
XPCSHELL_TESTS_MANIFESTS += [ 'tests/xpcshell.ini' ]
FINAL_LIBRARY = 'xul'

View file

@ -0,0 +1,53 @@
function run_test() {
const storage = Components.classes["@mozilla.org/consoleAPI-storage;1"]
.getService(Components.interfaces.nsIConsoleAPIStorage);
Components.utils.import("resource://gre/modules/Services.jsm");
storage.clearEvents();
try {
for (let i = 0; i < 3501; i++) {
storage.recordEvent("ring-test", "outer", { timeStamp: i });
if (i === 998 || i === 999 || i === 1000 || i === 1999 || i === 3500) {
let events = storage.getEvents("ring-test");
equal(events.length, Math.min(i + 1, 1000));
for (let j = 0; j < events.length; j++) {
equal(events[j].timeStamp, i + 1 - events.length + j);
}
events.length = 0;
equal(storage.getEvents("ring-test").length, Math.min(i + 1, 1000));
}
}
storage.recordEvent("other", "outer", { timeStamp: 2500.5 });
let all = storage.getEvents();
equal(all.length, 1001);
equal(all[0].timeStamp, 2500.5);
equal(all[1].timeStamp, 2501);
equal(all[1000].timeStamp, 3500);
let reentered = false;
let observer = {
observe(subject, topic, data) {
if (data === "ring-test" && !reentered) {
equal(storage.getEvents(data)[999].timeStamp, 3501);
reentered = true;
storage.recordEvent("ring-test", "outer", { timeStamp: 3502 });
}
}
};
Services.obs.addObserver(observer, "console-storage-cache-event", false);
try {
storage.recordEvent("ring-test", "outer", { timeStamp: 3501 });
} finally {
Services.obs.removeObserver(observer, "console-storage-cache-event");
}
equal(reentered, true);
equal(storage.getEvents("ring-test")[999].timeStamp, 3502);
storage.clearEvents("ring-test");
equal(storage.getEvents("ring-test").length, 0);
equal(storage.getEvents("other").length, 1);
storage.recordEvent("ring-test", "outer", { timeStamp: 4000 });
equal(storage.getEvents("ring-test")[0].timeStamp, 4000);
} finally {
storage.clearEvents();
}
equal(storage.getEvents().length, 0);
}

View file

@ -0,0 +1,5 @@
[DEFAULT]
head =
tail =
[test_console_storage_ring.js]