packages feed

bloodhound-1.0.0.0: tests/Test/ReloadSearchAnalyzersSpec.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}

module Test.ReloadSearchAnalyzersSpec (spec) where

import Data.List (sort)
import Database.Bloodhound.Common.Types
import Optics (set, view)
import TestsUtils.Common
import TestsUtils.Import

-- | Stable ordering for equality: 'withQueries' preserves the order in
-- which params are emitted, but the tests compare the @Set@ of params
-- to avoid coupling to internal field ordering.
normalize :: [(Text, Maybe Text)] -> [(Text, Maybe Text)]
normalize = sort

spec :: Spec
spec = do
  -- ------------------------------------------------------------------ --
  -- Pure JSON decoder tests (no ES required).                          --
  -- ------------------------------------------------------------------ --
  describe "ReloadSearchAnalyzersResponse JSON parsing" $ do
    let docBody =
          "{\"_shards\":{\"total\":2,\"successful\":2,\"failed\":0},\
          \\"reload_details\":[{\"index\":\"my-index-000001\",\
          \\"reloaded_analyzers\":[\"my_synonyms\"],\
          \\"reloaded_node_ids\":[\"mfdqTXn_T7SGr2Ho2KT8uw\"]}]}"
        minimalBody =
          "{\"_shards\":{\"total\":0,\"successful\":0,\"failed\":0}}"

    it "parses the documented response (shards + one reload detail)" $ do
      let Just (r :: ReloadSearchAnalyzersResponse) = decode docBody
      shardTotal (rsarShards r) `shouldBe` 2
      shardsSuccessful (rsarShards r) `shouldBe` 2
      shardsFailed (rsarShards r) `shouldBe` 0
      -- skipped is absent in the doc example; parsed leniently as 0.
      shardsSkipped (rsarShards r) `shouldBe` 0
      case rsarReloadDetails r of
        [d] -> do
          rdIndex d `shouldBe` [qqIndexName|my-index-000001|]
          rdReloadedAnalyzers d `shouldBe` ["my_synonyms"]
          rdReloadedNodeIds d `shouldBe` ["mfdqTXn_T7SGr2Ho2KT8uw"]
        other ->
          expectationFailure ("expected singleton reload_details, got " <> show other)

    it "parses the minimal response with no reload_details as []" $ do
      let Just (r :: ReloadSearchAnalyzersResponse) = decode minimalBody
      rsarReloadDetails r `shouldBe` []

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

  describe "ReloadDetail JSON parsing" $ do
    let fullBody =
          "{\"index\":\"my-index-000001\",\
          \\"reloaded_analyzers\":[\"a\",\"b\"],\
          \\"reloaded_node_ids\":[\"n1\"]}"
        bareBody = "{\"index\":\"bare-idx\"}"

    it "parses all fields when present" $ do
      let Just (d :: ReloadDetail) = decode fullBody
      rdIndex d `shouldBe` [qqIndexName|my-index-000001|]
      rdReloadedAnalyzers d `shouldBe` ["a", "b"]
      rdReloadedNodeIds d `shouldBe` ["n1"]

    it "defaults the array fields to [] when absent" $ do
      let Just (d :: ReloadDetail) = decode bareBody
      rdIndex d `shouldBe` [qqIndexName|bare-idx|]
      rdReloadedAnalyzers d `shouldBe` []
      rdReloadedNodeIds d `shouldBe` []

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

  -- ------------------------------------------------------------------ --
  -- Optics.                                                            --
  -- ------------------------------------------------------------------ --
  describe "ReloadSearchAnalyzers lenses" $ do
    it "rsarReloadDetailsLens is a lawful get/set" $ do
      let Just (r :: ReloadSearchAnalyzersResponse) =
            decode "{\"_shards\":{\"total\":1,\"successful\":1,\"failed\":0}}"
          d = ReloadDetail [qqIndexName|ix|] ["an"] ["node"]
          r' = set rsarReloadDetailsLens [d] r
      view rsarReloadDetailsLens r' `shouldBe` [d]

    it "rdIndexLens is a lawful get/set" $ do
      let d = ReloadDetail [qqIndexName|ix|] [] []
          d' = set rdIndexLens [qqIndexName|other|] d
      view rdIndexLens d' `shouldBe` [qqIndexName|other|]

  -- ------------------------------------------------------------------ --
  -- Options rendering.                                                 --
  -- ------------------------------------------------------------------ --
  describe "ReloadSearchAnalyzersOptions URI param rendering" $ do
    it "defaultReloadSearchAnalyzersOptions emits no params" $
      reloadSearchAnalyzersOptionsParams defaultReloadSearchAnalyzersOptions
        `shouldBe` []

    it "renders ignore_unavailable / allow_no_indices as true/false" $ do
      let opts =
            defaultReloadSearchAnalyzersOptions
              { rsaoIgnoreUnavailable = Just False,
                rsaoAllowNoIndices = Just True
              }
      normalize (reloadSearchAnalyzersOptionsParams opts)
        `shouldBe` [ ("allow_no_indices", Just "true"),
                     ("ignore_unavailable", Just "false")
                   ]

    it "renders expand_wildcards as a comma-separated list" $ do
      let opts =
            defaultReloadSearchAnalyzersOptions
              { rsaoExpandWildcards = Just (ExpandWildcardsOpen :| [ExpandWildcardsClosed])
              }
      reloadSearchAnalyzersOptionsParams opts
        `shouldBe` [("expand_wildcards", Just "open,closed")]

  -- ------------------------------------------------------------------ --
  -- Endpoint shape (BHRequest, no ES required).                        --
  -- ------------------------------------------------------------------ --
  describe "reloadSearchAnalyzers endpoint shape" $ do
    let idx = [qqIndexName|my-idx|]

    it "POSTs /{index}/_reload_search_analyzers with no params by default" $ do
      let req = reloadSearchAnalyzers idx
      bhRequestMethod req `shouldBe` "POST"
      getRawEndpoint (bhRequestEndpoint req)
        `shouldBe` ["my-idx", "_reload_search_analyzers"]
      getRawEndpointQueries (bhRequestEndpoint req) `shouldBe` []

    it "sends an empty body" $ do
      let req = reloadSearchAnalyzers idx
      bhRequestBody req `shouldBe` Just ""

    it "forwards options as query params via the With variant" $ do
      let opts =
            defaultReloadSearchAnalyzersOptions
              { rsaoIgnoreUnavailable = Just True
              }
          req = reloadSearchAnalyzersWith opts idx
      lookup "ignore_unavailable" (getRawEndpointQueries (bhRequestEndpoint req))
        `shouldBe` Just (Just "true")