@@ -233,3 +233,100 @@ impl<'a> WALBuilder<'a> {
233233 Ok ( ( current_sequence, entries) )
234234 }
235235}
236+
237+ #[ cfg( test) ]
238+ mod tests {
239+ use super :: * ;
240+ use crate :: wal:: endec:: implements:: bitcode:: { BitcodeDecoder , BitcodeEncoder } ;
241+ use crate :: wal:: types:: { EntryType , WALEntry } ;
242+ use std:: fs:: { self , File } ;
243+ use std:: io:: Write ;
244+ use std:: path:: { Path , PathBuf } ;
245+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
246+
247+ fn get_test_config ( wal_dir_path : & Path ) -> GlobalConfig {
248+ GlobalConfig {
249+ port : 22208 ,
250+ host : "127.0.0.1" . to_string ( ) ,
251+ data_directory : "./test_db_data" . to_string ( ) ,
252+ wal_enabled : true ,
253+ wal_directory : wal_dir_path. to_str ( ) . unwrap ( ) . to_string ( ) ,
254+ wal_segment_size : 1024 ,
255+ wal_extension : "waltest" . to_string ( ) ,
256+ }
257+ }
258+
259+ fn setup_test_wal_dir ( test_name : & str ) -> PathBuf {
260+ let wal_dir = PathBuf :: from ( format ! ( "target/test_wal_data/{}" , test_name) ) ;
261+ if wal_dir. exists ( ) {
262+ fs:: remove_dir_all ( & wal_dir)
263+ . unwrap_or_else ( |e| panic ! ( "Failed to remove old test WAL dir {:?}: {}" , wal_dir, e) ) ;
264+ }
265+ fs:: create_dir_all ( & wal_dir)
266+ . unwrap_or_else ( |e| panic ! ( "Failed to create test WAL dir {:?}: {}" , wal_dir, e) ) ;
267+ wal_dir
268+ }
269+
270+ fn create_entry ( entry_type : EntryType , data_str : Option < & str > ) -> WALEntry {
271+ WALEntry {
272+ entry_type,
273+ data : data_str. map ( |s| s. as_bytes ( ) . to_vec ( ) ) ,
274+ timestamp : SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . unwrap ( ) . as_millis ( ) ,
275+ transaction_id : None ,
276+ }
277+ }
278+
279+ // WAL 파일에 엔트리들을 기록하는 헬퍼 함수
280+ fn write_wal_file ( config : & GlobalConfig , sequence : usize , entries : & Vec < WALEntry > ) {
281+ let encoder = BitcodeEncoder :: new ( ) ;
282+ let encoded_data = encoder. encode ( entries) . unwrap ( ) ;
283+ let file_path = PathBuf :: from ( & config. wal_directory )
284+ . join ( format ! ( "{:08X}.{}" , sequence, config. wal_extension) ) ;
285+
286+ let mut file = File :: create ( & file_path)
287+ . unwrap_or_else ( |e| panic ! ( "Failed to create wal file {:?}: {}" , file_path, e) ) ;
288+ file. write_all ( & encoded_data)
289+ . unwrap_or_else ( |e| panic ! ( "Failed to write to wal file {:?}: {}" , file_path, e) ) ;
290+ file. sync_all ( )
291+ . unwrap_or_else ( |e| panic ! ( "Failed to sync wal file {:?}: {}" , file_path, e) ) ;
292+ }
293+
294+ #[ tokio:: test]
295+ async fn test_build_no_wal_files ( ) {
296+ let wal_dir = setup_test_wal_dir ( "no_wal_files" ) ;
297+ let config = get_test_config ( & wal_dir) ;
298+
299+ let builder = WALBuilder :: new ( & config) ;
300+ let encoder = BitcodeEncoder :: new ( ) ;
301+ let decoder = BitcodeDecoder :: new ( ) ;
302+
303+ let wal_manager = builder. build ( decoder, encoder) . await . unwrap ( ) ;
304+
305+ assert_eq ! ( wal_manager. sequence, 1 , "Sequence should be 1 when no WAL files exist" ) ;
306+ assert ! ( wal_manager. buffers. is_empty( ) , "Buffers should be empty when no WAL files exist" ) ;
307+ }
308+
309+ #[ tokio:: test]
310+ async fn test_build_single_file_with_checkpoint ( ) {
311+ let wal_dir = setup_test_wal_dir ( "single_file_checkpoint" ) ;
312+ let config = get_test_config ( & wal_dir) ;
313+
314+ // 테스트용 WAL 파일 생성 (시퀀스 1, 마지막은 체크포인트)
315+ let entries_seq1 = vec ! [
316+ create_entry( EntryType :: Insert , Some ( "data1" ) ) ,
317+ create_entry( EntryType :: Set , Some ( "data2" ) ) ,
318+ create_entry( EntryType :: Checkpoint , None ) ,
319+ ] ;
320+ write_wal_file ( & config, 1 , & entries_seq1) ;
321+
322+ let builder = WALBuilder :: new ( & config) ;
323+ let encoder = BitcodeEncoder :: new ( ) ;
324+ let decoder = BitcodeDecoder :: new ( ) ;
325+
326+ let wal_manager = builder. build ( decoder, encoder) . await . unwrap ( ) ;
327+
328+ // 시퀀스는 2여야 하고, 버퍼는 비어있어야 함 (체크포인트 완료)
329+ assert_eq ! ( wal_manager. sequence, 2 , "Sequence should be 2 after a checkpointed file" ) ;
330+ assert ! ( wal_manager. buffers. is_empty( ) , "Buffers should be empty after a checkpointed file" ) ;
331+ }
332+ }
0 commit comments