packages feed

bloodhound-1.0.0.0: tests/Test/ScriptLanguagesSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Test.ScriptLanguagesSpec (spec) where

import Database.Bloodhound.Client.Cluster (BackendType (..))
import Database.Bloodhound.Common.Types
import TestsUtils.Common
import TestsUtils.Import

spec :: Spec
spec = do
  -- ------------------------------------------------------------------ --
  -- Pure JSON decoder tests (no ES required).                          --
  -- ------------------------------------------------------------------ --
  describe "ScriptLanguagesResponse JSON parsing" $ do
    let emptyBody = "{\"types_allowed\":[],\"language_contexts\":[]}"
        -- Captured from a live ES 7.17.25 cluster (trimmed to the
        -- expression + mustache languages; painless carries a long
        -- contexts list omitted here for brevity).
        fullBody =
          "{\"types_allowed\":[\"inline\",\"stored\"],\
          \\"language_contexts\":[\
          \{\"language\":\"expression\",\"contexts\":[\"aggs\",\"field\",\"filter\"]},\
          \{\"language\":\"mustache\",\"contexts\":[\"template\"]}\
          \]}"

    it "parses the empty response" $ do
      let Just (r :: ScriptLanguagesResponse) = decode emptyBody
      slrTypesAllowed r `shouldBe` []
      slrLanguageContexts r `shouldBe` []

    it "parses types_allowed and language_contexts" $ do
      let Just (r :: ScriptLanguagesResponse) = decode fullBody
      slrTypesAllowed r `shouldBe` ["inline", "stored"]
      length (slrLanguageContexts r) `shouldBe` 2
      let firstCtx = head (slrLanguageContexts r)
      slcLanguage firstCtx `shouldBe` ScriptLanguage "expression"
      slcContexts firstCtx `shouldContain` ["aggs", "field", "filter"]

    it "treats missing arrays as the empty list" $ do
      let Just (r :: ScriptLanguagesResponse) = decode "{}"
      slrTypesAllowed r `shouldBe` []
      slrLanguageContexts r `shouldBe` []

    it "round-trips the full response via ToJSON/FromJSON" $ do
      let Just (original :: ScriptLanguagesResponse) = decode fullBody
          reDecoded = decode (encode original) :: Maybe ScriptLanguagesResponse
      Just original `shouldBe` reDecoded

  describe "ScriptLanguageContext JSON parsing" $ do
    let body =
          "{\"language\":\"painless\",\"contexts\":[\"aggs\",\"score\",\"update\"]}"

    it "parses language and contexts" $ do
      let Just (c :: ScriptLanguageContext) = decode body
      slcLanguage c `shouldBe` ScriptLanguage "painless"
      slcContexts c `shouldBe` ["aggs", "score", "update"]

    it "uses parseJSON directly (covers the withObject path)" $
      case parseEither parseJSON (object ["language" .= String "expression"]) ::
             Either String ScriptLanguageContext of
        Right c -> slcLanguage c `shouldBe` ScriptLanguage "expression"
        Left err -> expectationFailure ("parseJSON failed: " <> err)

  -- ------------------------------------------------------------------ --
  -- Endpoint shape: pure checks against the BHRequest value; no live   --
  -- backend needed.                                                     --
  -- ------------------------------------------------------------------ --
  describe "getScriptLanguages endpoint shape" $ do
    it "GETs /_script_language with no body and no params" $ do
      let req = getScriptLanguages
      bhRequestMethod req `shouldBe` "GET"
      getRawEndpoint (bhRequestEndpoint req) `shouldBe` ["_script_language"]
      getRawEndpointQueries (bhRequestEndpoint req) `shouldBe` []
      bhRequestBody req `shouldBe` Nothing

  -- ------------------------------------------------------------------ --
  -- Live backend tests (need ES on ES_TEST_SERVER, default 9200).      --
  -- _script_language is served by ES 7.x/8.x/9.x and OpenSearch        --
  -- 2.x/3.x, but returns HTTP 500 on OpenSearch 1.3 (a server bug:     --
  -- null_pointer_exception in the response body). The block is gated   --
  -- by 'backendSpecific' so the OS 1.3 matrix job marks it pending     --
  -- instead of red.                                                    --
  -- ------------------------------------------------------------------ --
  describe "getScriptLanguages live API"
    $ backendSpecific
      [ ElasticSearch7,
        ElasticSearch8,
        ElasticSearch9,
        OpenSearch2,
        OpenSearch3
      ]
    $ do
      it "returns inline/stored as allowed types and a painless entry" $
        withTestEnv $ do
          r <- performBHRequest getScriptLanguages
          liftIO $ do
            slrTypesAllowed r `shouldContain` ["inline", "stored"]
            map slcLanguage (slrLanguageContexts r)
              `shouldContain` [ScriptLanguage "painless"]