bloodhound-1.0.0.0: tests/Test/FieldCapsSpec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns -Wno-x-partial #-}
module Test.FieldCapsSpec (spec) where
import Data.Aeson (Value (..), object, (.=))
import Data.Aeson.Key (fromText)
import Data.Aeson.KeyMap qualified as KM
import Data.ByteString.Lazy.Char8 qualified as BL8
import TestsUtils.Common
import TestsUtils.Import
spec :: Spec
spec = do
describe "FieldCapsRequest JSON" $ do
it "encodes an empty body as {}" $
let req = defaultFieldCapsRequest
Object o = toJSON req
in KM.toList o `shouldBe` []
it "includes index_filter and runtime_mappings when provided" $
let req =
FieldCapsRequest
{ fieldCapsRequestIndexFilter = Just (MatchAllQuery Nothing),
fieldCapsRequestRuntimeMappings = Just (KM.fromList [(fromText "rate", object ["type" .= ("double" :: Text)])])
}
Object o = toJSON req
in do
KM.lookup (fromText "index_filter") o `shouldBe` Just (toJSON (MatchAllQuery Nothing))
KM.member (fromText "runtime_mappings") o `shouldBe` True
KM.lookup (fromText "fields") o `shouldBe` (Nothing :: Maybe Value)
describe "FieldCapsOptions params" $ do
it "renders fields as a comma-joined URI param" $
let opts =
defaultFieldCapsOptions
{ fcoFields = Just [FieldPattern "user", FieldPattern "geo*"]
}
in lookup "fields" (fieldCapsOptionsParams opts) `shouldBe` Just (Just "user,geo*")
it "omits fields when Nothing" $
lookup "fields" (fieldCapsOptionsParams defaultFieldCapsOptions) `shouldBe` Nothing
it "renders include_unmapped as a boolean string" $
let opts = defaultFieldCapsOptions {fcoIncludeUnmapped = Just True}
in lookup "include_unmapped" (fieldCapsOptionsParams opts) `shouldBe` Just (Just "true")
it "renders allow_no_indices as a boolean string" $
let opts = defaultFieldCapsOptions {fcoAllowNoIndices = Just False}
in lookup "allow_no_indices" (fieldCapsOptionsParams opts) `shouldBe` Just (Just "false")
it "renders expand_wildcards using Search.expandWildcardsText" $
let opts =
defaultFieldCapsOptions
{ fcoExpandWildcards = Just [ExpandWildcardsOpen, ExpandWildcardsClosed]
}
in lookup "expand_wildcards" (fieldCapsOptionsParams opts) `shouldBe` Just (Just "open,closed")
describe "FieldCapsResponse JSON" $ do
it "decodes the canonical ES doc example with multi-type field" $
let bytes =
BL8.pack
"{\"indices\":[\"index1\",\"index2\",\"index3\",\"index4\",\"index5\"],\"fields\":{\"rating\":{\"long\":{\"type\":\"long\",\"metadata_field\":false,\"searchable\":true,\"aggregatable\":false,\"indices\":[\"index1\",\"index2\"],\"non_aggregatable_indices\":[\"index1\"]},\"keyword\":{\"type\":\"keyword\",\"metadata_field\":false,\"searchable\":false,\"aggregatable\":true,\"indices\":[\"index3\",\"index4\"],\"non_searchable_indices\":[\"index4\"]}},\"title\":{\"text\":{\"type\":\"text\",\"metadata_field\":false,\"searchable\":true,\"aggregatable\":false}}}}"
Just resp = decode bytes
fields = fieldCapsResponseFields resp
Just rating = KM.lookup (fromText "rating") fields
Just ratingLong = KM.lookup (fromText "long") rating
Just ratingKeyword = KM.lookup (fromText "keyword") rating
Just title = KM.lookup (fromText "title") fields
Just titleText = KM.lookup (fromText "text") title
in do
fieldCapsResponseIndices resp
`shouldBe` Just
[ [qqIndexName|index1|],
[qqIndexName|index2|],
[qqIndexName|index3|],
[qqIndexName|index4|],
[qqIndexName|index5|]
]
fieldCapabilityType ratingLong `shouldBe` "long"
fieldCapabilitySearchable ratingLong `shouldBe` True
fieldCapabilityAggregatable ratingLong `shouldBe` False
fieldCapabilityIndices ratingLong
`shouldBe` Just [[qqIndexName|index1|], [qqIndexName|index2|]]
fieldCapabilityNonAggregatableIndices ratingLong
`shouldBe` Just [[qqIndexName|index1|]]
fieldCapabilityType ratingKeyword `shouldBe` "keyword"
fieldCapabilitySearchable ratingKeyword `shouldBe` False
fieldCapabilityAggregatable ratingKeyword `shouldBe` True
fieldCapabilityNonSearchableIndices ratingKeyword
`shouldBe` Just [[qqIndexName|index4|]]
fieldCapabilityType titleText `shouldBe` "text"
fieldCapabilitySearchable titleText `shouldBe` True
fieldCapabilityAggregatable titleText `shouldBe` False
fieldCapabilityIndices titleText `shouldBe` Nothing
it "decodes a response with null indices" $
let bytes =
BL8.pack
"{\"indices\":null,\"fields\":{\"user\":{\"text\":{\"type\":\"text\",\"searchable\":true,\"aggregatable\":false}}}}"
Just resp = decode bytes
in do
fieldCapsResponseIndices resp `shouldBe` Nothing
KM.size (fieldCapsResponseFields resp) `shouldBe` 1
it "decodes a capability with metadata_field and meta map" $
let bytes =
BL8.pack
"{\"indices\":[\"idx\"],\"fields\":{\"_id\":{\"_id\":{\"type\":\"_id\",\"searchable\":true,\"aggregatable\":true,\"metadata_field\":true,\"meta\":{\"_foo\":[\"bar\"]}}}}}"
Just resp = decode bytes
fields = fieldCapsResponseFields resp
Just _id = KM.lookup (fromText "_id") fields
Just _idCap = KM.lookup (fromText "_id") _id
in do
fieldCapabilityMetadataField _idCap `shouldBe` Just True
fieldCapabilityMeta _idCap
`shouldBe` Just (KM.fromList [(fromText "_foo", [String "bar"])])
it "ignores unknown experimental fields (time_series_dimension etc.)" $
let bytes =
BL8.pack
"{\"indices\":null,\"fields\":{\"metric\":{\"long\":{\"type\":\"long\",\"searchable\":true,\"aggregatable\":true,\"time_series_dimension\":true,\"time_series_metric\":\"gauge\"}}}}"
Just resp = decode bytes
fields = fieldCapsResponseFields resp
Just metric = KM.lookup (fromText "metric") fields
Just longCap = KM.lookup (fromText "long") metric
in fieldCapabilityType longCap `shouldBe` "long"
describe "Field Caps endpoint" $ do
it "returns capabilities for a single field via POST /_field_caps" $
withTestEnv $ do
_ <- insertData
resp <-
performBHRequest $
getFieldCaps (Just [testIndex]) [FieldPattern "user"]
liftIO $ do
let fields = fieldCapsResponseFields resp
Just user = KM.lookup (fromText "user") fields
KM.size user `shouldBe` 1
let Just userText = KM.lookup (fromText "text") user
-- The TweetMapping in TestsUtils.Common sets fielddata=true
-- on user, so it is both searchable and aggregatable.
fieldCapabilitySearchable userText `shouldBe` True
fieldCapabilityAggregatable userText `shouldBe` True
it "reports integer fields as aggregatable" $
withTestEnv $ do
_ <- insertData
resp <-
performBHRequest $
getFieldCaps (Just [testIndex]) [FieldPattern "age"]
liftIO $ do
let fields = fieldCapsResponseFields resp
Just age = KM.lookup (fromText "age") fields
cap =
case KM.lookup (fromText "long") age of
Just c -> c
Nothing -> case KM.lookup (fromText "integer") age of
Just c -> c
Nothing -> error "expected long or integer capability for age"
fieldCapabilitySearchable cap `shouldBe` True
fieldCapabilityAggregatable cap `shouldBe` True
it "supports glob patterns" $
withTestEnv $ do
_ <- insertData
resp <-
performBHRequest $
getFieldCaps (Just [testIndex]) [FieldPattern "*"]
liftIO $
KM.size (fieldCapsResponseFields resp) `shouldSatisfy` (> 1)
it "works without an explicit index (POST /_field_caps)" $
withTestEnv $ do
_ <- insertData
resp <-
performBHRequest $
getFieldCaps Nothing [FieldPattern "user"]
liftIO $
KM.member (fromText "user") (fieldCapsResponseFields resp) `shouldBe` True
it "passes include_unmapped via FieldCapsOptions" $
withTestEnv $ do
_ <- insertData
resp <-
performBHRequest $
getFieldCapsWith
(Just [testIndex])
defaultFieldCapsOptions
{ fcoIncludeUnmapped = Just True,
fcoFields = Just [FieldPattern "nonexistent_*"]
}
defaultFieldCapsRequest
liftIO $
KM.size (fieldCapsResponseFields resp) `shouldBe` 0
it "accepts Just [] as equivalent to Nothing for the index list" $
withTestEnv $ do
_ <- insertData
resp <-
performBHRequest $
getFieldCaps (Just []) [FieldPattern "user"]
liftIO $
KM.member (fromText "user") (fieldCapsResponseFields resp) `shouldBe` True
it "passes expand_wildcards via FieldCapsOptions" $
withTestEnv $ do
_ <- insertData
resp <-
performBHRequest $
getFieldCapsWith
(Just [testIndex])
defaultFieldCapsOptions
{ fcoFields = Just [FieldPattern "user"],
fcoExpandWildcards = Just [ExpandWildcardsOpen]
}
defaultFieldCapsRequest
liftIO $
KM.member (fromText "user") (fieldCapsResponseFields resp) `shouldBe` True
it "accepts an index_filter in the request body" $
withTestEnv $ do
_ <- insertData
resp <-
performBHRequest $
getFieldCapsWith
(Just [testIndex])
defaultFieldCapsOptions {fcoFields = Just [FieldPattern "age"]}
( defaultFieldCapsRequest
{ fieldCapsRequestIndexFilter = Just (MatchAllQuery Nothing)
}
)
liftIO $ do
let fields = fieldCapsResponseFields resp
KM.member (fromText "age") fields `shouldBe` True