subsetting_test.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. # Copyright 2021 The gRPC Authors
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import collections
  15. from typing import List, Optional
  16. from absl import flags
  17. from absl import logging
  18. from absl.testing import absltest
  19. from google.protobuf import json_format
  20. from framework import xds_k8s_testcase
  21. from framework import xds_url_map_testcase
  22. from framework.infrastructure import k8s
  23. from framework.test_app import server_app
  24. flags.adopt_module_key_flags(xds_k8s_testcase)
  25. # Type aliases
  26. _XdsTestServer = xds_k8s_testcase.XdsTestServer
  27. _XdsTestClient = xds_k8s_testcase.XdsTestClient
  28. _SUBSET_SIZE = 4
  29. _NUM_BACKENDS = 8
  30. _NUM_CLIENTS = 3
  31. class SubsettingTest(xds_k8s_testcase.RegularXdsKubernetesTestCase):
  32. def test_subsetting_basic(self) -> None:
  33. with self.subTest('00_create_health_check'):
  34. self.td.create_health_check()
  35. with self.subTest('01_create_backend_services'):
  36. self.td.create_backend_service(subset_size=_SUBSET_SIZE)
  37. with self.subTest('02_create_url_map'):
  38. self.td.create_url_map(self.server_xds_host, self.server_xds_port)
  39. with self.subTest('03_create_target_proxy'):
  40. self.td.create_target_proxy()
  41. with self.subTest('04_create_forwarding_rule'):
  42. self.td.create_forwarding_rule(self.server_xds_port)
  43. with self.subTest('05_start_test_servers'):
  44. self.test_servers: List[_XdsTestServer] = self.startTestServers(
  45. replica_count=_NUM_BACKENDS)
  46. with self.subTest('06_add_server_backends_to_backend_services'):
  47. self.setupServerBackends()
  48. rpc_distribution = collections.defaultdict(int)
  49. with self.subTest('07_start_test_client'):
  50. for i in range(_NUM_CLIENTS):
  51. # Clean created client pods if there is any
  52. self.client_runner.cleanup(force=True)
  53. # Create a test client
  54. test_client: _XdsTestClient = self.startTestClient(
  55. self.test_servers[0])
  56. # Validate the number of received endpoints
  57. config = test_client.csds.fetch_client_status(
  58. log_level=logging.INFO)
  59. self.assertIsNotNone(config)
  60. json_config = json_format.MessageToDict(config)
  61. parsed = xds_url_map_testcase.DumpedXdsConfig(json_config)
  62. logging.info('Client %d received endpoints (len=%s): %s', i,
  63. len(parsed.endpoints), parsed.endpoints)
  64. self.assertLen(parsed.endpoints, _SUBSET_SIZE)
  65. # Record RPC stats
  66. lb_stats = self.getClientRpcStats(test_client,
  67. _NUM_BACKENDS * 25)
  68. for key, value in lb_stats.rpcs_by_peer.items():
  69. rpc_distribution[key] += value
  70. with self.subTest('08_log_rpc_distribution'):
  71. server_entries = sorted(rpc_distribution.items(),
  72. key=lambda x: -x[1])
  73. # Validate if clients are receiving different sets of backends (3
  74. # client received a total of 4 unique backends == FAIL, a total of 5
  75. # unique backends == PASS)
  76. self.assertGreater(len(server_entries), _SUBSET_SIZE)
  77. logging.info('RPC distribution (len=%s): %s', len(server_entries),
  78. server_entries)
  79. peak = server_entries[0][1]
  80. mean = sum(map(lambda x: x[1],
  81. server_entries)) / len(server_entries)
  82. logging.info('Peak=%d Mean=%.1f Peak-to-Mean-Ratio=%.2f', peak,
  83. mean, peak / mean)
  84. if __name__ == '__main__':
  85. absltest.main(failfast=True)