@@ -184,6 +184,111 @@ def test_free_kv_cache_block_queue_operations():
184184 assert str (e .value ) == "No free blocks available"
185185
186186
187+ def test_free_kv_cache_block_queue_append_n ():
188+ # Create an empty FreeKVCacheBlockQueue with these blocks
189+ queue = FreeKVCacheBlockQueue ([])
190+ blocks = [KVCacheBlock (block_id = i ) for i in range (6 )]
191+ # Append 0 block
192+ # fake_head->fake_tail
193+ queue .append_n ([])
194+ assert queue .num_free_blocks == 0
195+ assert (queue .fake_free_list_head .next_free_block
196+ is queue .fake_free_list_tail )
197+ assert (queue .fake_free_list_tail .prev_free_block
198+ is queue .fake_free_list_head )
199+ # Append 1 block
200+ # fake_head->b0->fake_tail
201+ queue .append_n (blocks [0 :1 ])
202+ assert queue .num_free_blocks == 1
203+ assert queue .fake_free_list_head .next_free_block is blocks [0 ]
204+ assert blocks [0 ].prev_free_block is queue .fake_free_list_head
205+ assert blocks [0 ].next_free_block is queue .fake_free_list_tail
206+ assert queue .fake_free_list_tail .prev_free_block is blocks [0 ]
207+ # Append 2 blocks
208+ # fake_head->b0->b4->b5->fake_tail
209+ queue .append_n (blocks [4 :6 ])
210+ assert queue .num_free_blocks == 3
211+ assert queue .fake_free_list_head .next_free_block is blocks [0 ]
212+ assert blocks [0 ].prev_free_block is queue .fake_free_list_head
213+ assert blocks [0 ].next_free_block is blocks [4 ]
214+ assert blocks [4 ].prev_free_block is blocks [0 ]
215+ assert blocks [4 ].next_free_block is blocks [5 ]
216+ assert blocks [5 ].prev_free_block is blocks [4 ]
217+ assert blocks [5 ].next_free_block is queue .fake_free_list_tail
218+ assert queue .fake_free_list_tail .prev_free_block is blocks [5 ]
219+ # Append 3 blocks
220+ # fake_head->b0->b4->b5->b1->b2->b3->fake_tail
221+ queue .append_n (blocks [1 :4 ])
222+ assert queue .num_free_blocks == 6
223+ assert queue .fake_free_list_head .next_free_block is blocks [0 ]
224+ assert blocks [0 ].prev_free_block is queue .fake_free_list_head
225+ assert blocks [0 ].next_free_block is blocks [4 ]
226+ assert blocks [4 ].prev_free_block is blocks [0 ]
227+ assert blocks [4 ].next_free_block is blocks [5 ]
228+ assert blocks [5 ].prev_free_block is blocks [4 ]
229+ assert blocks [5 ].next_free_block is blocks [1 ]
230+ assert blocks [1 ].prev_free_block is blocks [5 ]
231+ assert blocks [1 ].next_free_block is blocks [2 ]
232+ assert blocks [2 ].prev_free_block is blocks [1 ]
233+ assert blocks [2 ].next_free_block is blocks [3 ]
234+ assert blocks [3 ].prev_free_block is blocks [2 ]
235+ assert blocks [3 ].next_free_block is queue .fake_free_list_tail
236+ assert queue .fake_free_list_tail .prev_free_block is blocks [3 ]
237+
238+
239+ def test_free_kv_cache_block_queue_popleft_n ():
240+ blocks = [KVCacheBlock (block_id = i ) for i in range (6 )]
241+ # Create a empty FreeKVCacheBlockQueue with these blocks
242+ queue = FreeKVCacheBlockQueue (
243+ [blocks [1 ], blocks [3 ], blocks [5 ], blocks [4 ], blocks [0 ], blocks [2 ]])
244+ assert queue .num_free_blocks == 6
245+ assert queue .fake_free_list_head .next_free_block is blocks [1 ]
246+ assert blocks [1 ].prev_free_block is queue .fake_free_list_head
247+ assert blocks [1 ].next_free_block is blocks [3 ]
248+ assert blocks [3 ].prev_free_block is blocks [1 ]
249+ assert blocks [3 ].next_free_block is blocks [5 ]
250+ assert blocks [5 ].prev_free_block is blocks [3 ]
251+ assert blocks [5 ].next_free_block is blocks [4 ]
252+ assert blocks [4 ].prev_free_block is blocks [5 ]
253+ assert blocks [4 ].next_free_block is blocks [0 ]
254+ assert blocks [0 ].prev_free_block is blocks [4 ]
255+ assert blocks [0 ].next_free_block is blocks [2 ]
256+ assert blocks [2 ].prev_free_block is blocks [0 ]
257+ assert blocks [2 ].next_free_block is queue .fake_free_list_tail
258+ assert queue .fake_free_list_tail .prev_free_block is blocks [2 ]
259+
260+ # Pop 0 block
261+ # fake_head->b1->b3->b5->b4->b0->b2->fake_tail
262+ assert len (queue .popleft_n (0 )) == 0
263+ # Pop 1 block
264+ # fake_head->b3->b5->b4->b0->b2->fake_tail
265+ result_blocks = queue .popleft_n (1 )
266+ assert len (result_blocks ) == 1
267+ assert result_blocks [0 ] is blocks [1 ]
268+ for block in result_blocks :
269+ assert block .prev_free_block is None
270+ assert block .next_free_block is None
271+ # Pop 2 blocks
272+ # fake_head->b4->b0->b2->fake_tail
273+ result_blocks = queue .popleft_n (2 )
274+ assert len (result_blocks ) == 2
275+ assert result_blocks [0 ] is blocks [3 ]
276+ assert result_blocks [1 ] is blocks [5 ]
277+ for block in result_blocks :
278+ assert block .prev_free_block is None
279+ assert block .next_free_block is None
280+ # Pop 3 blocks
281+ # fake_head->fake_tail
282+ result_blocks = queue .popleft_n (3 )
283+ assert len (result_blocks ) == 3
284+ assert result_blocks [0 ] is blocks [4 ]
285+ assert result_blocks [1 ] is blocks [0 ]
286+ assert result_blocks [2 ] is blocks [2 ]
287+ for block in result_blocks :
288+ assert block .prev_free_block is None
289+ assert block .next_free_block is None
290+
291+
187292def test_free_kv_cache_block_queue_get_all_free_blocks ():
188293 # Create a list of KVCacheBlock objects
189294 blocks = [KVCacheBlock (block_id = i ) for i in range (5 )]
0 commit comments