@@ -8,6 +8,76 @@ const makeEmbeddings = () =>
88 tokenizerSource : 'file://tokenizer.json' ,
99 } ) ;
1010
11+ describe ( 'LFMEmbeddings.runWithLoadedModel' , ( ) => {
12+ it ( 'loads for an operation and always unloads afterwards' , async ( ) => {
13+ const embeddings = makeEmbeddings ( ) ;
14+ const load = jest . spyOn ( embeddings , 'load' ) . mockResolvedValue ( embeddings ) ;
15+ const unload = jest . spyOn ( embeddings , 'unload' ) . mockResolvedValue ( ) ;
16+ const operation = jest . fn ( ) . mockResolvedValue ( 'result' ) ;
17+
18+ await expect ( embeddings . runWithLoadedModel ( operation ) ) . resolves . toBe (
19+ 'result'
20+ ) ;
21+ expect ( load ) . toHaveBeenCalledTimes ( 1 ) ;
22+ expect ( operation ) . toHaveBeenCalledTimes ( 1 ) ;
23+ expect ( unload ) . toHaveBeenCalledTimes ( 1 ) ;
24+ expect ( load . mock . invocationCallOrder [ 0 ] ) . toBeLessThan (
25+ operation . mock . invocationCallOrder [ 0 ]
26+ ) ;
27+ expect ( operation . mock . invocationCallOrder [ 0 ] ) . toBeLessThan (
28+ unload . mock . invocationCallOrder [ 0 ]
29+ ) ;
30+ } ) ;
31+
32+ it ( 'unloads when the operation fails' , async ( ) => {
33+ const embeddings = makeEmbeddings ( ) ;
34+ jest . spyOn ( embeddings , 'load' ) . mockResolvedValue ( embeddings ) ;
35+ const unload = jest . spyOn ( embeddings , 'unload' ) . mockResolvedValue ( ) ;
36+
37+ await expect (
38+ embeddings . runWithLoadedModel ( async ( ) => {
39+ throw new Error ( 'embedding failed' ) ;
40+ } )
41+ ) . rejects . toThrow ( 'embedding failed' ) ;
42+ expect ( unload ) . toHaveBeenCalledTimes ( 1 ) ;
43+ } ) ;
44+
45+ it ( 'serializes operations so one cannot unload another model session' , async ( ) => {
46+ const embeddings = makeEmbeddings ( ) ;
47+ const load = jest . spyOn ( embeddings , 'load' ) . mockResolvedValue ( embeddings ) ;
48+ const unload = jest . spyOn ( embeddings , 'unload' ) . mockResolvedValue ( ) ;
49+ let finishFirst ! : ( ) => void ;
50+ let markFirstStarted ! : ( ) => void ;
51+ const firstGate = new Promise < void > ( ( resolve ) => {
52+ finishFirst = resolve ;
53+ } ) ;
54+ const firstStarted = new Promise < void > ( ( resolve ) => {
55+ markFirstStarted = resolve ;
56+ } ) ;
57+ const order : string [ ] = [ ] ;
58+
59+ const first = embeddings . runWithLoadedModel ( async ( ) => {
60+ order . push ( 'first-start' ) ;
61+ markFirstStarted ( ) ;
62+ await firstGate ;
63+ order . push ( 'first-end' ) ;
64+ } ) ;
65+ const second = embeddings . runWithLoadedModel ( async ( ) => {
66+ order . push ( 'second' ) ;
67+ } ) ;
68+
69+ await firstStarted ;
70+ expect ( order ) . toEqual ( [ 'first-start' ] ) ;
71+
72+ finishFirst ( ) ;
73+ await Promise . all ( [ first , second ] ) ;
74+
75+ expect ( order ) . toEqual ( [ 'first-start' , 'first-end' , 'second' ] ) ;
76+ expect ( load ) . toHaveBeenCalledTimes ( 2 ) ;
77+ expect ( unload ) . toHaveBeenCalledTimes ( 2 ) ;
78+ } ) ;
79+ } ) ;
80+
1181describe ( 'embedding input limits' , ( ) => {
1282 it ( 'sends a short query through with its prefix intact' , async ( ) => {
1383 const embeddings = makeEmbeddings ( ) ;
0 commit comments