...

Text file src/github.com/emissary-ingress/emissary/v3/python/tests/kat/t_active_health_check.py

Documentation: github.com/emissary-ingress/emissary/v3/python/tests/kat

     1import time
     2from typing import Generator, Tuple, Union
     3
     4from abstract_tests import AmbassadorTest, HealthCheckServer, Node
     5from kat.harness import Query
     6
     7
     8class ActiveHealthCheckTest(AmbassadorTest):
     9    def init(self):
    10        self.target = HealthCheckServer()
    11
    12    def config(self) -> Generator[Union[str, Tuple[Node, str]], None, None]:
    13        yield self, self.format(
    14            """
    15---
    16apiVersion: getambassador.io/v3alpha1
    17kind: Mapping
    18name:  {self.target.path.k8s}-health
    19hostname: "*"
    20prefix: /healthcheck/
    21service: {self.target.path.fqdn}
    22resolver: endpoint
    23load_balancer:
    24  policy: round_robin
    25health_checks:
    26- unhealthy_threshold: 1
    27  interval: 1s
    28  health_check:
    29    http:
    30      path: /healthcheck/actualcheck/
    31"""
    32        )  # The round robin load balancer is not necessary for the test but should help make the request distribution even across the pods
    33
    34    def queries(self):
    35        yield Query(self.url("healthcheck/"), phase=1)  # Just making sure things are running
    36        yield Query(self.url("ambassador/v0/diag/"), phase=1)
    37
    38        yield Query(
    39            self.url("healthcheck/makeUnhealthy/"), phase=1
    40        )  # the deployment has 5 pods. This will make one of them start returning errors
    41
    42        # These three queries on their own in separate phases are just a hack way of getting the kat client
    43        # to wait a little bit after the previous query so that the automated health checks have time to notice
    44        # that one of the pods is misbehaving before we start blasting requests out.
    45        yield Query(self.url("healthcheck/"), expected=[200, 500], phase=2)
    46        yield Query(self.url("healthcheck/"), expected=[200, 500], phase=3)
    47        yield Query(self.url("healthcheck/"), expected=[200, 500], phase=4)
    48
    49        # Make 1000 requests split into two groups to reduce any flakes
    50        for _ in range(500):
    51            yield Query(self.url("healthcheck/"), expected=[200, 500], phase=5)
    52            time.sleep(0.06)
    53
    54        for _ in range(500):
    55            yield Query(self.url("healthcheck/"), expected=[200, 500], phase=6)
    56            time.sleep(0.06)
    57
    58    def check(self):
    59        # Add up the number of 500 and 200 responses that we got.
    60        valid = 0
    61        errors = 0
    62        for i in range(6, 1006):
    63            if self.results[i].status == 200:
    64                valid += 1
    65            elif self.results[i].status == 500:
    66                errors += 1
    67
    68        # with 1000 requests and 1/5 being an error response, we should have the following distribution +/- 10
    69        # assert 190 <= errors <= 210
    70        # assert 790 <= valid <= 810
    71
    72        # But since we configure health checking we should actually see 0 errors because the health checks noticed
    73        # that one of the pods was unhealthy and didn't route any traffic to it.
    74        msg = "Errors: {}, Valid: {}".format(errors, valid)
    75        assert errors == 0, msg
    76        assert valid == 1000, msg
    77
    78
    79class NoHealthCheckTest(AmbassadorTest):
    80    def init(self):
    81        self.target = HealthCheckServer()
    82
    83    def config(self) -> Generator[Union[str, Tuple[Node, str]], None, None]:
    84        yield self, self.format(
    85            """
    86---
    87apiVersion: getambassador.io/v3alpha1
    88kind: Mapping
    89name:  {self.target.path.k8s}-health
    90hostname: "*"
    91prefix: /healthcheck/
    92service: {self.target.path.fqdn}
    93resolver: endpoint
    94load_balancer:
    95  policy: round_robin
    96"""
    97        )  # The round robin load balancer is not necessary for the test but should help make the request distribution even across the pods
    98
    99    def queries(self):
   100        yield Query(self.url("healthcheck/"), phase=1)  # Just making sure things are running
   101        yield Query(self.url("ambassador/v0/diag/"), phase=1)
   102
   103        yield Query(
   104            self.url("healthcheck/makeUnhealthy/"), phase=1
   105        )  # the deployment has 5 pods. This will make one of them start returning errors
   106
   107        # Make 1000 requests and split them up so that we're not hammering the service too much all at once.
   108        for _ in range(500):
   109            yield Query(self.url("healthcheck/"), expected=[200, 500], phase=2)
   110            time.sleep(0.06)
   111
   112        for _ in range(500):
   113            yield Query(self.url("healthcheck/"), expected=[200, 500], phase=3)
   114            time.sleep(0.06)
   115
   116    def check(self):
   117        # Since we haven't configured any health checking, we should expect to see a fair number of error responses
   118        valid = 0
   119        errors = 0
   120        for i in range(3, 1003):
   121            if self.results[i].status == 200:
   122                valid += 1
   123            elif self.results[i].status == 500:
   124                errors += 1
   125        msg = "Errors: {}, Valid: {}".format(errors, valid)
   126
   127        # with 1000 requests and 1/5 being an error response, we should have the following distribution +/- some
   128        # margin might need tuned
   129        margin = 100
   130        assert abs(errors - 200) < margin
   131        assert abs(valid - 800) < margin

View as plain text