runtime: count only trigger event frames and harden metrics tests
This commit is contained in:
@@ -6,6 +6,7 @@ module HomeAssistant.Runtime.Connection
|
|||||||
, writerAction
|
, writerAction
|
||||||
, encodeService
|
, encodeService
|
||||||
, dedupeBatch
|
, dedupeBatch
|
||||||
|
, isTriggerEvent
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
@@ -23,7 +24,7 @@ import Control.Concurrent (threadDelay)
|
|||||||
import Control.Exception (onException)
|
import Control.Exception (onException)
|
||||||
import Control.Exception.Annotated (throw)
|
import Control.Exception.Annotated (throw)
|
||||||
import Control.Lens ((^?))
|
import Control.Lens ((^?))
|
||||||
import Control.Monad (forever, forM_)
|
import Control.Monad (forever, forM_, when)
|
||||||
import Data.Aeson (Value, eitherDecode, encode, object, (.=))
|
import Data.Aeson (Value, eitherDecode, encode, object, (.=))
|
||||||
import Data.Aeson.Lens (key, _String)
|
import Data.Aeson.Lens (key, _String)
|
||||||
import Data.List (sort)
|
import Data.List (sort)
|
||||||
@@ -69,6 +70,9 @@ expectType expected msg =
|
|||||||
Just t | t == expected -> pure ()
|
Just t | t == expected -> pure ()
|
||||||
_ -> throw (Fatal $ "expected " <> expected <> ", got: " <> T.pack (show msg))
|
_ -> throw (Fatal $ "expected " <> expected <> ", got: " <> T.pack (show msg))
|
||||||
|
|
||||||
|
isTriggerEvent :: Value -> Bool
|
||||||
|
isTriggerEvent v = v ^? key "type" . _String == Just "event"
|
||||||
|
|
||||||
subscribe :: Bus -> WS.Connection -> S.Set T.Text -> IO ()
|
subscribe :: Bus -> WS.Connection -> S.Set T.Text -> IO ()
|
||||||
subscribe bus conn ents =
|
subscribe bus conn ents =
|
||||||
forM_ (S.toList ents) $ \entityId -> do
|
forM_ (S.toList ents) $ \entityId -> do
|
||||||
@@ -97,7 +101,7 @@ receiveLoop bus conn = forever $ do
|
|||||||
Right msg -> case eitherDecode msg of
|
Right msg -> case eitherDecode msg of
|
||||||
Left err -> putStrLn $ "[reader] skipping undecodable message: " <> err
|
Left err -> putStrLn $ "[reader] skipping undecodable message: " <> err
|
||||||
Right v -> do
|
Right v -> do
|
||||||
recordInbound bus
|
when (isTriggerEvent v) (recordInbound bus)
|
||||||
atomically $ writeTChan (busInbound bus) (Event v)
|
atomically $ writeTChan (busInbound bus) (Event v)
|
||||||
|
|
||||||
receiveJSON :: WS.Connection -> IO Value
|
receiveJSON :: WS.Connection -> IO Value
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import Data.Text (Text)
|
|||||||
import Data.Time (UTCTime (..), utc)
|
import Data.Time (UTCTime (..), utc)
|
||||||
import Data.UUID (fromString)
|
import Data.UUID (fromString)
|
||||||
import HomeAssistant.Controller (Service (..), Target(..))
|
import HomeAssistant.Controller (Service (..), Target(..))
|
||||||
import HomeAssistant.Runtime.Connection (encodeService, dedupeBatch)
|
import HomeAssistant.Runtime.Connection (encodeService, dedupeBatch, isTriggerEvent)
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
|
|
||||||
spec :: Spec
|
spec :: Spec
|
||||||
@@ -36,6 +36,14 @@ spec = do
|
|||||||
, "service_data" .= object ["brightness" .= (200 :: Int)]
|
, "service_data" .= object ["brightness" .= (200 :: Int)]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
describe "isTriggerEvent" $ do
|
||||||
|
it "is true for event frames" $
|
||||||
|
isTriggerEvent (object ["type" .= ("event" :: Text)]) `shouldBe` True
|
||||||
|
it "is false for result frames" $
|
||||||
|
isTriggerEvent (object ["type" .= ("result" :: Text)]) `shouldBe` False
|
||||||
|
it "is false when there is no type" $
|
||||||
|
isTriggerEvent (object ["id" .= (1 :: Int)]) `shouldBe` False
|
||||||
|
|
||||||
describe "dedupeBatch" $ do
|
describe "dedupeBatch" $ do
|
||||||
it "collapses identical calls to one" $
|
it "collapses identical calls to one" $
|
||||||
let batch = [ (req 1, lightOn [AreaId "x"])
|
let batch = [ (req 1, lightOn [AreaId "x"])
|
||||||
|
|||||||
+20
-19
@@ -4,7 +4,6 @@ module MetricsSpec (spec) where
|
|||||||
|
|
||||||
import Data.HashMap.Strict (HashMap)
|
import Data.HashMap.Strict (HashMap)
|
||||||
import qualified Data.HashMap.Strict as HM
|
import qualified Data.HashMap.Strict as HM
|
||||||
import Data.Int (Int64)
|
|
||||||
import Data.List (isPrefixOf)
|
import Data.List (isPrefixOf)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
@@ -18,7 +17,6 @@ import HomeAssistant.Runtime.Metrics
|
|||||||
, buildUpdateArgs
|
, buildUpdateArgs
|
||||||
, ensureRrd
|
, ensureRrd
|
||||||
, sampleAndUpdate
|
, sampleAndUpdate
|
||||||
, metricsAction
|
|
||||||
, parseInfoDs
|
, parseInfoDs
|
||||||
, schemaMatches
|
, schemaMatches
|
||||||
, AppMetrics (..)
|
, AppMetrics (..)
|
||||||
@@ -26,7 +24,7 @@ import HomeAssistant.Runtime.Metrics
|
|||||||
)
|
)
|
||||||
import qualified System.Metrics as M (Value (..))
|
import qualified System.Metrics as M (Value (..))
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import Control.Exception (try, SomeException)
|
import Control.Exception (try, SomeException, finally)
|
||||||
import Control.Monad (forM_)
|
import Control.Monad (forM_)
|
||||||
import System.Directory (findExecutable, getTemporaryDirectory, listDirectory, removeFile)
|
import System.Directory (findExecutable, getTemporaryDirectory, listDirectory, removeFile)
|
||||||
import System.Exit (ExitCode (ExitSuccess))
|
import System.Exit (ExitCode (ExitSuccess))
|
||||||
@@ -171,9 +169,10 @@ spec = do
|
|||||||
store <- Metrics.newStore
|
store <- Metrics.newStore
|
||||||
m <- registerAppMetrics store
|
m <- registerAppMetrics store
|
||||||
Counter.inc (amTriggersIn m)
|
Counter.inc (amTriggersIn m)
|
||||||
|
Counter.inc (amServicesOut m)
|
||||||
sample <- Metrics.sampleAll store
|
sample <- Metrics.sampleAll store
|
||||||
HM.lookup "hass.trigger.in" sample `shouldBe` Just (M.Counter 1)
|
HM.lookup "hass.trigger.in" sample `shouldBe` Just (M.Counter 1)
|
||||||
HM.lookup "hass.service.out" sample `shouldBe` Just (M.Counter 0)
|
HM.lookup "hass.service.out" sample `shouldBe` Just (M.Counter 1)
|
||||||
|
|
||||||
describe "end-to-end (rrdtool-gated)" $ do
|
describe "end-to-end (rrdtool-gated)" $ do
|
||||||
it "creates an rrd, samples, and updates it" $ do
|
it "creates an rrd, samples, and updates it" $ do
|
||||||
@@ -208,18 +207,20 @@ spec = do
|
|||||||
bakPrefix = "hass-controller-schema-change-test.rrd.bak-"
|
bakPrefix = "hass-controller-schema-change-test.rrd.bak-"
|
||||||
base = [ DsSpec "a" "a" Derive, DsSpec "b" "b" Gauge ]
|
base = [ DsSpec "a" "a" Derive, DsSpec "b" "b" Gauge ]
|
||||||
expanded = base ++ [ DsSpec "c" "c" Derive ]
|
expanded = base ++ [ DsSpec "c" "c" Derive ]
|
||||||
_ <- try (removeFile rrdPath) :: IO (Either SomeException ())
|
clean = do
|
||||||
ensureRrd rrdtool rrdPath base
|
stale <- filter (isPrefixOf bakPrefix) <$> listDirectory tmp
|
||||||
ensureRrd rrdtool rrdPath base
|
forM_ (rrdPath : map (\f -> tmp ++ "/" ++ f) stale) $ \f ->
|
||||||
noBackups <- filter (isPrefixOf bakPrefix) <$> listDirectory tmp
|
try (removeFile f) :: IO (Either SomeException ())
|
||||||
noBackups `shouldBe` []
|
clean
|
||||||
ensureRrd rrdtool rrdPath expanded
|
( do
|
||||||
backups <- filter (isPrefixOf bakPrefix) <$> listDirectory tmp
|
ensureRrd rrdtool rrdPath base
|
||||||
length backups `shouldBe` 1
|
ensureRrd rrdtool rrdPath base
|
||||||
(rc, out, _) <- readProcessWithExitCode rrdtool ["info", rrdPath] ""
|
noBackups <- filter (isPrefixOf bakPrefix) <$> listDirectory tmp
|
||||||
rc `shouldBe` ExitSuccess
|
noBackups `shouldBe` []
|
||||||
out `shouldContain` "ds[c].type"
|
ensureRrd rrdtool rrdPath expanded
|
||||||
_ <- try (removeFile rrdPath) :: IO (Either SomeException ())
|
backups <- filter (isPrefixOf bakPrefix) <$> listDirectory tmp
|
||||||
forM_ backups $ \f -> do
|
length backups `shouldBe` 1
|
||||||
_ <- try (removeFile (tmp ++ "/" ++ f)) :: IO (Either SomeException ())
|
(rc, out, _) <- readProcessWithExitCode rrdtool ["info", rrdPath] ""
|
||||||
pure ()
|
rc `shouldBe` ExitSuccess
|
||||||
|
out `shouldContain` "ds[c].type"
|
||||||
|
) `finally` clean
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ spec = pure ()
|
|||||||
--
|
--
|
||||||
-- spec :: Spec
|
-- spec :: Spec
|
||||||
-- spec = describe "runController" $ do
|
-- spec = describe "runController" $ do
|
||||||
-- it "feeds inbound events through the machine and forwards service calls" $ withBus InfoS $ \bus -> do
|
-- it "feeds inbound events through the machine and forwards service calls" $ withBus severity appMetrics $ \bus -> do
|
||||||
-- _ <- async (runController bus (Controller "test" lightController True))
|
-- _ <- async (runController bus (Controller "test" lightController True))
|
||||||
-- putStrLn "Before the delay"
|
-- putStrLn "Before the delay"
|
||||||
-- threadDelay 100000 -- let the controller dup its inbound channel
|
-- threadDelay 100000 -- let the controller dup its inbound channel
|
||||||
|
|||||||
Reference in New Issue
Block a user