'Do one iteration of a convergence loop.
:param initial_action: First ``IStateChange`` provider to
calculate as necessary action.
:param later_actions: List of ``IStateChange``, to be returned
second and third times discovery is done, i.e. after first
iteration.
:return: ``ConvergenceLoop`` in SLEEPING state.'

@validate_logging(assert_full_logging)
def convergence_iteration(self, logger, initial_action=ControllableAction(result=succeed(None)), later_actions=[ControllableAction(result=succeed(None)), ControllableAction(result=succeed(None))]):

    self.local_state = local_state = NodeState(hostname=u'192.0.2.123')
    self.configuration = configuration = Deployment()
    self.cluster_state = received_state = DeploymentState(nodes=[])
    self.action = initial_action
    self.deployer = deployer = ControllableDeployer(local_state.hostname, [succeed(local_state), succeed(local_state)], ([initial_action] + later_actions))
    client = self.make_amp_client([local_state])
    self.reactor = reactor = Clock()
    loop = build_convergence_loop_fsm(reactor, deployer)
    self.patch(loop, 'logger', logger)
    loop.receive(_ClientStatusUpdate(client=client, configuration=configuration, state=received_state))
    expected_cluster_state = DeploymentState(nodes=[local_state])
    self.assertTupleEqual((deployer.calculate_inputs, client.calls), ([(local_state, configuration, expected_cluster_state)], [(NodeStateCommand, dict(state_changes=(local_state,)))]))
    self.assertEqual(loop.state, ConvergenceLoopStates.SLEEPING)
    return loop
