Skip to content

Commit

Permalink
Update tests to reflect changes in the algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
sondrelg committed Jul 21, 2021
1 parent 517201d commit 3eca51e
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 37 deletions.
19 changes: 13 additions & 6 deletions src/pytest_split/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,21 @@ def duration_based_chunks(splits: int, items: "List[nodes.Item]", durations: "Di
duration: "List[float]" = [0 for i in range(splits)]

group_idx = 0
for item in items:
test_count = len(items)
for index, item in enumerate(items):
item_duration = tests_and_durations.pop(item)

if duration[group_idx] + item_duration > time_per_group:
if not selected[group_idx]:
# Add test to current group if group has no tests
pass
elif group_idx + 1 >= splits:
tests_left = test_count - index
groups_left = splits - group_idx

if not selected[group_idx]:
# Add test to current group if group has no tests
pass
elif tests_left < groups_left:
# Make sure that we assign at least one test to each group
group_idx += 1
elif duration[group_idx] + item_duration > time_per_group:
if group_idx + 1 >= splits:
# Stay with group index if it's the final group in the split
pass
else:
Expand Down
30 changes: 15 additions & 15 deletions tests/test_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from pytest_split.algorithms import Algorithms
from src.pytest_split.algorithms import Algorithms, duration_based_chunks

item = namedtuple("item", "nodeid")

Expand All @@ -11,7 +11,7 @@ class TestAlgorithms:
@pytest.mark.parametrize("algo_name", Algorithms.names())
def test__split_test(self, algo_name):
durations = {"a": 1, "b": 1, "c": 1}
items = [item(x) for x in durations.keys()]
items = [item(x) for x in durations]
algo = Algorithms[algo_name].value
first, second, third = algo(splits=3, items=items, durations=durations)

Expand Down Expand Up @@ -84,26 +84,26 @@ def test__split_tests_calculates_avg_test_duration_only_on_present_tests(self, a
assert first.selected == expected_first
assert second.selected == expected_second

def test_each_group_is_assigned_a_test(self):
from collections import namedtuple
def test_each_group_is_assigned_a_test_front_loaded(self):
item = namedtuple("item", "nodeid")

durations = {"a": 100, "b": 1, "c": 1, "d": 1, "e": 1, "f": 1, "g": 1, "h": 1}

items = [item(x) for x in ["a", "b", "c", "d", "e", "f", "g", "h"]]

from pytest_split import algorithms
groups = duration_based_chunks(8, items, durations)

for i in range(7):
assert groups[i].selected != []

def test_each_group_is_assigned_a_test_back_loaded(self):
item = namedtuple("item", "nodeid")

durations = {}
durations["a"] = 2313.7016449670773
durations["b"] = 46.880724348986405
durations["c"] = 2196.7077018650016
durations["d"] = 379.9717799640057
durations["e"] = 1476.3481151770247
durations["f"] = 979.7326026459923
durations["g"] = 1876.5443489580794
durations["h"] = 1.3951316330058035
durations = {"a": 1, "b": 1, "c": 1, "d": 1, "e": 1, "f": 1, "g": 1, "h": 100}

items = [item(x) for x in ["a", "b", "c", "d", "e", "f", "g", "h"]]

groups = algorithms.duration_based_chunks(7, items, durations)
groups = duration_based_chunks(8, items, durations)

for i in range(7):
assert groups[i].selected != []
33 changes: 17 additions & 16 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,20 @@ class TestSplitToSuites:
"least_duration",
["test_1", "test_2", "test_3", "test_4", "test_5", "test_6", "test_7", "test_8", "test_9", "test_10"],
),
(2, 1, "duration_based_chunks", ["test_1", "test_2", "test_3", "test_4", "test_5", "test_6", "test_7"]),
(2, 2, "duration_based_chunks", ["test_8", "test_9", "test_10"]),
(2, 1, "duration_based_chunks", ["test_1", "test_2", "test_3", "test_4", "test_5", "test_6"]),
(2, 2, "duration_based_chunks", ["test_7", "test_8", "test_9", "test_10"]),
(2, 1, "least_duration", ["test_1", "test_3", "test_5", "test_7", "test_9"]),
(2, 2, "least_duration", ["test_2", "test_4", "test_6", "test_8", "test_10"]),
(3, 1, "duration_based_chunks", ["test_1", "test_2", "test_3", "test_4", "test_5"]),
(3, 2, "duration_based_chunks", ["test_6", "test_7", "test_8"]),
(3, 3, "duration_based_chunks", ["test_9", "test_10"]),
(3, 2, "duration_based_chunks", ["test_6", "test_7"]),
(3, 3, "duration_based_chunks", ["test_8", "test_9", "test_10"]),
(3, 1, "least_duration", ["test_1", "test_4", "test_7", "test_10"]),
(3, 2, "least_duration", ["test_2", "test_5", "test_8"]),
(3, 3, "least_duration", ["test_3", "test_6", "test_9"]),
(4, 1, "duration_based_chunks", ["test_1", "test_2", "test_3", "test_4"]),
(4, 2, "duration_based_chunks", ["test_5", "test_6", "test_7"]),
(4, 3, "duration_based_chunks", ["test_8", "test_9"]),
(4, 4, "duration_based_chunks", ["test_10"]),
(4, 1, "duration_based_chunks", ["test_1", "test_2", "test_3"]),
(4, 2, "duration_based_chunks", ["test_4", "test_5"]),
(4, 3, "duration_based_chunks", ["test_6"]),
(4, 4, "duration_based_chunks", ["test_7", "test_8", "test_9", "test_10"]),
(4, 1, "least_duration", ["test_1", "test_5", "test_9"]),
(4, 2, "least_duration", ["test_2", "test_6", "test_10"]),
(4, 3, "least_duration", ["test_3", "test_7"]),
Expand Down Expand Up @@ -107,6 +107,7 @@ def test_it_splits(self, test_idx, splits, group, algo, expected, legacy_flag, e
"--splitting-algorithm",
algo,
)

result.assertoutcome(passed=len(expected))
assert _passed_test_names(result) == expected

Expand All @@ -128,16 +129,16 @@ def test_it_adapts_splits_based_on_new_and_deleted_tests(self, example_suite, du
json.dump(durations, f)

result = example_suite.inline_run("--splits", "3", "--group", "1", "--durations-path", durations_path)
result.assertoutcome(passed=4)
assert _passed_test_names(result) == ["test_1", "test_2", "test_3", "test_4"]
result.assertoutcome(passed=3)
assert _passed_test_names(result) == ["test_1", "test_2", "test_3"] # 3 sec

result = example_suite.inline_run("--splits", "3", "--group", "2", "--durations-path", durations_path)
result.assertoutcome(passed=3)
assert _passed_test_names(result) == ["test_5", "test_6", "test_7"]
result.assertoutcome(passed=1)
assert _passed_test_names(result) == ["test_4"] # 1 sec

result = example_suite.inline_run("--splits", "3", "--group", "3", "--durations-path", durations_path)
result.assertoutcome(passed=3)
assert _passed_test_names(result) == ["test_8", "test_9", "test_10"]
result.assertoutcome(passed=6)
assert _passed_test_names(result) == ["test_5", "test_6", "test_7", "test_8", "test_9", "test_10"] # 3 sec

def test_handles_case_of_no_durations_for_group(self, example_suite, durations_path):
with open(durations_path, "w") as f:
Expand All @@ -149,8 +150,8 @@ def test_handles_case_of_no_durations_for_group(self, example_suite, durations_p

def test_it_splits_with_other_collect_hooks(self, testdir, durations_path):
expected_tests_per_group = [
["test_1", "test_2", "test_3"],
["test_4", "test_5"],
["test_1", "test_2"],
["test_3", "test_4", "test_5"],
]

tests_to_run = "".join(f"@pytest.mark.mark_one\ndef test_{num}(): pass\n" for num in range(1, 6))
Expand Down

0 comments on commit 3eca51e

Please sign in to comment.