|
1 | 1 | from typing import TypedDict |
2 | 2 | from datetime import datetime |
3 | 3 | from django.db import connection |
| 4 | +from itertools import repeat |
4 | 5 |
|
5 | 6 | from kernelCI_app.helpers.database import dict_fetchall |
6 | 7 | from kernelCI_app.cache import get_query_cache, set_query_cache |
@@ -339,15 +340,145 @@ def get_hardware_details_data( |
339 | 340 | return records |
340 | 341 |
|
341 | 342 |
|
| 343 | +def get_hardware_details_summary( |
| 344 | + *, |
| 345 | + hardware_id: str, |
| 346 | + origin: str, |
| 347 | + trees_with_selected_commits: list[Tree], |
| 348 | + start_datetime: datetime, |
| 349 | + end_datetime: datetime, |
| 350 | +): |
| 351 | + |
| 352 | + cache_key = "hardwareDetailsSummary" |
| 353 | + |
| 354 | + tests_cache_params = { |
| 355 | + "hardware_id": hardware_id, |
| 356 | + "origin": origin, |
| 357 | + "trees": trees_with_selected_commits, |
| 358 | + "start_date": start_datetime, |
| 359 | + "end_date": end_datetime, |
| 360 | + } |
| 361 | + |
| 362 | + query_rows = get_query_cache(cache_key, tests_cache_params) |
| 363 | + |
| 364 | + if query_rows: |
| 365 | + return query_rows |
| 366 | + |
| 367 | + commit_hashes = [tree.head_git_commit_hash for tree in trees_with_selected_commits] |
| 368 | + |
| 369 | + query = """ |
| 370 | + (SELECT |
| 371 | + COUNT(distinct builds.id) AS count, |
| 372 | + checkouts.origin, |
| 373 | + builds.status AS status, |
| 374 | + count(incidents.id) AS known_issues, |
| 375 | + array[builds.compiler, builds.architecture] AS compiler_arch, |
| 376 | + builds.config_name, |
| 377 | + builds.misc->>'runtime' AS lab, |
| 378 | + tests.environment_misc->>'platform' AS platform, |
| 379 | + tests.environment_compatible, |
| 380 | + checkouts.origin, |
| 381 | + checkouts.tree_name, |
| 382 | + checkouts.git_repository_url, |
| 383 | + checkouts.git_commit_tags, |
| 384 | + checkouts.git_commit_name, |
| 385 | + checkouts.git_repository_branch, |
| 386 | + checkouts.git_commit_hash, |
| 387 | + true AS is_build, |
| 388 | + false AS is_test, |
| 389 | + false AS is_boot |
| 390 | + FROM |
| 391 | + builds |
| 392 | + INNER JOIN tests ON |
| 393 | + tests.build_id = builds.id |
| 394 | + INNER JOIN checkouts ON |
| 395 | + builds.checkout_id = checkouts.id |
| 396 | + LEFT OUTER JOIN incidents ON |
| 397 | + builds.id = incidents.build_id |
| 398 | + WHERE |
| 399 | + ( |
| 400 | + builds.config_name IS NOT NULL |
| 401 | + AND builds.id not like 'maestro:dummy_%%' |
| 402 | + AND (tests.environment_compatible @> ARRAY[%s]::TEXT[] |
| 403 | + OR tests.environment_misc ->> 'platform' = %s) |
| 404 | + ) |
| 405 | + AND builds.origin = %s |
| 406 | + AND builds.start_time >= %s |
| 407 | + AND builds.start_time <= %s |
| 408 | + AND checkouts.git_commit_hash IN ({0}) |
| 409 | + GROUP BY checkouts.id, builds.status, tests.environment_compatible, compiler_arch, |
| 410 | + builds.config_name, lab, platform, is_boot) |
| 411 | + UNION ALL |
| 412 | + (SELECT |
| 413 | + COUNT(*) AS tests_count, |
| 414 | + checkouts.origin, |
| 415 | + tests.status AS status, |
| 416 | + count(incidents.id) AS known_issues, |
| 417 | + array[builds.compiler, builds.architecture] AS compiler_arch, |
| 418 | + builds.config_name, |
| 419 | + tests.misc->>'runtime' AS lab, |
| 420 | + tests.environment_misc->>'platform' AS platform, |
| 421 | + tests.environment_compatible, |
| 422 | + checkouts.origin, |
| 423 | + checkouts.tree_name, |
| 424 | + checkouts.git_repository_url, |
| 425 | + checkouts.git_commit_tags, |
| 426 | + checkouts.git_commit_name, |
| 427 | + checkouts.git_repository_branch, |
| 428 | + checkouts.git_commit_hash, |
| 429 | + false AS is_build, |
| 430 | + true AS is_test, |
| 431 | + (tests.path like 'boot.%%' or tests.path = 'boot') AS is_boot |
| 432 | + FROM |
| 433 | + builds |
| 434 | + inner JOIN tests ON |
| 435 | + tests.build_id = builds.id |
| 436 | + INNER JOIN checkouts ON |
| 437 | + builds.checkout_id = checkouts.id |
| 438 | + LEFT OUTER JOIN incidents ON |
| 439 | + tests.id = incidents.test_id |
| 440 | + WHERE |
| 441 | + ( |
| 442 | + builds.config_name IS NOT NULL |
| 443 | + AND builds.id not like 'maestro:dummy_%%' |
| 444 | + AND (tests.environment_compatible @> ARRAY[%s]::TEXT[] |
| 445 | + OR tests.environment_misc ->> 'platform' = %s) |
| 446 | + ) |
| 447 | + AND tests.origin = %s |
| 448 | + AND tests.start_time >= %s |
| 449 | + AND tests.start_time <= %s |
| 450 | + AND checkouts.git_commit_hash IN ({0}) |
| 451 | + GROUP BY checkouts.id, tests.status, tests.environment_compatible, compiler_arch, |
| 452 | + builds.config_name, lab, platform, is_boot); |
| 453 | + """.format( |
| 454 | + ",".join(repeat("%s", len(commit_hashes))) |
| 455 | + ) |
| 456 | + |
| 457 | + params = [ |
| 458 | + hardware_id, |
| 459 | + hardware_id, |
| 460 | + origin, |
| 461 | + start_datetime, |
| 462 | + end_datetime, |
| 463 | + *commit_hashes, |
| 464 | + ] |
| 465 | + |
| 466 | + # TODO: check if we can reuse parameters to avoid double passing |
| 467 | + params = [*params, *params] |
| 468 | + |
| 469 | + with connection.cursor() as cursor: |
| 470 | + cursor.execute(query, params) |
| 471 | + query_rows = dict_fetchall(cursor) |
| 472 | + set_query_cache(key=cache_key, params=tests_cache_params, rows=query_rows) |
| 473 | + return query_rows |
| 474 | + |
| 475 | + |
342 | 476 | def query_records( |
343 | 477 | *, hardware_id: str, origin: str, trees: list[Tree], start_date: int, end_date: int |
344 | 478 | ) -> list[dict] | None: |
345 | 479 | commit_hashes = [tree.head_git_commit_hash for tree in trees] |
346 | 480 |
|
347 | | - # TODO Treat commit_hash collision (it can happen between repos) |
348 | | - with connection.cursor() as cursor: |
349 | | - cursor.execute( |
350 | | - """ |
| 481 | + query = """ |
351 | 482 | SELECT |
352 | 483 | tests.id, |
353 | 484 | tests.origin AS test_origin, |
@@ -411,19 +542,22 @@ def query_records( |
411 | 542 | ORDER BY |
412 | 543 | issues."_timestamp" DESC |
413 | 544 | """.format( |
414 | | - ",".join(["%s"] * len(commit_hashes)) |
415 | | - ), |
416 | | - [ |
417 | | - hardware_id, |
418 | | - hardware_id, |
419 | | - origin, |
420 | | - start_date, |
421 | | - end_date, |
422 | | - ] |
423 | | - + commit_hashes, |
424 | | - ) |
| 545 | + ",".join(["%s"] * len(commit_hashes)) |
| 546 | + ) |
425 | 547 |
|
426 | | - return dict_fetchall(cursor) |
| 548 | + params = [ |
| 549 | + hardware_id, |
| 550 | + hardware_id, |
| 551 | + origin, |
| 552 | + start_date, |
| 553 | + end_date, |
| 554 | + ] + commit_hashes |
| 555 | + |
| 556 | + # TODO Treat commit_hash collision (it can happen between repos) |
| 557 | + with connection.cursor() as cursor: |
| 558 | + cursor.execute(query, params) |
| 559 | + query_rows = dict_fetchall(cursor) |
| 560 | + return query_rows |
427 | 561 |
|
428 | 562 |
|
429 | 563 | def get_hardware_summary_data( |
|
0 commit comments