refactor(test): provide means to validate metrics and observations
Some helpers are provided for introspecting metrics already (used in JWT cache tests). This change provides facilities to additionally validate emited Observation events. A new Spec module is also implemented, adding basic tests of schema cache reloading - their main goal is to excercise the new infrastructure.
This commit is contained in:
committed by
Steve Chavez
parent
8262faa235
commit
afb95a5268
@@ -1,4 +1,5 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
module Observation.JwtCache where
|
||||
|
||||
@@ -13,9 +14,11 @@ import PostgREST.Metrics (MetricsState (..))
|
||||
import Protolude
|
||||
import Test.Hspec.Wai.JSON (json)
|
||||
|
||||
spec :: SpecWith (MetricsState, Application)
|
||||
spec :: SpecWith (SpecState, Application)
|
||||
spec = describe "Server started with JWT and metrics enabled" $ do
|
||||
it "Should not have JWT in cache" $ do
|
||||
expectCounters <- checkState' . specMetrics <$> getState
|
||||
|
||||
let auth = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe1"}|]
|
||||
|
||||
expectCounters
|
||||
@@ -27,6 +30,8 @@ spec = describe "Server started with JWT and metrics enabled" $ do
|
||||
request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200
|
||||
|
||||
it "Should have JWT in cache" $ do
|
||||
expectCounters <- checkState' . specMetrics <$> getState
|
||||
|
||||
let auth = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe2"}|]
|
||||
|
||||
expectCounters
|
||||
@@ -39,6 +44,8 @@ spec = describe "Server started with JWT and metrics enabled" $ do
|
||||
*> request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200
|
||||
|
||||
it "Should not cache invalid JWTs" $ do
|
||||
expectCounters <- checkState' . specMetrics <$> getState
|
||||
|
||||
let auth = authHeaderJWT "some random bytes"
|
||||
|
||||
expectCounters
|
||||
@@ -51,6 +58,8 @@ spec = describe "Server started with JWT and metrics enabled" $ do
|
||||
*> request methodGet "/authors_only" [auth] "" `shouldRespondWith` 401
|
||||
|
||||
it "Should cache expired JWTs" $ do
|
||||
expectCounters <- checkState' . specMetrics <$> getState
|
||||
|
||||
let auth = genToken [json|{"exp": 1, "role": "postgrest_test_author", "id": "jdoe2"}|]
|
||||
|
||||
expectCounters
|
||||
@@ -63,6 +72,8 @@ spec = describe "Server started with JWT and metrics enabled" $ do
|
||||
*> request methodGet "/authors_only" [auth] "" `shouldRespondWith` 401
|
||||
|
||||
it "Should evict entries from the JWT cache (jwt cache max is 2)" $ do
|
||||
expectCounters <- checkState' . specMetrics <$> getState
|
||||
|
||||
let jwt1 = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe3"}|]
|
||||
jwt2 = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe4"}|]
|
||||
jwt3 = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe5"}|]
|
||||
@@ -82,6 +93,8 @@ spec = describe "Server started with JWT and metrics enabled" $ do
|
||||
*> request methodGet "/authors_only" [jwt3] ""
|
||||
|
||||
it "Should not evict entries from the JWT cache in FIFO order" $ do
|
||||
expectCounters <- checkState' . specMetrics <$> getState
|
||||
|
||||
let jwt1 = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe6"}|]
|
||||
jwt2 = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe7"}|]
|
||||
jwt3 = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe8"}|]
|
||||
@@ -108,6 +121,8 @@ spec = describe "Server started with JWT and metrics enabled" $ do
|
||||
-- The test case was added based on coverage report
|
||||
-- showing this scenario was not covered by previous tests
|
||||
it "Should evict entries even though all were hit" $ do
|
||||
expectCounters <- checkState' . specMetrics <$> getState
|
||||
|
||||
let jwt1 = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe9"}|]
|
||||
jwt2 = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe10"}|]
|
||||
jwt3 = genToken [json|{"exp": 9999999999, "role": "postgrest_test_author", "id": "jdoe11"}|]
|
||||
@@ -135,4 +150,3 @@ spec = describe "Server started with JWT and metrics enabled" $ do
|
||||
requests = expectCounter @"jwtCacheRequests"
|
||||
hits = expectCounter @"jwtCacheHits"
|
||||
evictions = expectCounter @"jwtCacheEvictions"
|
||||
expectCounters = checkState
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE MonadComprehensions #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
|
||||
module Observation.MetricsSpec where
|
||||
|
||||
import Data.List (lookup)
|
||||
import Network.Wai (Application)
|
||||
import ObsHelper
|
||||
import qualified PostgREST.AppState as AppState
|
||||
import PostgREST.Config (AppConfig (configDbSchemas))
|
||||
import qualified PostgREST.Metrics as Metrics
|
||||
import PostgREST.Observation
|
||||
import Prometheus (getCounter, getVectorWith)
|
||||
import Protolude
|
||||
import Test.Hspec (SpecWith, describe, it)
|
||||
import Test.Hspec.Wai (getState)
|
||||
|
||||
spec :: SpecWith (SpecState, Application)
|
||||
spec = describe "Server started with metrics enabled" $ do
|
||||
it "Should update pgrst_schema_cache_loads_total[SUCCESS]" $ do
|
||||
SpecState{specAppState = appState, specMetrics = metrics, specObsChan} <- getState
|
||||
let waitFor = waitForObs specObsChan
|
||||
|
||||
liftIO $ checkState' metrics [
|
||||
schemaCacheLoads "SUCCESS" (+1)
|
||||
] $ do
|
||||
AppState.schemaCacheLoader appState
|
||||
waitFor (1 * sec) "SchemaCacheLoadedObs" $ \x -> [ o | o@(SchemaCacheLoadedObs{}) <- pure x]
|
||||
|
||||
it "Should update pgrst_schema_cache_loads_total[ERROR]" $ do
|
||||
SpecState{specAppState = appState, specMetrics = metrics, specObsChan} <- getState
|
||||
let waitFor = waitForObs specObsChan
|
||||
|
||||
liftIO $ checkState' metrics [
|
||||
schemaCacheLoads "FAIL" (+1),
|
||||
schemaCacheLoads "SUCCESS" (+1)
|
||||
] $ do
|
||||
AppState.getConfig appState >>= \prev -> do
|
||||
AppState.putConfig appState $ prev { configDbSchemas = pure "bad_schema" }
|
||||
AppState.schemaCacheLoader appState
|
||||
waitFor (1 * sec) "SchemaCacheErrorObs" $ \x -> [ o | o@(SchemaCacheErrorObs{}) <- pure x]
|
||||
AppState.putConfig appState prev
|
||||
|
||||
-- wait up to 2 secs so that retry can happen
|
||||
waitFor (2 * sec) "SchemaCacheLoadedObs" $ \x -> [ o | o@(SchemaCacheLoadedObs{}) <- pure x]
|
||||
|
||||
where
|
||||
-- prometheus-client api to handle vectors is convoluted
|
||||
schemaCacheLoads label = expectField @"schemaCacheLoads" $
|
||||
fmap (maybe (0::Int) round . lookup label) . (`getVectorWith` getCounter)
|
||||
sec = 1000000
|
||||
Reference in New Issue
Block a user