2019-11-20 21:21:30 +03:00
|
|
|
{-# LANGUAGE UndecidableInstances #-}
|
|
|
|
|
|
|
|
module Hasura.Server.MigrateSpec (CacheRefT(..), spec) where
|
2019-11-18 21:45:54 +03:00
|
|
|
|
|
|
|
import Hasura.Prelude
|
|
|
|
|
2021-09-09 14:54:19 +03:00
|
|
|
import qualified Data.ByteString.Lazy.UTF8 as LBS
|
2021-01-09 02:09:15 +03:00
|
|
|
import qualified Data.Environment as Env
|
|
|
|
import qualified Database.PG.Query as Q
|
|
|
|
import qualified Network.HTTP.Client.Extended as HTTP
|
|
|
|
|
2019-11-27 01:49:42 +03:00
|
|
|
import Control.Concurrent.MVar.Lifted
|
2020-12-28 15:56:00 +03:00
|
|
|
import Control.Monad.Morph
|
2020-12-08 17:22:31 +03:00
|
|
|
import Control.Monad.Trans.Control (MonadBaseControl)
|
2019-11-27 01:49:42 +03:00
|
|
|
import Control.Monad.Unique
|
2020-12-08 17:22:31 +03:00
|
|
|
import Control.Natural ((:~>) (..))
|
2021-09-09 14:54:19 +03:00
|
|
|
import Data.Aeson (encode)
|
2020-12-08 17:22:31 +03:00
|
|
|
import Data.Time.Clock (getCurrentTime)
|
2019-11-20 21:21:30 +03:00
|
|
|
import Test.Hspec.Core.Spec
|
|
|
|
import Test.Hspec.Expectations.Lifted
|
2019-11-18 21:45:54 +03:00
|
|
|
|
2021-01-07 12:04:22 +03:00
|
|
|
import Hasura.Backends.Postgres.Connection
|
2021-05-11 18:18:31 +03:00
|
|
|
import Hasura.Base.Error
|
2021-09-09 14:54:19 +03:00
|
|
|
import Hasura.Logging
|
2021-05-26 19:19:26 +03:00
|
|
|
import Hasura.Metadata.Class
|
2020-12-08 17:22:31 +03:00
|
|
|
import Hasura.RQL.DDL.Metadata (ClearMetadata (..), runClearMetadata)
|
2019-11-20 21:21:30 +03:00
|
|
|
import Hasura.RQL.DDL.Schema
|
2020-12-28 15:56:00 +03:00
|
|
|
import Hasura.RQL.DDL.Schema.Cache.Common
|
2020-12-08 17:22:31 +03:00
|
|
|
import Hasura.RQL.DDL.Schema.LegacyCatalog
|
2019-11-27 01:49:42 +03:00
|
|
|
import Hasura.RQL.Types
|
2020-04-24 10:55:51 +03:00
|
|
|
import Hasura.Server.API.PGDump
|
2020-12-08 17:22:31 +03:00
|
|
|
import Hasura.Server.Init (DowngradeOptions (..))
|
2019-11-18 21:45:54 +03:00
|
|
|
import Hasura.Server.Migrate
|
2021-08-06 20:05:17 +03:00
|
|
|
import Hasura.Server.Types (MaintenanceMode (..))
|
2020-12-08 17:22:31 +03:00
|
|
|
import Hasura.Server.Version (HasVersion)
|
2021-01-09 02:09:15 +03:00
|
|
|
import Hasura.Session
|
|
|
|
|
|
|
|
|
2019-11-18 21:45:54 +03:00
|
|
|
|
2020-07-06 07:38:26 +03:00
|
|
|
-- -- NOTE: downgrade test disabled for now (see #5273)
|
|
|
|
|
2019-11-20 21:21:30 +03:00
|
|
|
newtype CacheRefT m a
|
2020-12-14 07:30:19 +03:00
|
|
|
= CacheRefT { runCacheRefT :: MVar RebuildableSchemaCache -> m a }
|
2019-11-20 21:21:30 +03:00
|
|
|
deriving
|
|
|
|
( Functor, Applicative, Monad, MonadIO, MonadError e, MonadBase b, MonadBaseControl b
|
2021-05-26 19:19:26 +03:00
|
|
|
, MonadTx, MonadUnique, UserInfoM, HTTP.HasHttpManagerM, HasServerConfigCtx, MonadMetadataStorage, MonadMetadataStorageQueryAPI)
|
2020-12-14 07:30:19 +03:00
|
|
|
via (ReaderT (MVar RebuildableSchemaCache) m)
|
2019-11-20 21:21:30 +03:00
|
|
|
|
|
|
|
instance MonadTrans CacheRefT where
|
|
|
|
lift = CacheRefT . const
|
|
|
|
|
2020-12-28 15:56:00 +03:00
|
|
|
instance MFunctor CacheRefT where
|
|
|
|
hoist f (CacheRefT m) = CacheRefT (f . m)
|
|
|
|
|
|
|
|
-- instance (MonadBase IO m) => TableCoreInfoRM 'Postgres (CacheRefT m)
|
2019-11-20 21:21:30 +03:00
|
|
|
instance (MonadBase IO m) => CacheRM (CacheRefT m) where
|
|
|
|
askSchemaCache = CacheRefT (fmap lastBuiltSchemaCache . readMVar)
|
|
|
|
|
2021-05-26 19:19:26 +03:00
|
|
|
instance (MonadIO m, MonadBaseControl IO m, MonadError QErr m, HTTP.HasHttpManagerM m
|
2021-01-29 08:48:17 +03:00
|
|
|
, MonadResolveSource m, HasServerConfigCtx m) => CacheRWM (CacheRefT m) where
|
2021-04-06 06:25:02 +03:00
|
|
|
buildSchemaCacheWithOptions reason invalidations metadata =
|
|
|
|
CacheRefT $ flip modifyMVar \schemaCache -> do
|
|
|
|
((), cache, _) <- runCacheRWT schemaCache (buildSchemaCacheWithOptions reason invalidations metadata)
|
|
|
|
pure (cache, ())
|
|
|
|
|
|
|
|
setMetadataResourceVersionInSchemaCache resourceVersion =
|
|
|
|
CacheRefT $ flip modifyMVar \schemaCache -> do
|
|
|
|
((), cache, _) <- runCacheRWT schemaCache (setMetadataResourceVersionInSchemaCache resourceVersion)
|
|
|
|
pure (cache, ())
|
2019-11-18 21:45:54 +03:00
|
|
|
|
2020-12-08 17:22:31 +03:00
|
|
|
instance Example (MetadataT (CacheRefT m) ()) where
|
|
|
|
type Arg (MetadataT (CacheRefT m) ()) = MetadataT (CacheRefT m) :~> IO
|
2019-11-20 21:21:30 +03:00
|
|
|
evaluateExample m params action = evaluateExample (action ($$ m)) params ($ ())
|
|
|
|
|
2020-12-08 17:22:31 +03:00
|
|
|
type SpecWithCache m = SpecWith (MetadataT (CacheRefT m) :~> IO)
|
2019-11-20 21:21:30 +03:00
|
|
|
|
2020-12-08 17:22:31 +03:00
|
|
|
singleTransaction :: MetadataT (CacheRefT m) () -> MetadataT (CacheRefT m) ()
|
2019-11-20 21:21:30 +03:00
|
|
|
singleTransaction = id
|
|
|
|
|
|
|
|
spec
|
2020-12-28 15:56:00 +03:00
|
|
|
:: forall m
|
|
|
|
. ( HasVersion
|
2020-01-23 00:55:55 +03:00
|
|
|
, MonadIO m
|
2019-11-20 21:21:30 +03:00
|
|
|
, MonadBaseControl IO m
|
2021-01-09 02:09:15 +03:00
|
|
|
, HTTP.HasHttpManagerM m
|
2021-01-29 08:48:17 +03:00
|
|
|
, HasServerConfigCtx m
|
2020-12-28 15:56:00 +03:00
|
|
|
, MonadResolveSource m
|
2021-05-26 19:19:26 +03:00
|
|
|
, MonadMetadataStorageQueryAPI m
|
2019-11-20 21:21:30 +03:00
|
|
|
)
|
2021-02-14 09:07:52 +03:00
|
|
|
=> PostgresConnConfiguration -> PGExecCtx -> Q.ConnInfo -> SpecWithCache m
|
2020-12-28 15:56:00 +03:00
|
|
|
spec srcConfig pgExecCtx pgConnInfo = do
|
|
|
|
let migrateCatalogAndBuildCache env time = do
|
2021-02-18 19:46:14 +03:00
|
|
|
(migrationResult, metadata) <- runTx pgExecCtx $ migrateCatalog (Just srcConfig) MaintenanceModeDisabled time
|
2021-08-06 20:05:17 +03:00
|
|
|
(,migrationResult) <$> runCacheBuildM (buildRebuildableSchemaCache env metadata)
|
2020-12-28 15:56:00 +03:00
|
|
|
|
|
|
|
dropAndInit env time = lift $ CacheRefT $ flip modifyMVar \_ ->
|
2021-01-07 12:04:22 +03:00
|
|
|
(runTx pgExecCtx dropHdbCatalogSchema) *> (migrateCatalogAndBuildCache env time)
|
|
|
|
downgradeTo v = runTx pgExecCtx . downgradeCatalog (Just srcConfig) DowngradeOptions{ dgoDryRun = False, dgoTargetVersion = v }
|
2020-04-24 10:55:51 +03:00
|
|
|
|
2019-11-18 21:45:54 +03:00
|
|
|
describe "migrateCatalog" $ do
|
2019-11-20 21:21:30 +03:00
|
|
|
it "initializes the catalog" $ singleTransaction do
|
2020-07-14 22:00:58 +03:00
|
|
|
env <- liftIO Env.getEnvironment
|
|
|
|
time <- liftIO getCurrentTime
|
2020-10-28 19:40:33 +03:00
|
|
|
dropAndInit env time `shouldReturn` MRInitialized
|
2019-11-18 21:45:54 +03:00
|
|
|
|
2019-11-20 21:21:30 +03:00
|
|
|
it "is idempotent" \(NT transact) -> do
|
2020-12-28 15:56:00 +03:00
|
|
|
let dumpSchema = execPGDump (PGDumpReqBody defaultSource ["--schema-only"] False) pgConnInfo
|
2020-07-14 22:00:58 +03:00
|
|
|
env <- Env.getEnvironment
|
2019-11-18 21:45:54 +03:00
|
|
|
time <- getCurrentTime
|
2020-07-14 22:00:58 +03:00
|
|
|
transact (dropAndInit env time) `shouldReturn` MRInitialized
|
2020-02-07 14:03:12 +03:00
|
|
|
firstDump <- transact dumpSchema
|
2020-07-14 22:00:58 +03:00
|
|
|
transact (dropAndInit env time) `shouldReturn` MRInitialized
|
2020-02-07 14:03:12 +03:00
|
|
|
secondDump <- transact dumpSchema
|
2019-11-18 21:45:54 +03:00
|
|
|
secondDump `shouldBe` firstDump
|
2020-04-24 10:55:51 +03:00
|
|
|
|
2020-02-07 14:03:12 +03:00
|
|
|
it "supports upgrades after downgrade to version 12" \(NT transact) -> do
|
2020-12-08 17:22:31 +03:00
|
|
|
let upgradeToLatest env time = lift $ CacheRefT $ flip modifyMVar \_ ->
|
2020-12-28 15:56:00 +03:00
|
|
|
migrateCatalogAndBuildCache env time
|
2020-07-14 22:00:58 +03:00
|
|
|
env <- Env.getEnvironment
|
2020-02-07 14:03:12 +03:00
|
|
|
time <- getCurrentTime
|
2020-07-14 22:00:58 +03:00
|
|
|
transact (dropAndInit env time) `shouldReturn` MRInitialized
|
2020-02-07 14:03:12 +03:00
|
|
|
downgradeResult <- (transact . lift) (downgradeTo "12" time)
|
|
|
|
downgradeResult `shouldSatisfy` \case
|
|
|
|
MRMigrated{} -> True
|
2021-01-09 02:09:15 +03:00
|
|
|
_ -> False
|
2020-07-14 22:00:58 +03:00
|
|
|
transact (upgradeToLatest env time) `shouldReturn` MRMigrated "12"
|
2020-04-24 10:55:51 +03:00
|
|
|
|
2020-07-06 07:38:26 +03:00
|
|
|
-- -- NOTE: this has been problematic in CI and we're not quite sure how to
|
|
|
|
-- -- make this work reliably given the way we do releases and create
|
|
|
|
-- -- beta tags and so on. Phil and Alexis are okay just commenting
|
|
|
|
-- -- this until we need revisit. See #5273:
|
|
|
|
-- it "supports downgrades for every Git tag" $ singleTransaction do
|
|
|
|
-- gitOutput <- liftIO $ readProcess "git" ["log", "--no-walk", "--tags", "--pretty=%D"] ""
|
|
|
|
-- let filterOldest = filter (not . isPrefixOf "v1.0.0-alpha")
|
|
|
|
-- extractTagName = Safe.headMay . splitOn ", " <=< stripPrefix "tag: "
|
|
|
|
-- supportedDowngrades = sort (map fst downgradeShortcuts)
|
|
|
|
-- gitTags = (sort . filterOldest . mapMaybe extractTagName . tail . lines) gitOutput
|
|
|
|
-- for_ gitTags \t ->
|
|
|
|
-- t `shouldSatisfy` (`elem` supportedDowngrades)
|
2019-11-18 21:45:54 +03:00
|
|
|
|
|
|
|
describe "recreateSystemMetadata" $ do
|
2020-12-28 15:56:00 +03:00
|
|
|
let dumpMetadata = execPGDump (PGDumpReqBody defaultSource ["--schema=hdb_catalog"] False) pgConnInfo
|
2021-09-09 14:54:19 +03:00
|
|
|
logger :: Logger Hasura = Logger $ \l -> do
|
|
|
|
let (logLevel, logType :: EngineLogType Hasura, logDetail) = toEngineLog l
|
|
|
|
t <- liftIO $ getFormattedTime Nothing
|
|
|
|
liftIO $ putStrLn $ LBS.toString $ encode $ EngineLog t logLevel logType logDetail
|
2019-11-20 21:21:30 +03:00
|
|
|
|
|
|
|
it "is idempotent" \(NT transact) -> do
|
2020-07-14 22:00:58 +03:00
|
|
|
env <- Env.getEnvironment
|
|
|
|
time <- getCurrentTime
|
2020-10-28 19:40:33 +03:00
|
|
|
transact (dropAndInit env time) `shouldReturn` MRInitialized
|
2020-12-08 17:22:31 +03:00
|
|
|
-- Downgrade to catalog version before metadata separation
|
|
|
|
downgradeResult <- (transact . lift) (downgradeTo "42" time)
|
|
|
|
downgradeResult `shouldSatisfy` \case
|
|
|
|
MRMigrated{} -> True
|
2021-01-09 02:09:15 +03:00
|
|
|
_ -> False
|
2019-11-20 21:21:30 +03:00
|
|
|
firstDump <- transact dumpMetadata
|
2020-12-28 15:56:00 +03:00
|
|
|
transact (runTx pgExecCtx recreateSystemMetadata)
|
2019-11-20 21:21:30 +03:00
|
|
|
secondDump <- transact dumpMetadata
|
2019-11-18 21:45:54 +03:00
|
|
|
secondDump `shouldBe` firstDump
|
|
|
|
|
2019-11-20 21:21:30 +03:00
|
|
|
it "does not create any objects affected by ClearMetadata" \(NT transact) -> do
|
2020-07-14 22:00:58 +03:00
|
|
|
env <- Env.getEnvironment
|
|
|
|
time <- getCurrentTime
|
2020-10-28 19:40:33 +03:00
|
|
|
transact (dropAndInit env time) `shouldReturn` MRInitialized
|
2019-11-20 21:21:30 +03:00
|
|
|
firstDump <- transact dumpMetadata
|
2021-09-09 14:54:19 +03:00
|
|
|
transact (flip runReaderT logger $ runClearMetadata ClearMetadata) `shouldReturn` successMsg
|
2019-11-20 21:21:30 +03:00
|
|
|
secondDump <- transact dumpMetadata
|
2019-11-18 21:45:54 +03:00
|
|
|
secondDump `shouldBe` firstDump
|
2020-12-28 15:56:00 +03:00
|
|
|
|
|
|
|
runTx
|
|
|
|
:: (MonadError QErr m, MonadIO m, MonadBaseControl IO m)
|
|
|
|
=> PGExecCtx -> LazyTxT QErr m a -> m a
|
|
|
|
runTx pgExecCtx = liftEitherM . runExceptT . runLazyTx pgExecCtx Q.ReadWrite
|