chore(tests): pass BigQuery service account env var through to HGE

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8532
GitOrigin-RevId: 68e4c846e23369f476fa672b987d6769fad43cbf
This commit is contained in:
Daniel Harvey 2023-03-30 18:57:27 +01:00 committed by hasura-bot
parent 5a81eaa9b6
commit 4905dc1675
10 changed files with 190 additions and 117 deletions

View File

@ -13,15 +13,16 @@ import Data.Char qualified as Char
import Data.IORef
import Data.List qualified as List
import Database.PostgreSQL.Simple.Options qualified as Options
import Harness.Constants qualified as Constants
import Harness.Exceptions (HasCallStack, bracket)
import Harness.GraphqlEngine (startServerThread)
import Harness.Logging
import Harness.Services.Composed (mkTestServicesConfig)
import Harness.Test.BackendType (BackendType (..))
import Harness.TestEnvironment (GlobalTestEnvironment (..), Protocol (..), TestingMode (..), stopServer)
import Harness.TestEnvironment (GlobalTestEnvironment (..), PassthroughEnvVars (..), Protocol (..), TestingMode (..), stopServer)
import Hasura.Prelude
import System.Directory
import System.Environment (getEnvironment)
import System.Environment (getEnvironment, lookupEnv)
import System.FilePath
import System.IO.Unsafe (unsafePerformIO)
import System.Log.FastLogger qualified as FL
@ -75,6 +76,7 @@ setupTestEnvironment :: TestingMode -> Logger -> IO GlobalTestEnvironment
setupTestEnvironment testingMode logger = do
server <- startServerThread
servicesConfig <- mkTestServicesConfig
passthroughEnvVars <- mkPassthroughEnv
pure GlobalTestEnvironment {requestProtocol = HTTP, ..}
-- | tear down the shared server
@ -138,3 +140,14 @@ globalConfigRef = unsafePerformIO $ newIORef Nothing
setupGlobalConfig :: TestingMode -> FL.LogType -> IO ()
setupGlobalConfig testingMode logType =
writeIORef globalConfigRef $ Just (testingMode, logType)
envToPassthrough :: [String]
envToPassthrough = [Constants.bigqueryServiceKeyVar]
-- | grab items from env to pass through to new HGE instances
mkPassthroughEnv :: IO PassthroughEnvVars
mkPassthroughEnv =
let lookup' env = do
value <- fromMaybe "" <$> lookupEnv env
pure (env, value)
in PassthroughEnvVars <$> traverse lookup' envToPassthrough

View File

@ -233,7 +233,8 @@ setup tables' (testEnvironment, _) = do
}
)
tables'
serviceAccount <- getServiceAccount
-- add metadata using env var name so not to log the key
let serviceAccountEnvVar = Constants.bigqueryServiceKeyVar
projectId <- getProjectId
-- create the dataset
createDataset schemaName
@ -249,7 +250,8 @@ setup tables' (testEnvironment, _) = do
kind: *backendType
tables: []
configuration:
service_account: *serviceAccount
service_account:
from_env: *serviceAccountEnvVar
project_id: *projectId
datasets: [*schemaName]
retry_limit: 5

View File

@ -38,7 +38,7 @@ where
import Data.HashSet qualified as Set
import Data.Word (Word16)
import Database.PG.Query qualified as PG
import Harness.TestEnvironment (UniqueTestId)
import Harness.UniqueTestId (UniqueTestId)
import Hasura.Backends.Postgres.Connection.MonadTx (ExtensionsSchema (..))
import Hasura.GraphQL.Execute.Subscription.Options qualified as ES
import Hasura.GraphQL.Schema.Options qualified as Options

View File

@ -0,0 +1,105 @@
-- | GlobalTestEnvironment shared by tests. We intentionally use an abstract type to
-- wrap up the values we need for tests, with accessors. This way, the
-- tests are less liable to refactorings when we add or change the
-- globalTestEnvironment.
module Harness.GlobalTestEnvironment
( GlobalTestEnvironment (..),
Protocol (..),
Server (..),
TestingMode (..),
PassthroughEnvVars (..),
serverUrl,
)
where
import Control.Concurrent.Async (Async)
import Data.Has
import Data.Word
import Database.PostgreSQL.Simple.Options (Options)
import Harness.Logging.Messages
import Harness.PassthroughEnvVars
import Harness.Services.Composed qualified as Services
import Harness.Test.BackendType
import Hasura.Prelude
import Network.WebSockets qualified as WS
-- | static information across an entire test suite run
data GlobalTestEnvironment = GlobalTestEnvironment
{ -- | shared function to log information from tests
logger :: Logger,
-- | the mode in which we're running the tests. See 'TestingMode' for
-- details'.
testingMode :: TestingMode,
-- | connection details for the instance of HGE we're connecting to
server :: Server,
-- | The protocol with which we make server requests.
requestProtocol :: Protocol,
-- | Any environment variable names we wish to pass through to any new HGE
-- instance
passthroughEnvVars :: PassthroughEnvVars,
servicesConfig :: Services.TestServicesConfig
}
instance Has Logger GlobalTestEnvironment where
getter = logger
modifier f x = x {logger = f (logger x)}
instance Has Services.TestServicesConfig GlobalTestEnvironment where
getter = servicesConfig
modifier f x = x {servicesConfig = f (servicesConfig x)}
instance Has Services.HgeBinPath GlobalTestEnvironment where
getter = getter . getter @Services.TestServicesConfig
modifier f = modifier (modifier @_ @Services.TestServicesConfig f)
instance Has Services.PostgresServerUrl GlobalTestEnvironment where
getter = getter . getter @Services.TestServicesConfig
modifier f = modifier (modifier @_ @Services.TestServicesConfig f)
instance Has PassthroughEnvVars GlobalTestEnvironment where
getter = passthroughEnvVars
modifier f x = x {passthroughEnvVars = f (passthroughEnvVars x)}
instance Show GlobalTestEnvironment where
show GlobalTestEnvironment {server} =
"<GlobalTestEnvironment: " ++ urlPrefix server ++ ":" ++ show (port server) ++ " >"
-- | How should we make requests to `graphql-engine`? Both WebSocket- and HTTP-
-- based requests are supported.
data Protocol = HTTP | WebSocket WS.Connection
-- | Credentials for our testing modes. See 'SpecHook.setupTestingMode' for the
-- practical consequences of this type.
data TestingMode
= -- | run all tests, unfiltered
TestEverything
| -- | run only tests containing this BackendType (or a RemoteSchema, so
-- those aren't missed)
TestBackend BackendType
| -- | run "all the other tests"
TestNoBackends
| -- | test a Postgres-compatible using a custom connection string
TestNewPostgresVariant Options
deriving (Eq, Ord, Show)
-- | Information about a server that we're working with.
data Server = Server
{ -- | The port to connect on.
port :: Word16,
-- | The full URI prefix e.g. http://localhost
urlPrefix :: String,
-- | The thread that the server is running on, so we can stop it later.
thread :: Async ()
}
instance Show Server where
show = serverUrl
-- | Extracts the full URL prefix and port number from a given 'Server'.
--
-- @
-- > serverUrl (Server 8080 "http://localhost" someThreadId)
-- "http://localhost:8080"
-- @
serverUrl :: Server -> String
serverUrl Server {urlPrefix, port} = urlPrefix ++ ":" ++ show port

View File

@ -0,0 +1,12 @@
-- | PassthroughEnvVars separated into own file for circular dep reasons
module Harness.PassthroughEnvVars
( PassthroughEnvVars (..),
)
where
import Hasura.Prelude
-- | When spawning new HGE instances from a binary, we may want to pass through
-- some environment variables (for database credentials, for instance).
newtype PassthroughEnvVars
= PassthroughEnvVars [(String, String)]

View File

@ -28,6 +28,7 @@ import Data.Vector (fromList)
import Harness.Exceptions
import Harness.Http qualified as Http
import Harness.Logging
import Harness.PassthroughEnvVars
import Harness.Services.PostgresDb
import Hasura.Prelude
import Network.HTTP.Simple qualified as Http
@ -65,20 +66,22 @@ emptyHgeConfig = HgeConfig []
-- crashes. Ensuring that would require making Hge listen for heartbeats, or
-- use a helper process that does.
withHge ::
( Has HgeBinPath a,
Has PostgresServerUrl a,
Has Logger a
( Has HgeBinPath env,
Has PostgresServerUrl env,
Has Logger env,
Has PassthroughEnvVars env
) =>
HgeConfig ->
SpecWith (HgeServerInstance, a) ->
SpecWith a
SpecWith (HgeServerInstance, env) ->
SpecWith env
withHge hgeConfig specs = do
flip aroundWith specs \action a -> runManaged do
let hgeBin = getter a
pgUrl = getter a
let logger = getter @Logger a
server <- spawnServer logger pgUrl hgeBin hgeConfig
liftIO $ action (server, a)
flip aroundWith specs \action env -> runManaged do
let hgeBin = getter env
pgUrl = getter env
logger = getter @Logger env
passthroughEnvVars = getter env
server <- spawnServer logger pgUrl hgeBin hgeConfig passthroughEnvVars
liftIO $ action (server, env)
-- | spin up a Manager HGE instance and check it is healthy
spawnServer ::
@ -86,10 +89,12 @@ spawnServer ::
PostgresServerUrl ->
HgeBinPath ->
HgeConfig ->
PassthroughEnvVars ->
Managed HgeServerInstance
spawnServer logger pgUrl (HgeBinPath hgeBinPath) (HgeConfig {hgeConfigEnvironmentVars}) = do
spawnServer logger pgUrl (HgeBinPath hgeBinPath) (HgeConfig {hgeConfigEnvironmentVars}) (PassthroughEnvVars envVars) = do
freshDb <- mkFreshPostgresDb logger pgUrl
let metadataDbUrl = mkFreshDbConnectionString pgUrl freshDb
let allEnv = hgeConfigEnvironmentVars <> envVars
metadataDbUrl = mkFreshDbConnectionString pgUrl freshDb
((_, Just hgeStdOut, Just hgeStdErr, _), port) <-
managed
( bracket
@ -112,7 +117,7 @@ spawnServer logger pgUrl (HgeBinPath hgeBinPath) (HgeConfig {hgeConfigEnvironmen
{ env =
Just $
("HASURA_GRAPHQL_GRACEFUL_SHUTDOWN_TIMEOUT", "0")
: hgeConfigEnvironmentVars,
: allEnv,
std_out = CreatePipe,
std_err = CreatePipe,
create_group = True

View File

@ -132,6 +132,7 @@ hgeWithEnv env = do
(getter globalTestEnvironment)
(getter globalTestEnvironment)
hgeConfig
(getter globalTestEnvironment)
liftIO $ useHgeInTestEnvironment globalTestEnvironment hgeServerInstance >>= specs
)

View File

@ -5,6 +5,7 @@
module Harness.TestEnvironment
( TestEnvironment (..),
GlobalTestEnvironment (..),
PassthroughEnvVars (..),
Protocol (..),
Server (..),
TestingMode (..),
@ -26,13 +27,9 @@ module Harness.TestEnvironment
)
where
import Control.Concurrent.Async (Async)
import Control.Concurrent.Async qualified as Async
import Data.Char qualified
import Data.Has
import Data.UUID (UUID)
import Data.Word
import Database.PostgreSQL.Simple.Options (Options)
import Harness.GlobalTestEnvironment
import Harness.Logging.Messages
import Harness.Permissions.Types (Permission)
import Harness.Services.Composed qualified as Services
@ -40,53 +37,12 @@ import Harness.Test.BackendType
import Harness.Test.CustomOptions qualified as Custom
import Harness.Test.FixtureName
import Harness.Test.ScalarType
import Harness.UniqueTestId
import Harness.Yaml
import Hasura.Prelude
import Network.WebSockets qualified as WS
import System.Process (readProcess)
import Text.Pretty.Simple
newtype UniqueTestId = UniqueTestId {getUniqueTestId :: UUID}
-- | Sanitise UUID for use in BigQuery dataset name
-- must be alphanumeric (plus underscores)
instance Show UniqueTestId where
show (UniqueTestId uuid) =
fmap
( \a ->
if Data.Char.isAlphaNum a
then a
else '_'
)
. show
$ uuid
-- | static information across an entire test suite run
data GlobalTestEnvironment = GlobalTestEnvironment
{ -- | shared function to log information from tests
logger :: Logger,
-- | the mode in which we're running the tests. See 'TestingMode' for
-- details'.
testingMode :: TestingMode,
-- | connection details for the instance of HGE we're connecting to
server :: Server,
-- | The protocol with which we make server requests.
requestProtocol :: Protocol,
servicesConfig :: Services.TestServicesConfig
}
instance Has Logger GlobalTestEnvironment where
getter = logger
modifier f x = x {logger = f (logger x)}
instance Has GlobalTestEnvironment TestEnvironment where
getter = globalEnvironment
modifier f x = x {globalEnvironment = f (globalEnvironment x)}
instance Show GlobalTestEnvironment where
show GlobalTestEnvironment {server} =
"<GlobalTestEnvironment: " ++ urlPrefix server ++ ":" ++ show (port server) ++ " >"
-- | A testEnvironment that's passed to all tests.
data TestEnvironment = TestEnvironment
{ -- | shared setup not related to a particular test
@ -112,10 +68,6 @@ scalarTypeToText TestEnvironment {fixtureName} = case fixtureName of
-- the given permissions will be applied.
data TestingRole = Admin | NonAdmin [Permission]
-- | How should we make requests to `graphql-engine`? Both WebSocket- and HTTP-
-- based requests are supported.
data Protocol = HTTP | WebSocket WS.Connection
instance Has Logger TestEnvironment where
getter = logger . globalEnvironment
modifier f x =
@ -129,17 +81,9 @@ instance Has Logger TestEnvironment where
}
}
instance Has Services.TestServicesConfig GlobalTestEnvironment where
getter = servicesConfig
modifier f x = x {servicesConfig = f (servicesConfig x)}
instance Has Services.HgeBinPath GlobalTestEnvironment where
getter = getter . getter @Services.TestServicesConfig
modifier f = modifier (modifier @_ @Services.TestServicesConfig f)
instance Has Services.PostgresServerUrl GlobalTestEnvironment where
getter = getter . getter @Services.TestServicesConfig
modifier f = modifier (modifier @_ @Services.TestServicesConfig f)
instance Has GlobalTestEnvironment TestEnvironment where
getter = globalEnvironment
modifier f x = x {globalEnvironment = f (globalEnvironment x)}
instance Has Services.TestServicesConfig TestEnvironment where
getter = getter . getter @GlobalTestEnvironment
@ -196,46 +140,10 @@ focusFixtureRight testEnv =
_ -> error "Could not focus on right-hand FixtureName"
}
-- | Credentials for our testing modes. See 'SpecHook.setupTestingMode' for the
-- practical consequences of this type.
data TestingMode
= -- | run all tests, unfiltered
TestEverything
| -- | run only tests containing this BackendType (or a RemoteSchema, so
-- those aren't missed)
TestBackend BackendType
| -- | run "all the other tests"
TestNoBackends
| -- | test a Postgres-compatible using a custom connection string
TestNewPostgresVariant Options
deriving (Eq, Ord, Show)
-- | Information about a server that we're working with.
data Server = Server
{ -- | The port to connect on.
port :: Word16,
-- | The full URI prefix e.g. http://localhost
urlPrefix :: String,
-- | The thread that the server is running on, so we can stop it later.
thread :: Async ()
}
instance Show Server where
show = serverUrl
-- | Retrieve the 'Server' associated with some 'TestEnvironment'.
getServer :: TestEnvironment -> Server
getServer TestEnvironment {globalEnvironment} = server globalEnvironment
-- | Extracts the full URL prefix and port number from a given 'Server'.
--
-- @
-- > serverUrl (Server 8080 "http://localhost" someThreadId)
-- "http://localhost:8080"
-- @
serverUrl :: Server -> String
serverUrl Server {urlPrefix, port} = urlPrefix ++ ":" ++ show port
-- | Retrieve the 'TestingMode' associated with some 'TestEnvironment'
getTestingMode :: TestEnvironment -> TestingMode
getTestingMode = testingMode . globalEnvironment

View File

@ -0,0 +1,24 @@
-- | Extracted from `TestEnvironment` to stop circular dep hell
module Harness.UniqueTestId
( UniqueTestId (..),
)
where
import Data.Char qualified
import Data.UUID (UUID)
import Hasura.Prelude
newtype UniqueTestId = UniqueTestId {getUniqueTestId :: UUID}
-- | Sanitise UUID for use in BigQuery dataset name
-- must be alphanumeric (plus underscores)
instance Show UniqueTestId where
show (UniqueTestId uuid) =
fmap
( \a ->
if Data.Char.isAlphaNum a
then a
else '_'
)
. show
$ uuid

View File

@ -133,10 +133,12 @@ library
Harness.DataConnectorAgent
Harness.Env
Harness.Exceptions
Harness.GlobalTestEnvironment
Harness.GraphqlEngine
Harness.Http
Harness.Logging
Harness.Logging.Messages
Harness.PassthroughEnvVars
Harness.Permissions
Harness.PytestPortedCompat
Harness.Quoter.Graphql
@ -162,6 +164,7 @@ library
Harness.Test.SetupAction
Harness.Test.TestResource
Harness.TestEnvironment
Harness.UniqueTestId
Harness.WebSockets
Harness.Webhook
Harness.Yaml