Skip to content

Commit c825cc9

Browse files
committed
Prefix snapshot codec golden files using the current snapshot version
As a result, we keep around golden files for old snapshot versions as newer ones are created. The upside of this is that we could test the backwards compatiblity of the snapshot codec: run versioned decoders on the golden files for older snapshot versions and check that there are no errors. I've not implemented such a test yet, but this would be one step in that direction.
1 parent 0855e88 commit c825cc9

File tree

56 files changed

+51
-38
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+51
-38
lines changed

src/Database/LSMTree/Internal/Snapshot/Codec.hs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module Database.LSMTree.Internal.Snapshot.Codec (
77
SnapshotVersion (..)
88
, prettySnapshotVersion
99
, currentSnapshotVersion
10+
, allCompatibleSnapshotVersions
1011
-- * Writing and reading files
1112
, writeFileSnapshotMetaData
1213
, readFileSnapshotMetaData
@@ -74,10 +75,22 @@ prettySnapshotVersion V0 = "v0"
7475
currentSnapshotVersion :: SnapshotVersion
7576
currentSnapshotVersion = V0
7677

78+
-- | All snapshot versions that the current snapshpt version is compatible with.
79+
--
80+
-- >>> allCompatibleSnapshotVersions
81+
-- [V0]
82+
--
83+
-- >>> last allCompatibleSnapshotVersions == currentSnapshotVersion
84+
-- True
85+
allCompatibleSnapshotVersions :: [SnapshotVersion]
86+
allCompatibleSnapshotVersions = [V0]
87+
7788
isCompatible :: SnapshotVersion -> Either String ()
78-
isCompatible otherVersion = do
79-
case ( currentSnapshotVersion, otherVersion ) of
80-
(V0, V0) -> Right ()
89+
isCompatible otherVersion
90+
-- for the moment, all versions are backwards compatible:
91+
| otherVersion `elem` allCompatibleSnapshotVersions
92+
= Right ()
93+
| otherwise = Left "forward compatibility not supported"
8194

8295
{-------------------------------------------------------------------------------
8396
Writing and reading files

test/Test/Database/LSMTree/Internal/Snapshot/Codec/Golden.hs

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ import Database.LSMTree.Internal.RunBuilder (IndexType (..),
2626
import Database.LSMTree.Internal.RunNumber (RunNumber (..))
2727
import Database.LSMTree.Internal.Snapshot
2828
import Database.LSMTree.Internal.Snapshot.Codec
29+
import qualified System.Directory as Dir
30+
import System.FilePath
2931
import qualified System.FS.API as FS
30-
import System.FS.API.Types (FsPath, MountPoint (..), fsToFilePath,
31-
mkFsPath, (<.>))
32-
import System.FS.IO (HandleIO, ioHasFS)
32+
import System.FS.API.Types (MountPoint (..))
33+
import System.FS.IO (ioHasFS)
3334
import Test.QuickCheck (Property, counterexample, ioProperty, once,
3435
(.&&.))
3536
import qualified Test.Tasty as Tasty
@@ -70,47 +71,36 @@ snapshotCodecGoldenTest ::
7071
=> Proxy a
7172
-> [TestTree]
7273
snapshotCodecGoldenTest proxy = [
73-
go (nameGolden proxy annotation) datum
74+
go annotation datum
7475
| (annotation, datum) <- enumGoldenAnnotated' proxy
7576
]
7677
where
77-
go name datum =
78-
let -- Various paths
79-
--
80-
-- There are three paths for both the checksum and the snapshot files:
81-
-- 1. The filepath of type @FsPath@ to which data is written.
82-
-- 2. The filepath of type @FilePath@ from which data is read.
83-
-- 3. The filepath of type @FilePath@ against which the data is compared.
84-
--
85-
-- These file types' bindings have the following infix annotations, respectively:
86-
-- 1. (Fs) for FsPath
87-
-- 2. (Hs) for "Haskell" path
88-
-- 3. (Au) for "Golden file" path
89-
snapshotFsPath = mkFsPath [name] <.> "snapshot"
90-
snapshotHsPath = fsToFilePath goldenDataMountPoint snapshotFsPath
91-
snapshotAuPath = snapshotHsPath <> ".golden"
78+
go ann datum =
79+
let v = currentSnapshotVersion
80+
outputFilePath = goldenDataFilePath </> filePathOutput proxy ann v
81+
goldenFilePath = goldenDataFilePath </> filePathGolden proxy ann v
9282

9383
-- IO actions
94-
runnerIO :: FS.HasFS IO HandleIO
95-
runnerIO = ioHasFS goldenDataMountPoint
96-
removeIfExists :: FsPath -> IO ()
84+
removeIfExists :: FilePath -> IO ()
9785
removeIfExists fp =
98-
FS.doesFileExist runnerIO fp >>= (`when` (FS.removeFile runnerIO fp))
86+
Dir.doesFileExist fp >>= (`when` (Dir.removeFile fp))
9987
outputAction :: IO ()
10088
outputAction = do
10189
-- Ensure that if the output file already exists, we remove it and
10290
-- re-write out the serialized data. This ensures that there are no
10391
-- false-positives, false-negatives, or irrelevant I/O exceptions.
104-
removeIfExists snapshotFsPath
105-
BSL.writeFile snapshotHsPath . toLazyByteString $ encode datum
92+
removeIfExists outputFilePath
93+
BSL.writeFile outputFilePath . toLazyByteString $ encode datum
10694

107-
in Au.goldenVsFile name snapshotAuPath snapshotHsPath outputAction
95+
in Au.goldenVsFile (nameGolden proxy ann v) goldenFilePath outputFilePath outputAction
10896

10997
-- | Check that are no missing or unexpected files in the output directory
11098
prop_noUnexpectedOrMissingGoldenFiles :: Property
11199
prop_noUnexpectedOrMissingGoldenFiles = once $ ioProperty $ do
112-
let expectedFiles = Set.fromList $ concat $ forallSnapshotTypes filePathsGolden
113-
100+
let expectedFiles = Set.fromList $ concat $ forallSnapshotTypes $ \p -> concat [
101+
filePathsGolden p v
102+
| v <- supportedVersions p
103+
]
114104

115105
let hfs = ioHasFS goldenDataMountPoint
116106
actualDirectoryEntries <- FS.listDirectory hfs (FS.mkFsPath [])
@@ -231,6 +221,9 @@ class EnumGolden a where
231221
singGolden :: a
232222
singGolden = snd $ head enumGoldenAnnotated
233223

224+
supportedVersions :: Proxy a -> [SnapshotVersion]
225+
supportedVersions _ = allCompatibleSnapshotVersions
226+
234227
type Annotation = String
235228

236229
enumGoldenAnnotated' :: EnumGolden a => Proxy a -> [(Annotation, a)]
@@ -240,21 +233,28 @@ enumGoldenAnnotated' _ = enumGoldenAnnotated
240233
Enumeration class: names and file paths
241234
-------------------------------------------------------------------------------}
242235

243-
nameGolden :: Typeable a => Proxy a -> Annotation -> String
244-
nameGolden p ann = map spaceToUnderscore (show $ typeRep p) ++ "." ++ ann
236+
nameGolden :: Typeable a => Proxy a -> Annotation -> SnapshotVersion -> String
237+
nameGolden p ann v = show v ++ "." ++ map spaceToUnderscore (show $ typeRep p) ++ "." ++ ann
245238

246239
spaceToUnderscore :: Char -> Char
247240
spaceToUnderscore ' ' = '_'
248241
spaceToUnderscore c = c
249242

250-
filePathsGolden :: (EnumGolden a, Typeable a) => Proxy a -> [String]
251-
filePathsGolden p = [
252-
filePathGolden p annotation
243+
filePathsGolden ::
244+
(EnumGolden a, Typeable a)
245+
=> Proxy a
246+
-> SnapshotVersion
247+
-> [String]
248+
filePathsGolden p v = [
249+
filePathGolden p annotation v
253250
| (annotation, _) <- enumGoldenAnnotated' p
254251
]
255252

256-
filePathGolden :: Typeable a => Proxy a -> String -> String
257-
filePathGolden p ann = nameGolden p ann ++ ".snapshot.golden"
253+
filePathOutput :: Typeable a => Proxy a -> String -> SnapshotVersion -> String
254+
filePathOutput p ann v = nameGolden p ann v ++ ".snapshot"
255+
256+
filePathGolden :: Typeable a => Proxy a -> String -> SnapshotVersion -> String
257+
filePathGolden p ann v = nameGolden p ann v ++ ".snapshot.golden"
258258

259259
{-------------------------------------------------------------------------------
260260
Enumeration class: instances

0 commit comments

Comments
 (0)