packages feed

glean-0.1.0.0: glean/test/lib/Glean/Database/Catalog/Test.hs

{-
  Copyright (c) Meta Platforms, Inc. and affiliates.
  All rights reserved.

  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree.
-}

{-# LANGUAGE TypeApplications #-}
module Glean.Database.Catalog.Test
  ( MockStore(..)
  , memStore
  , withMemCatalog
  , checkConsistency
  ) where

import Control.Exception hiding (assert)
import Control.Monad
import Data.Default
import Data.HashMap.Strict (HashMap)
import Data.List ((\\))
import Data.Proxy
import qualified Data.Text as Text
import Test.HUnit

import Util.STM

import Glean.Database.Catalog (Catalog)
import qualified Glean.Database.Catalog as Catalog
import qualified Glean.Database.Catalog.Local.Memory as Catalog
import Glean.Database.Catalog.Filter
import qualified Glean.Database.Catalog.Store as Store
import Glean.Database.Meta (Meta)
import Glean.Test.HUnit
import Glean.Test.Mock
import Glean.Types (Repo(..), UnknownDatabase(..))

data MockStore = MockStore
  { storeList :: Mock (IO (HashMap Repo Meta))
  , storeCreate :: Mock (Repo -> Meta -> IO Bool)
  , storeDelete :: Mock (Repo -> IO Bool)
  , storePut :: Mock (Repo -> Meta -> IO Bool)
  , storeGet :: Mock (Repo -> IO (Maybe Meta))
  }

instance Store.Store MockStore where
  list = call . storeList
  create = call . storeCreate
  delete = call . storeDelete
  put = call . storePut
  get = call . storeGet

memStore :: IO MockStore
memStore = do
  cat <- Catalog.memoryCatalog
  storeList <- implement "Store.list" $ Store.list cat
  storeCreate <- implement "Store.create" $ Store.create cat
  storeDelete <- implement "Store.delete" $ Store.delete cat
  storePut <- implement "Store.put" $ Store.put cat
  storeGet <- implement "Store.get" $ Store.get cat
  return MockStore{..}

withMemCatalog :: (MockStore -> Catalog -> IO a) -> IO a
withMemCatalog f = do
  store <- memStore
  bracket (Catalog.open store) Catalog.close $ f store


checkConsistency :: Catalog -> IO ()
checkConsistency cat = do
  xs <- map itemRepo <$> atomically (Catalog.list cat [Local] everythingF)
  mapM_ live xs
  mapM_ not_live
    $ take 4
    $ map (Repo "test" . Text.pack . show) [1::Int ..] \\ xs
  where
    live repo = do
      assert $ Catalog.exists cat [Local] repo
      assert $ void $ Catalog.readMeta cat repo
      assert $ Catalog.writeMeta cat repo def
      assert $ void $ Catalog.modifyMeta cat repo return

    not_live repo = do
      assert $ not <$> Catalog.exists cat [Local] repo
      assertThrowsType "" (Proxy @UnknownDatabase)
        $ atomically $ Catalog.readMeta cat repo
      assertThrowsType "" (Proxy @UnknownDatabase)
        $ atomically $ Catalog.writeMeta cat repo def
      assertThrowsType "" (Proxy @UnknownDatabase)
        $ atomically $ Catalog.modifyMeta cat repo return