headroom-0.4.3.0: test/Headroom/UpdaterSpec.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
module Headroom.UpdaterSpec
( spec
)
where
import Data.Aeson ( Value )
import qualified Data.Aeson as A
import Data.String.Interpolate ( i )
import Data.Time ( UTCTime(..) )
import Headroom.Config.Global ( UpdaterConfig(..) )
import Headroom.Data.Has ( Has(..) )
import Headroom.Data.Lens ( suffixLenses
, suffixLensesFor
)
import Headroom.IO.KVStore ( KVStore(..)
, inMemoryKVStore
, valueKey
)
import Headroom.IO.Network ( Network(..)
, NetworkError(..)
)
import Headroom.Meta ( buildVersion )
import Headroom.Meta.Version ( printVersionP
, pvp
)
import Headroom.Updater
import RIO
import qualified RIO.ByteString as B
import qualified RIO.ByteString.Lazy as BL
import RIO.FilePath ( (</>) )
import RIO.Partial ( fromJust )
import RIO.Time ( addDays
, getCurrentTime
)
import Test.Hspec
data TestEnv = TestEnv
{ envKVStore :: KVStore (RIO TestEnv)
, envNetwork :: Network (RIO TestEnv)
}
suffixLenses ''TestEnv
suffixLensesFor ["nDownloadContent"] ''Network
instance Has (KVStore (RIO TestEnv)) TestEnv where
hasLens = envKVStoreL
instance Has (Network (RIO TestEnv)) TestEnv where
hasLens = envNetworkL
spec :: Spec
spec = do
let testFile = "test-data" </> "updater" </> "github-resp.json"
storeKey = valueKey @UTCTime "updater/last-check-date"
describe "checkUpdates" $ do
it "returns Nothing if current version is the latest" $ do
store@KVStore {..} <- runRIO env0 inMemoryKVStore
let json = [i|{"name": "#{printVersionP buildVersion}"}|]
env =
env0
& (envKVStoreL .~ kvStore')
& (envNetworkL . nDownloadContentL .~ nDownloadContent')
nDownloadContent' = const . pure $ json
updaterConfig' = UpdaterConfig True 2
kvStore' = store
actual <- runRIO env (checkUpdates updaterConfig')
maybeLastCheckDate <- runRIO env $ kvGetValue storeKey
actual `shouldBe` Nothing
maybeLastCheckDate `shouldSatisfy` isJust
it "returns newer version if current version is outdated" $ do
store@KVStore {..} <- runRIO env0 inMemoryKVStore
let json = [i|{"name": "v999.0.0.0"}|]
env =
env0
& (envKVStoreL .~ kvStore')
& (envNetworkL . nDownloadContentL .~ nDownloadContent')
nDownloadContent' = const . pure $ json
updaterConfig' = UpdaterConfig True 2
kvStore' = store
actual <- runRIO env (checkUpdates updaterConfig')
maybeLastCheckDate <- runRIO env $ kvGetValue storeKey
actual `shouldBe` Just [pvp|999.0.0.0|]
maybeLastCheckDate `shouldSatisfy` isJust
it "doesn't check for updates if still within check interval" $ do
store@KVStore {..} <- runRIO env0 inMemoryKVStore
oneDayAgo <- addDays' (-1) <$> getCurrentTime
let json = [i|{"name": "v999.0.0.0"}|]
env =
env0
& (envKVStoreL .~ kvStore')
& (envNetworkL . nDownloadContentL .~ nDownloadContent')
nDownloadContent' = const . pure $ json
updaterConfig' = UpdaterConfig True 2
kvStore' = store
actual <- runRIO env $ do
kvPutValue storeKey oneDayAgo
checkUpdates updaterConfig'
actual `shouldBe` Nothing
it "returns Nothing if checking for updates is disabled" $ do
store@KVStore {..} <- runRIO env0 inMemoryKVStore
let json = [i|{"name": "v999.0.0.0"}|]
env =
env0
& (envKVStoreL .~ kvStore')
& (envNetworkL . nDownloadContentL .~ nDownloadContent')
nDownloadContent' = const . pure $ json
updaterConfig' = UpdaterConfig False 2
kvStore' = store
actual <- runRIO env (checkUpdates updaterConfig')
maybeLastCheckDate <- runRIO env $ kvGetValue storeKey
actual `shouldBe` Nothing
maybeLastCheckDate `shouldBe` Nothing
describe "fetchLatestVersion" $ do
it "gets latest version info" $ do
raw <- B.readFile testFile
let env = env0 & (envNetworkL . nDownloadContentL .~ nDownloadContent')
nDownloadContent' = const . pure $ raw
actual <- runRIO env fetchLatestVersion
actual `shouldBe` [pvp|0.4.2.0|]
it "returns error if version cannot be fetched" $ do
let env = env0 & (envNetworkL . nDownloadContentL .~ nDownloadContent')
nDownloadContent' = \uri -> throwM $ ConnectionFailure uri "error"
runRIO env fetchLatestVersion `shouldThrow` \case
(CannotDetectVersion _) -> True
describe "parseLatestVersion" $ do
it "parses latest version from raw JSON input" $ do
raw <- BL.readFile testFile
actual <- parseLatestVersion (fromJust . A.decode @Value $ raw)
actual `shouldBe` [pvp|0.4.2.0|]
env0 :: TestEnv
env0 = TestEnv
{ envKVStore = KVStore { kvGetValue = undefined, kvPutValue = undefined }
, envNetwork = Network { nDownloadContent = undefined }
}
addDays' :: Integer -> UTCTime -> UTCTime
addDays' noOfDays (UTCTime day timeOfDay) =
UTCTime (addDays noOfDays day) timeOfDay