mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-17 12:31:52 +03:00
926da74819
Dupe of https://github.com/hasura/graphql-engine-mono/pull/2853 with branch renamed so it doesn't break a tool. prev pr: https://github.com/hasura/graphql-engine-mono/pull/2911 next pr: https://github.com/hasura/graphql-engine-mono/pull/2922 This implements https://github.com/hasura/graphql-engine/issues/7801 Some points to keep in mind for review: * How state is passed to the tests. Do we like how this works? * I quite like it, with the opaque type [`State`](68f33051ca/server/tests-hspec/Harness/State.hs (L17)
), we can avoid churn when adding things. * The [setup/teardown](68f33051ca/server/tests-hspec/Spec.hs (L19-L31)
) seems clean. * By using hspec's own means to pass and denote context, we avoid "getting new ideas" for how to structure the tests -- we use a standard. Hopefully, that means the tests' structure rarely change. * The various flags passed in the [ServeOptions](68f33051ca/server/tests-hspec/Harness/Constants.hs (L123)
) - if there are any causes for concern, raise them here. My thinking is that, there are lots. I've picked some "sane" defaults (mostly empty). The tests pass. I think as we add more complex tests, these flags will be scrutinised and updated as needed. I think it's valuable that all flags are explicitly listed here, though. PR-URL: https://github.com/hasura/graphql-engine-mono/pull/2921 GitOrigin-RevId: 2c2e70bf784ef571a48509a7e5006fd0f48773b5
135 lines
4.6 KiB
Haskell
135 lines
4.6 KiB
Haskell
{-# LANGUAGE ViewPatterns #-}
|
|
|
|
-- | Helpers for talking to graphql engine.
|
|
module Harness.GraphqlEngine
|
|
( post,
|
|
post_,
|
|
postGraphql,
|
|
postGraphqlYaml,
|
|
startServerThread,
|
|
stopServer,
|
|
serverUrl,
|
|
Server,
|
|
)
|
|
where
|
|
|
|
import Control.Concurrent
|
|
import Control.Exception
|
|
import Control.Monad.Trans.Managed (ManagedT (..), lowerManagedT)
|
|
import Data.Aeson
|
|
import Data.Environment qualified as Env
|
|
import Data.Functor
|
|
import Data.Text qualified as T
|
|
import Data.Time
|
|
import GHC.Stack
|
|
import Harness.Constants qualified as Constants
|
|
import Harness.Http qualified as Http
|
|
import Harness.State
|
|
import Hasura.App
|
|
import Hasura.Logging (Hasura)
|
|
import Hasura.Prelude hiding (State)
|
|
import Hasura.RQL.Types
|
|
import Hasura.Server.Init
|
|
import Hasura.Server.Metrics (ServerMetricsSpec, createServerMetrics)
|
|
import Network.Socket qualified as Socket
|
|
import Network.Wai.Handler.Warp qualified as Warp
|
|
import System.Metrics qualified as EKG
|
|
|
|
-- | Used only for 'runApp' below.
|
|
data TestMetricsSpec name metricType tags
|
|
= ServerSubset (ServerMetricsSpec name metricType tags)
|
|
|
|
-- | Post some JSON to graphql-engine, getting back more
|
|
-- JSON. Optimistically assumes success. Use another function if you
|
|
-- want to test for failure.
|
|
post :: HasCallStack => State -> String -> Value -> IO Value
|
|
post (getServer -> Server {urlPrefix, port}) path =
|
|
Http.postValue_ (urlPrefix ++ ":" ++ show port ++ path)
|
|
|
|
-- | Same as post, but ignores the value.
|
|
post_ :: HasCallStack => State -> String -> Value -> IO ()
|
|
post_ server path = void . post server path
|
|
|
|
-- | Same as post, but defaults to the graphql end-point.
|
|
postGraphqlYaml :: HasCallStack => State -> Value -> IO Value
|
|
postGraphqlYaml server = post server "/v1/graphql"
|
|
|
|
-- | Same as 'postGraphqlYaml', but adds the {query:..} wrapper.
|
|
postGraphql :: HasCallStack => State -> Value -> IO Value
|
|
postGraphql server value = postGraphqlYaml server (object ["query" .= value])
|
|
|
|
-- | Choose a random port and start a graphql-engine server on that
|
|
-- port accessible from localhost. It waits until the server is
|
|
-- available before returning.
|
|
--
|
|
-- The port availability is subject to races.
|
|
startServerThread :: Maybe (String, Int) -> IO Server
|
|
startServerThread murlPrefixport = do
|
|
(urlPrefix, port, threadId) <-
|
|
case murlPrefixport of
|
|
Just (urlPrefix, port) -> do
|
|
threadId <- forkIO (forever (threadDelay 1000000)) -- Just wait.
|
|
pure (urlPrefix, port, threadId)
|
|
Nothing -> do
|
|
port <- bracket (Warp.openFreePort) (Socket.close . snd) (pure . fst)
|
|
let urlPrefix = "http://127.0.0.1"
|
|
threadId <-
|
|
forkIO (runApp Constants.serveOptions {soPort = fromIntegral port})
|
|
pure (urlPrefix, port, threadId)
|
|
let server = Server {port = fromIntegral port, urlPrefix, threadId}
|
|
Http.healthCheck (serverUrl server)
|
|
pure server
|
|
|
|
-- | Stop the server.
|
|
stopServer :: Server -> IO ()
|
|
stopServer Server {threadId} = killThread threadId
|
|
|
|
-- | Get the server URL, for sanity checking.
|
|
serverUrl :: Server -> String
|
|
serverUrl Server {urlPrefix, port} = urlPrefix ++ ":" ++ show port
|
|
|
|
-- | Run the graphql-engine server.
|
|
runApp :: ServeOptions Hasura.Logging.Hasura -> IO ()
|
|
runApp serveOptions = do
|
|
let rci =
|
|
PostgresConnInfo
|
|
{ _pciDatabaseConn =
|
|
Just
|
|
( UrlFromParams
|
|
PGConnectionParams
|
|
{ _pgcpHost = T.pack Constants.postgresHost,
|
|
_pgcpUsername = T.pack Constants.postgresUser,
|
|
_pgcpPassword = Just (T.pack Constants.postgresPassword),
|
|
_pgcpPort = fromIntegral Constants.postgresPort,
|
|
_pgcpDatabase = T.pack Constants.postgresDb
|
|
}
|
|
),
|
|
_pciRetries = Nothing
|
|
}
|
|
metadataDbUrl = Just Constants.postgresqlConnectionString
|
|
env <- Env.getEnvironment
|
|
initTime <- liftIO getCurrentTime
|
|
globalCtx <- initGlobalCtx env metadataDbUrl rci
|
|
do
|
|
(ekgStore, serverMetrics) <-
|
|
liftIO $ do
|
|
store <- EKG.newStore @TestMetricsSpec
|
|
serverMetrics <-
|
|
liftIO $ createServerMetrics $ EKG.subset ServerSubset store
|
|
pure (EKG.subset EKG.emptyOf store, serverMetrics)
|
|
runManagedT (initialiseServeCtx env globalCtx serveOptions) $ \serveCtx ->
|
|
do
|
|
let Loggers _ _logger pgLogger = _scLoggers serveCtx
|
|
flip runPGMetadataStorageAppT (_scMetadataDbPool serveCtx, pgLogger)
|
|
. lowerManagedT
|
|
$ do
|
|
runHGEServer
|
|
(const $ pure ())
|
|
env
|
|
serveOptions
|
|
serveCtx
|
|
initTime
|
|
Nothing
|
|
serverMetrics
|
|
ekgStore
|