mirror of https://github.com/grpc/grpc.git
Port basic non-security tests to k8s (#26360)
* wip: port non-security tests to k8s * port forwarding offset * combine and log health status changes * split tests * add remove_neg method * implement assertRpcsEventuallyGoToGivenServers * remove neg and change backend * make maxRatePerEndpoint configurable * _test suffix * "rebase" onto master * yapf and isort * add to grpc_xds_k8s.sh * undo change to run_test_server.py * fix (avoid?) cleanup error with reuse_namespace=True when run with force_cleanup flag otherwise cleaning up the secondary KubernetesServerRunner tries to delete the namespace as well (since force overrides the reuse_namespace flag in https://github.com/grpc/grpc/blob/master/tools/run_tests/xds_k8s_test_driver/framework/test_app/base_runner.py#L76) I'm not sure of the intended semantics of reuse_namespace and force, so unclear if that conditional in base_runner.py should be changed to allow the calls to cleanup the secondary KubernetesServerRunners continue to forward the values of the cleanup/force_cleanup flags * fix dates * Add support for secondary kube context for failover test * Revert "Add support for secondary kube context for failover test" This reverts commitpull/26877/headb7455f2a92
. * Revert "add to grpc_xds_k8s.sh" This reverts commit737f13fdc8
.
parent
639b7acdfa
commit
239acada8d
12 changed files with 649 additions and 35 deletions
@ -0,0 +1,106 @@ |
||||
# Copyright 2021 gRPC authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
import logging |
||||
from typing import List, Optional |
||||
|
||||
from absl import flags |
||||
from absl.testing import absltest |
||||
|
||||
from framework import xds_k8s_testcase |
||||
from framework.infrastructure import k8s |
||||
from framework.test_app import server_app |
||||
|
||||
logger = logging.getLogger(__name__) |
||||
flags.adopt_module_key_flags(xds_k8s_testcase) |
||||
|
||||
# Type aliases |
||||
_XdsTestServer = xds_k8s_testcase.XdsTestServer |
||||
_XdsTestClient = xds_k8s_testcase.XdsTestClient |
||||
|
||||
|
||||
class ChangeBackendServiceTest(xds_k8s_testcase.RegularXdsKubernetesTestCase): |
||||
|
||||
def setUp(self): |
||||
super().setUp() |
||||
self.alternate_k8s_namespace = k8s.KubernetesNamespace( |
||||
self.k8s_api_manager, self.server_namespace) |
||||
self.alternate_server_runner = server_app.KubernetesServerRunner( |
||||
self.alternate_k8s_namespace, |
||||
deployment_name=self.server_name + '-alt', |
||||
image_name=self.server_image, |
||||
gcp_service_account=self.gcp_service_account, |
||||
td_bootstrap_image=self.td_bootstrap_image, |
||||
gcp_project=self.project, |
||||
gcp_api_manager=self.gcp_api_manager, |
||||
xds_server_uri=self.xds_server_uri, |
||||
network=self.network, |
||||
debug_use_port_forwarding=self.debug_use_port_forwarding, |
||||
reuse_namespace=True) |
||||
|
||||
def tearDown(self): |
||||
if hasattr(self, 'alternate_server_runner'): |
||||
self.alternate_server_runner.cleanup() |
||||
super().tearDown() |
||||
|
||||
def test_change_backend_service(self) -> None: |
||||
with self.subTest('00_create_health_check'): |
||||
self.td.create_health_check() |
||||
|
||||
with self.subTest('01_create_backend_services'): |
||||
self.td.create_backend_service() |
||||
self.td.create_alternative_backend_service() |
||||
|
||||
with self.subTest('02_create_url_map'): |
||||
self.td.create_url_map(self.server_xds_host, self.server_xds_port) |
||||
|
||||
with self.subTest('03_create_target_proxy'): |
||||
self.td.create_target_proxy() |
||||
|
||||
with self.subTest('04_create_forwarding_rule'): |
||||
self.td.create_forwarding_rule(self.server_xds_port) |
||||
|
||||
with self.subTest('05_start_test_servers'): |
||||
self.default_test_servers: List[ |
||||
_XdsTestServer] = self.startTestServers() |
||||
self.same_zone_test_servers: List[ |
||||
_XdsTestServer] = self.startTestServers( |
||||
server_runner=self.alternate_server_runner) |
||||
|
||||
with self.subTest('06_add_server_backends_to_backend_services'): |
||||
self.setupServerBackends() |
||||
# Add backend to alternative backend service |
||||
neg_name_alt, neg_zones_alt = self.alternate_k8s_namespace.get_service_neg( |
||||
self.alternate_server_runner.service_name, self.server_port) |
||||
self.td.alternative_backend_service_add_neg_backends( |
||||
neg_name_alt, neg_zones_alt) |
||||
|
||||
with self.subTest('07_start_test_client'): |
||||
self.test_client: _XdsTestClient = self.startTestClient( |
||||
self.default_test_servers[0]) |
||||
|
||||
with self.subTest('08_test_client_xds_config_exists'): |
||||
self.assertXdsConfigExists(self.test_client) |
||||
|
||||
with self.subTest('09_test_server_received_rpcs_from_test_client'): |
||||
self.assertSuccessfulRpcs(self.test_client) |
||||
|
||||
with self.subTest('10_change_backend_service'): |
||||
self.td.patch_url_map(self.server_xds_host, self.server_xds_port, |
||||
self.td.alternative_backend_service) |
||||
self.assertRpcsEventuallyGoToGivenServers( |
||||
self.test_client, self.same_zone_test_servers) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
absltest.main(failfast=True) |
@ -0,0 +1,127 @@ |
||||
# Copyright 2021 gRPC authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
import logging |
||||
from typing import List |
||||
|
||||
from absl import flags |
||||
from absl.testing import absltest |
||||
|
||||
from framework import xds_k8s_testcase |
||||
from framework.infrastructure import k8s |
||||
from framework.test_app import server_app |
||||
|
||||
logger = logging.getLogger(__name__) |
||||
flags.adopt_module_key_flags(xds_k8s_testcase) |
||||
|
||||
# Type aliases |
||||
_XdsTestServer = xds_k8s_testcase.XdsTestServer |
||||
_XdsTestClient = xds_k8s_testcase.XdsTestClient |
||||
|
||||
|
||||
class FailoverTest(xds_k8s_testcase.RegularXdsKubernetesTestCase): |
||||
REPLICA_COUNT = 3 |
||||
MAX_RATE_PER_ENDPOINT = 100 |
||||
|
||||
def setUp(self): |
||||
super().setUp() |
||||
self.secondary_server_runner = server_app.KubernetesServerRunner( |
||||
k8s.KubernetesNamespace(self.secondary_k8s_api_manager, |
||||
self.server_namespace), |
||||
deployment_name=self.server_name + '-alt', |
||||
image_name=self.server_image, |
||||
gcp_service_account=self.gcp_service_account, |
||||
td_bootstrap_image=self.td_bootstrap_image, |
||||
gcp_project=self.project, |
||||
gcp_api_manager=self.gcp_api_manager, |
||||
xds_server_uri=self.xds_server_uri, |
||||
network=self.network, |
||||
debug_use_port_forwarding=self.debug_use_port_forwarding, |
||||
reuse_namespace=True) |
||||
|
||||
def tearDown(self): |
||||
if hasattr(self, 'secondary_server_runner'): |
||||
self.secondary_server_runner.cleanup() |
||||
super().tearDown() |
||||
|
||||
def test_failover(self) -> None: |
||||
with self.subTest('00_create_health_check'): |
||||
self.td.create_health_check() |
||||
|
||||
with self.subTest('01_create_backend_services'): |
||||
self.td.create_backend_service() |
||||
|
||||
with self.subTest('02_create_url_map'): |
||||
self.td.create_url_map(self.server_xds_host, self.server_xds_port) |
||||
|
||||
with self.subTest('03_create_target_proxy'): |
||||
self.td.create_target_proxy() |
||||
|
||||
with self.subTest('04_create_forwarding_rule'): |
||||
self.td.create_forwarding_rule(self.server_xds_port) |
||||
|
||||
with self.subTest('05_start_test_servers'): |
||||
self.default_test_servers: List[ |
||||
_XdsTestServer] = self.startTestServers( |
||||
replica_count=self.REPLICA_COUNT) |
||||
|
||||
self.alternate_test_servers: List[ |
||||
_XdsTestServer] = self.startTestServers( |
||||
server_runner=self.secondary_server_runner) |
||||
|
||||
with self.subTest('06_add_server_backends_to_backend_services'): |
||||
self.setupServerBackends( |
||||
max_rate_per_endpoint=self.MAX_RATE_PER_ENDPOINT) |
||||
self.setupServerBackends( |
||||
server_runner=self.secondary_server_runner, |
||||
max_rate_per_endpoint=self.MAX_RATE_PER_ENDPOINT) |
||||
|
||||
with self.subTest('07_start_test_client'): |
||||
self.test_client: _XdsTestClient = self.startTestClient( |
||||
self.default_test_servers[0]) |
||||
|
||||
with self.subTest('08_test_client_xds_config_exists'): |
||||
self.assertXdsConfigExists(self.test_client) |
||||
|
||||
with self.subTest('09_primary_locality_receives_requests'): |
||||
self.assertRpcsEventuallyGoToGivenServers(self.test_client, |
||||
self.default_test_servers) |
||||
|
||||
with self.subTest( |
||||
'10_secondary_locality_receives_no_requests_on_partial_primary_failure' |
||||
): |
||||
self.default_test_servers[0].set_not_serving() |
||||
self.assertRpcsEventuallyGoToGivenServers( |
||||
self.test_client, self.default_test_servers[1:]) |
||||
|
||||
with self.subTest('11_gentle_failover'): |
||||
self.default_test_servers[1].set_not_serving() |
||||
self.assertRpcsEventuallyGoToGivenServers( |
||||
self.test_client, |
||||
self.default_test_servers[2:] + self.alternate_test_servers) |
||||
|
||||
with self.subTest( |
||||
'12_secondary_locality_receives_requests_on_primary_failure'): |
||||
self.default_test_servers[2].set_not_serving() |
||||
self.assertRpcsEventuallyGoToGivenServers( |
||||
self.test_client, self.alternate_test_servers) |
||||
|
||||
with self.subTest('13_traffic_resumes_to_healthy_backends'): |
||||
for i in range(self.REPLICA_COUNT): |
||||
self.default_test_servers[i].set_serving() |
||||
self.assertRpcsEventuallyGoToGivenServers(self.test_client, |
||||
self.default_test_servers) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
absltest.main(failfast=True) |
@ -0,0 +1,103 @@ |
||||
# Copyright 2021 gRPC authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
import logging |
||||
from typing import List, Optional |
||||
|
||||
from absl import flags |
||||
from absl.testing import absltest |
||||
|
||||
from framework import xds_k8s_testcase |
||||
from framework.infrastructure import k8s |
||||
from framework.test_app import server_app |
||||
|
||||
logger = logging.getLogger(__name__) |
||||
flags.adopt_module_key_flags(xds_k8s_testcase) |
||||
|
||||
# Type aliases |
||||
_XdsTestServer = xds_k8s_testcase.XdsTestServer |
||||
_XdsTestClient = xds_k8s_testcase.XdsTestClient |
||||
|
||||
|
||||
class RemoveNegTest(xds_k8s_testcase.RegularXdsKubernetesTestCase): |
||||
|
||||
def setUp(self): |
||||
super().setUp() |
||||
self.alternate_server_runner = server_app.KubernetesServerRunner( |
||||
k8s.KubernetesNamespace(self.k8s_api_manager, |
||||
self.server_namespace), |
||||
deployment_name=self.server_name + '-alt', |
||||
image_name=self.server_image, |
||||
gcp_service_account=self.gcp_service_account, |
||||
td_bootstrap_image=self.td_bootstrap_image, |
||||
gcp_project=self.project, |
||||
gcp_api_manager=self.gcp_api_manager, |
||||
xds_server_uri=self.xds_server_uri, |
||||
network=self.network, |
||||
debug_use_port_forwarding=self.debug_use_port_forwarding, |
||||
reuse_namespace=True) |
||||
|
||||
def tearDown(self): |
||||
if hasattr(self, 'alternate_server_runner'): |
||||
self.alternate_server_runner.cleanup() |
||||
super().tearDown() |
||||
|
||||
def test_remove_neg(self) -> None: |
||||
with self.subTest('00_create_health_check'): |
||||
self.td.create_health_check() |
||||
|
||||
with self.subTest('01_create_backend_services'): |
||||
self.td.create_backend_service() |
||||
|
||||
with self.subTest('02_create_url_map'): |
||||
self.td.create_url_map(self.server_xds_host, self.server_xds_port) |
||||
|
||||
with self.subTest('03_create_target_proxy'): |
||||
self.td.create_target_proxy() |
||||
|
||||
with self.subTest('04_create_forwarding_rule'): |
||||
self.td.create_forwarding_rule(self.server_xds_port) |
||||
|
||||
with self.subTest('05_start_test_servers'): |
||||
self.default_test_servers: List[ |
||||
_XdsTestServer] = self.startTestServers() |
||||
self.same_zone_test_servers: List[ |
||||
_XdsTestServer] = self.startTestServers( |
||||
server_runner=self.alternate_server_runner) |
||||
|
||||
with self.subTest('06_add_server_backends_to_backend_services'): |
||||
self.setupServerBackends() |
||||
self.setupServerBackends(server_runner=self.alternate_server_runner) |
||||
|
||||
with self.subTest('07_start_test_client'): |
||||
self.test_client: _XdsTestClient = self.startTestClient( |
||||
self.default_test_servers[0]) |
||||
|
||||
with self.subTest('08_test_client_xds_config_exists'): |
||||
self.assertXdsConfigExists(self.test_client) |
||||
|
||||
with self.subTest('09_test_server_received_rpcs_from_test_client'): |
||||
self.assertSuccessfulRpcs(self.test_client) |
||||
|
||||
with self.subTest('10_remove_neg'): |
||||
self.assertRpcsEventuallyGoToGivenServers( |
||||
self.test_client, |
||||
self.default_test_servers + self.same_zone_test_servers) |
||||
self.removeServerBackends( |
||||
server_runner=self.alternate_server_runner) |
||||
self.assertRpcsEventuallyGoToGivenServers(self.test_client, |
||||
self.default_test_servers) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
absltest.main(failfast=True) |
@ -0,0 +1,88 @@ |
||||
# Copyright 2021 gRPC authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
import logging |
||||
from typing import List, Optional |
||||
|
||||
from absl import flags |
||||
from absl.testing import absltest |
||||
|
||||
from framework import xds_k8s_testcase |
||||
from framework.infrastructure import k8s |
||||
from framework.test_app import server_app |
||||
|
||||
logger = logging.getLogger(__name__) |
||||
flags.adopt_module_key_flags(xds_k8s_testcase) |
||||
|
||||
# Type aliases |
||||
_XdsTestServer = xds_k8s_testcase.XdsTestServer |
||||
_XdsTestClient = xds_k8s_testcase.XdsTestClient |
||||
|
||||
|
||||
class RoundRobinTest(xds_k8s_testcase.RegularXdsKubernetesTestCase): |
||||
|
||||
def test_round_robin(self) -> None: |
||||
REPLICA_COUNT = 2 |
||||
|
||||
with self.subTest('00_create_health_check'): |
||||
self.td.create_health_check() |
||||
|
||||
with self.subTest('01_create_backend_services'): |
||||
self.td.create_backend_service() |
||||
|
||||
with self.subTest('02_create_url_map'): |
||||
self.td.create_url_map(self.server_xds_host, self.server_xds_port) |
||||
|
||||
with self.subTest('03_create_target_proxy'): |
||||
self.td.create_target_proxy() |
||||
|
||||
with self.subTest('04_create_forwarding_rule'): |
||||
self.td.create_forwarding_rule(self.server_xds_port) |
||||
|
||||
with self.subTest('05_start_test_servers'): |
||||
self.test_servers: List[_XdsTestServer] = self.startTestServers( |
||||
replica_count=REPLICA_COUNT) |
||||
|
||||
with self.subTest('06_add_server_backends_to_backend_services'): |
||||
self.setupServerBackends() |
||||
|
||||
with self.subTest('07_start_test_client'): |
||||
self.test_client: _XdsTestClient = self.startTestClient( |
||||
self.test_servers[0]) |
||||
|
||||
with self.subTest('08_test_client_xds_config_exists'): |
||||
self.assertXdsConfigExists(self.test_client) |
||||
|
||||
with self.subTest('09_test_server_received_rpcs_from_test_client'): |
||||
self.assertSuccessfulRpcs(self.test_client) |
||||
|
||||
with self.subTest('10_round_robin'): |
||||
num_rpcs = 100 |
||||
expected_rpcs_per_replica = num_rpcs / REPLICA_COUNT |
||||
|
||||
rpcs_by_peer = self.getClientRpcStats(self.test_client, |
||||
num_rpcs).rpcs_by_peer |
||||
total_requests_received = sum(rpcs_by_peer[x] for x in rpcs_by_peer) |
||||
self.assertEqual(total_requests_received, num_rpcs, |
||||
'Wrong number of RPCS') |
||||
for server in self.test_servers: |
||||
pod_name = server.pod_name |
||||
self.assertIn(pod_name, rpcs_by_peer, |
||||
f'pod {pod_name} did not receive RPCs') |
||||
self.assertLessEqual( |
||||
abs(rpcs_by_peer[pod_name] - expected_rpcs_per_replica), 1, |
||||
f'Wrong number of RPCs for {pod_name}') |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
absltest.main(failfast=True) |
Loading…
Reference in new issue