namespace Raft.Test open NUnit.Framework open Raft open FsUnitTyped open FsCheck [] module TestInMemoryPersistentState = [] let ``Properties of empty`` () = let s = InMemoryPersistentState () :> IPersistentState<_> s.CurrentLogIndex |> shouldEqual 0 for i in -2 .. 10 do match s.GetLogEntry (i * 1) with | Some _ -> failwith "should not have had a log entry" | None -> () s.CurrentTerm |> shouldEqual 0 s.VotedFor |> shouldEqual None match s.GetLastLogEntry () with | Some _ -> failwith "should not have had a log entry" | None -> () let ofList<'a> (xs : ('a * int) list) : InMemoryPersistentState<'a> = let s = InMemoryPersistentState<'a> () for x, term in xs do (s :> IPersistentState<_>).AppendToLog (LogEntry.ClientEntry (x, 1, 1, ignore)) term s let isPrefix (prefix : 'a list) (l : 'a list) : bool = l |> List.truncate prefix.Length |> List.zip prefix |> List.forall (fun (x, y) -> x = y) [] let ``Nonzero truncation followed by Get succeeds`` () = let property (truncate : int) (xs : (byte * int) list) : bool = let truncate = abs truncate + 1 let uut = ofList xs let oldLog = uut.GetLog () |> List.map (fun (entry, term) -> SerialisedLogEntry.Make entry, term) match (uut :> IPersistentState<_>).GetLogEntry truncate with | None -> (uut :> IPersistentState<_>).TruncateLog truncate let newLog = uut.GetLog () |> List.map (fun (entry, term) -> SerialisedLogEntry.Make entry, term) newLog = oldLog | Some (itemStored, entry) -> (uut :> IPersistentState<_>).TruncateLog truncate let newLog = uut.GetLog () |> List.map (fun (entry, term) -> SerialisedLogEntry.Make entry, term) let retrieved, logEntry = Option.get ((uut :> IPersistentState<_>).GetLastLogEntry ()) logEntry = { Index = truncate Term = entry } && (SerialisedLogEntry.Make retrieved = SerialisedLogEntry.Make itemStored) && isPrefix newLog oldLog && (uut :> IPersistentState<_>).CurrentLogIndex = truncate Check.QuickThrowOnFailure property [] let ``Zero truncation results in empty log`` () = let property (truncate : int) (xs : (int * int) list) : bool = let truncate = -abs truncate let uut = ofList xs // It's not meaningful to take the 0th element match (uut :> IPersistentState<_>).GetLogEntry truncate with | Some _ -> failwith "should not have had any elements" | None -> () (uut :> IPersistentState<_>).TruncateLog truncate match uut.GetLog () with | [] -> () | _ -> failwith "should not have had log entries" let uut = uut :> IPersistentState<_> match uut.GetLastLogEntry () with | Some _ -> false | None -> uut.CurrentLogIndex = 0 Check.QuickThrowOnFailure property