Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create utils for accessing testrun timescale models #1078

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

joseph-sentry
Copy link
Contributor

this PR creates some utility functions for inserting and aggregating testrun data in timescale

transaction=True is required for the test_get_testrun_summary for the continuous aggregates to populate the data that is expected to be in the summary for the test to pass

depends on: codecov/shared#508

Copy link

codecov bot commented Feb 10, 2025

Codecov Report

Attention: Patch coverage is 97.00000% with 6 lines in your changes missing coverage. Please review.

Project coverage is 97.77%. Comparing base (4abcb17) to head (b23aa8b).

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
services/test_analytics/ta_timeseries.py 95.71% 3 Missing ⚠️
services/test_analytics/utils.py 76.92% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1078      +/-   ##
==========================================
- Coverage   97.78%   97.77%   -0.01%     
==========================================
  Files         443      446       +3     
  Lines       36565    36765     +200     
==========================================
+ Hits        35754    35948     +194     
- Misses        811      817       +6     
Flag Coverage Δ
integration 42.85% <76.50%> (+0.18%) ⬆️
unit 90.49% <63.50%> (-0.15%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@codecov-qa
Copy link

codecov-qa bot commented Feb 10, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
1 1 0 0
View the top 1 failed test(s) by shortest run time
services/tests/test_ta_timeseries/test_ta_timeseries.py::services.tests.test_ta_timeseries.test_ta_timeseries
Stack Traces | 0s run time
ImportError while importing test module '.../tests/test_ta_timeseries/test_ta_timeseries.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
.../local/lib/python3.13/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
.../tests/test_ta_timeseries/test_ta_timeseries.py:6: in <module>
    from shared.django_apps.timeseries.models import Testrun
E   ImportError: cannot import name 'Testrun' from 'shared.django_apps.timeseries.models' (.../local/lib/python3.13.../django_apps/timeseries/models.py)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Copy link

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
1 1 0 0
View the top 1 failed tests by shortest run time
services/tests/test_ta_timeseries/test_ta_timeseries.py::::services.tests.test_ta_timeseries.test_ta_timeseries
Stack Traces | 0s run time
No failure message available

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

Copy link

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
2 2 0 0
View the top 2 failed tests by shortest run time
services.tests.test_ta_timeseries.test_ta_timeseries
Stack Traces | 0.000s run time
No failure message available
services.tests.test_ta_timeseries.test_ta_timeseries
Stack Traces | 0.000s run time
No failure message available

📣 Thoughts on this report? Let Codecov know! | Powered by Codecov

Copy link
Contributor

@Swatinem Swatinem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

finally some tests that you can actually run locally :-)
though my main concern is whether the aggregates are actually live, see the specific comment.

upload_id=upload_id,
)
)
Testrun.objects.bulk_create(testruns_to_create)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use the batch_size parameter here. Otherwise you would end up with "unique queries" for each of the N number of tests you have.

Its really unfortunate that SQL does not have a proper batch create query for these purposes.

Comment on lines 44 to 50
repo_id: int | None,
commit_sha: str | None,
branch: str | None,
upload_id: int | None,
flags: list[str] | None,
parsing_info: test_results_parser.ParsingInfo,
flaky_test_ids: set[bytes] | None = None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are all these optionally None?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they shouldn't be, except for maybe flags and flaky_test_ids, i'll fix

Comment on lines 115 to 116
"test_id": bytes(test_id),
"flags_hash": bytes(flags_hash),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the test_id as returned by the database hex-encoded? in that case casting this to bytes does not make any sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a memoryview, which is basically just a pointer, and to dereference we must wrap it in bytes

Comment on lines 165 to 169
with connections["timeseries"].cursor() as cursor:
cursor.execute(
"UPDATE timeseries_testrun SET outcome = %s WHERE timestamp = %s AND test_id = %s AND flags_hash = %s",
["flaky_failure", timestamp, test_id, flags_hash],
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use the ORM instead of a raw query here.



def get_testrun_summary(
repo_id: int, interval: Interval, branch: str | None = None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the branch parameter is unused

) -> list[TestrunSummary]:
timestamp_bin = datetime.now() - timedelta(days=interval.value)
return list(
TestrunSummary.objects.filter(repo_id=repo_id, timestamp_bin__gte=timestamp_bin)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both these functions return the daily buckets to python, instead of aggregating across the interval within the DB, is that really the intention here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can discuss this more, but I thought we wanted to use the same idea from your binary format where the cached file has individual rows for each day so that we can prune out of date rows when reading from the cache file

if we're skipping the cached file and doing this query on the fly each time, then we should aggregate within the DB

but i think we should compare those 2 alternatives in prod with real data to see which one is faster

testruns = get_testruns_for_flake_detection(
1,
{
calc_test_id("flaky_test_name", "test_classname", "test_suite"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the weird autoformatting gives us a hint to make this a local variable :-D

'timeseries_testrun_summary_1day',
start_offset => '7 days',
end_offset => NULL,
schedule_interval => INTERVAL '1 milliseconds'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a bit weird. given that the default is set to one day, does that mean these aggregates are only updated once a day, and if you query these during the day, they would not give you any result for "today"?

I think the "continuous aggregation" should indeed be continuous and live.
meaning that when you INSERT into the testruns table, the materialized view with the aggregate should yield aggregates for that immediately. without having to mess with some kind of setting, and without having to put a sleep into the test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so from what i understand about timescale, the continuous aggregates, aren't actually continuous, they're aggregated using basically a cron job, and we can tweak the schedule of the cron job based on this policy. There is a setting where on read, it will get all the data that has been materialized by the cron job, AND get all the unmaterialized data, materialize it on the fly, and merge it into the results but that would obviously be more expensive

assert summaries[0].fail_count == 1
assert summaries[0].flaky_fail_count == 0
assert summaries[0].skip_count == 0
assert summaries[0].flags == [["flag1"], ["flag2"]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting. so the aggregates are aggregating across all the flags? I thought you still wanted to filter these 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a direct port of what we're showing in the UI right now, to change this would require a product-focused discussion

relies on shared changes from:
codecov/shared#508

this implements the following TA functionality using data from
Timescale:
- PR comment summary
- PR comment failure details
- PR flake set
- Flake detection relevant testruns
- Flake detection relevant flakes
- All branches testrun summary
- Main branches testrun summary
- Feature branch testrun summary

Also moves the flag id calculation to a new file
@joseph-sentry joseph-sentry force-pushed the joseph/ta-timeseries branch from 4458704 to b23aa8b Compare March 3, 2025 20:42
@codecov-notifications
Copy link

codecov-notifications bot commented Mar 3, 2025

Codecov Report

Attention: Patch coverage is 97.00000% with 6 lines in your changes missing coverage. Please review.

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
services/test_analytics/ta_timeseries.py 95.71% 3 Missing ⚠️
services/test_analytics/utils.py 76.92% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants