git.iko.soy/typeable/bloodhound
on master help sign in
Tests passing with snapshots repo API
commitabb7052f57f3cecd028564abb087be5444ebbb2f authorMichael Xavier <michael@michaelxavier.net> dateWed 20 Jul 2016, 10:58 (10 years ago) parent06819a6
4 files changed+118−45
bloodhound.cabal+3−2 src/Database/Bloodhound/Client.hs+22−21 src/Database/Bloodhound/Types.hs+27−17 tests/tests.hs+66−5
bloodhound.cabal+3−2
@@ -74,8 +74,9 @@ test-suite tests
7474 quickcheck-properties,
7575 derive,
7676 errors,
77− resourcet,
78− temporary-resourcet
77+ exceptions,
78+ temporary,
79+ unix
7980 default-language: Haskell2010
8081
8182test-suite doctests
src/Database/Bloodhound/Client.hs+22−21
@@ -75,32 +75,33 @@ module Database.Bloodhound.Client
7575 )
7676 where
7777
78−import qualified Blaze.ByteString.Builder as BB
79−import Control.Applicative as A
78+import qualified Blaze.ByteString.Builder as BB
79+import Control.Applicative as A
8080import Control.Monad
8181import Control.Monad.Catch
8282import Control.Monad.IO.Class
8383import Data.Aeson
8484import Data.ByteString.Lazy.Builder
85−import qualified Data.ByteString.Lazy.Char8 as L
86−import Data.Foldable (toList)
87−import qualified Data.HashMap.Strict as HM
85+import qualified Data.ByteString.Lazy.Char8 as L
86+import Data.Foldable (toList)
87+import qualified Data.HashMap.Strict as HM
8888import Data.Ix
89−import qualified Data.List as LS (filter, foldl')
90−import Data.List.NonEmpty (NonEmpty (..))
91−import Data.Maybe (catMaybes, fromMaybe, isJust)
89+import qualified Data.List as LS (filter, foldl')
90+import Data.List.NonEmpty (NonEmpty (..))
91+import Data.Maybe (catMaybes, fromMaybe,
92+ isJust)
9293import Data.Monoid
93−import Data.Text (Text)
94−import qualified Data.Text as T
95−import qualified Data.Text.Encoding as T
94+import Data.Text (Text)
95+import qualified Data.Text as T
96+import qualified Data.Text.Encoding as T
9697import Data.Time.Clock
97−import qualified Data.Vector as V
98+import qualified Data.Vector as V
9899import Network.HTTP.Client
99−import qualified Network.HTTP.Types.Method as NHTM
100−import qualified Network.HTTP.Types.Status as NHTS
101−import qualified Network.HTTP.Types.URI as NHTU
102−import qualified Network.URI as URI
103−import Prelude hiding (filter, head)
100+import qualified Network.HTTP.Types.Method as NHTM
101+import qualified Network.HTTP.Types.Status as NHTS
102+import qualified Network.HTTP.Types.URI as NHTU
103+import qualified Network.URI as URI
104+import Prelude hiding (filter, head)
104105
105106import Database.Bloodhound.Types
106107
@@ -291,7 +292,7 @@ instance FromJSON GSRs where
291292 parseJSON = withObject "Collection of GenericSnapshotRepo" parse
292293 where
293294 parse = fmap GSRs . mapM (uncurry go) . HM.toList
294− go rawName = withObject "GenericSnapshotRepo" $ \o ->
295+ go rawName = withObject "GenericSnapshotRepo" $ \o -> do
295296 GenericSnapshotRepo (SnapshotRepoName rawName) <$> o .: "type"
296297 <*> o .: "settings"
297298
@@ -304,14 +305,14 @@ updateSnapshotRepo
304305 => SnapshotRepoUpdateSettings
305306 -- ^ Use 'defaultSnapshotRepoUpdateSettings' if unsure
306307 -> repo
307− -> m Reply --TODO: more specific?
308+ -> m Reply
308309updateSnapshotRepo SnapshotRepoUpdateSettings {..} repo = bindM2 post url (return (Just body))
309310 where
310− url = addQuery params <$> joinPath ["_snapshots", snapshotRepoName gSnapshotRepoName]
311+ url = addQuery params <$> joinPath ["_snapshot", snapshotRepoName gSnapshotRepoName]
311312 params
312313 | repoUpdateVerify = []
313314 | otherwise = [("verify", Just "false")]
314− body = encode $ object [ "types" .= gSnapshotRepoName
315+ body = encode $ object [ "type" .= gSnapshotRepoType
315316 , "settings" .= gSnapshotRepoSettings
316317 ]
317318 GenericSnapshotRepo {..} = toGSnapshotRepo repo
src/Database/Bloodhound/Types.hs+27−17
@@ -2988,7 +2988,7 @@ instance FromJSON UpdatableIndexSetting where
29882988 <|> blocksWrite `taggedAt` ["blocks", "write"]
29892989 <|> blocksMetaData `taggedAt` ["blocks", "metadata"]
29902990 where taggedAt f ks = taggedAt' f (Object o) ks
2991− taggedAt' f v [] = f =<< (parseJSON v <|> (parseJSON =<< unStringlyTypeJSON v))
2991+ taggedAt' f v [] = f =<< (parseJSON v <|> (parseJSON (unStringlyTypeJSON v)))
29922992 taggedAt' f v (k:ks) = withObject "Object" (\o -> do v' <- o .: k
29932993 taggedAt' f v' ks) v
29942994 numberOfReplicas = pure . NumberOfReplicas
@@ -3030,18 +3030,17 @@ instance FromJSON IndexSettingsSummary where
30303030 redundant (NumberOfReplicas _) = True
30313031 redundant _ = False
30323032
3033−-- | For some reason in the settings API, all leaf values get returned
3033+-- | For some reason in several settings APIs, all leaf values get returned
30343034-- as strings. This function attepmts to recover from this for all
3035−-- non-recursive JSON types. If nothing can be done or the same value
3036−-- would be return, it returns 'mzero'
3037−unStringlyTypeJSON :: MonadPlus m => Value -> m Value
3038−unStringlyTypeJSON (String "true") = return (Bool True)
3039−unStringlyTypeJSON (String "false") = return (Bool False)
3040−unStringlyTypeJSON (String "null") = return Null
3041−unStringlyTypeJSON (String t) = case readMay (T.unpack t) of
3042− Just n -> return (Number n)
3043− Nothing -> mzero
3044−unStringlyTypeJSON _ = mzero
3035+-- non-recursive JSON types. If nothing can be done, the value is left alone.
3036+unStringlyTypeJSON :: Value -> Value
3037+unStringlyTypeJSON (String "true") = Bool True
3038+unStringlyTypeJSON (String "false") = Bool False
3039+unStringlyTypeJSON (String "null") = Null
3040+unStringlyTypeJSON v@(String t) = case readMay (T.unpack t) of
3041+ Just n -> Number n
3042+ Nothing -> v
3043+unStringlyTypeJSON v = v
30453044
30463045
30473046parseSettings :: Object -> Parser [UpdatableIndexSetting]
@@ -3680,7 +3679,7 @@ data SnapshotRepoPattern = ExactRepo SnapshotRepoName
36803679
36813680-- | The unique name of a snapshot repository.
36823681newtype SnapshotRepoName = SnapshotRepoName { snapshotRepoName :: Text }
3683− deriving (Eq, Generic, Show, Typeable, ToJSON, FromJSON)
3682+ deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
36843683
36853684
36863685-- | A generic representation of a snapshot repo. This is what gets
@@ -3696,15 +3695,26 @@ data GenericSnapshotRepo = GenericSnapshotRepo {
36963695 } deriving (Eq, Generic, Show, Typeable)
36973696
36983697
3698+instance SnapshotRepo GenericSnapshotRepo where
3699+ toGSnapshotRepo = id
3700+ fromGSnapshotRepo = Right
3701+
3702+
36993703newtype SnapshotRepoType = SnapshotRepoType { snapshotRepoType :: Text }
3700− deriving (Eq, Generic, Show, Typeable, ToJSON, FromJSON)
3704+ deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
37013705
37023706
37033707-- | Opaque representation of snapshot repo settings. Instances of
37043708-- 'SnapshotRepo' will produce this.
37053709newtype GenericSnapshotRepoSettings = GenericSnapshotRepoSettings { gSnapshotRepoSettingsObject :: Object }
3706− deriving (Eq, Generic, Show, Typeable, ToJSON, FromJSON)
3710+ deriving (Eq, Generic, Show, Typeable, ToJSON)
3711+
37073712
3713+ -- Regardless of whether you send strongly typed json, my version of
3714+ -- ES sends back stringly typed json in the settings, e.g. booleans
3715+ -- as strings, so we'll try to convert them.
3716+instance FromJSON GenericSnapshotRepoSettings where
3717+ parseJSON = fmap (GenericSnapshotRepoSettings . fmap unStringlyTypeJSON). parseJSON
37083718
37093719-- | The result of running 'verifySnapshotRepo'. --TODO: more detail once you know what a failure looks like
37103720newtype SnapshotVerification = SnapshotVerification { snapshotNodeVerifications :: [SnapshotNodeVerification] }
@@ -3730,11 +3740,11 @@ data SnapshotNodeVerification = SnapshotNodeVerification {
37303740-- | Unique, automatically-generated name assigned to nodes that are
37313741-- usually returned in node-oriented APIs.
37323742newtype FullNodeId = FullNodeId { fullNodeId :: Text }
3733− deriving (Eq, Generic, Show, Typeable, FromJSON)
3743+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
37343744
37353745
37363746newtype NodeName = NodeName { nodeName :: Text }
3737− deriving (Eq, Generic, Show, Typeable, FromJSON)
3747+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
37383748
37393749
37403750data SnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings {
tests/tests.hs+66−5
@@ -3,6 +3,7 @@
33{-# LANGUAGE FlexibleContexts #-}
44{-# LANGUAGE GeneralizedNewtypeDeriving #-}
55{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE RecordWildCards #-}
67{-# LANGUAGE ScopedTypeVariables #-}
78{-# LANGUAGE TemplateHaskell #-}
89{-# LANGUAGE TypeOperators #-}
@@ -11,10 +12,10 @@ module Main where
1112
1213import Control.Applicative
1314import Control.Error
14−import Control.Exception
15+import Control.Exception (evaluate)
1516import Control.Monad
17+import Control.Monad.Catch
1618import Control.Monad.Reader
17−import Control.Monad.Trans.Resource
1819import Data.Aeson
1920import Data.Aeson.Types (parseEither)
2021import qualified Data.ByteString.Lazy.Char8 as BL8
@@ -26,6 +27,7 @@ import Data.List.NonEmpty (NonEmpty (..))
2627import qualified Data.List.NonEmpty as NE
2728import qualified Data.Map.Strict as M
2829import Data.Monoid
30+import Data.Ord (comparing)
2931import Data.Proxy
3032import Data.Text (Text)
3133import qualified Data.Text as T
@@ -40,6 +42,7 @@ import Network.HTTP.Client hiding (Proxy)
4042import qualified Network.HTTP.Types.Status as NHTS
4143import Prelude hiding (filter)
4244import System.IO.Temp
45+import System.Posix.Files
4346import Test.Hspec
4447import Test.QuickCheck.Property.Monoid (T (..), eq, prop_Monoid)
4548
@@ -56,10 +59,14 @@ testMapping = MappingName "tweet"
5659withTestEnv :: BH IO a -> IO a
5760withTestEnv = withBH defaultManagerSettings testServer
5861
59−validateStatus :: Response body -> Int -> Expectation
62+validateStatus :: Show body => Response body -> Int -> Expectation
6063validateStatus resp expected =
61− (NHTS.statusCode $ responseStatus resp)
62− `shouldBe` (expected :: Int)
64+ if actual == expected
65+ then return ()
66+ else expectationFailure ("Expected " <> show expected <> " but got " <> show actual <> ": " <> show body)
67+ where
68+ actual = NHTS.statusCode (responseStatus resp)
69+ body = responseBody resp
6370
6471createExampleIndex :: BH IO Reply
6572createExampleIndex = createIndex (IndexSettings (ShardCount 1) (ReplicaCount 0)) testIndex
@@ -314,6 +321,28 @@ searchExpectSource src expected = do
314321 liftIO $
315322 value `shouldBe` expected
316323
324+withSnapshotRepo
325+ :: ( MonadMask m
326+ , MonadBH m
327+ )
328+ => SnapshotRepoName
329+ -> (GenericSnapshotRepo -> m a)
330+ -> m a
331+withSnapshotRepo srn@(SnapshotRepoName n) f =
332+ withSystemTempDirectory (T.unpack n) $ \dir -> bracket (alloc dir) free f
333+ where
334+ alloc dir = do
335+ liftIO (setFileMode dir mode)
336+ let repo = FsSnapshotRepo srn dir True Nothing Nothing Nothing
337+ resp <- updateSnapshotRepo defaultSnapshotRepoUpdateSettings repo
338+ liftIO (validateStatus resp 200)
339+ return (toGSnapshotRepo repo)
340+ mode = ownerModes `unionFileModes` groupModes `unionFileModes` otherModes
341+ free GenericSnapshotRepo {..} = do
342+ resp <- deleteSnapshotRepo gSnapshotRepoName
343+ liftIO (validateStatus resp 200)
344+
345+
317346data BulkTest = BulkTest { name :: Text } deriving (Eq, Generic, Show)
318347instance FromJSON BulkTest where
319348 parseJSON = genericParseJSON defaultOptions
@@ -1379,6 +1408,38 @@ main = hspec $ do
13791408 Left e -> expectationFailure ("Expected a right but got Left " <> show e)
13801409 Right _ -> return ()
13811410
1411+ it "finds an existing list of repos" $ withTestEnv $ do
1412+ let r1n = SnapshotRepoName "bloodhound-repo1"
1413+ let r2n = SnapshotRepoName "bloodhound-repo2"
1414+ withSnapshotRepo r1n $ \r1 ->
1415+ withSnapshotRepo r2n $ \r2 -> do
1416+ repos <- getSnapshotRepos (SnapshotRepoList (ExactRepo r1n :| [ExactRepo r2n]))
1417+ liftIO $ case repos of
1418+ Right xs -> do
1419+ let srt = L.sortBy (comparing gSnapshotRepoName)
1420+ srt xs `shouldBe` srt [r1, r2]
1421+ Left e -> expectationFailure (show e)
1422+
1423+ it "creates and updates with updateSnapshotRepo" $ withTestEnv $ do
1424+ let r1n = SnapshotRepoName "bloodhound-repo1"
1425+ withSnapshotRepo r1n $ \r1 -> do
1426+ let Just (String dir) = HM.lookup "location" (gSnapshotRepoSettingsObject (gSnapshotRepoSettings r1))
1427+ let noCompression = FsSnapshotRepo r1n (T.unpack dir) False Nothing Nothing Nothing
1428+ resp <- updateSnapshotRepo defaultSnapshotRepoUpdateSettings noCompression
1429+ liftIO (validateStatus resp 200)
1430+ Right [roundtrippedNoCompression] <- getSnapshotRepos (SnapshotRepoList (ExactRepo r1n :| []))
1431+ liftIO (roundtrippedNoCompression `shouldBe` toGSnapshotRepo noCompression)
1432+
1433+ it "can verify existing repos" $ withTestEnv $ do
1434+ let r1n = SnapshotRepoName "bloodhound-repo1"
1435+ withSnapshotRepo r1n $ \_ -> do
1436+ res <- verifySnapshotRepo r1n
1437+ liftIO $ case res of
1438+ Right (SnapshotVerification vs)
1439+ | null vs -> expectationFailure "Expected nonempty set of verifying nodes"
1440+ | otherwise -> return ()
1441+ Left e -> expectationFailure (show e)
1442+
13821443 describe "Enum DocVersion" $ do
13831444 it "follows the laws of Enum, Bounded" $ do
13841445 evaluate (succ maxBound :: DocVersion) `shouldThrow` anyErrorCall