feat: use tree_tests_rollup for tree details summary#1842
Conversation
c003c95 to
3a35e46
Compare
| ROLLUP_TEST_ID = "rollup_test" | ||
|
|
||
|
|
||
| def normalize_build_dict(row_dict: dict) -> dict: |
| ): | ||
| return True | ||
|
|
||
| if len(platform_filters) > 0 and test_platform not in platform_filters: |
There was a problem hiding this comment.
prefer to check if platform_filters instead of using len
| if len(platform_filters) > 0 and test_platform not in platform_filters: | ||
| return True | ||
|
|
||
| if len(origin_filters) > 0 and test_origin not in origin_filters: |
| origin_summary = instance.test_summary["origins"] | ||
| typed_summary = instance.test_summary_typed | ||
|
|
||
| arch_key = "%s-%s" % (build_arch, build_compiler) |
There was a problem hiding this comment.
can we use a tuple as a key here?
| lab_entry = typed_summary.labs.setdefault(test_lab, StatusCount()) | ||
| setattr(lab_entry, status_name, getattr(lab_entry, status_name) + count) | ||
|
|
||
| if is_status_failure(status_name): |
There was a problem hiding this comment.
nit: we can avoid this conditional, and just use the value:
has_status_failure |= is_status_failure(status_name)
There was a problem hiding this comment.
Or even simpler, just add current test_platform to platforms_failing here
| issue_comment: Optional[str], | ||
| issue_report_url: Optional[str], | ||
| starting_count_status: Optional[DatabaseStatusValues], | ||
| autoincrement: bool = True, |
There was a problem hiding this comment.
Do we need to add this flag? Cant it be the default behaviour?
There was a problem hiding this comment.
it still behaves as before because the flag defaults to True. however, I needed to reuse this function for rollup aggregations in the view, and in that context it's not appropriate to increment the status after creating the IssueTyped.
this also highlights some technical debt: a function named create_issue_typed having a hidden side effect (incrementing status values) is confusing.
There was a problem hiding this comment.
Pull request overview
This PR refactors the tree details summary endpoint to use the denormalized tree_tests_rollup table for test/boot aggregation (instead of scanning per-test rows), while keeping builds fetched from a dedicated builds query to reduce load and improve performance.
Changes:
- Refactor summary view to fetch/process builds and rollup rows via separate queries and sanitization paths.
- Add
treeDetailsRollup.pyhelpers for build normalization plus rollup-based filters, issues, and status summaries. - Extend seed data + factories to generate
tree_tests_rolluprows for tests/incidents; enhance status counting utilities to support increment-by-count.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| backend/kernelCI_app/views/treeDetailsSummaryView.py | Switch summary aggregation to two-query model (builds + rollup) and separate sanitization. |
| backend/kernelCI_app/helpers/treeDetailsRollup.py | New helper module to aggregate filters/issues/summaries from rollup rows and normalize build rows. |
| backend/kernelCI_app/queries/tree.py | Add get_tree_details_builds and get_tree_details_rollup queries (cached) to support the new summary flow. |
| backend/kernelCI_app/management/commands/seed_test_data.py | Seed tree_tests_rollup rows derived from seeded tests/incidents and clear rollup table on reset. |
| backend/kernelCI_app/utils.py | Extend create_issue_typed with autoincrement to support rollup-driven issue counts. |
| backend/kernelCI_app/typeModels/common.py | Allow StatusCount.increment() to increment by an arbitrary count (for rollups). |
| backend/kernelCI_app/tests/factories/tree_tests_rollup_factory.py | Add a factory for TreeTestsRollup model rows. |
| backend/kernelCI_app/tests/factories/init.py | Export the new TreeTestsRollupFactory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ): | ||
| row_dict["issue_id"] = UNCATEGORIZED_STRING | ||
|
|
||
| return row_dict |
There was a problem hiding this comment.
The function seems pretty nice, but do you thing that using this code below might improve readability? Feel free to resolve it if you disagree.
defaults = {
"build_status": NULL_STATUS,
"build_architecture": UNKNOWN_STRING,
"build_compiler": UNKNOWN_STRING,
"build_config_name": UNKNOWN_STRING,
}
for key, default in defaults.items():
row_dict.setdefault(key, default)| ) | ||
| config_entry = config_map.setdefault(build_config, {}) | ||
|
|
||
| is_env_compatible = hardware_key != UNKNOWN_STRING and hardware_key != test_platform |
There was a problem hiding this comment.
nit: is_env_compatible = hardware_key not in {test_platform, UNKNOWN_STRING} looks more pythonic to me as it has less repetitions
| tree_name_full_clause = "AND " + tree_name_clause if tree_name_clause else "" | ||
| git_url_full_clause = "AND " + git_url_clause if git_url_clause else "" | ||
|
|
||
| query = f""" |
There was a problem hiding this comment.
nit: have you thought of creating another file with bigger queries? I believe that would help improve the view readability
e582372 to
a57bb74
Compare
a57bb74 to
689d120
Compare
| } | ||
|
|
||
| rows = get_query_cache(cache_key, params) | ||
| if rows is None: |
There was a problem hiding this comment.
nit: prefer to return early if not None
There was a problem hiding this comment.
as it is kinda of a pattern within the other functions, I would prefer to leave it as it is
| git_branch_clause = checkout_clauses.get("git_branch_clause") | ||
| tree_name_clause = checkout_clauses.get("tree_name_clause") | ||
| git_url_clause = checkout_clauses.get("git_url_clause") | ||
| tree_name_full_clause = "AND " + tree_name_clause if tree_name_clause else "" | ||
| git_url_full_clause = "AND " + git_url_clause if git_url_clause else "" |
There was a problem hiding this comment.
very nit: why not a full_clause for git_branch?
| git_branch_clause = checkout_clauses.get("git_branch_clause") | ||
| tree_name_clause = checkout_clauses.get("tree_name_clause") | ||
| git_url_clause = checkout_clauses.get("git_url_clause") | ||
| tree_name_full_clause = "AND " + tree_name_clause if tree_name_clause else "" | ||
| git_url_full_clause = "AND " + git_url_clause if git_url_clause else "" |
| git_url_full_clause = "AND " + git_url_clause if git_url_clause else "" | ||
|
|
||
| query = f""" | ||
| WITH RELEVANT_CHECKOUTS AS ( |
There was a problem hiding this comment.
not blocker but maybe we could move the relevant_checkouts query to a separate builder method so it can be reused between the queries that require it
Description
Tree details summary now reads pre-aggregated test and boot data from tree_tests_rollup instead of scanning per-test rows from a single large query. Builds still come from a dedicated builds query. This matches the denormalized rollup model and should reduce work for the summary endpoint.
Changes
How to test
Closes #1801