test_MemoriesChatSource.js (5632B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 do_get_profile(); 6 7 const { getRecentChats, computeFreshnessScore } = ChromeUtils.importESModule( 8 "moz-src:///browser/components/aiwindow/models/memories/MemoriesChatSource.sys.mjs" 9 ); 10 const { ChatStore, ChatMessage, MESSAGE_ROLE } = ChromeUtils.importESModule( 11 "moz-src:///browser/components/aiwindow/ui/modules/ChatStore.sys.mjs" 12 ); 13 const { sinon } = ChromeUtils.importESModule( 14 "resource://testing-common/Sinon.sys.mjs" 15 ); 16 17 const MS_PER_DAY = 1000 * 60 * 60 * 24; 18 19 function normalizeToMs(value) { 20 if (value instanceof Date) { 21 return value.getTime(); 22 } 23 if (typeof value === "number") { 24 return value; 25 } 26 // assume string (e.g. ISO date) 27 return Date.parse(value); 28 } 29 30 let sandbox; 31 32 add_setup(function () { 33 sandbox = sinon.createSandbox(); 34 registerCleanupFunction(() => { 35 sandbox.restore(); 36 }); 37 }); 38 39 // past date check 40 add_task(function test_computeFreshnessScore_past_date_check() { 41 const createdDate = new Date(Date.now() - 10 * MS_PER_DAY); 42 const score = computeFreshnessScore(createdDate, 7); 43 44 Assert.less(score, 0.5, "Freshness score should be < 0.5"); 45 }); 46 47 // future date check 48 add_task(function test_computeFreshnessScore_future_date_check() { 49 const createdDate = new Date(Date.now() + 1 * MS_PER_DAY); 50 const score = computeFreshnessScore(createdDate, 7); 51 Assert.equal(score, 1, "Freshness score should be 1"); 52 }); 53 54 // current date check 55 add_task(function test_computeFreshnessScore_current_date_check() { 56 const createdDate = new Date(); 57 const score = computeFreshnessScore(createdDate, 7); 58 // allow tiny floating point / timing jitter 59 Assert.greaterOrEqual(score, 0.9999, "Freshness score should be ≈ 1"); 60 Assert.lessOrEqual(score, 1, "Freshness score must be <= 1"); 61 }); 62 63 // approx halflife check 64 add_task(function test_computeFreshnessScore_halflife_approx_check() { 65 const createdDate = new Date(Date.now() - 7 * MS_PER_DAY); 66 const score = computeFreshnessScore(createdDate, 7); 67 // making sure that score in between 0.49 & 0.51 (closer to halflife) 68 Assert.less(score, 0.51, "Freshness score should be < 0.51"); 69 Assert.greater(score, 0.49, "Freshness score should be > 0.49"); 70 }); 71 72 // older vs recent score check 73 add_task(function test_computeFreshnessScore_older_vs_recent_check() { 74 const olderDate = new Date(Date.now() - 30 * MS_PER_DAY); 75 const recentDate = new Date(Date.now() - 1 * MS_PER_DAY); 76 const olderScore = computeFreshnessScore(olderDate, 7); 77 const recentScore = computeFreshnessScore(recentDate, 7); 78 Assert.less(olderScore, recentScore, "Older score should be < recent score"); 79 }); 80 81 add_task(async function test_getRecentChats_basic_mapping_and_limit() { 82 const fixedNow = 1_700_000_000_000; 83 84 const clock = sandbox.useFakeTimers({ now: fixedNow }); 85 86 const messages = [ 87 new ChatMessage({ 88 createdDate: fixedNow - 1_000, 89 ordinal: 1, 90 role: MESSAGE_ROLE.USER, 91 content: { type: "text", body: "msg1" }, 92 pageUrl: "https://example.com/1", 93 turnIndex: 0, 94 }), 95 new ChatMessage({ 96 createdDate: fixedNow - 10_000, 97 ordinal: 2, 98 role: MESSAGE_ROLE.USER, 99 content: { type: "text", body: "msg2" }, 100 pageUrl: "https://example.com/2", 101 turnIndex: 0, 102 }), 103 new ChatMessage({ 104 createdDate: fixedNow - 100_000, 105 ordinal: 3, 106 role: MESSAGE_ROLE.USER, 107 content: { type: "text", body: "msg3" }, 108 pageUrl: "https://example.com/3", 109 turnIndex: 0, 110 }), 111 ]; 112 113 messages.forEach(msg => { 114 Assert.ok( 115 "createdDate" in msg, 116 "Test stub message should have createdDate (camelCase)" 117 ); 118 Assert.ok( 119 msg.content && 120 typeof msg.content === "object" && 121 !Array.isArray(msg.content), 122 "msg.content should be an object, not an array" 123 ); 124 Assert.ok("body" in msg.content, "msg.content should have a body field"); 125 }); 126 127 const maxResults = 3; 128 const halfLifeDays = 7; 129 const startTime = fixedNow - 1_000_000; 130 131 // Stub the method 132 const stub = sandbox 133 .stub(ChatStore.prototype, "findMessagesByDate") 134 .callsFake(async (startTimeArg, endTimeArg, roleArg, limitArg) => { 135 Assert.equal( 136 roleArg, 137 MESSAGE_ROLE.USER, 138 "Role passed to findMessagesByDate should be USER" 139 ); 140 const startMs = normalizeToMs(startTimeArg); 141 const endMs = normalizeToMs(endTimeArg); 142 Assert.greaterOrEqual(endMs, startMs, "endTime should be >= startTime"); 143 Assert.equal(limitArg, maxResults, "limit should match maxResults"); 144 return messages; 145 }); 146 147 const result = await getRecentChats(startTime, maxResults, halfLifeDays); 148 149 // Assert stub was actually called 150 Assert.equal(stub.callCount, 1, "findMessagesByDate should be called once"); 151 152 const [startTimeArg, , roleArg] = stub.firstCall.args; 153 Assert.equal(roleArg, MESSAGE_ROLE.USER, "Role should be USER"); 154 const startMs = normalizeToMs(startTimeArg); 155 156 Assert.equal( 157 startMs, 158 fixedNow - 1_000_000, 159 "startTime should be fixedNow - 1_000_000 in ms" 160 ); 161 162 Assert.equal(result.length, maxResults, "Should respect maxResults"); 163 164 const first = result[0]; 165 const second = result[1]; 166 167 Assert.equal(first.content, "msg1"); 168 Assert.equal(second.content, "msg2"); 169 170 Assert.ok("freshness_score" in first); 171 Assert.greater( 172 first.freshness_score, 173 second.freshness_score, 174 "More recent message should have higher freshness_score" 175 ); 176 177 clock.restore?.(); 178 });