bloodhound-1.0.0.0: tests/Test/DownsampleSpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Test.DownsampleSpec (spec) where
import Data.Aeson
import Data.ByteString.Lazy.Char8 qualified as LBS
import Database.Bloodhound.ElasticSearch9.Requests qualified as RequestsES9
import Database.Bloodhound.ElasticSearch9.Types qualified as Types
import TestsUtils.Import
spec :: Spec
spec = describe "Downsample index API (/{index}/_downsample/{target_index})" $ do
describe "DownsampleRequest JSON" $ do
it "encodes a minimal request (no sampling_method)" $ do
let req = Types.DownsampleRequest (FixedInterval 1 Hours) Nothing
encode req `shouldBe` "{\"fixed_interval\":\"1h\"}"
it "round-trips a minimal request" $ do
let req = Types.DownsampleRequest (FixedInterval 1 Hours) Nothing
decode (encode req) `shouldBe` Just req
it "encodes sampling_method: aggregate as a JSON string" $ do
let req =
Types.DownsampleRequest
(FixedInterval 1 Hours)
(Just Types.Aggregate)
-- Inspect the wire form (order-independent via Object equality):
-- \"aggregate\" must be a string.
decode (encode req)
`shouldBe` Just
( object
[ "fixed_interval" .= String "1h",
"sampling_method" .= String "aggregate"
]
)
it "encodes sampling_method: last_value as a JSON string" $ do
let req =
Types.DownsampleRequest
(FixedInterval 30 Minutes)
(Just Types.LastValue)
decode (encode req)
`shouldBe` Just
( object
[ "fixed_interval" .= String "30m",
"sampling_method" .= String "last_value"
]
)
it "round-trips a request with sampling_method" $ do
let req =
Types.DownsampleRequest
(FixedInterval 30 Minutes)
(Just Types.LastValue)
decode (encode req) `shouldBe` Just req
it "decodes a fully-populated request body" $ do
let raw =
LBS.pack
"{\"fixed_interval\":\"1h\",\"sampling_method\":\"last_value\"}"
case decode raw :: Maybe Types.DownsampleRequest of
Just req -> do
Types.downsampleRequestSamplingMethod req
`shouldBe` Just Types.LastValue
Nothing ->
expectationFailure "failed to decode DownsampleRequest"
it "decodes a body without sampling_method (server default aggregate)" $ do
let raw = LBS.pack "{\"fixed_interval\":\"1h\"}"
case decode raw :: Maybe Types.DownsampleRequest of
Just req ->
Types.downsampleRequestSamplingMethod req
`shouldBe` (Nothing :: Maybe Types.SamplingMethod)
Nothing ->
expectationFailure "failed to decode DownsampleRequest"
it "rejects an unknown sampling_method value" $ do
let raw = LBS.pack "{\"fixed_interval\":\"1h\",\"sampling_method\":\"bogus\"}"
decode raw `shouldBe` (Nothing :: Maybe Types.DownsampleRequest)
describe "DownsampleResponse JSON" $ do
it "round-trips an acknowledged response" $ do
let resp = Types.DownsampleResponse True True
decode (encode resp) `shouldBe` Just resp
it "decodes {acknowledged, shards_acknowledged} both true" $
decode (LBS.pack "{\"acknowledged\":true,\"shards_acknowledged\":true}")
`shouldBe` Just (Types.DownsampleResponse True True)
it "defaults shards_acknowledged to False when absent" $
decode (LBS.pack "{\"acknowledged\":true}")
`shouldBe` Just (Types.DownsampleResponse True False)
it "decodes an empty object as both False" $
decode (LBS.pack "{}")
`shouldBe` Just (Types.DownsampleResponse False False)
describe "downsampleOptionsParams URI rendering" $ do
it "defaultDownsampleOptions emits no params" $
Types.downsampleOptionsParams Types.defaultDownsampleOptions
`shouldBe` []
it "renders wait_for_active_shards: all as \"all\"" $ do
let opts =
Types.defaultDownsampleOptions
{ Types.downsampleOptionsWaitForActiveShards = Just AllActiveShards
}
Types.downsampleOptionsParams opts
`shouldBe` [("wait_for_active_shards", Just "all")]
it "renders wait_for_active_shards: n as a bare number" $ do
let opts =
Types.defaultDownsampleOptions
{ Types.downsampleOptionsWaitForActiveShards = Just (ActiveShards 2)
}
Types.downsampleOptionsParams opts
`shouldBe` [("wait_for_active_shards", Just "2")]
it "renders master_timeout and timeout" $ do
let opts =
Types.defaultDownsampleOptions
{ Types.downsampleOptionsMasterTimeout = Just "30s",
Types.downsampleOptionsTimeout = Just "1m"
}
Types.downsampleOptionsParams opts
`shouldBe` [("master_timeout", Just "30s"), ("timeout", Just "1m")]
it "renders only the set field" $ do
let opts =
Types.defaultDownsampleOptions
{ Types.downsampleOptionsTimeout = Just "5s"
}
Types.downsampleOptionsParams opts
`shouldBe` [("timeout", Just "5s")]
it "renders all three params together in canonical order" $ do
let opts =
Types.defaultDownsampleOptions
{ Types.downsampleOptionsWaitForActiveShards = Just AllActiveShards,
Types.downsampleOptionsMasterTimeout = Just "10s",
Types.downsampleOptionsTimeout = Just "1m"
}
Types.downsampleOptionsParams opts
`shouldBe` [ ("wait_for_active_shards", Just "all"),
("master_timeout", Just "10s"),
("timeout", Just "1m")
]
describe "endpoint shape" $ do
let body = Types.DownsampleRequest (FixedInterval 1 Hours) Nothing
Right idx = mkIndexName "metrics"
Right target = mkIndexName "metrics-downsample"
it "POSTs /<index>/_downsample/<target_index> with a body" $ do
let req = RequestsES9.downsampleIndex idx target body
getRawEndpoint (bhRequestEndpoint req)
`shouldBe` ["metrics", "_downsample", "metrics-downsample"]
bhRequestBody req `shouldSatisfy` isJust
it "downsampleIndexWith appends timeout query params" $ do
let opts =
Types.defaultDownsampleOptions
{ Types.downsampleOptionsMasterTimeout = Just "10s"
}
req = RequestsES9.downsampleIndexWith idx target body opts
getRawEndpoint (bhRequestEndpoint req)
`shouldBe` ["metrics", "_downsample", "metrics-downsample"]
getRawEndpointQueries (bhRequestEndpoint req)
`shouldBe` [("master_timeout", Just "10s")]
it "downsampleIndexWith forwards wait_for_active_shards as a query param" $ do
let opts =
Types.defaultDownsampleOptions
{ Types.downsampleOptionsWaitForActiveShards = Just AllActiveShards
}
req = RequestsES9.downsampleIndexWith idx target body opts
getRawEndpoint (bhRequestEndpoint req)
`shouldBe` ["metrics", "_downsample", "metrics-downsample"]
getRawEndpointQueries (bhRequestEndpoint req)
`shouldBe` [("wait_for_active_shards", Just "all")]
it "the request body round-trips through the DownsampleRequest type" $ do
let req = RequestsES9.downsampleIndex idx target body
case bhRequestBody req of
Just bs -> case decode bs :: Maybe Types.DownsampleRequest of
Just decoded ->
decoded `shouldBe` body
Nothing ->
expectationFailure "request body did not decode as DownsampleRequest"
Nothing ->
expectationFailure "downsampleIndex should carry a request body"