Skip to content

Commit 2a68f6e

Browse files
committed
Add a golden test for trace messages.
The idea is to cover as much of the public API as possible to trace most (if not all) unique trace messages at least once. The trace output is useful in two ways: * By using golden tests based on the trace output we can help to ensure that trace datatypes and their printing do not change unexpectedly. * The trace output serves as an example that can be manually inspected to see whether the trace messages are printed correctly and whether they are useful.
1 parent 4c7c8fa commit 2a68f6e

File tree

4 files changed

+237
-1
lines changed

4 files changed

+237
-1
lines changed

lsm-tree.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ test-suite lsm-tree-test
845845
Test.Database.LSMTree.StateMachine
846846
Test.Database.LSMTree.StateMachine.DL
847847
Test.Database.LSMTree.StateMachine.Op
848+
Test.Database.LSMTree.Tracer.Golden
848849
Test.Database.LSMTree.UnitTests
849850
Test.FS
850851
Test.Util.Arbitrary

test/Main.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import qualified Test.Database.LSMTree.Model.Table
4545
import qualified Test.Database.LSMTree.Resolve
4646
import qualified Test.Database.LSMTree.StateMachine
4747
import qualified Test.Database.LSMTree.StateMachine.DL
48+
import qualified Test.Database.LSMTree.Tracer.Golden
4849
import qualified Test.Database.LSMTree.UnitTests
4950
import qualified Test.FS
5051
import Test.Tasty
@@ -91,9 +92,10 @@ main = do
9192
, Test.Database.LSMTree.Internal.WriteBufferReader.FS.tests
9293
, Test.Database.LSMTree.Model.Table.tests
9394
, Test.Database.LSMTree.Resolve.tests
94-
, Test.Database.LSMTree.UnitTests.tests
9595
, Test.Database.LSMTree.StateMachine.tests
9696
, Test.Database.LSMTree.StateMachine.DL.tests
97+
, Test.Database.LSMTree.Tracer.Golden.tests
98+
, Test.Database.LSMTree.UnitTests.tests
9799
, Test.FS.tests
98100
]
99101
Control.RefCount.checkForgottenRefs
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
{-# LANGUAGE OverloadedLists #-}
2+
{-# LANGUAGE OverloadedStrings #-}
3+
4+
module Test.Database.LSMTree.Tracer.Golden (tests) where
5+
6+
import Control.Exception (mask_)
7+
import Control.Monad (void)
8+
import Control.Tracer
9+
import qualified Data.List.NonEmpty as NE
10+
import Data.Monoid (Sum (..))
11+
import Data.Word
12+
import Database.LSMTree as R
13+
import Prelude hiding (lookup)
14+
import System.FilePath
15+
import qualified System.FS.API as FS
16+
import qualified System.IO as IO
17+
import Test.Tasty (TestTree, localOption, testGroup)
18+
import Test.Tasty.Golden
19+
import Test.Util.FS (withTempIOHasBlockIO)
20+
21+
22+
tests :: TestTree
23+
tests =
24+
localOption OnPass $
25+
testGroup "Test.Database.LSMTree.Tracer.Golden" [
26+
goldenVsFile
27+
"golden_traceMessages"
28+
goldenDataFile
29+
dataFile
30+
(golden_traceMessages dataFile)
31+
]
32+
33+
goldenDataDirectory :: FilePath
34+
goldenDataDirectory = "test/golden-file-data/tracer"
35+
36+
-- | Path to the /golden/ file for 'golden_traceMessages'
37+
goldenDataFile :: FilePath
38+
goldenDataFile = dataFile <.> "golden"
39+
40+
-- | Path to the output file for 'golden_traceMessages'
41+
dataFile :: FilePath
42+
dataFile = goldenDataDirectory </> "golden_traceMessages"
43+
44+
-- | A monadic action that traces messages emitted by the public API of
45+
-- @lsm-tree@ to a file.
46+
--
47+
-- The idea is to cover as much of the public API as possible to trace most (if
48+
-- not all) unique trace messages at least once. The trace output is useful in
49+
-- two ways:
50+
--
51+
-- * By using golden tests based on the trace output we can help to ensure that
52+
-- trace datatypes and their printing do not change unexpectedly.
53+
--
54+
-- * The trace output serves as an example that can be manually inspected to see
55+
-- whether the trace messages are printed correctly and whether they are
56+
-- useful.
57+
golden_traceMessages :: FilePath -> IO ()
58+
golden_traceMessages file =
59+
withTempIOHasBlockIO "golden_traceMessages" $ \hfs hbio ->
60+
withBinaryFileTracer file $ \(contramap show -> tr) -> do
61+
62+
let sessionPath = FS.mkFsPath ["session-dir"]
63+
FS.createDirectory hfs sessionPath
64+
65+
-- Open and close a session
66+
withOpenSession tr hfs hbio 4 sessionPath $ \s -> do
67+
-- Open and close a table
68+
withTable s $ \(t1 :: Table IO K V B) -> do
69+
-- Try out all the update variants
70+
update t1 (K 0) (Insert (V 0) Nothing)
71+
insert t1 (K 1) (V 1) (Just (B 1))
72+
delete t1 (K 2)
73+
upsert t1 (K 3) (V 3)
74+
75+
-- Perform a lookup and its member variant
76+
FoundWithBlob (V 1) bref <- lookup t1 (K 1)
77+
void $ member t1 (K 2)
78+
79+
void $ rangeLookup t1 (FromToExcluding (K 0) (K 3))
80+
81+
-- Open and close a cursor
82+
withCursorAtOffset t1 (K 1) $ \c -> do
83+
-- Read from a cursor
84+
[EntryWithBlob (K 1) (V 1) _] <- R.takeWhile 2 (< K 3) c
85+
void $ R.next c
86+
-- Retrieve blobs (we didn't try this before this part)
87+
B 1 <- retrieveBlob s bref
88+
pure ()
89+
90+
let snapA = "snapshot_a"
91+
snapB = "snapshot_b"
92+
93+
-- Try out a few snapshot operations, and keep one saved snapshot for
94+
-- later
95+
saveSnapshot snapA snapLabel t1
96+
saveSnapshot snapB snapLabel t1
97+
void $ listSnapshots s
98+
deleteSnapshot s snapB
99+
void $ doesSnapshotExist s snapA
100+
101+
-- Open a table from a snapshot and close it again
102+
withTableFromSnapshot s snapA snapLabel $ \ t2 -> do
103+
104+
-- Create a table duplicate and close it again
105+
withDuplicate t1 $ \t3 -> do
106+
107+
let unionInputs = NE.fromList [t1, t2, t3]
108+
109+
-- One-shot union
110+
withUnions unionInputs $ \_ -> pure ()
111+
112+
-- Incremental union
113+
withIncrementalUnions unionInputs $ \t4 -> do
114+
UnionDebt d <- remainingUnionDebt t4
115+
void $ supplyUnionCredits t4 (UnionCredits (d - 1))
116+
UnionDebt d' <- remainingUnionDebt t4
117+
void $ supplyUnionCredits t4 (UnionCredits (d' + 1))
118+
void $ remainingUnionDebt t4
119+
120+
-- Open a table and cursor, but close them automatically as part of
121+
-- closing the session instead of closing them manually.
122+
(t :: Table IO K V B) <- mask_ $ newTable s
123+
_c <- mask_ $ newCursor t
124+
125+
pure ()
126+
127+
-- | A tracer that emits trace messages to a file handle
128+
fileHandleTracer :: IO.Handle -> Tracer IO String
129+
fileHandleTracer h = Tracer $ emit (IO.hPutStrLn h)
130+
131+
132+
-- | A tracer that emits trace messages to a binary file
133+
withBinaryFileTracer :: FilePath -> (Tracer IO String -> IO a) -> IO a
134+
withBinaryFileTracer fp k =
135+
IO.withBinaryFile fp IO.WriteMode $ \h ->
136+
k (fileHandleTracer h)
137+
138+
{-------------------------------------------------------------------------------
139+
Key and value types
140+
-------------------------------------------------------------------------------}
141+
142+
newtype K = K Word64
143+
deriving stock (Show, Eq, Ord)
144+
deriving newtype (SerialiseKey)
145+
146+
newtype V = V Word64
147+
deriving stock (Show, Eq, Ord)
148+
deriving newtype (SerialiseValue)
149+
150+
deriving via Sum Word64 instance ResolveValue V
151+
152+
newtype B = B Word64
153+
deriving stock (Show, Eq, Ord)
154+
deriving newtype (SerialiseValue)
155+
156+
snapLabel :: SnapshotLabel
157+
snapLabel = SnapshotLabel "KVBs"
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
TraceSession (SessionId session-dir) TraceOpenSession
2+
TraceSession (SessionId session-dir) TraceNewSession
3+
TraceSession (SessionId session-dir) TraceCreatedSession
4+
TraceTable (TableId 0) (TraceNewTable (TableConfig {confMergePolicy = LazyLevelling, confMergeSchedule = Incremental, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries 20000, confBloomFilterAlloc = AllocRequestFPR 1.0e-3, confFencePointerIndex = OrdinaryIndex, confDiskCachePolicy = DiskCacheAll, confMergeBatchSize = MergeBatchSize 20000}))
5+
TraceTable (TableId 0) (TraceCreatedTable (SessionId session-dir) (TableConfig {confMergePolicy = LazyLevelling, confMergeSchedule = Incremental, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries 20000, confBloomFilterAlloc = AllocRequestFPR 1.0e-3, confFencePointerIndex = OrdinaryIndex, confDiskCachePolicy = DiskCacheAll, confMergeBatchSize = MergeBatchSize 20000}))
6+
TraceTable (TableId 0) (TraceUpdates 1)
7+
TraceTable (TableId 0) (TraceUpdated 1)
8+
TraceTable (TableId 0) (TraceUpdates 1)
9+
TraceTable (TableId 0) (TraceUpdated 1)
10+
TraceTable (TableId 0) (TraceUpdates 1)
11+
TraceTable (TableId 0) (TraceUpdated 1)
12+
TraceTable (TableId 0) (TraceUpdates 1)
13+
TraceTable (TableId 0) (TraceUpdated 1)
14+
TraceTable (TableId 0) (TraceLookups 1)
15+
TraceTable (TableId 0) (TraceLookups 1)
16+
TraceTable (TableId 0) (TraceRangeLookup (FromToExcluding (SerialisedKey [0,0,0,0,0,0,0,0]) (SerialisedKey [0,0,0,0,0,0,0,3])))
17+
TraceCursor (CursorId 2) (TraceNewCursor (TableId 0) (OffsetKey (SerialisedKey [0,0,0,0,0,0,0,0])))
18+
TraceCursor (CursorId 2) (TraceCreatedCursor (SessionId session-dir))
19+
TraceCursor (CursorId 2) (TraceReadingCursor 500)
20+
TraceCursor (CursorId 2) (TraceReadCursor 500 2)
21+
TraceCursor (CursorId 2) TraceCloseCursor
22+
TraceCursor (CursorId 2) TraceClosedCursor
23+
TraceCursor (CursorId 3) (TraceNewCursor (TableId 0) (OffsetKey (SerialisedKey [0,0,0,0,0,0,0,1])))
24+
TraceCursor (CursorId 3) (TraceCreatedCursor (SessionId session-dir))
25+
TraceCursor (CursorId 3) (TraceReadingCursor 2)
26+
TraceCursor (CursorId 3) (TraceReadCursor 2 1)
27+
TraceCursor (CursorId 3) (TraceReadingCursor 1)
28+
TraceCursor (CursorId 3) (TraceReadCursor 1 1)
29+
TraceSession (SessionId session-dir) (TraceRetrieveBlobs 1)
30+
TraceCursor (CursorId 3) TraceCloseCursor
31+
TraceCursor (CursorId 3) TraceClosedCursor
32+
TraceTable (TableId 0) (TraceSaveSnapshot "snapshot_a")
33+
TraceTable (TableId 0) (TraceSavedSnapshot "snapshot_a")
34+
TraceTable (TableId 0) (TraceSaveSnapshot "snapshot_b")
35+
TraceTable (TableId 0) (TraceSavedSnapshot "snapshot_b")
36+
TraceSession (SessionId session-dir) TraceListSnapshots
37+
TraceSession (SessionId session-dir) (TraceDeleteSnapshot "snapshot_b")
38+
TraceSession (SessionId session-dir) (TraceDeletedSnapshot "snapshot_b")
39+
TraceTable (TableId 6) (TraceOpenTableFromSnapshot "snapshot_a" (TableConfigOverride {overrideDiskCachePolicy = Nothing, overrideMergeBatchSize = Nothing}))
40+
TraceTable (TableId 6) (TraceCreatedTable (SessionId session-dir) (TableConfig {confMergePolicy = LazyLevelling, confMergeSchedule = Incremental, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries 20000, confBloomFilterAlloc = AllocRequestFPR 1.0e-3, confFencePointerIndex = OrdinaryIndex, confDiskCachePolicy = DiskCacheAll, confMergeBatchSize = MergeBatchSize 20000}))
41+
TraceTable (TableId 8) (TraceDuplicate (TableId 0))
42+
TraceTable (TableId 8) (TraceCreatedTable (SessionId session-dir) (TableConfig {confMergePolicy = LazyLevelling, confMergeSchedule = Incremental, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries 20000, confBloomFilterAlloc = AllocRequestFPR 1.0e-3, confFencePointerIndex = OrdinaryIndex, confDiskCachePolicy = DiskCacheAll, confMergeBatchSize = MergeBatchSize 20000}))
43+
TraceTable (TableId 9) (TraceIncrementalUnions (TableId 0 :| [TableId 6,TableId 8]))
44+
TraceTable (TableId 9) (TraceCreatedTable (SessionId session-dir) (TableConfig {confMergePolicy = LazyLevelling, confMergeSchedule = Incremental, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries 20000, confBloomFilterAlloc = AllocRequestFPR 1.0e-3, confFencePointerIndex = OrdinaryIndex, confDiskCachePolicy = DiskCacheAll, confMergeBatchSize = MergeBatchSize 20000}))
45+
TraceTable (TableId 9) TraceRemainingUnionDebt
46+
TraceTable (TableId 9) (TraceSupplyUnionCredits 13)
47+
TraceTable (TableId 9) (TraceSuppliedUnionCredits 13 1)
48+
TraceTable (TableId 9) TraceCloseTable
49+
TraceTable (TableId 9) TraceClosedTable
50+
TraceTable (TableId 15) (TraceIncrementalUnions (TableId 0 :| [TableId 6,TableId 8]))
51+
TraceTable (TableId 15) (TraceCreatedTable (SessionId session-dir) (TableConfig {confMergePolicy = LazyLevelling, confMergeSchedule = Incremental, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries 20000, confBloomFilterAlloc = AllocRequestFPR 1.0e-3, confFencePointerIndex = OrdinaryIndex, confDiskCachePolicy = DiskCacheAll, confMergeBatchSize = MergeBatchSize 20000}))
52+
TraceTable (TableId 15) TraceRemainingUnionDebt
53+
TraceTable (TableId 15) (TraceSupplyUnionCredits 12)
54+
TraceTable (TableId 15) (TraceSuppliedUnionCredits 12 0)
55+
TraceTable (TableId 15) TraceRemainingUnionDebt
56+
TraceTable (TableId 15) (TraceSupplyUnionCredits 2)
57+
TraceTable (TableId 15) (TraceSuppliedUnionCredits 2 2)
58+
TraceTable (TableId 15) TraceRemainingUnionDebt
59+
TraceTable (TableId 15) TraceCloseTable
60+
TraceTable (TableId 15) TraceClosedTable
61+
TraceTable (TableId 8) TraceCloseTable
62+
TraceTable (TableId 8) TraceClosedTable
63+
TraceTable (TableId 6) TraceCloseTable
64+
TraceTable (TableId 6) TraceClosedTable
65+
TraceTable (TableId 0) TraceCloseTable
66+
TraceTable (TableId 0) TraceClosedTable
67+
TraceTable (TableId 21) (TraceNewTable (TableConfig {confMergePolicy = LazyLevelling, confMergeSchedule = Incremental, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries 20000, confBloomFilterAlloc = AllocRequestFPR 1.0e-3, confFencePointerIndex = OrdinaryIndex, confDiskCachePolicy = DiskCacheAll, confMergeBatchSize = MergeBatchSize 20000}))
68+
TraceTable (TableId 21) (TraceCreatedTable (SessionId session-dir) (TableConfig {confMergePolicy = LazyLevelling, confMergeSchedule = Incremental, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries 20000, confBloomFilterAlloc = AllocRequestFPR 1.0e-3, confFencePointerIndex = OrdinaryIndex, confDiskCachePolicy = DiskCacheAll, confMergeBatchSize = MergeBatchSize 20000}))
69+
TraceCursor (CursorId 23) (TraceNewCursor (TableId 21) NoOffsetKey)
70+
TraceCursor (CursorId 23) (TraceCreatedCursor (SessionId session-dir))
71+
TraceSession (SessionId session-dir) TraceCloseSession
72+
TraceCursor (CursorId 23) TraceCloseCursor
73+
TraceCursor (CursorId 23) TraceClosedCursor
74+
TraceTable (TableId 21) TraceCloseTable
75+
TraceTable (TableId 21) TraceClosedTable
76+
TraceSession (SessionId session-dir) TraceClosedSession

0 commit comments

Comments
 (0)