module Hydra.Network.HeartbeatSpec where import Hydra.Prelude import Test.Hydra.Prelude import Control.Concurrent.Class.MonadSTM (MonadSTM (readTVarIO), modifyTVar', newTVarIO) import Control.Monad.IOSim (runSimOrThrow) import Hydra.Network (Network (..), NodeId (..)) import Hydra.Network.Heartbeat (Heartbeat (..), withHeartbeat) import Hydra.Network.Message (Connectivity (Connected, Disconnected)) spec :: Spec spec :: Spec spec = Spec -> Spec forall a. SpecWith a -> SpecWith a parallel (Spec -> Spec) -> Spec -> Spec forall a b. (a -> b) -> a -> b $ do let captureOutgoing :: TVar m [a] -> p -> (Network m a -> b) -> b captureOutgoing TVar m [a] msgqueue p _cb Network m a -> b action = Network m a -> b action (Network m a -> b) -> Network m a -> b forall a b. (a -> b) -> a -> b $ Network{$sel:broadcast:Network :: a -> m () broadcast = \a msg -> STM m () -> m () forall a. HasCallStack => STM m a -> m a forall (m :: * -> *) a. (MonadSTM m, HasCallStack) => STM m a -> m a atomically (STM m () -> m ()) -> STM m () -> m () forall a b. (a -> b) -> a -> b $ TVar m [a] -> ([a] -> [a]) -> STM m () forall a. TVar m a -> (a -> a) -> STM m () forall (m :: * -> *) a. MonadSTM m => TVar m a -> (a -> a) -> STM m () modifyTVar' TVar m [a] msgqueue (a msg :)} captureIncoming :: TVar m [a] -> a -> m () captureIncoming TVar m [a] receivedMessages a msg = STM m () -> m () forall a. HasCallStack => STM m a -> m a forall (m :: * -> *) a. (MonadSTM m, HasCallStack) => STM m a -> m a atomically (STM m () -> m ()) -> STM m () -> m () forall a b. (a -> b) -> a -> b $ TVar m [a] -> ([a] -> [a]) -> STM m () forall a. TVar m a -> (a -> a) -> STM m () forall (m :: * -> *) a. MonadSTM m => TVar m a -> (a -> a) -> STM m () modifyTVar' TVar m [a] receivedMessages (a msg :) nodeId :: NodeId nodeId = Text -> NodeId NodeId Text "node_id-1" otherNodeId :: NodeId otherNodeId = Text -> NodeId NodeId Text "node_id-2" String -> Expectation -> SpecWith (Arg Expectation) forall a. (HasCallStack, Example a) => String -> a -> SpecWith (Arg a) it String "sends a heartbeat message with local host after 500 ms" (Expectation -> SpecWith (Arg Expectation)) -> Expectation -> SpecWith (Arg Expectation) forall a b. (a -> b) -> a -> b $ do let sentHeartbeats :: [Heartbeat ()] sentHeartbeats = (forall s. IOSim s [Heartbeat ()]) -> [Heartbeat ()] forall a. (forall s. IOSim s a) -> a runSimOrThrow ((forall s. IOSim s [Heartbeat ()]) -> [Heartbeat ()]) -> (forall s. IOSim s [Heartbeat ()]) -> [Heartbeat ()] forall a b. (a -> b) -> a -> b $ do TVar s [Heartbeat ()] sentMessages <- [Heartbeat ()] -> IOSim s (TVar (IOSim s) [Heartbeat ()]) forall a. a -> IOSim s (TVar (IOSim s) a) forall (m :: * -> *) a. MonadSTM m => a -> m (TVar m a) newTVarIO ([] :: [Heartbeat ()]) NodeId -> ConnectionMessages (IOSim s) -> NetworkComponent (IOSim s) (Heartbeat Any) (Heartbeat ()) () -> NetworkComponent (IOSim s) Any () () forall (m :: * -> *) msg1 msg a. (MonadAsync m, MonadDelay m) => NodeId -> ConnectionMessages m -> NetworkComponent m (Heartbeat msg1) (Heartbeat msg) a -> NetworkComponent m msg1 msg a withHeartbeat NodeId nodeId ConnectionMessages (IOSim s) forall (m :: * -> *) b. Monad m => b -> m () noop (TVar (IOSim s) [Heartbeat ()] -> NetworkComponent (IOSim s) (Heartbeat Any) (Heartbeat ()) () forall {m :: * -> *} {a} {p} {b}. MonadSTM m => TVar m [a] -> p -> (Network m a -> b) -> b captureOutgoing TVar (IOSim s) [Heartbeat ()] TVar s [Heartbeat ()] sentMessages) Any -> IOSim s () forall (m :: * -> *) b. Monad m => b -> m () noop ((Network (IOSim s) () -> IOSim s ()) -> IOSim s ()) -> (Network (IOSim s) () -> IOSim s ()) -> IOSim s () forall a b. (a -> b) -> a -> b $ \Network (IOSim s) () _ -> DiffTime -> IOSim s () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 1.1 TVar (IOSim s) [Heartbeat ()] -> IOSim s [Heartbeat ()] forall a. TVar (IOSim s) a -> IOSim s a forall (m :: * -> *) a. MonadSTM m => TVar m a -> m a readTVarIO TVar (IOSim s) [Heartbeat ()] TVar s [Heartbeat ()] sentMessages [Heartbeat ()] sentHeartbeats [Heartbeat ()] -> [Heartbeat ()] -> Expectation forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation `shouldBe` [NodeId -> Heartbeat () forall msg. NodeId -> Heartbeat msg Ping NodeId nodeId] String -> Expectation -> SpecWith (Arg Expectation) forall a. (HasCallStack, Example a) => String -> a -> SpecWith (Arg a) it String "sends Connected when Ping received from other peer" (Expectation -> SpecWith (Arg Expectation)) -> Expectation -> SpecWith (Arg Expectation) forall a b. (a -> b) -> a -> b $ do let receivedHeartbeats :: [Connectivity] receivedHeartbeats = (forall s. IOSim s [Connectivity]) -> [Connectivity] forall a. (forall s. IOSim s a) -> a runSimOrThrow ((forall s. IOSim s [Connectivity]) -> [Connectivity]) -> (forall s. IOSim s [Connectivity]) -> [Connectivity] forall a b. (a -> b) -> a -> b $ do TVar s [Connectivity] receivedMessages <- [Connectivity] -> IOSim s (TVar (IOSim s) [Connectivity]) forall a. a -> IOSim s (TVar (IOSim s) a) forall (m :: * -> *) a. MonadSTM m => a -> m (TVar m a) newTVarIO ([] :: [Connectivity]) NodeId -> ConnectionMessages (IOSim s) -> NetworkComponent (IOSim s) (Heartbeat Any) (Heartbeat Any) () -> NetworkComponent (IOSim s) Any Any () forall (m :: * -> *) msg1 msg a. (MonadAsync m, MonadDelay m) => NodeId -> ConnectionMessages m -> NetworkComponent m (Heartbeat msg1) (Heartbeat msg) a -> NetworkComponent m msg1 msg a withHeartbeat NodeId nodeId (TVar (IOSim s) [Connectivity] -> ConnectionMessages (IOSim s) forall {m :: * -> *} {a}. MonadSTM m => TVar m [a] -> a -> m () captureIncoming TVar (IOSim s) [Connectivity] TVar s [Connectivity] receivedMessages) (\NetworkCallback (Heartbeat Any) (IOSim s) incoming Network (IOSim s) (Heartbeat Any) -> IOSim s () _ -> NetworkCallback (Heartbeat Any) (IOSim s) incoming (NodeId -> Heartbeat Any forall msg. NodeId -> Heartbeat msg Ping NodeId otherNodeId)) Any -> IOSim s () forall (m :: * -> *) b. Monad m => b -> m () noop ((Network (IOSim s) Any -> IOSim s ()) -> IOSim s ()) -> (Network (IOSim s) Any -> IOSim s ()) -> IOSim s () forall a b. (a -> b) -> a -> b $ \Network (IOSim s) Any _ -> DiffTime -> IOSim s () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 1 TVar (IOSim s) [Connectivity] -> IOSim s [Connectivity] forall a. TVar (IOSim s) a -> IOSim s a forall (m :: * -> *) a. MonadSTM m => TVar m a -> m a readTVarIO TVar (IOSim s) [Connectivity] TVar s [Connectivity] receivedMessages [Connectivity] receivedHeartbeats [Connectivity] -> [Connectivity] -> Expectation forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation `shouldBe` [NodeId -> Connectivity Connected NodeId otherNodeId] String -> Expectation -> SpecWith (Arg Expectation) forall a. (HasCallStack, Example a) => String -> a -> SpecWith (Arg a) it String "sends Connected when any message received from other party" (Expectation -> SpecWith (Arg Expectation)) -> Expectation -> SpecWith (Arg Expectation) forall a b. (a -> b) -> a -> b $ do let receivedHeartbeats :: [Connectivity] receivedHeartbeats = (forall s. IOSim s [Connectivity]) -> [Connectivity] forall a. (forall s. IOSim s a) -> a runSimOrThrow ((forall s. IOSim s [Connectivity]) -> [Connectivity]) -> (forall s. IOSim s [Connectivity]) -> [Connectivity] forall a b. (a -> b) -> a -> b $ do TVar s [Connectivity] receivedMessages <- [Connectivity] -> IOSim s (TVar (IOSim s) [Connectivity]) forall a. a -> IOSim s (TVar (IOSim s) a) forall (m :: * -> *) a. MonadSTM m => a -> m (TVar m a) newTVarIO ([] :: [Connectivity]) NodeId -> ConnectionMessages (IOSim s) -> NetworkComponent (IOSim s) (Heartbeat ()) (Heartbeat Any) () -> NetworkComponent (IOSim s) () Any () forall (m :: * -> *) msg1 msg a. (MonadAsync m, MonadDelay m) => NodeId -> ConnectionMessages m -> NetworkComponent m (Heartbeat msg1) (Heartbeat msg) a -> NetworkComponent m msg1 msg a withHeartbeat NodeId nodeId (TVar (IOSim s) [Connectivity] -> ConnectionMessages (IOSim s) forall {m :: * -> *} {a}. MonadSTM m => TVar m [a] -> a -> m () captureIncoming TVar (IOSim s) [Connectivity] TVar s [Connectivity] receivedMessages) (\NetworkCallback (Heartbeat ()) (IOSim s) incoming Network (IOSim s) (Heartbeat Any) -> IOSim s () _ -> NetworkCallback (Heartbeat ()) (IOSim s) incoming (NodeId -> () -> Heartbeat () forall msg. NodeId -> msg -> Heartbeat msg Data NodeId otherNodeId ())) () -> IOSim s () forall (m :: * -> *) b. Monad m => b -> m () noop ((Network (IOSim s) Any -> IOSim s ()) -> IOSim s ()) -> (Network (IOSim s) Any -> IOSim s ()) -> IOSim s () forall a b. (a -> b) -> a -> b $ \Network (IOSim s) Any _ -> DiffTime -> IOSim s () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 1 TVar (IOSim s) [Connectivity] -> IOSim s [Connectivity] forall a. TVar (IOSim s) a -> IOSim s a forall (m :: * -> *) a. MonadSTM m => TVar m a -> m a readTVarIO TVar (IOSim s) [Connectivity] TVar s [Connectivity] receivedMessages [Connectivity] receivedHeartbeats [Connectivity] -> [Connectivity] -> Expectation forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation `shouldBe` [NodeId -> Connectivity Connected NodeId otherNodeId] String -> Expectation -> SpecWith (Arg Expectation) forall a. (HasCallStack, Example a) => String -> a -> SpecWith (Arg a) it String "do not send Connected on subsequent messages from already Connected party" (Expectation -> SpecWith (Arg Expectation)) -> Expectation -> SpecWith (Arg Expectation) forall a b. (a -> b) -> a -> b $ do let receivedHeartbeats :: [Connectivity] receivedHeartbeats = (forall s. IOSim s [Connectivity]) -> [Connectivity] forall a. (forall s. IOSim s a) -> a runSimOrThrow ((forall s. IOSim s [Connectivity]) -> [Connectivity]) -> (forall s. IOSim s [Connectivity]) -> [Connectivity] forall a b. (a -> b) -> a -> b $ do TVar s [Connectivity] receivedMessages <- [Connectivity] -> IOSim s (TVar (IOSim s) [Connectivity]) forall a. a -> IOSim s (TVar (IOSim s) a) forall (m :: * -> *) a. MonadSTM m => a -> m (TVar m a) newTVarIO ([] :: [Connectivity]) NodeId -> ConnectionMessages (IOSim s) -> NetworkComponent (IOSim s) (Heartbeat ()) (Heartbeat Any) () -> NetworkComponent (IOSim s) () Any () forall (m :: * -> *) msg1 msg a. (MonadAsync m, MonadDelay m) => NodeId -> ConnectionMessages m -> NetworkComponent m (Heartbeat msg1) (Heartbeat msg) a -> NetworkComponent m msg1 msg a withHeartbeat NodeId nodeId (TVar (IOSim s) [Connectivity] -> ConnectionMessages (IOSim s) forall {m :: * -> *} {a}. MonadSTM m => TVar m [a] -> a -> m () captureIncoming TVar (IOSim s) [Connectivity] TVar s [Connectivity] receivedMessages) (\NetworkCallback (Heartbeat ()) (IOSim s) incoming Network (IOSim s) (Heartbeat Any) -> IOSim s () _ -> NetworkCallback (Heartbeat ()) (IOSim s) incoming (NodeId -> () -> Heartbeat () forall msg. NodeId -> msg -> Heartbeat msg Data NodeId otherNodeId ()) IOSim s () -> IOSim s () -> IOSim s () forall a b. IOSim s a -> IOSim s b -> IOSim s b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> NetworkCallback (Heartbeat ()) (IOSim s) incoming (NodeId -> Heartbeat () forall msg. NodeId -> Heartbeat msg Ping NodeId otherNodeId)) () -> IOSim s () forall (m :: * -> *) b. Monad m => b -> m () noop ((Network (IOSim s) Any -> IOSim s ()) -> IOSim s ()) -> (Network (IOSim s) Any -> IOSim s ()) -> IOSim s () forall a b. (a -> b) -> a -> b $ \Network (IOSim s) Any _ -> DiffTime -> IOSim s () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 1 TVar (IOSim s) [Connectivity] -> IOSim s [Connectivity] forall a. TVar (IOSim s) a -> IOSim s a forall (m :: * -> *) a. MonadSTM m => TVar m a -> m a readTVarIO TVar (IOSim s) [Connectivity] TVar s [Connectivity] receivedMessages [Connectivity] receivedHeartbeats [Connectivity] -> [Connectivity] -> Expectation forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation `shouldBe` [NodeId -> Connectivity Connected NodeId otherNodeId] String -> Expectation -> SpecWith (Arg Expectation) forall a. (HasCallStack, Example a) => String -> a -> SpecWith (Arg a) it String "sends Disconnected given no messages has been received from known party within twice heartbeat delay" (Expectation -> SpecWith (Arg Expectation)) -> Expectation -> SpecWith (Arg Expectation) forall a b. (a -> b) -> a -> b $ do let receivedHeartbeats :: [Connectivity] receivedHeartbeats = (forall s. IOSim s [Connectivity]) -> [Connectivity] forall a. (forall s. IOSim s a) -> a runSimOrThrow ((forall s. IOSim s [Connectivity]) -> [Connectivity]) -> (forall s. IOSim s [Connectivity]) -> [Connectivity] forall a b. (a -> b) -> a -> b $ do TVar s [Connectivity] receivedMessages <- [Connectivity] -> IOSim s (TVar (IOSim s) [Connectivity]) forall a. a -> IOSim s (TVar (IOSim s) a) forall (m :: * -> *) a. MonadSTM m => a -> m (TVar m a) newTVarIO ([] :: [Connectivity]) let component :: (Heartbeat msg -> m a) -> (Network m msg -> m a) -> m () component Heartbeat msg -> m a incoming Network m msg -> m a action = m a -> m () -> m () forall a b. m a -> m b -> m () forall (m :: * -> *) a b. MonadAsync m => m a -> m b -> m () race_ (Network m msg -> m a action ((msg -> m ()) -> Network m msg forall (m :: * -> *) msg. (msg -> m ()) -> Network m msg Network msg -> m () forall (m :: * -> *) b. Monad m => b -> m () noop)) (Heartbeat msg -> m a incoming (NodeId -> Heartbeat msg forall msg. NodeId -> Heartbeat msg Ping NodeId otherNodeId) m a -> m () -> m () forall a b. m a -> m b -> m b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> DiffTime -> m () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 4 m () -> m a -> m a forall a b. m a -> m b -> m b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> Heartbeat msg -> m a incoming (NodeId -> Heartbeat msg forall msg. NodeId -> Heartbeat msg Ping NodeId otherNodeId) m a -> m () -> m () forall a b. m a -> m b -> m b forall (m :: * -> *) a b. Monad m => m a -> m b -> m b >> DiffTime -> m () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 7) NodeId -> ConnectionMessages (IOSim s) -> NetworkComponent (IOSim s) (Heartbeat Any) (Heartbeat Any) () -> NetworkComponent (IOSim s) Any Any () forall (m :: * -> *) msg1 msg a. (MonadAsync m, MonadDelay m) => NodeId -> ConnectionMessages m -> NetworkComponent m (Heartbeat msg1) (Heartbeat msg) a -> NetworkComponent m msg1 msg a withHeartbeat NodeId nodeId (TVar (IOSim s) [Connectivity] -> ConnectionMessages (IOSim s) forall {m :: * -> *} {a}. MonadSTM m => TVar m [a] -> a -> m () captureIncoming TVar (IOSim s) [Connectivity] TVar s [Connectivity] receivedMessages) NetworkComponent (IOSim s) (Heartbeat Any) (Heartbeat Any) () forall {m :: * -> *} {m :: * -> *} {msg} {a} {msg} {a}. (MonadAsync m, MonadDelay m, Monad m) => (Heartbeat msg -> m a) -> (Network m msg -> m a) -> m () component Any -> IOSim s () forall (m :: * -> *) b. Monad m => b -> m () noop ((Network (IOSim s) Any -> IOSim s ()) -> IOSim s ()) -> (Network (IOSim s) Any -> IOSim s ()) -> IOSim s () forall a b. (a -> b) -> a -> b $ \Network (IOSim s) Any _ -> DiffTime -> IOSim s () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 20 TVar (IOSim s) [Connectivity] -> IOSim s [Connectivity] forall a. TVar (IOSim s) a -> IOSim s a forall (m :: * -> *) a. MonadSTM m => TVar m a -> m a readTVarIO TVar (IOSim s) [Connectivity] TVar s [Connectivity] receivedMessages [Connectivity] receivedHeartbeats [Connectivity] -> [Connectivity] -> Expectation forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation `shouldBe` [NodeId -> Connectivity Disconnected NodeId otherNodeId, NodeId -> Connectivity Connected NodeId otherNodeId] String -> Expectation -> SpecWith (Arg Expectation) forall a. (HasCallStack, Example a) => String -> a -> SpecWith (Arg a) it String "stop sending heartbeat message given action sends a message" (Expectation -> SpecWith (Arg Expectation)) -> Expectation -> SpecWith (Arg Expectation) forall a b. (a -> b) -> a -> b $ do let sentHeartbeats :: [Heartbeat ()] sentHeartbeats = (forall s. IOSim s [Heartbeat ()]) -> [Heartbeat ()] forall a. (forall s. IOSim s a) -> a runSimOrThrow ((forall s. IOSim s [Heartbeat ()]) -> [Heartbeat ()]) -> (forall s. IOSim s [Heartbeat ()]) -> [Heartbeat ()] forall a b. (a -> b) -> a -> b $ do TVar s [Heartbeat ()] sentMessages <- [Heartbeat ()] -> IOSim s (TVar (IOSim s) [Heartbeat ()]) forall a. a -> IOSim s (TVar (IOSim s) a) forall (m :: * -> *) a. MonadSTM m => a -> m (TVar m a) newTVarIO ([] :: [Heartbeat ()]) NodeId -> ConnectionMessages (IOSim s) -> NetworkComponent (IOSim s) (Heartbeat Any) (Heartbeat ()) () -> NetworkComponent (IOSim s) Any () () forall (m :: * -> *) msg1 msg a. (MonadAsync m, MonadDelay m) => NodeId -> ConnectionMessages m -> NetworkComponent m (Heartbeat msg1) (Heartbeat msg) a -> NetworkComponent m msg1 msg a withHeartbeat NodeId nodeId ConnectionMessages (IOSim s) forall (m :: * -> *) b. Monad m => b -> m () noop (TVar (IOSim s) [Heartbeat ()] -> NetworkComponent (IOSim s) (Heartbeat Any) (Heartbeat ()) () forall {m :: * -> *} {a} {p} {b}. MonadSTM m => TVar m [a] -> p -> (Network m a -> b) -> b captureOutgoing TVar (IOSim s) [Heartbeat ()] TVar s [Heartbeat ()] sentMessages) Any -> IOSim s () forall (m :: * -> *) b. Monad m => b -> m () noop ((Network (IOSim s) () -> IOSim s ()) -> IOSim s ()) -> (Network (IOSim s) () -> IOSim s ()) -> IOSim s () forall a b. (a -> b) -> a -> b $ \Network{() -> IOSim s () $sel:broadcast:Network :: forall (m :: * -> *) msg. Network m msg -> msg -> m () broadcast :: () -> IOSim s () broadcast} -> do DiffTime -> IOSim s () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 0.6 () -> IOSim s () broadcast () DiffTime -> IOSim s () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 1 TVar (IOSim s) [Heartbeat ()] -> IOSim s [Heartbeat ()] forall a. TVar (IOSim s) a -> IOSim s a forall (m :: * -> *) a. MonadSTM m => TVar m a -> m a readTVarIO TVar (IOSim s) [Heartbeat ()] TVar s [Heartbeat ()] sentMessages [Heartbeat ()] sentHeartbeats [Heartbeat ()] -> [Heartbeat ()] -> Expectation forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation `shouldBe` [NodeId -> () -> Heartbeat () forall msg. NodeId -> msg -> Heartbeat msg Data NodeId nodeId (), NodeId -> Heartbeat () forall msg. NodeId -> Heartbeat msg Ping NodeId nodeId] String -> Expectation -> SpecWith (Arg Expectation) forall a. (HasCallStack, Example a) => String -> a -> SpecWith (Arg a) it String "restart sending heartbeat messages given last message sent is older than heartbeat delay" (Expectation -> SpecWith (Arg Expectation)) -> Expectation -> SpecWith (Arg Expectation) forall a b. (a -> b) -> a -> b $ do let sentHeartbeats :: [Heartbeat ()] sentHeartbeats = (forall s. IOSim s [Heartbeat ()]) -> [Heartbeat ()] forall a. (forall s. IOSim s a) -> a runSimOrThrow ((forall s. IOSim s [Heartbeat ()]) -> [Heartbeat ()]) -> (forall s. IOSim s [Heartbeat ()]) -> [Heartbeat ()] forall a b. (a -> b) -> a -> b $ do TVar s [Heartbeat ()] sentMessages <- [Heartbeat ()] -> IOSim s (TVar (IOSim s) [Heartbeat ()]) forall a. a -> IOSim s (TVar (IOSim s) a) forall (m :: * -> *) a. MonadSTM m => a -> m (TVar m a) newTVarIO ([] :: [Heartbeat ()]) NodeId -> ConnectionMessages (IOSim s) -> NetworkComponent (IOSim s) (Heartbeat Any) (Heartbeat ()) () -> NetworkComponent (IOSim s) Any () () forall (m :: * -> *) msg1 msg a. (MonadAsync m, MonadDelay m) => NodeId -> ConnectionMessages m -> NetworkComponent m (Heartbeat msg1) (Heartbeat msg) a -> NetworkComponent m msg1 msg a withHeartbeat NodeId nodeId ConnectionMessages (IOSim s) forall (m :: * -> *) b. Monad m => b -> m () noop (TVar (IOSim s) [Heartbeat ()] -> NetworkComponent (IOSim s) (Heartbeat Any) (Heartbeat ()) () forall {m :: * -> *} {a} {p} {b}. MonadSTM m => TVar m [a] -> p -> (Network m a -> b) -> b captureOutgoing TVar (IOSim s) [Heartbeat ()] TVar s [Heartbeat ()] sentMessages) Any -> IOSim s () forall (m :: * -> *) b. Monad m => b -> m () noop ((Network (IOSim s) () -> IOSim s ()) -> IOSim s ()) -> (Network (IOSim s) () -> IOSim s ()) -> IOSim s () forall a b. (a -> b) -> a -> b $ \Network{() -> IOSim s () $sel:broadcast:Network :: forall (m :: * -> *) msg. Network m msg -> msg -> m () broadcast :: () -> IOSim s () broadcast} -> do DiffTime -> IOSim s () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 0.6 () -> IOSim s () broadcast () DiffTime -> IOSim s () forall (m :: * -> *). MonadDelay m => DiffTime -> m () threadDelay DiffTime 3.6 TVar (IOSim s) [Heartbeat ()] -> IOSim s [Heartbeat ()] forall a. TVar (IOSim s) a -> IOSim s a forall (m :: * -> *) a. MonadSTM m => TVar m a -> m a readTVarIO TVar (IOSim s) [Heartbeat ()] TVar s [Heartbeat ()] sentMessages [Heartbeat ()] sentHeartbeats [Heartbeat ()] -> [Heartbeat ()] -> Expectation forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation `shouldBe` [NodeId -> Heartbeat () forall msg. NodeId -> Heartbeat msg Ping NodeId nodeId, NodeId -> () -> Heartbeat () forall msg. NodeId -> msg -> Heartbeat msg Data NodeId nodeId (), NodeId -> Heartbeat () forall msg. NodeId -> Heartbeat msg Ping NodeId nodeId] noop :: Monad m => b -> m () noop :: forall (m :: * -> *) b. Monad m => b -> m () noop = m () -> b -> m () forall a b. a -> b -> a const (m () -> b -> m ()) -> m () -> b -> m () forall a b. (a -> b) -> a -> b $ () -> m () forall a. a -> m a forall (f :: * -> *) a. Applicative f => a -> f a pure ()