def setUp(self):
   self._http_signaler = mox.MockObject(HttpSignaler)
   self._status_health_check = StatusHealthCheck()
   self._http_health_check = HttpHealthCheck(self._http_signaler)
   self._smart_health_check = InstanceWatcherHealthCheck(self._http_signaler)
   self._health_check_a = mox.MockObject(HealthCheck)
   self._health_check_b = mox.MockObject(HealthCheck)
class HealthCheckTest(unittest.TestCase):
  HOST = 'host-a'
  HEALTH_PORT = 33333

  def setUp(self):
    self._http_signaler = mox.MockObject(HttpSignaler)
    self._status_health_check = StatusHealthCheck()
    self._http_health_check = HttpHealthCheck(self._http_signaler)
    self._smart_health_check = InstanceWatcherHealthCheck(self._http_signaler)
    self._health_check_a = mox.MockObject(HealthCheck)
    self._health_check_b = mox.MockObject(HealthCheck)

  def create_task(self, instance_id, task_id, status=RUNNING, host=HOST, port=HEALTH_PORT):
    ports = {}
    if port:
      ports['health'] = port
    assigned_task = AssignedTask(taskId=task_id,
                                 instanceId=instance_id,
                                 task=TaskConfig(),
                                 slaveHost=host,
                                 assignedPorts=ports)
    return ScheduledTask(assignedTask=assigned_task, status=status)

  def expect_http_signaler_creation(self, host=HOST, port=HEALTH_PORT):
    self._http_signaler(port, host).AndReturn(self._http_signaler)

  def expect_health_check(self, status=True):
    self._http_signaler.health().AndReturn((status, 'reason'))

  def replay(self):
    mox.Replay(self._http_signaler)
    mox.Replay(self._health_check_a)
    mox.Replay(self._health_check_b)

  def verify(self):
    mox.Verify(self._http_signaler)
    mox.Verify(self._health_check_a)
    mox.Verify(self._health_check_b)

  def test_simple_status_health_check(self):
    """Verify that running instances are reported healthy"""
    task_a = self.create_task(0, 'a')
    task_b = self.create_task(1, 'b')
    assert self._status_health_check.health(task_a) == Retriable.alive()
    assert self._status_health_check.health(task_b) == Retriable.alive()

  def test_failed_status_health_check(self):
    """Verify that the health check fails for tasks in a state other than RUNNING"""
    pending_task = self.create_task(0, 'a', status=PENDING)
    failed_task = self.create_task(1, 'b', status=FAILED)
    assert self._status_health_check.health(pending_task) == Retriable.dead()
    assert self._status_health_check.health(failed_task) == Retriable.dead()

  def test_changed_task_id(self):
    """Verifes that an instance with a different task id causes the health check to fail"""
    task_a = self.create_task(0, 'a')
    task_b = self.create_task(0, 'b')
    assert self._status_health_check.health(task_a) == Retriable.alive()
    assert self._status_health_check.health(task_b) == NotRetriable.dead()

  def test_http_health_check(self):
    """Verify successful and failed http health checks for a task"""
    task_a = self.create_task(0, 'a')
    self.expect_http_signaler_creation()
    self.expect_health_check()
    self.expect_health_check(status=False)
    self.replay()
    assert self._http_health_check.health(task_a) == Retriable.alive()
    assert self._http_health_check.health(task_a) == Retriable.dead()
    self.verify()

  def test_unmatched_host_port(self):
    """Test if an instance with a modified a (host, port) triggers a new http health checker creation"""
    instance_id = 0
    task_a = self.create_task(instance_id, 'a')
    self.expect_http_signaler_creation()
    self.expect_health_check()
    task_b = self.create_task(instance_id, 'b', host='host-b', port=44444)
    self.expect_http_signaler_creation(host='host-b', port=44444)
    self.expect_health_check()
    self.replay()
    assert self._http_health_check.health(task_a) == Retriable.alive()
    assert self._http_health_check.health(task_b) == Retriable.alive()
    self.verify()

  def test_simple_chained_health_check(self):
    """Verify successful health check"""
    task = self.create_task(0, 'a')
    self._health_check_a.health(task).AndReturn(Retriable.alive())
    self._health_check_b.health(task).AndReturn(Retriable.alive())
    health_check = ChainedHealthCheck(self._health_check_a, self._health_check_b)
    self.replay()
    assert health_check.health(task) == Retriable.alive()
    self.verify()

  def test_failed_primary_health_check(self):
    """Verifies that a secondary health check is not invoked when a primary check fails"""
    task = self.create_task(0, 'a')
    self._health_check_a.health(task).AndReturn(NotRetriable.dead())
    self._health_check_a.health(task).AndReturn(Retriable.dead())
    health_check = ChainedHealthCheck(self._health_check_a, self._health_check_b)
    self.replay()
    assert health_check.health(task) == NotRetriable.dead()
    assert health_check.health(task) == Retriable.dead()
    self.verify()

  def test_failed_secondary_health_check(self):
    """Verifies that a secondary health check is not invoked when a primary check fails"""
    task = self.create_task(0, 'a')
    self._health_check_a.health(task).AndReturn(Retriable.alive())
    self._health_check_b.health(task).AndReturn(Retriable.dead())
    health_check = ChainedHealthCheck(self._health_check_a, self._health_check_b)
    self.replay()
    assert health_check.health(task) == Retriable.dead()
    self.verify()

  def test_health_statuses(self):
    """Verfies that the health status tuple (health, retry_status) are as expected"""
    assert Retriable.alive() == (True, True)
    assert Retriable.dead() == (False, True)
    assert NotRetriable.alive() == (True, False)
    assert NotRetriable.dead() == (False, False)

  def test_instancewatcher_health_check(self):
    """Verifies that if the task has no health port, only status check is performed"""
    task = self.create_task(0, 'a', port=None)
    self.replay()
    assert self._smart_health_check.health(task) == Retriable.alive()
    self.verify()

  def test_instancewatcher_http_health_check(self):
    """Verifies that http health check is performed if the task has a health port"""
    task = self.create_task(0, 'a')
    self.expect_http_signaler_creation()
    self.expect_health_check(status=False)
    self.replay()
    assert self._smart_health_check.health(task) == Retriable.dead()
    self.verify()

  def test_instancewatcher_http_health_check_one_http_signaler(self):
    """Verifies that upon multiple http health checks only one HttpHealthChecker is created"""
    task = self.create_task(0, 'a')
    self.expect_http_signaler_creation()
    self.expect_health_check()
    self.expect_health_check()
    self.replay()
    assert self._smart_health_check.health(task) == Retriable.alive()
    assert self._smart_health_check.health(task) == Retriable.alive()
    self.verify()