@@ -1,24 +1,32 @@
1−{-# LANGUAGE OverloadedStrings #-}
1+{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE RecordWildCards #-}
2+{-# LANGUAGE RecordWildCards #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
3−{-# LANGUAGE TemplateHaskell #-}
4+{-# LANGUAGE TemplateHaskell #-}
9-------------------------------------------------------------------------------
10-------------------------------------------------------------------------------
11+import Control.Applicative
10−import Control.Lens hiding (mapping)
12+import Control.Lens hiding (mapping, (.=))
11import Control.Monad
13import Control.Monad
12import Control.Monad.IO.Class
14import Control.Monad.IO.Class
13import Data.Aeson
15import Data.Aeson
14import Data.Aeson.Lens
16import Data.Aeson.Lens
17+import Data.Aeson.Types
18+import qualified Data.HashMap.Strict as HM
15import qualified Data.Map as M
19import qualified Data.Map as M
16import Data.Monoid
20import Data.Monoid
21+import Data.Scientific
22+import qualified Data.Vector as V
17import Database.Bloodhound hiding (key)
23import Database.Bloodhound hiding (key)
18import Network.HTTP.Client
24import Network.HTTP.Client
19import Network.HTTP.Types.Status
25import Network.HTTP.Types.Status
26+import Test.QuickCheck.Instances ()
20import Test.Tasty
27import Test.Tasty
21import Test.Tasty.HUnit
28import Test.Tasty.HUnit
29+import Test.Tasty.QuickCheck
22-------------------------------------------------------------------------------
30-------------------------------------------------------------------------------
23import Katip
31import Katip
24import Katip.Scribes.ElasticSearch
32import Katip.Scribes.ElasticSearch
@@ -29,6 +37,7 @@ main :: IO ()
29main = defaultMain $ testGroup "katip-elasticsearch"
37main = defaultMain $ testGroup "katip-elasticsearch"
31 withResource setupSearch teardownSearch esTests
39 withResource setupSearch teardownSearch esTests
@@ -36,7 +45,7 @@ main = defaultMain $ testGroup "katip-elasticsearch"
36setupSearch :: IO (Scribe, IO ())
45setupSearch :: IO (Scribe, IO ())
37setupSearch = do
46setupSearch = do
38 bh recreateESSchema
47 bh recreateESSchema
39− mkEsScribe defaultEsScribeCfg svr ixn mn DebugS V3
48+ mkEsScribe defaultEsScribeCfg { essAnnotateTypes = True } svr ixn mn DebugS V3
42-------------------------------------------------------------------------------
51-------------------------------------------------------------------------------
@@ -51,13 +60,73 @@ esTests :: IO (Scribe, IO ()) -> TestTree
51esTests setup = testGroup "elasticsearch scribe"
60esTests setup = testGroup "elasticsearch scribe"
53 testCase "it flushes to elasticsearch" $ withTestLogging setup $ \done -> do
62 testCase "it flushes to elasticsearch" $ withTestLogging setup $ \done -> do
54− $(logT) () mempty InfoS "A test message"
63+ $(logT) (ExampleCtx True) mempty InfoS "A test message"
55 liftIO $ do
64 liftIO $ do
57 logs <- getLogs
66 logs <- getLogs
58 length logs @?= 1
67 length logs @?= 1
59 let l = head logs
68 let l = head logs
60 l ^? key "_source" . key "msg" . _String @?= Just "A test message"
69 l ^? key "_source" . key "msg" . _String @?= Just "A test message"
70+ l ^? key "_source" . key "data" . key "whatever::boolean" . _Bool @?= Just True
74+-------------------------------------------------------------------------------
75+data ExampleCtx = ExampleCtx {
79+instance ToJSON ExampleCtx where
80+ toJSON c = object ["whatever" .= ecBool c]
83+instance ToObject ExampleCtx
86+instance LogItem ExampleCtx where
87+ payloadKeys _ _ = AllKeys
89+-------------------------------------------------------------------------------
90+typeAnnotatedTests :: TestTree
91+typeAnnotatedTests = testGroup "TypeAnnotated"
93+ testCase "annotates values on toJSON" $ do
94+ toJSON (TypeAnnotated exampleValue) @?= annotatedExampleValue
95+ , testCase "deannotates on parseJSON" $ do
96+ parseEither parseJSON (toJSON exampleValue) @?= Right exampleValue
97+ , testProperty "roundtrips the same as raw" $ \(v :: Value) ->
98+ let res = typeAnnotatedValue <$> (parseEither parseJSON (toJSON (TypeAnnotated v)))
103+-------------------------------------------------------------------------------
104+exampleValue :: Value
105+exampleValue = Array $ V.fromList [Null, Object ob]
107+ ob = HM.fromList [ ("a bool", Bool False)
108+ , ("a long", Number 24)
109+ , ("a double", Number 52.3)
110+ , ("a string", String "s")
112+ , ("a map", Object (HM.singleton "baz" (Bool True)))
116+-------------------------------------------------------------------------------
117+annotatedExampleValue :: Value
118+annotatedExampleValue = Array $ V.fromList
121+ , Object $ HM.fromList
123+ ("a map",Object $ HM.fromList [("baz::boolean", Bool True)])
124+ , ("a bool::boolean", Bool False)
125+ , ("a null::null", Null)
126+ , ("a string::string", String "s")
127+ , ("a double::double", Number 52.3)
128+ , ("a long::long", Number 24.0)
@@ -126,3 +195,21 @@ createESSchema :: BH IO Reply
126createESSchema = do
195createESSchema = do
127 createIndex ixs ixn
196 createIndex ixs ixn
128 putMapping ixn mn mapping
197 putMapping ixn mn mapping
200+-------------------------------------------------------------------------------
201+instance Arbitrary Value where
203+ [ Object <$> reduceSize arbitrary
204+ , Array . V.fromList <$> reduceSize arbitrary
205+ , String <$> arbitrary
206+ , Number <$> (scientific <$> arbitrary <*> arbitrary)
207+ , Bool <$> arbitrary
212+-------------------------------------------------------------------------------
213+-- | Reduce the size of Arbitrary input for the given generator
214+reduceSize :: Gen a -> Gen a
215+reduceSize f = sized $ \ n -> resize (n `div` 2) f