[PSM Interop] Print stacktrace before test case teardown (#34023)

* Before change, stacktrace will only be printed at the end of test,
after change, we'll also print the stacktrace before test teardown.
* Stacktrace format is similar to
[unittest/runner.py](https://github.com/python/cpython/blob/3.10/Lib/unittest/runner.py#L112,L125)
* Sample log for url_map (from [this test
run](https://source.cloud.google.com/results/invocations/2345d431-6202-478b-97c2-2a1b64bd13c0)):
```
[  FAILED  ] csds_test.TestBasicCsds.test_client_config
I0810 18:36:25.332329 139712423387136 base_testcase.py:34] ----- TestCase csds_test.TestBasicCsds.test_client_config FAILED -----
E0810 18:36:25.332529 139712423387136 base_testcase.py:53] ERROR Traceback in: csds_test.TestBasicCsds.test_client_config:
E0810 18:36:25.332598 139712423387136 base_testcase.py:54] Traceback (most recent call last):
  File "/tmp/tmp.qFY6iMjIkq/grpc/tools/run_tests/xds_k8s_test_driver/framework/xds_url_map_testcase.py", line 492, in test_client_config
    retryer(self._fetch_and_check_xds_config)
  File "/tmp/tmp.qFY6iMjIkq/grpc/tools/run_tests/xds_k8s_test_driver/venv/lib/python3.10/site-packages/tenacity/__init__.py", line 423, in __call__
    do = self.iter(retry_state=retry_state)
  File "/tmp/tmp.qFY6iMjIkq/grpc/tools/run_tests/xds_k8s_test_driver/venv/lib/python3.10/site-packages/tenacity/__init__.py", line 369, in iter
    return self.retry_error_callback(retry_state=retry_state)
  File "/tmp/tmp.qFY6iMjIkq/grpc/tools/run_tests/xds_k8s_test_driver/framework/helpers/retryers.py", line 141, in error_handler
    raise RetryError(
framework.helpers.retryers.RetryError: Retry error calling framework.xds_url_map_testcase.XdsUrlMapTestCase._fetch_and_check_xds_config: timeout 0:10:00 (h:mm:ss) exceeded. Last exception: AssertionError: 2 != 3

I0810 18:36:25.332715 139712423387136 xds_url_map_testcase.py:478] Aborting TestBasicCsds
I0810 18:36:25.332844 139712423387136 xds_url_map_testcase.py:408] ----- TestCase TestBasicCsds teardown -----
```
* Sample log when testing locally with multiple errors:
```
Running tests under Python 3.10.9: /usr/local/google/home/xuanwn/.pyenv/versions/310xds/bin/python
I0814 17:07:22.553086 140334944188224 xds_k8s_testcase.py:130] ----- Testing BaselineTest -----
I0814 17:07:22.553292 140334944188224 xds_k8s_testcase.py:131] Logs timezone: UTC
I0814 17:07:22.553575 140334944188224 skips.py:124] Detected language and version: TestConfig(client_lang='java', server_lang='java', version=None)
I0814 17:07:22.592908 140334944188224 k8s.py:129] Using kubernetes context "gke_xuanwn-xds_us-central1-a_xds-k8s-interop-tests-cluster", active host: https://34.132.21.170
I0814 17:07:22.733086 140334944188224 k8s.py:129] Using kubernetes context "None", active host: https://34.144.123.58
[ RUN      ] BaselineTest.test_another
I0814 17:07:22.740435 140334944188224 xds_k8s_testcase.py:590] Test run resource prefix: xds-k8s-test, suffix: dev
I0814 17:07:29.515993 140334944188224 xds_k8s_testcase.py:640] ----- TestMethod __main__.BaselineTest.test_another teardown -----
I0814 17:07:29.517023 140334944188224 xds_k8s_testcase.py:664] ----- Test client/server logs -----
I0814 17:07:29.517564 140334944188224 k8s_base_runner.py:621] No completed deployments of psm-grpc-client
I0814 17:07:29.517683 140334944188224 k8s_base_runner.py:621] No completed deployments of psm-grpc-server
[  FAILED  ] BaselineTest.test_another
I0814 17:07:29.518238 140334944188224 base_testcase.py:40] ----- TestCase __main__.BaselineTest.test_another FAILED -----
E0814 17:07:29.518383 140334944188224 base_testcase.py:61] FAILURE Traceback in __main__.BaselineTest.test_another:
Traceback (most recent call last):
  File "/usr/local/google/home/xuanwn/workspace/xds/grpc/tools/run_tests/xds_k8s_test_driver/tests/baseline_test.py", line 34, in test_another
    self.assertEqual("test another", None)
AssertionError: 'test another' != None

[ RUN      ] BaselineTest.test_another_2
I0814 17:07:29.518589 140334944188224 xds_k8s_testcase.py:590] Test run resource prefix: xds-k8s-test, suffix: dev
I0814 17:07:29.535759 140334944188224 xds_k8s_testcase.py:640] ----- TestMethod __main__.BaselineTest.test_another_2 teardown -----
I0814 17:07:29.536597 140334944188224 xds_k8s_testcase.py:664] ----- Test client/server logs -----
I0814 17:07:29.536783 140334944188224 k8s_base_runner.py:621] No completed deployments of psm-grpc-client
I0814 17:07:29.536932 140334944188224 k8s_base_runner.py:621] No completed deployments of psm-grpc-server
[       OK ] BaselineTest.test_another_2
I0814 17:07:29.537171 140334944188224 base_testcase.py:53] ----- TestCase __main__.BaselineTest.test_another_2 PASSED -----
[ RUN      ] BaselineTest.test_expect_error
I0814 17:07:29.537445 140334944188224 xds_k8s_testcase.py:590] Test run resource prefix: xds-k8s-test, suffix: dev
I0814 17:07:29.554539 140334944188224 xds_k8s_testcase.py:640] ----- TestMethod __main__.BaselineTest.test_expect_error teardown -----
I0814 17:07:29.555363 140334944188224 xds_k8s_testcase.py:664] ----- Test client/server logs -----
I0814 17:07:29.555552 140334944188224 k8s_base_runner.py:621] No completed deployments of psm-grpc-client
I0814 17:07:29.555636 140334944188224 k8s_base_runner.py:621] No completed deployments of psm-grpc-server
[  FAILED  ] BaselineTest.test_expect_error
I0814 17:07:29.555815 140334944188224 base_testcase.py:46] ----- TestCase __main__.BaselineTest.test_expect_error UNEXPECTEDLY SUCCEED -----
[ RUN      ] BaselineTest.test_skip
[  SKIPPED ] BaselineTest.test_skip
I0814 17:07:29.555988 140334944188224 base_testcase.py:50] ----- TestCase __main__.BaselineTest.test_skip SKIPPED -----
I0814 17:07:29.556062 140334944188224 base_testcase.py:51] Reason for skipping: ['skip for once']
[ RUN      ] BaselineTest.test_traffic_director_grpc_setup
I0814 17:07:29.556408 140334944188224 xds_k8s_testcase.py:590] Test run resource prefix: xds-k8s-test, suffix: dev
I0814 17:07:29.572924 140334944188224 xds_k8s_testcase.py:640] ----- TestMethod __main__.BaselineTest.test_traffic_director_grpc_setup teardown -----
I0814 17:07:29.573563 140334944188224 xds_k8s_testcase.py:664] ----- Test client/server logs -----
I0814 17:07:29.573725 140334944188224 k8s_base_runner.py:621] No completed deployments of psm-grpc-client
I0814 17:07:29.573856 140334944188224 k8s_base_runner.py:621] No completed deployments of psm-grpc-server
[  FAILED  ] BaselineTest.test_traffic_director_grpc_setup
I0814 17:07:29.574180 140334944188224 base_testcase.py:40] ----- TestCase __main__.BaselineTest.test_traffic_director_grpc_setup FAILED -----
E0814 17:07:29.574276 140334944188224 base_testcase.py:61] FAILURE Traceback in __main__.BaselineTest.test_traffic_director_grpc_setup:
Traceback (most recent call last):
  File "/usr/local/google/home/xuanwn/workspace/xds/grpc/tools/run_tests/xds_k8s_test_driver/tests/baseline_test.py", line 31, in test_traffic_director_grpc_setup
    self.assertEqual("test grpc setup", None)
AssertionError: 'test grpc setup' != None

======================================================================
FAIL: test_another (__main__.BaselineTest)
BaselineTest.test_another
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/google/home/xuanwn/workspace/xds/grpc/tools/run_tests/xds_k8s_test_driver/tests/baseline_test.py", line 34, in test_another
    self.assertEqual("test another", None)
AssertionError: 'test another' != None

======================================================================
FAIL: test_traffic_director_grpc_setup (__main__.BaselineTest)
BaselineTest.test_traffic_director_grpc_setup
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/google/home/xuanwn/workspace/xds/grpc/tools/run_tests/xds_k8s_test_driver/tests/baseline_test.py", line 31, in test_traffic_director_grpc_setup
    self.assertEqual("test grpc setup", None)
AssertionError: 'test grpc setup' != None

----------------------------------------------------------------------
Ran 5 tests in 7.021s

FAILED (failures=2, skipped=1, unexpected successes=1)
```
pull/34100/head
Xuan Wang 2 years ago committed by GitHub
parent b4b6319ecc
commit 5fbc1a841b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      tools/run_tests/xds_k8s_test_driver/framework/test_cases/__init__.py
  2. 65
      tools/run_tests/xds_k8s_test_driver/framework/test_cases/base_testcase.py
  3. 4
      tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py
  4. 6
      tools/run_tests/xds_k8s_test_driver/framework/xds_url_map_testcase.py

@ -0,0 +1,13 @@
# Copyright 2023 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.

@ -0,0 +1,65 @@
# Copyright 2023 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.
"""Base test case used for xds test suites."""
from typing import Optional
import unittest
from absl import logging
from absl.testing import absltest
class BaseTestCase(absltest.TestCase):
def run(self, result: Optional[unittest.TestResult] = None) -> None:
super().run(result)
test_errors = [error for test, error in result.errors if test is self]
test_failures = [
failure for test, failure in result.failures if test is self
]
test_unexpected_successes = [
test for test in result.unexpectedSuccesses if test is self
]
test_skipped = next(
(reason for test, reason in result.skipped if test is self),
None,
)
# Assume one test case will only have one status.
if test_errors or test_failures:
logging.info("----- TestCase %s FAILED -----", self.id())
if test_errors:
self._print_error_list(test_errors, is_unexpected_error=True)
if test_failures:
self._print_error_list(test_failures)
elif test_unexpected_successes:
logging.info(
"----- TestCase %s UNEXPECTEDLY SUCCEEDED -----", self.id()
)
elif test_skipped:
logging.info("----- TestCase %s SKIPPED -----", self.id())
logging.info("Reason for skipping: %s", test_skipped)
else:
logging.info("----- TestCase %s PASSED -----", self.id())
def _print_error_list(
self, errors: list[str], is_unexpected_error: bool = False
) -> None:
# FAILUREs are those errors explicitly signalled using
# the TestCase.assert*() methods.
for err in errors:
logging.error(
"%s Traceback in %s:\n%s",
"ERROR" if is_unexpected_error else "FAILURE",
self.id(),
err,
)

@ -24,7 +24,6 @@ from types import FrameType
from typing import Any, Callable, List, Optional, Tuple, Union from typing import Any, Callable, List, Optional, Tuple, Union
from absl import flags from absl import flags
from absl.testing import absltest
from google.protobuf import json_format from google.protobuf import json_format
import grpc import grpc
@ -46,6 +45,7 @@ from framework.test_app import client_app
from framework.test_app import server_app from framework.test_app import server_app
from framework.test_app.runners.k8s import k8s_xds_client_runner from framework.test_app.runners.k8s import k8s_xds_client_runner
from framework.test_app.runners.k8s import k8s_xds_server_runner from framework.test_app.runners.k8s import k8s_xds_server_runner
from framework.test_cases import base_testcase
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# TODO(yashkt): We will no longer need this flag once Core exposes local certs # TODO(yashkt): We will no longer need this flag once Core exposes local certs
@ -84,7 +84,7 @@ class TdPropagationRetryableError(Exception):
"""Indicates that TD config hasn't propagated yet, and it's safe to retry""" """Indicates that TD config hasn't propagated yet, and it's safe to retry"""
class XdsKubernetesBaseTestCase(absltest.TestCase): class XdsKubernetesBaseTestCase(base_testcase.BaseTestCase):
lang_spec: skips.TestConfig lang_spec: skips.TestConfig
client_namespace: str client_namespace: str
client_runner: KubernetesClientRunner client_runner: KubernetesClientRunner

@ -26,7 +26,6 @@ import unittest
from absl import flags from absl import flags
from absl import logging from absl import logging
from absl.testing import absltest
from google.protobuf import json_format from google.protobuf import json_format
import grpc import grpc
@ -38,6 +37,7 @@ from framework.helpers import skips
from framework.infrastructure import k8s from framework.infrastructure import k8s
from framework.test_app import client_app from framework.test_app import client_app
from framework.test_app.runners.k8s import k8s_xds_client_runner from framework.test_app.runners.k8s import k8s_xds_client_runner
from framework.test_cases import base_testcase
# Load existing flags # Load existing flags
flags.adopt_module_key_flags(xds_k8s_testcase) flags.adopt_module_key_flags(xds_k8s_testcase)
@ -268,7 +268,9 @@ class _MetaXdsUrlMapTestCase(type):
return new_class return new_class
class XdsUrlMapTestCase(absltest.TestCase, metaclass=_MetaXdsUrlMapTestCase): class XdsUrlMapTestCase(
base_testcase.BaseTestCase, metaclass=_MetaXdsUrlMapTestCase
):
"""XdsUrlMapTestCase is the base class for urlMap related tests. """XdsUrlMapTestCase is the base class for urlMap related tests.
The subclass is expected to implement 3 methods: The subclass is expected to implement 3 methods:

Loading…
Cancel
Save