Skip to content

Commit

Permalink
refactor(test-details-view): update endpoint
Browse files Browse the repository at this point in the history
- Added documentation and response validation
- Changed from raw query to django ORM
- Updated the requests file

Part of #86
Closes #807
  • Loading branch information
murilx committed Feb 7, 2025
1 parent b867845 commit f3af17f
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 118 deletions.
9 changes: 7 additions & 2 deletions backend/kernelCI_app/typeModels/databases.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List, Optional, Dict, Literal, Any, Union
from typing import List, Optional, Dict, Literal, Any, Union, Annotated
from datetime import datetime

from kernelCI_app.typeModels.commonDetails import EnvironmentMisc
Expand All @@ -16,7 +16,7 @@

type DatabaseStatusValues = Literal["FAIL", "PASS", "SKIP", "ERROR", "MISS", "DONE"]

type Jsonb = Union[Dict[str, Any], List[Dict[str, Any]]]
Jsonb = Annotated[Union[Dict[str, Any], List[Dict[str, Any]]], "Jsonb"]

type Origin = str
type Timestamp = datetime
Expand All @@ -27,6 +27,7 @@
type Checkout__GitCommitName = Optional[str]
type Checkout__GitCommitTags = Optional[List[str]]
type Checkout__GitRepositoryBranch = Optional[str]
type Checkout__GitRepositoryUrl = Optional[str]

type Build__Id = str
type Build__Architecture = Optional[str]
Expand All @@ -49,6 +50,10 @@
type Test__StartTime = Optional[datetime]
type Test__EnvironmentCompatible = Optional[List[str]]
type Test__EnvironmentMisc = Optional[EnvironmentMisc]
type Test__LogExcerpt = Optional[str]
type Test__LogUrl = Optional[str]
type Test__Misc = Optional[Jsonb]
type Test__OutputFiles = Optional[Jsonb]

type Issue__Id = str
type Issue__Version = int
Expand Down
53 changes: 53 additions & 0 deletions backend/kernelCI_app/typeModels/testDetails.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from pydantic import BaseModel, Field

from kernelCI_app.typeModels.databases import (
Test__Id,
Build__Id,
Test__Status,
Test__Path,
Test__LogExcerpt,
Test__LogUrl,
Test__Misc,
Test__EnvironmentMisc,
Test__StartTime,
Test__EnvironmentCompatible,
Test__OutputFiles,
Build__Compiler,
Build__Architecture,
Build__ConfigName,
Checkout__GitCommitHash,
Checkout__GitRepositoryBranch,
Checkout__GitRepositoryUrl,
Checkout__GitCommitTags,
Checkout__TreeName,
)


class TestDetailsResponse(BaseModel):
id: Test__Id
build_id: Build__Id
status: Test__Status
path: Test__Path
log_excerpt: Test__LogExcerpt
log_url: Test__LogUrl
misc: Test__Misc
environment_misc: Test__EnvironmentMisc
start_time: Test__StartTime
environment_compatible: Test__EnvironmentCompatible
output_files: Test__OutputFiles
compiler: Build__Compiler = Field(validation_alias="build__compiler")
architecture: Build__Architecture = Field(validation_alias="build__architecture")
config_name: Build__ConfigName = Field(validation_alias="build__config_name")
git_commit_hash: Checkout__GitCommitHash = Field(
validation_alias="build__checkout__git_commit_hash"
)
git_repository_branch: Checkout__GitRepositoryBranch = Field(
validation_alias="build__checkout__git_repository_branch"
)
git_repository_url: Checkout__GitRepositoryUrl = Field(
validation_alias="build__checkout__git_repository_url"
)
git_commit_tags: Checkout__GitCommitTags = Field(
validation_alias="build__checkout__git_commit_tags"
)
tree_name: Checkout__TreeName = Field(validation_alias="build__checkout__tree_name")
112 changes: 42 additions & 70 deletions backend/kernelCI_app/views/testDetailsView.py
Original file line number Diff line number Diff line change
@@ -1,78 +1,50 @@
from django.http import JsonResponse
from django.db import connection
from django.views import View
from http import HTTPStatus
from kernelCI_app.helpers.errorHandling import create_error_response
from kernelCI_app.utils import string_to_json
from kernelCI_app.helpers.errorHandling import create_api_error_response
from kernelCI_app.models import Tests
from kernelCI_app.typeModels.testDetails import TestDetailsResponse
from drf_spectacular.utils import extend_schema
from rest_framework.views import APIView
from rest_framework.response import Response
from pydantic import ValidationError


class TestDetails(View):
def get(self, _request, test_id: str | None):
names_map = {
"id": "combined_tests.id",
"build_id": "combined_tests.build_id",
"status": "combined_tests.status",
"path": "combined_tests.path",
"log_excerpt": "combined_tests.log_excerpt",
"log_url": "combined_tests.log_url",
"misc": "combined_tests.misc",
"environment_misc": "combined_tests.environment_misc",
"start_time": "combined_tests.start_time",
"environment_compatible": "combined_tests.environment_compatible",
"output_files": "combined_tests.output_files",
"compiler": "builds.compiler",
"architecture": "builds.architecture",
"config_name": "builds.config_name",
"git_commit_hash": "checkouts.git_commit_hash",
"git_repository_branch": "checkouts.git_repository_branch",
"git_repository_url": "checkouts.git_repository_url",
"git_commit_tags": "checkouts.git_commit_tags",
"tree_name": "checkouts.tree_name",
}
class TestDetails(APIView):
@extend_schema(
responses=TestDetailsResponse,
)
def get(self, _request, test_id: str) -> Response:
fields = [
"id",
"build_id",
"status",
"path",
"log_excerpt",
"log_url",
"misc",
"environment_misc",
"start_time",
"environment_compatible",
"output_files",
"build__compiler",
"build__architecture",
"build__config_name",
"build__checkout__git_commit_hash",
"build__checkout__git_repository_branch",
"build__checkout__git_repository_url",
"build__checkout__git_commit_tags",
"build__checkout__tree_name",
]

query = """
SELECT
tests.id,
tests.build_id,
tests.status,
tests.path,
tests.log_excerpt,
tests.log_url,
tests.misc,
tests.environment_misc,
tests.start_time,
tests.environment_compatible,
tests.output_files,
builds.compiler,
builds.architecture,
builds.config_name,
checkouts.git_commit_hash,
checkouts.git_repository_branch,
checkouts.git_repository_url,
checkouts.git_commit_tags,
checkouts.tree_name
FROM tests
LEFT JOIN builds
ON tests.build_id = builds.id
LEFT JOIN checkouts
ON builds.checkout_id = checkouts.id
WHERE tests.id = %s
"""
response = Tests.objects.filter(id=test_id).values(*fields).first()

response = {}
with connection.cursor() as cursor:
cursor.execute(query, [test_id])
row = cursor.fetchone()
if row:
for idx, key in enumerate(names_map.keys()):
response[key] = row[idx]
response["misc"] = string_to_json(response["misc"])
response["environment_misc"] = string_to_json(response["environment_misc"])
response["output_files"] = string_to_json(response["output_files"])

if len(response) == 0:
return create_error_response(
if response is None:
return create_api_error_response(
error_message="Test not found", status_code=HTTPStatus.OK
)

return JsonResponse(response, safe=False)
try:
valid_response = TestDetailsResponse(**response)
except ValidationError as e:
return Response(data=e.json(), status=HTTPStatus.INTERNAL_SERVER_ERROR)

return Response(valid_response.model_dump())
69 changes: 52 additions & 17 deletions backend/requests/test-details-get.sh
Original file line number Diff line number Diff line change
@@ -1,20 +1,55 @@
# Database tested - `playground_kcidb`
http 'http://localhost:8000/api/test/maestro:66b4883fd22b231086764dc2'
http 'http://localhost:8000/api/test/maestro:67a182c5661a7bc8748b9905'

# HTTP/1.1 200 OK
# Allow: GET, HEAD, OPTIONS
# Cache-Control: max-age=0
# Content-Length: 18610
# Content-Type: application/json
# Cross-Origin-Opener-Policy: same-origin
# Date: Wed, 05 Feb 2025 17:35:56 GMT
# Expires: Wed, 05 Feb 2025 17:35:56 GMT
# Referrer-Policy: same-origin
# Server: WSGIServer/0.2 CPython/3.12.7
# Vary: Accept, Cookie, origin
# X-Content-Type-Options: nosniff
# X-Frame-Options: DENY

# {
# "id": "maestro:66b4883fd22b231086764dc2",
# "build_id": "maestro:66b480a5d22b2310867645aa",
# "status": "PASS",
# "path": "boot",
# "log_excerpt": "",
# "log_url": "https://kciapistagingstorage1.file.core.windows.net/staging/baseline-x86-intel-66b4883fd22b231086764dc2/log.txt.gz?sv=2022-11-02&ss=f&srt=sco&sp=r&se=2024-10-17T19:19:12Z&st=2023-10-17T11:19:12Z&spr=https&sig=sLmFlvZHXRrZsSGubsDUIvTiv%2BtzgDq6vALfkrtWnv8%3D",
# "misc": "{\"arch\": \"x86_64\", \"compiler\": \"gcc-12\", \"kernel_type\": \"bzimage\"}",
# "environment_misc": "{\"job_id\": \"15084320\", \"platform\": \"hp-x360-14-G1-sona\"}",
# "start_time": "2024-08-08T08:56:30.998Z",
# "compiler": "gcc-12",
# "architecture": "x86_64",
# "config_name": "cros://chromeos-6.1/x86_64/chromeos-intel-pineview.flavour.config",
# "git_commit_hash": "f6ea44ffd3e9f55a94cfa89e3f58626132e259b7",
# "git_repository_branch": "staging-stable",
# "git_repository_url": "https://github.com/kernelci/linux.git"
# "architecture": "x86_64",
# "build_id": "maestro:dummy_67a17d87661a7bc8748b90cd_x86_64",
# "compiler": null,
# "config_name": null,
# "environment_compatible": null,
# "environment_misc": {
# "platform": "kubernetes"
# },
# "git_commit_hash": "170c9fb62732486d54f4876cfee81654f217364c",
# "git_commit_tags": [],
# "git_repository_branch": "android15-6.6",
# "git_repository_url": "https://android.googlesource.com/kernel/common",
# "id": "maestro:67a182c5661a7bc8748b9905",
# "log_excerpt": "n_order_2\naction_order_1\n ... (Too big to show here)
# "log_url": "https://kciapistagingstorage1.file.core.windows.net/production/kunit-x86_64-67a17e87661a7bc8748b9409/test_log?sv=2022-11-02&ss=f&srt=sco&sp=r&se=2026-10-18T13:36:18Z&st=2024-10-17T05:36:18Z&spr=https&sig=xFxYOOh5uXJWeN9I3YKAUvpGGQivo89HKZbD78gcxvc%3D",
# "misc": {
# "arch": "x86_64",
# "runtime": "k8s-gke-eu-west4"
# },
# "output_files": [
# {
# "name": "tarball",
# "url": "https://kciapistagingstorage1.file.core.windows.net/production/linux-android-android15-6.6-android15-6.6.66_r00-80-g170c9fb627324.tar.gz?sv=2022-11-02&ss=f&srt=sco&sp=r&se=2026-10-18T13:36:18Z&st=2024-10-17T05:36:18Z&spr=https&sig=xFxYOOh5uXJWeN9I3YKAUvpGGQivo89HKZbD78gcxvc%3D"
# },
# {
# "name": "job_txt",
# "url": "https://kciapistagingstorage1.file.core.windows.net/production/kunit-x86_64-67a17e87661a7bc8748b9409/job_txt?sv=2022-11-02&ss=f&srt=sco&sp=r&se=2026-10-18T13:36:18Z&st=2024-10-17T05:36:18Z&spr=https&sig=xFxYOOh5uXJWeN9I3YKAUvpGGQivo89HKZbD78gcxvc%3D"
# },
# {
# "name": "kunit_json",
# "url": "https://kciapistagingstorage1.file.core.windows.net/production/kunit-x86_64-67a17e87661a7bc8748b9409/kunit_json?sv=2022-11-02&ss=f&srt=sco&sp=r&se=2026-10-18T13:36:18Z&st=2024-10-17T05:36:18Z&spr=https&sig=xFxYOOh5uXJWeN9I3YKAUvpGGQivo89HKZbD78gcxvc%3D"
# }
# ],
# "path": "kunit.exec.siphash",
# "start_time": "2025-02-04T03:00:21.480000Z",
# "status": "PASS",
# "tree_name": "android"
# }
Loading

0 comments on commit f3af17f

Please sign in to comment.