Skip to content

Commit

Permalink
Move testing related function to a dedicated lib + move unit tests (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinFairise2 authored Oct 11, 2024
1 parent 460a46b commit b2159bf
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 121 deletions.
7 changes: 6 additions & 1 deletion tasks/libs/common/junit_upload_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
GITHUB_JIRA_MAP,
GITHUB_SLACK_MAP,
)
from tasks.libs.testing.flakes import get_tests_family, is_known_flaky_test
from tasks.modules import DEFAULT_MODULES

E2E_INTERNAL_ERROR_STRING = "E2E INTERNAL ERROR"
Expand Down Expand Up @@ -210,7 +211,11 @@ def split_junitxml(root_dir: Path, xml_path: Path, codeowners, flaky_tests):
# Flag the test as known flaky if gotestsum already knew it
for test_case in suite.iter("testcase"):
test_name = "/".join([test_case.attrib["classname"], test_case.attrib["name"]])
test_case.attrib["agent_is_known_flaky"] = "true" if test_name in flaky_tests else "false"
if is_known_flaky_test(test_name, flaky_tests, get_tests_family(list(flaky_tests))):
test_case.attrib["agent_is_known_flaky"] = "true"
print("KNOWN FLAKY:", test_name)
else:
test_case.attrib["agent_is_known_flaky"] = "false"

xml.getroot().append(suite)

Expand Down
58 changes: 58 additions & 0 deletions tasks/libs/testing/flakes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
def get_tests_family_if_failing_tests(test_name_list, failing_tests: set):
"""Get the parent tests of a list of tests only if the marked test is failing
For example with the test ["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestCPU"]
this method should return the set{"TestEKSSuite/TestCPU/TestCPUUtilization", "TestEKSSuite/TestCPU", "TestEKSSuite", "TestKindSuite/TestCPU", "TestKindSuite"}
if TestKindSuite/TestCPU and TestEKSSuite/TestCPU/TestCPUUtilization are failing
Another example, with the test ["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestCPU"]
if only TestKindSuite/TestCPU is failing, the method should return the set{"TestKindSuite/TestCPU", "TestKindSuite"}
Args:
test_name_list (list): List of test names to get the parent tests from
failing_tests (set): Set of tests that are failing
"""
test_name_set = set(test_name_list)
marked_tests_failing = failing_tests.intersection(test_name_set)
return get_tests_family(list(marked_tests_failing))


def get_tests_family(test_name_list):
"""Get the parent tests of a list of tests
Get the parent tests of a list of tests
For example with the test ["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestCPU"]
this method should return the set{"TestEKSSuite/TestCPU/TestCPUUtilization", "TestEKSSuite/TestCPU", "TestEKSSuite", "TestKindSuite/TestCPU", "TestKindSuite"}
Args:
test_name_list (list): List of test names to get the parent tests from
"""
test_family = set(test_name_list)
for test_name in test_name_list:
while test_name.count('/') > 0:
test_name = test_name.rsplit('/', 1)[0]
test_family.add(test_name)
return test_family


def is_known_flaky_test(failing_test, known_flaky_tests, known_flaky_tests_parents):
"""Check if a test is known to be flaky
If a test is a parent of a test that is known to be flaky, the test should be considered flaky
For example:
- if TestEKSSuite/TestCPU is known to be flaky, TestEKSSuite/TestCPU/TestCPUUtilization should be considered flaky
- if TestEKSSuite/TestCPU is known to be flaky, TestEKSSuite should be considered flaky unless TestEKSSuite/TestCPU is not failing
- if TestEKSSuite/TestCPU is known to be flaky, TestEKSSuite/TestMemory should not be considered flaky
Args:
failing_test (str): The test that is failing
known_flaky_tests (set): Set of tests that are known to be flaky
known_flaky_tests_parents (set): Set of tests that are parent of a test that is known to be flaky
"""

failing_test_parents = get_tests_family([failing_test])

if any(parent in known_flaky_tests for parent in failing_test_parents):
return True

return failing_test in known_flaky_tests_parents
52 changes: 3 additions & 49 deletions tasks/testwasher.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
resolve_gitlab_ci_configuration,
)
from tasks.libs.common.utils import gitlab_section
from tasks.libs.testing.flakes import get_tests_family_if_failing_tests, is_known_flaky_test
from tasks.test_core import ModuleTestResult

FLAKY_TEST_INDICATOR = "flakytest: this is a known flaky test"
Expand Down Expand Up @@ -40,11 +41,11 @@ def get_non_flaky_failing_tests(self, failing_tests: dict, flaky_marked_tests: d

for package, tests in failing_tests.items():
non_flaky_failing_tests_in_package = set()
known_flaky_tests_parents = self.get_tests_family_if_failing_tests(
known_flaky_tests_parents = get_tests_family_if_failing_tests(
all_known_flakes[package], failing_tests[package]
)
for failing_test in tests:
if not self.is_known_flaky_test(failing_test, all_known_flakes[package], known_flaky_tests_parents):
if not is_known_flaky_test(failing_test, all_known_flakes[package], known_flaky_tests_parents):
non_flaky_failing_tests_in_package.add(failing_test)
if non_flaky_failing_tests_in_package:
non_flaky_failing_tests[package] = non_flaky_failing_tests_in_package
Expand Down Expand Up @@ -125,53 +126,6 @@ def process_module_results(self, module_results: list[ModuleTestResult]):

return should_succeed

def is_known_flaky_test(self, failing_test, known_flaky_tests, known_flaky_tests_parents):
"""
Check if a test is known to be flaky
The method should be called with the following arguments:
- failing_test: the test that is failing
- known_flaky_tests: the set of tests that are known to be flaky
- known_flaky_tests_parents: the set of tests that are ancestors of a known flaky test, thus would fail when the flaky leaf test fails
If a test is a parent of a test that is known to be flaky, the test should be considered flaky
For example:
- if TestEKSSuite/TestCPU is known to be flaky, TestEKSSuite/TestCPU/TestCPUUtilization should be considered flaky
- if TestEKSSuite/TestCPU is known to be flaky, TestEKSSuite should be considered flaky unless TestEKSSuite/TestCPU is not failing
- if TestEKSSuite/TestCPU is known to be flaky, TestEKSSuite/TestMemory should not be considered flaky
"""

failing_test_parents = self.get_tests_family([failing_test])

if any(parent in known_flaky_tests for parent in failing_test_parents):
return True

return failing_test in known_flaky_tests_parents

def get_tests_family_if_failing_tests(self, test_name_list, failing_tests: set):
"""
Get the parent tests of a list of tests only if the marked test is failing
For example with the test ["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestCPU"]
this method should return the set{"TestEKSSuite/TestCPU/TestCPUUtilization", "TestEKSSuite/TestCPU", "TestEKSSuite", "TestKindSuite/TestCPU", "TestKindSuite"}
if TestKindSuite/TestCPU and TestEKSSuite/TestCPU/TestCPUUtilization are failing
Another example, with the test ["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestCPU"]
if only TestKindSuite/TestCPU is failing, the method should return the set{"TestKindSuite/TestCPU", "TestKindSuite"}
"""
test_name_set = set(test_name_list)
marked_tests_failing = failing_tests.intersection(test_name_set)
return self.get_tests_family(list(marked_tests_failing))

def get_tests_family(self, test_name_list):
"""
Get the parent tests of a list of tests
For example with the test ["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestCPU"]
this method should return the set{"TestEKSSuite/TestCPU/TestCPUUtilization", "TestEKSSuite/TestCPU", "TestEKSSuite", "TestKindSuite/TestCPU", "TestKindSuite"}
"""
test_family = set(test_name_list)
for test_name in test_name_list:
while test_name.count('/') > 0:
test_name = test_name.rsplit('/', 1)[0]
test_family.add(test_name)
return test_family


@task
def generate_flake_finder_pipeline(ctx, n=3):
Expand Down
96 changes: 96 additions & 0 deletions tasks/unit_tests/flakes_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import unittest

from tasks.libs.testing.flakes import get_tests_family, get_tests_family_if_failing_tests, is_known_flaky_test


class TestGetTestParents(unittest.TestCase):
def test_get_tests_parents(self):
parents = get_tests_family(["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestKind"])
self.assertEqual(
parents,
{
"TestEKSSuite",
"TestEKSSuite/TestCPU",
"TestEKSSuite/TestCPU/TestCPUUtilization",
"TestKindSuite",
"TestKindSuite/TestKind",
},
)

def test_get_test_parents_empty(self):
parents = get_tests_family([])
self.assertEqual(
parents,
set(),
)

def test_get_test_parents_failing_no_failing_tests(self):
parents = get_tests_family_if_failing_tests(["TestEKSSuite/TestCPU/TestCPUUtilization"], set())
self.assertEqual(
parents,
set(),
)

def test_get_test_parents_failing_all_failing_tests(self):
parents = get_tests_family_if_failing_tests(
["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestCPU"],
{"TestKindSuite/TestCPU", "TestEKSSuite/TestCPU/TestCPUUtilization"},
)
self.assertEqual(
parents,
{
"TestEKSSuite",
"TestEKSSuite/TestCPU",
"TestEKSSuite/TestCPU/TestCPUUtilization",
"TestKindSuite",
"TestKindSuite/TestCPU",
},
)

def test_get_test_parents_failing_some_failing_tests(self):
parents = get_tests_family_if_failing_tests(
["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestCPU"], {"TestKindSuite/TestCPU"}
)
self.assertEqual(
parents,
{
"TestKindSuite",
"TestKindSuite/TestCPU",
},
)


class TestIsKnownFlake(unittest.TestCase):
def test_known_flake(self):
is_known_flaky = is_known_flaky_test(
"TestEKSSuite/mario", {"TestEKSSuite/mario"}, {"TestEKSSuite", "TestEKSSuite/mario"}
)
self.assertTrue(is_known_flaky)

def test_known_flake_parent_failing(self):
is_known_flaky = is_known_flaky_test(
"TestEKSSuite", {"TestEKSSuite/mario"}, {"TestEKSSuite", "TestEKSSuite/mario"}
)
self.assertTrue(is_known_flaky)

def test_known_flake_parent_failing_2(self):
is_known_flaky = is_known_flaky_test(
"TestEKSSuite/mario",
{"TestEKSSuite/mario/luigi"},
{"TestEKSSuite", "TestEKSSuite/mario", "TestEKSSuite/mario/luigi"},
)
self.assertTrue(is_known_flaky)

def test_not_known_flake(self):
is_known_flaky = is_known_flaky_test(
"TestEKSSuite/luigi", {"TestEKSSuite/mario"}, {"TestEKSSuite", "TestEKSSuite/mario"}
)
self.assertFalse(is_known_flaky)

def test_not_known_flake_ambiguous_start(self):
is_known_flaky = is_known_flaky_test("TestEKSSuiteVM/mario", {"TestEKSSuite/mario"}, {"TestEKSSuite"})
self.assertFalse(is_known_flaky)

def test_not_known_flake_ambiguous_start_2(self):
is_known_flaky = is_known_flaky_test("TestEKSSuite/mario", {"TestEKSSuiteVM/mario"}, {"TestEKSSuiteVM"})
self.assertFalse(is_known_flaky)
71 changes: 0 additions & 71 deletions tasks/unit_tests/testwasher_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ def test_should_not_be_considered_flaky(self):
non_flaky_failing_tests = test_washer.get_non_flaky_failing_tests(
failing_tests=failing_tests, flaky_marked_tests=marked_flaky_tests
)
print("TOTOTO", non_flaky_failing_tests)
self.assertEqual(
non_flaky_failing_tests,
{"github.com/DataDog/datadog-agent/test/new-e2e/tests/containers": {"TestEKSSuite"}},
Expand Down Expand Up @@ -133,73 +132,3 @@ def test_empty_yaml(self):
merged_flakes,
{"nintendo": {"mario", "luigi"}},
)


class TestGetTestParents(unittest.TestCase):
def test_get_tests_parents(self):
test_washer = TestWasher()
parents = test_washer.get_tests_family(["TestEKSSuite/TestCPU/TestCPUUtilization", "TestKindSuite/TestKind"])
self.assertEqual(
parents,
{
"TestEKSSuite",
"TestEKSSuite/TestCPU",
"TestEKSSuite/TestCPU/TestCPUUtilization",
"TestKindSuite",
"TestKindSuite/TestKind",
},
)

def test_get_test_parents_empty(self):
test_washer = TestWasher()
parents = test_washer.get_tests_family([])
self.assertEqual(
parents,
set(),
)


class TestIsKnownFlake(unittest.TestCase):
def test_known_flake(self):
test_washer = TestWasher()
is_known_flaky = test_washer.is_known_flaky_test(
"TestEKSSuite/mario", {"TestEKSSuite/mario"}, {"TestEKSSuite", "TestEKSSuite/mario"}
)
self.assertTrue(is_known_flaky)

def test_known_flake_parent_failing(self):
test_washer = TestWasher()
is_known_flaky = test_washer.is_known_flaky_test(
"TestEKSSuite", {"TestEKSSuite/mario"}, {"TestEKSSuite", "TestEKSSuite/mario"}
)
self.assertTrue(is_known_flaky)

def test_known_flake_parent_failing_2(self):
test_washer = TestWasher()
is_known_flaky = test_washer.is_known_flaky_test(
"TestEKSSuite/mario",
{"TestEKSSuite/mario/luigi"},
{"TestEKSSuite", "TestEKSSuite/mario", "TestEKSSuite/mario/luigi"},
)
self.assertTrue(is_known_flaky)

def test_not_known_flake(self):
test_washer = TestWasher()
is_known_flaky = test_washer.is_known_flaky_test(
"TestEKSSuite/luigi", {"TestEKSSuite/mario"}, {"TestEKSSuite", "TestEKSSuite/mario"}
)
self.assertFalse(is_known_flaky)

def test_not_known_flake_ambiguous_start(self):
test_washer = TestWasher()
is_known_flaky = test_washer.is_known_flaky_test(
"TestEKSSuiteVM/mario", {"TestEKSSuite/mario"}, {"TestEKSSuite"}
)
self.assertFalse(is_known_flaky)

def test_not_known_flake_ambiguous_start_2(self):
test_washer = TestWasher()
is_known_flaky = test_washer.is_known_flaky_test(
"TestEKSSuite/mario", {"TestEKSSuiteVM/mario"}, {"TestEKSSuiteVM"}
)
self.assertFalse(is_known_flaky)

0 comments on commit b2159bf

Please sign in to comment.