Update tests

This commit is contained in:
2026-08-21 11:55:27 +03:00
parent efcee8b90a
commit 5954c68682
5 changed files with 31 additions and 16 deletions
+1 -2
View File
@@ -55,8 +55,7 @@ runController bus (Controller _name machine) = do
go inbound f = do go inbound f = do
msg <- atomically (readTChan inbound) msg <- atomically (readTChan inbound)
uuid <- UUID.V4.nextRandom uuid <- UUID.V4.nextRandom
-- (_, f') <- step (channelHassEval bus) f (Event msg) (_, f') <- step (channelHassEval bus) uuid f (Event msg)
(_, f') <- step (dryRunHassEval (busGen bus)) uuid f (Event msg)
go inbound f' go inbound f'
defaultMain :: IO () defaultMain :: IO ()
+13 -3
View File
@@ -97,6 +97,16 @@ encodeService callId Service{..} = object $
, "type" .= ("call_service" :: T.Text) , "type" .= ("call_service" :: T.Text)
, "domain" .= serviceDomain , "domain" .= serviceDomain
, "service" .= serviceName , "service" .= serviceName
, "target" .= object [ "entity_id" .= [e | EntityId e <- serviceTarget] , "target" .= targetObject serviceTarget
, "area_id" .= [a | AreaId a <- serviceTarget]] ] <> maybe [] (\d -> ["service_data" .= d]) serviceData
] <> maybe [] (\d -> ["data" .= d]) serviceData
-- | A single target encodes as a scalar; multiple encode as a list. Empty
-- lists are omitted so Home Assistant receives only populated keys.
targetObject :: [Target] -> Value
targetObject targets = object $ entityPart <> areaPart
where
entityPart = emit "entity_id" [e | EntityId e <- targets]
areaPart = emit "area_id" [a | AreaId a <- targets]
emit _ [] = []
emit k [x] = [k .= x]
emit k many = [k .= many]
+2 -2
View File
@@ -9,7 +9,7 @@ import Control.Concurrent.STM
, writeTChan , writeTChan
) )
import Data.Aeson (Value (..)) import Data.Aeson (Value (..))
import HomeAssistant.Controller (HASSEff (..), Service (..)) import HomeAssistant.Controller (HASSEff (..), Service (..), Target(..))
import HomeAssistant.Runtime.Bus import HomeAssistant.Runtime.Bus
import Test.Hspec import Test.Hspec
@@ -28,7 +28,7 @@ spec = describe "Bus" $ do
it "channelHassEval writes CallService to the outbound channel" $ do it "channelHassEval writes CallService to the outbound channel" $ do
bus <- newBus 0 bus <- newBus 0
let svc = Service "light" "turn_on" Nothing "light.bedroom_masse" let svc = Service "light" "turn_on" Nothing [EntityId "light.bedroom_masse"]
channelHassEval bus (CallService svc) channelHassEval bus (CallService svc)
atomically (readTChan (busOutbound bus)) `shouldReturn` svc atomically (readTChan (busOutbound bus)) `shouldReturn` svc
+3 -3
View File
@@ -4,14 +4,14 @@ module ConnectionSpec (spec) where
import Data.Aeson (object, (.=)) import Data.Aeson (object, (.=))
import Data.Text (Text) import Data.Text (Text)
import HomeAssistant.Controller (Service (..)) import HomeAssistant.Controller (Service (..), Target(..))
import HomeAssistant.Runtime.Connection (encodeService) import HomeAssistant.Runtime.Connection (encodeService)
import Test.Hspec import Test.Hspec
spec :: Spec spec :: Spec
spec = describe "encodeService" $ do spec = describe "encodeService" $ do
it "encodes a call_service message" $ it "encodes a call_service message" $
encodeService 7 (Service "light" "turn_on" Nothing "light.bedroom_masse") encodeService 7 (Service "light" "turn_on" Nothing [EntityId "light.bedroom_masse"])
`shouldBe` object `shouldBe` object
[ "id" .= (7 :: Int) [ "id" .= (7 :: Int)
, "type" .= ("call_service" :: Text) , "type" .= ("call_service" :: Text)
@@ -21,7 +21,7 @@ spec = describe "encodeService" $ do
] ]
it "includes service_data when present" $ it "includes service_data when present" $
encodeService 8 (Service "light" "turn_on" (Just (object ["brightness" .= (200 :: Int)])) "light.bedroom_masse") encodeService 8 (Service "light" "turn_on" (Just (object ["brightness" .= (200 :: Int)])) [EntityId "light.bedroom_masse"])
`shouldBe` object `shouldBe` object
[ "id" .= (8 :: Int) [ "id" .= (8 :: Int)
, "type" .= ("call_service" :: Text) , "type" .= ("call_service" :: Text)
+12 -6
View File
@@ -2,11 +2,11 @@
module RuntimeSpec (spec) where module RuntimeSpec (spec) where
import Control.Concurrent (threadDelay) import Control.Concurrent (threadDelay)
import Control.Concurrent.Async (async) import Control.Concurrent.Async (async, race)
import Control.Concurrent.STM (atomically, isEmptyTChan, readTChan, writeTChan) import Control.Concurrent.STM (atomically, isEmptyTChan, readTChan, writeTChan)
import Data.Aeson (Value, object, (.=)) import Data.Aeson (Value, object, (.=))
import Data.Text (Text) import Data.Text (Text)
import HomeAssistant.Controller (light, lightController) import HomeAssistant.Controller (light, lightController, Target (..))
import HomeAssistant.Runtime (Controller (..), runController) import HomeAssistant.Runtime (Controller (..), runController)
import HomeAssistant.Runtime.Bus import HomeAssistant.Runtime.Bus
import Test.Hspec import Test.Hspec
@@ -16,15 +16,21 @@ spec = describe "runController" $ do
it "feeds inbound events through the machine and forwards service calls" $ do it "feeds inbound events through the machine and forwards service calls" $ do
bus <- newBus 0 bus <- newBus 0
_ <- async (runController bus (Controller "test" lightController)) _ <- async (runController bus (Controller "test" lightController))
putStrLn "Before the delay"
threadDelay 100000 -- let the controller dup its inbound channel threadDelay 100000 -- let the controller dup its inbound channel
putStrLn "After the delay"
atomically $ writeTChan (busInbound bus) (doorEvent "on") -- initial value: no change event atomically $ writeTChan (busInbound bus) (doorEvent "on") -- initial value: no change event
atomically $ writeTChan (busInbound bus) (doorEvent "off") -- door closes: lights on atomically $ writeTChan (busInbound bus) (doorEvent "off") -- door closes: lights on
atomically $ writeTChan (busInbound bus) (doorEvent "on") -- door opens: lights off atomically $ writeTChan (busInbound bus) (doorEvent "on") -- door opens: lights off
svc1 <- atomically (readTChan (busOutbound bus)) putStrLn "After the writes"
svc2 <- atomically (readTChan (busOutbound bus)) svc1 <- boundedRead (busOutbound bus)
svc1 `shouldBe` light True svc2 <- boundedRead (busOutbound bus)
svc2 `shouldBe` light False putStrLn "After the reads"
svc1 `shouldBe` Right (light [EntityId "light.bedroom_masse"] True)
svc2 `shouldBe` Right (light [EntityId "light.bedroom_masse"] False)
atomically (isEmptyTChan (busOutbound bus)) `shouldReturn` True atomically (isEmptyTChan (busOutbound bus)) `shouldReturn` True
where
boundedRead channel = race (threadDelay 10000) (atomically (readTChan channel))
doorEvent :: Text -> Value doorEvent :: Text -> Value
doorEvent state = object doorEvent state = object