Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions smart_tests/commands/inspect/subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def __init__(self, result: dict, is_subset: bool):
self._test_path = "#".join([path["type"] + "=" + path["name"]
for path in result["testPath"] if path.keys() >= {"type", "name"}])
self._is_subset = is_subset
self._density = result.get("density", 0.0)
self._is_new = result.get("numNewTests", 0) > 0


class SubsetResults(object):
Expand Down Expand Up @@ -57,19 +59,22 @@ class SubsetResultTableDisplay(SubsetResultAbstractDisplay):
def __init__(self, results: SubsetResults):
super().__init__(results)

def display(self):
header = ["Order", "Test Path", "In Subset", "Estimated duration (sec)"]
def display(self, new_tests_only: bool = False):
header = ["Order", "Test Path", "In Subset", "Density", "Duration", "New"]
rows = []
for idx, result in enumerate(self._results.list()):
results = [r for r in self._results.list() if r._is_new] if new_tests_only else self._results.list()
for idx, result in enumerate(results):
rows.append(
[
idx + 1,
result._test_path,
"✔" if result._is_subset else "",
result._estimated_duration_sec,
result._density,
"{:.3f}s".format(result._estimated_duration_sec),
"Yes" if result._is_new else "No",
]
)
click.echo_via_pager(tabulate(rows, header, tablefmt="github", floatfmt=".2f"))
click.echo_via_pager(tabulate(rows, header, tablefmt="github", floatfmt=".3f"))


class SubsetResultJSONDisplay(SubsetResultAbstractDisplay):
Expand Down Expand Up @@ -105,6 +110,10 @@ def subset(
json: Annotated[bool, typer.Option(
help="Display JSON format"
)] = False,
new_tests_only: Annotated[bool, typer.Option(
"--new-tests-only",
help="Show only tests that have no duration history"
)] = False,
):
is_json_format = json # Map parameter name

Expand Down Expand Up @@ -135,4 +144,7 @@ def subset(
else:
displayer = SubsetResultTableDisplay(results)

displayer.display()
if isinstance(displayer, SubsetResultTableDisplay):
displayer.display(new_tests_only=new_tests_only)
else:
displayer.display()
12 changes: 10 additions & 2 deletions smart_tests/commands/subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,12 +821,20 @@ def run(self):

org, workspace = get_org_workspace()

new_test_count = summary["subset"].get("newTestCount", 0)
subset_label = "Subset (New Tests)" if new_test_count > 0 else "Subset"
subset_candidates = (
"{} ({})".format(len(original_subset), new_test_count)
if new_test_count > 0
else len(original_subset)
)

header = ["", "Candidates",
"Estimated duration (%)", "Estimated duration (min)"]
rows = [
[
"Subset",
len(original_subset),
subset_label,
subset_candidates,
summary["subset"].get("rate", 0.0),
summary["subset"].get("duration", 0.0),
],
Expand Down
102 changes: 92 additions & 10 deletions tests/commands/inspect/test_subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,32 @@ class SubsetTest(CliTestCase):
mock_json = {
"testPaths": [
{"testPath": [
{"type": "file", "name": "test_file1.py"}], "duration": 1200},
{"type": "file", "name": "test_file1.py"}], "duration": 1200, "density": 0.8, "numNewTests": 0},
{"testPath": [
{"type": "file", "name": "test_file3.py"}], "duration": 600},
{"type": "file", "name": "test_file3.py"}], "duration": 600, "density": 0.5, "numNewTests": 0},
],
"rest": [
{"testPath": [
{"type": "file", "name": "test_file4.py"}], "duration": 1800},
{"type": "file", "name": "test_file4.py"}], "duration": 1800, "density": 0.3, "numNewTests": 0},
{"testPath": [
{"type": "file", "name": "test_file2.py"}], "duration": 100}
{"type": "file", "name": "test_file2.py"}], "duration": 100, "density": 0.1, "numNewTests": 0}

]
}

mock_json_with_new_tests = {
"testPaths": [
{"testPath": [
{"type": "file", "name": "test_new1.py"}], "duration": 0, "density": 0.0, "numNewTests": 1},
{"testPath": [
{"type": "file", "name": "test_known.py"}], "duration": 1200, "density": 0.8, "numNewTests": 0},
],
"rest": [
{"testPath": [
{"type": "file", "name": "test_new2.py"}], "duration": 0, "density": 0.0, "numNewTests": 1},
]
}

@responses.activate
@mock.patch.dict(os.environ, {"SMART_TESTS_TOKEN": CliTestCase.smart_tests_token})
def test_subset(self):
Expand All @@ -35,12 +48,81 @@ def test_subset(self):
status=200)

result = self.cli('inspect', 'subset', '--subset-id', self.subsetting_id, mix_stderr=False)
expect = """| Order | Test Path | In Subset | Estimated duration (sec) |
|---------|--------------------|-------------|----------------------------|
| 1 | file=test_file1.py | ✔ | 1.20 |
| 2 | file=test_file3.py | ✔ | 0.60 |
| 3 | file=test_file4.py | | 1.80 |
| 4 | file=test_file2.py | | 0.10 |
expect = """| Order | Test Path | In Subset | Density | Duration | New |
|---------|--------------------|-------------|-----------|------------|-------|
| 1 | file=test_file1.py | ✔ | 0.800 | 1.200s | No |
| 2 | file=test_file3.py | ✔ | 0.500 | 0.600s | No |
| 3 | file=test_file4.py | | 0.300 | 1.800s | No |
| 4 | file=test_file2.py | | 0.100 | 0.100s | No |
"""

self.assertEqual(result.stdout, expect)

@responses.activate
@mock.patch.dict(os.environ, {"SMART_TESTS_TOKEN": CliTestCase.smart_tests_token})
def test_subset_shows_new_column(self):
responses.replace(
responses.GET,
f"{get_base_url()}/intake/organizations/{self.organization}/workspaces/"
f"{self.workspace}/subset/{self.subsetting_id}",
json=self.mock_json_with_new_tests,
status=200)

result = self.cli('inspect', 'subset', '--subset-id', self.subsetting_id, mix_stderr=False)
expect = """| Order | Test Path | In Subset | Density | Duration | New |
|---------|--------------------|-------------|-----------|------------|-------|
| 1 | file=test_new1.py | ✔ | 0.000 | 0.000s | Yes |
| 2 | file=test_known.py | ✔ | 0.800 | 1.200s | No |
| 3 | file=test_new2.py | | 0.000 | 0.000s | Yes |
"""

self.assertEqual(result.stdout, expect)

@responses.activate
@mock.patch.dict(os.environ, {"SMART_TESTS_TOKEN": CliTestCase.smart_tests_token})
def test_subset_new_tests_only(self):
responses.replace(
responses.GET,
f"{get_base_url()}/intake/organizations/{self.organization}/workspaces/"
f"{self.workspace}/subset/{self.subsetting_id}",
json=self.mock_json_with_new_tests,
status=200)

result = self.cli(
'inspect', 'subset', '--subset-id', self.subsetting_id, '--new-tests-only',
mix_stderr=False)
expect = """| Order | Test Path | In Subset | Density | Duration | New |
|---------|-------------------|-------------|-----------|------------|-------|
| 1 | file=test_new1.py | ✔ | 0.000 | 0.000s | Yes |
| 2 | file=test_new2.py | | 0.000 | 0.000s | Yes |
"""

self.assertEqual(result.stdout, expect)

@responses.activate
@mock.patch.dict(os.environ, {"SMART_TESTS_TOKEN": CliTestCase.smart_tests_token})
def test_subset_new_tests_only_empty_in_brainless_mode(self):
brainless_mock_json = {
"testPaths": [
{"testPath": [
{"type": "file", "name": "test_file1.py"}], "duration": 0, "density": 0.0, "numNewTests": 0},
{"testPath": [
{"type": "file", "name": "test_file2.py"}], "duration": 0, "density": 0.0, "numNewTests": 0},
],
"rest": []
}
responses.replace(
responses.GET,
f"{get_base_url()}/intake/organizations/{self.organization}/workspaces/"
f"{self.workspace}/subset/{self.subsetting_id}",
json=brainless_mock_json,
status=200)

result = self.cli(
'inspect', 'subset', '--subset-id', self.subsetting_id, '--new-tests-only',
mix_stderr=False)
expect = """| Order | Test Path | In Subset | Density | Duration | New |
|---------|-------------|-------------|-----------|------------|-------|
"""

self.assertEqual(result.stdout, expect)
Expand Down
71 changes: 71 additions & 0 deletions tests/commands/test_subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1083,3 +1083,74 @@ def test_subset_id_file_round_trip(self):
self.assertEqual(payload.get('subsettingId'), self.subsetting_id)
finally:
os.unlink(id_file_path)

@responses.activate
@mock.patch.dict(os.environ, {"SMART_TESTS_TOKEN": CliTestCase.smart_tests_token})
def test_subset_shows_new_test_count_in_table(self):
pipe = "test_new.py\ntest_known.py\ntest_known2.py"
responses.replace(
responses.POST,
f"{get_base_url()}/intake/organizations/{self.organization}/workspaces/{self.workspace}/subset",
json={
"testPaths": [
[{"type": "file", "name": "test_new.py"}],
[{"type": "file", "name": "test_known.py"}],
],
"rest": [
[{"type": "file", "name": "test_known2.py"}],
],
"subsettingId": 123,
"summary": {
"subset": {"duration": 0, "candidates": 2, "rate": 67, "newTestCount": 1},
"rest": {"duration": 5, "candidates": 1, "rate": 33, "newTestCount": 0},
},
"isObservation": False,
},
status=200,
)

result = self.cli(
"subset", "file",
"--target", "70%",
"--session", self.session,
mix_stderr=False,
input=pipe,
)
self.assert_success(result)
self.assertIn("Subset (New Tests)", result.stderr)
self.assertIn("2 (1)", result.stderr)

@responses.activate
@mock.patch.dict(os.environ, {"SMART_TESTS_TOKEN": CliTestCase.smart_tests_token})
def test_subset_shows_plain_subset_label_when_no_new_tests(self):
pipe = "test_known.py\ntest_known2.py"
responses.replace(
responses.POST,
f"{get_base_url()}/intake/organizations/{self.organization}/workspaces/{self.workspace}/subset",
json={
"testPaths": [
[{"type": "file", "name": "test_known.py"}],
],
"rest": [
[{"type": "file", "name": "test_known2.py"}],
],
"subsettingId": 123,
"summary": {
"subset": {"duration": 10, "candidates": 1, "rate": 50},
"rest": {"duration": 10, "candidates": 1, "rate": 50},
},
"isObservation": False,
},
status=200,
)

result = self.cli(
"subset", "file",
"--target", "50%",
"--session", self.session,
mix_stderr=False,
input=pipe,
)
self.assert_success(result)
self.assertIn("| Subset", result.stderr)
self.assertNotIn("Subset (New Tests)", result.stderr)
Loading