1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
{-# LANGUAGE NoImplicitPrelude #-}
module Network.HTTP.Download.VerifiedSpec (spec) where
import Control.Retry (limitRetries)
import Crypto.Hash
import Network.HTTP.Client
import Network.HTTP.Download.Verified
import Path
import Path.IO -- hiding (withSystemTempDir)
import System.IO (writeFile, readFile)
import RIO
import RIO.PrettyPrint
import RIO.PrettyPrint.StylesUpdate
import Test.Hspec
-- TODO: share across test files
withTempDir' :: (Path Abs Dir -> IO a) -> IO a
withTempDir' = withSystemTempDir "NHD_VerifiedSpec"
-- | An example path to download the exampleReq.
getExamplePath :: Path Abs Dir -> IO (Path Abs File)
getExamplePath dir = do
file <- parseRelFile "cabal-install-1.22.4.0.tar.gz"
return (dir </> file)
-- | An example DownloadRequest that uses a SHA1
exampleReq :: DownloadRequest
exampleReq = fromMaybe (error "exampleReq") $ do
req <- parseRequest "http://download.fpcomplete.com/stackage-cli/linux64/cabal-install-1.22.4.0.tar.gz"
return $
setHashChecks [exampleHashCheck] $
setLengthCheck (Just exampleLengthCheck) $
setRetryPolicy (limitRetries 1) $
mkDownloadRequest req
exampleHashCheck :: HashCheck
exampleHashCheck = HashCheck
{ hashCheckAlgorithm = SHA1
, hashCheckHexDigest = CheckHexDigestString "b98eea96d321cdeed83a201c192dac116e786ec2"
}
exampleLengthCheck :: LengthCheck
exampleLengthCheck = 302513
-- | The wrong ContentLength for exampleReq
exampleWrongContentLength :: Int
exampleWrongContentLength = 302512
-- | The wrong SHA1 digest for exampleReq
exampleWrongDigest :: CheckHexDigest
exampleWrongDigest = CheckHexDigestString "b98eea96d321cdeed83a201c192dac116e786ec3"
exampleWrongContent :: String
exampleWrongContent = "example wrong content"
isWrongContentLength :: VerifiedDownloadException -> Bool
isWrongContentLength WrongContentLength{} = True
isWrongContentLength _ = False
isWrongDigest :: VerifiedDownloadException -> Bool
isWrongDigest WrongDigest{} = True
isWrongDigest _ = False
data TestTerm = TestTerm
instance HasLogFunc TestTerm where
-- ingoring output for now
logFuncL = lens (const $ mkLogFunc mempty) (\t _ -> t)
instance HasStylesUpdate TestTerm where
stylesUpdateL = lens (const $ StylesUpdate []) (\t _ -> t)
instance HasTerm TestTerm where
useColorL = lens (const False) (\t _ -> t)
termWidthL = lens (const 80) (\t _ -> t)
spec :: Spec
spec = do
let exampleProgressHook _ = return ()
describe "verifiedDownload" $ do
let run func = runRIO TestTerm func
-- Preconditions:
-- * the exampleReq server is running
-- * the test runner has working internet access to it
it "downloads the file correctly" $ withTempDir' $ \dir -> do
examplePath <- getExamplePath dir
doesFileExist examplePath `shouldReturn` False
let go = run $ verifiedDownload exampleReq examplePath exampleProgressHook
go `shouldReturn` True
doesFileExist examplePath `shouldReturn` True
it "is idempotent, and doesn't redownload unnecessarily" $ withTempDir' $ \dir -> do
examplePath <- getExamplePath dir
doesFileExist examplePath `shouldReturn` False
let go = run $ verifiedDownload exampleReq examplePath exampleProgressHook
go `shouldReturn` True
doesFileExist examplePath `shouldReturn` True
go `shouldReturn` False
doesFileExist examplePath `shouldReturn` True
-- https://github.com/commercialhaskell/stack/issues/372
it "does redownload when the destination file is wrong" $ withTempDir' $ \dir -> do
examplePath <- getExamplePath dir
let exampleFilePath = toFilePath examplePath
writeFile exampleFilePath exampleWrongContent
doesFileExist examplePath `shouldReturn` True
readFile exampleFilePath `shouldReturn` exampleWrongContent
let go = run $ verifiedDownload exampleReq examplePath exampleProgressHook
go `shouldReturn` True
doesFileExist examplePath `shouldReturn` True
readFile exampleFilePath `shouldNotReturn` exampleWrongContent
it "rejects incorrect content length" $ withTempDir' $ \dir -> do
examplePath <- getExamplePath dir
let wrongContentLengthReq = setLengthCheck (Just exampleWrongContentLength) exampleReq
let go = run $ verifiedDownload wrongContentLengthReq examplePath exampleProgressHook
go `shouldThrow` isWrongContentLength
doesFileExist examplePath `shouldReturn` False
it "rejects incorrect digest" $ withTempDir' $ \dir -> do
examplePath <- getExamplePath dir
let wrongHashCheck = exampleHashCheck { hashCheckHexDigest = exampleWrongDigest }
let wrongDigestReq = setHashChecks [wrongHashCheck] exampleReq
let go = run $ verifiedDownload wrongDigestReq examplePath exampleProgressHook
go `shouldThrow` isWrongDigest
doesFileExist examplePath `shouldReturn` False
-- https://github.com/commercialhaskell/stack/issues/240
it "can download hackage tarballs" $ withTempDir' $ \dir -> do
dest <- (dir </>) <$> parseRelFile "acme-missiles-0.3.tar.gz"
req <- parseRequest "http://hackage.haskell.org/package/acme-missiles-0.3/acme-missiles-0.3.tar.gz"
let dReq = setRetryPolicy (limitRetries 1) $ mkDownloadRequest req
let go = run $ verifiedDownload dReq dest exampleProgressHook
doesFileExist dest `shouldReturn` False
go `shouldReturn` True
doesFileExist dest `shouldReturn` True
it "does redownload when forceDownload is True" $ withTempDir' $ \dir -> do
examplePath <- getExamplePath dir
doesFileExist examplePath `shouldReturn` False
let go = run $ verifiedDownload exampleReq examplePath exampleProgressHook
go `shouldReturn` True
doesFileExist examplePath `shouldReturn` True
let forceReq = setForceDownload True exampleReq
let go' = run $ verifiedDownload forceReq examplePath exampleProgressHook
go' `shouldReturn` True
doesFileExist examplePath `shouldReturn` True
|