cabal-install-3.8.1.0: tests/UnitTests/Distribution/Client/Store.hs
module UnitTests.Distribution.Client.Store (tests) where
--import Control.Monad
--import Control.Concurrent (forkIO, threadDelay)
--import Control.Concurrent.MVar
import qualified Data.Set as Set
import System.FilePath
import System.Directory
--import System.Random
import Distribution.Package (UnitId, mkUnitId)
import Distribution.Compiler (CompilerId(..), CompilerFlavor(..))
import Distribution.Version (mkVersion)
import Distribution.Verbosity (Verbosity, silent)
import Distribution.Simple.Utils (withTempDirectory)
import Distribution.Client.Store
import Distribution.Client.RebuildMonad
import Test.Tasty
import Test.Tasty.HUnit
tests :: [TestTree]
tests =
[ testCase "list content empty" testListEmpty
, testCase "install serial" testInstallSerial
--, testCase "install parallel" testInstallParallel
--TODO: figure out some way to do a parallel test, see issue below
]
testListEmpty :: Assertion
testListEmpty =
withTempDirectory verbosity "." "store-" $ \tmp -> do
let storeDirLayout = defaultStoreDirLayout (tmp </> "store")
assertStoreEntryExists storeDirLayout compid unitid False
assertStoreContent tmp storeDirLayout compid Set.empty
where
compid = CompilerId GHC (mkVersion [1,0])
unitid = mkUnitId "foo-1.0-xyz"
testInstallSerial :: Assertion
testInstallSerial =
withTempDirectory verbosity "." "store-" $ \tmp -> do
let storeDirLayout = defaultStoreDirLayout (tmp </> "store")
copyFiles file content dir = do
-- we copy into a prefix inside the tmp dir and return the prefix
let destprefix = dir </> "prefix"
createDirectory destprefix
writeFile (destprefix </> file) content
return (destprefix,[])
assertNewStoreEntry tmp storeDirLayout compid unitid1
(copyFiles "file1" "content-foo") (return ())
UseNewStoreEntry
assertNewStoreEntry tmp storeDirLayout compid unitid1
(copyFiles "file1" "content-foo") (return ())
UseExistingStoreEntry
assertNewStoreEntry tmp storeDirLayout compid unitid2
(copyFiles "file2" "content-bar") (return ())
UseNewStoreEntry
let pkgDir :: UnitId -> FilePath
pkgDir = storePackageDirectory storeDirLayout compid
assertFileEqual (pkgDir unitid1 </> "file1") "content-foo"
assertFileEqual (pkgDir unitid2 </> "file2") "content-bar"
where
compid = CompilerId GHC (mkVersion [1,0])
unitid1 = mkUnitId "foo-1.0-xyz"
unitid2 = mkUnitId "bar-2.0-xyz"
{-
-- unfortunately a parallel test like the one below is thwarted by the normal
-- process-internal file locking. If that locking were not in place then we
-- ought to get the blocking behaviour, but due to the normal Handle locking
-- it just fails instead.
testInstallParallel :: Assertion
testInstallParallel =
withTempDirectory verbosity "." "store-" $ \tmp -> do
let storeDirLayout = defaultStoreDirLayout (tmp </> "store")
sync1 <- newEmptyMVar
sync2 <- newEmptyMVar
outv <- newEmptyMVar
regv <- newMVar (0 :: Int)
sequence_
[ do forkIO $ do
let copyFiles dir = do
delay <- randomRIO (1,100000)
writeFile (dir </> "file") (show n)
putMVar sync1 ()
readMVar sync2
threadDelay delay
register = do
modifyMVar_ regv (return . (+1))
threadDelay 200000
o <- newStoreEntry verbosity storeDirLayout
compid unitid
copyFiles register
putMVar outv (n, o)
| n <- [0..9 :: Int] ]
replicateM_ 10 (takeMVar sync1)
-- all threads are in the copyFiles action concurrently, release them:
putMVar sync2 ()
outcomes <- replicateM 10 (takeMVar outv)
regcount <- readMVar regv
let regcount' = length [ () | (_, UseNewStoreEntry) <- outcomes ]
assertEqual "num registrations" 1 regcount
assertEqual "num registrations" 1 regcount'
assertStoreContent tmp storeDirLayout compid (Set.singleton unitid)
let pkgDir :: UnitId -> FilePath
pkgDir = storePackageDirectory storeDirLayout compid
case [ n | (n, UseNewStoreEntry) <- outcomes ] of
[n] -> assertFileEqual (pkgDir unitid </> "file") (show n)
_ -> assertFailure "impossible"
where
compid = CompilerId GHC (mkVersion [1,0])
unitid = mkUnitId "foo-1.0-xyz"
-}
-------------
-- Utils
assertNewStoreEntry :: FilePath -> StoreDirLayout
-> CompilerId -> UnitId
-> (FilePath -> IO (FilePath,[FilePath])) -> IO ()
-> NewStoreEntryOutcome
-> Assertion
assertNewStoreEntry tmp storeDirLayout compid unitid
copyFiles register expectedOutcome = do
entries <- runRebuild tmp $ getStoreEntries storeDirLayout compid
outcome <- newStoreEntry verbosity storeDirLayout
compid unitid
copyFiles register
assertEqual "newStoreEntry outcome" expectedOutcome outcome
assertStoreEntryExists storeDirLayout compid unitid True
let expected = Set.insert unitid entries
assertStoreContent tmp storeDirLayout compid expected
assertStoreEntryExists :: StoreDirLayout
-> CompilerId -> UnitId -> Bool
-> Assertion
assertStoreEntryExists storeDirLayout compid unitid expected = do
actual <- doesStoreEntryExist storeDirLayout compid unitid
assertEqual "store entry exists" expected actual
assertStoreContent :: FilePath -> StoreDirLayout
-> CompilerId -> Set.Set UnitId
-> Assertion
assertStoreContent tmp storeDirLayout compid expected = do
actual <- runRebuild tmp $ getStoreEntries storeDirLayout compid
assertEqual "store content" actual expected
assertFileEqual :: FilePath -> String -> Assertion
assertFileEqual path expected = do
exists <- doesFileExist path
assertBool ("file does not exist:\n" ++ path) exists
actual <- readFile path
assertEqual ("file content for:\n" ++ path) expected actual
verbosity :: Verbosity
verbosity = silent