Skip to content

Commit

Permalink
feat(hardwareView): considerate head of the tree in the results
Browse files Browse the repository at this point in the history
Refactored HardwareView to consolidate __getSlowResult and __getFastResult
methods into a single _getResults method. Updated the order_by field in
checkouts_subquery to use "-start_time" for more accurate ordering that
considerates the head of the branch
Also fix the logic for calculating builds to account for the array of
hardwares

Closes #530
  • Loading branch information
WilsonNet committed Nov 22, 2024
1 parent 6098a80 commit e227a57
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 158 deletions.
77 changes: 42 additions & 35 deletions backend/kernelCI_app/views/hardwareView.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,46 @@
from django.db.models import Subquery
from django.http import JsonResponse
from django.views import View
from collections import defaultdict
from kernelCI_app.helpers.date import parse_start_and_end_timestamps_in_seconds_to_datetime
from kernelCI_app.helpers.date import (
parse_start_and_end_timestamps_in_seconds_to_datetime,
)
from kernelCI_app.helpers.errorHandling import ExceptionWithJsonResponse
from kernelCI_app.models import Tests
from kernelCI_app.models import Tests, Checkouts
from kernelCI_app.helpers.build import build_status_map
from kernelCI_app.constants.general import DEFAULT_ORIGIN


class HardwareView(View):
def __getSlowResult(self, start_date, end_date, origin):
def _getResults(self, start_date, end_date, origin):
tree_id_fields = [
"tree_name",
"git_repository_branch",
"git_repository_url",
]

processedBuilds = set()

checkouts_subquery = (
Checkouts.objects.filter(
origin=origin,
start_time__gte=start_date,
start_time__lte=end_date,
)
.order_by(
*tree_id_fields,
"-start_time",
)
.distinct(*tree_id_fields)
.values_list("git_commit_hash", flat=True)
)

tests = Tests.objects.filter(
start_time__gte=start_date,
start_time__lte=end_date,
environment_compatible__isnull=False,
origin=origin
).values("environment_compatible", "status", "build__valid", "path")
build__checkout__git_commit_hash__in=Subquery(checkouts_subquery),
).values(
"environment_compatible", "status", "build__valid", "path", "build__id"
)

hardware = {}
for test in tests:
Expand All @@ -35,6 +60,11 @@ def __getSlowResult(self, start_date, end_date, origin):
else:
hardware[compatible][statusCount][test["status"]] += 1

buildKey = test["build__id"] + compatible
if buildKey in processedBuilds:
continue
processedBuilds.add(buildKey)

build_status = build_status_map.get(test["build__valid"])
if build_status is not None:
hardware[compatible]["buildCount"][build_status] += 1
Expand All @@ -43,43 +73,20 @@ def __getSlowResult(self, start_date, end_date, origin):

return result

def __getFastResult(self, start_date, end_date, origin):
hardwares = set()
tests = Tests.objects.filter(
start_time__gte=start_date,
start_time__lte=end_date,
environment_compatible__isnull=False,
origin=origin
).values("environment_compatible")

for test in tests:
for compatible in test["environment_compatible"]:
hardwares.add(compatible)

hardwareResult = []
for hardware in hardwares:
hardwareResult.append({"hardwareName": hardware})
result = {"hardware": hardwareResult}
return result

def get(self, request):
mode = request.GET.get("mode", "fast")
origin = request.GET.get("origin", DEFAULT_ORIGIN)
start_timestamp_str = request.GET.get("startTimestampInSeconds")
end_timestamp_str = request.GET.get("endTimeStampInSeconds")

try:
(start_date, end_date) = parse_start_and_end_timestamps_in_seconds_to_datetime(
start_timestamp_str, end_timestamp_str
(start_date, end_date) = (
parse_start_and_end_timestamps_in_seconds_to_datetime(
start_timestamp_str, end_timestamp_str
)
)
except ExceptionWithJsonResponse as e:
return e.getJsonResponse()

if mode == "fast":
result = self.__getFastResult(start_date, end_date, origin)
elif mode == "slow":
result = self.__getSlowResult(start_date, end_date, origin)
else:
return JsonResponse({"error": "Invalid mode"}, status=400)
result = self._getResults(start_date, end_date, origin)

return JsonResponse(result, safe=False)
56 changes: 4 additions & 52 deletions dashboard/src/api/Hardware.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ import { useQuery } from '@tanstack/react-query';

import { useSearch } from '@tanstack/react-router';

import type {
HardwareFastResponse,
HardwareListingResponse,
} from '@/types/hardware';
import type { HardwareListingResponse } from '@/types/hardware';

import type { TOrigins } from '@/types/general';

import http from './api';
const fetchTreeCheckoutData = async (
const fetchHardwareListing = async (
origin: TOrigins,
startTimestampInSeconds: number,
endTimeStampInSeconds: number,
Expand All @@ -27,14 +24,9 @@ const fetchTreeCheckoutData = async (
return res.data;
};

export const useHardwareListingSlow = (
export const useHardwareListing = (
startTimestampInSeconds: number,
endTimestampInSeconds: number,
{
enabled,
}: {
enabled: boolean;
},
): UseQueryResult<HardwareListingResponse> => {
const { origin } = useSearch({ from: '/hardware' });

Expand All @@ -48,47 +40,7 @@ export const useHardwareListingSlow = (
return useQuery({
queryKey,
queryFn: () =>
fetchTreeCheckoutData(
origin,
startTimestampInSeconds,
endTimestampInSeconds,
),
enabled,
});
};

const fetchHardwareListingFastData = async (
origin: TOrigins,
startTimestampInSeconds: number,
endTimeStampInSeconds: number,
): Promise<HardwareFastResponse> => {
const res = await http.get('/api/hardware/', {
params: {
startTimestampInSeconds,
endTimeStampInSeconds,
mode: 'fast',
origin,
},
});
return res.data;
};

export const useHardwareListingFast = (
startTimestampInSeconds: number,
endTimestampInSeconds: number,
): UseQueryResult<HardwareFastResponse> => {
const { origin } = useSearch({ from: '/hardware' });
const queryKey = [
'hardwareListingFast',
startTimestampInSeconds,
endTimestampInSeconds,
origin,
];

return useQuery({
queryKey,
queryFn: () =>
fetchHardwareListingFastData(
fetchHardwareListing(
origin,
startTimestampInSeconds,
endTimestampInSeconds,
Expand Down
93 changes: 32 additions & 61 deletions dashboard/src/pages/Hardware/HardwareListingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,9 @@ import QuerySwitcher from '@/components/QuerySwitcher/QuerySwitcher';

import { Toaster } from '@/components/ui/toaster';

import type {
HardwareFastItem,
HardwareListingItem,
HardwareTableItem,
} from '@/types/hardware';
import type { HardwareTableItem } from '@/types/hardware';

import { useHardwareListingFast, useHardwareListingSlow } from '@/api/Hardware';
import { useHardwareListing } from '@/api/Hardware';

import { dateObjectToTimestampInSeconds, daysToSeconds } from '@/utils/date';

Expand All @@ -22,16 +18,6 @@ interface HardwareListingPageProps {
inputFilter: string;
}

function isCompleteHardware(
data: HardwareListingItem | HardwareFastItem,
): data is HardwareListingItem {
return (
'buildCount' in data &&
'testStatusCount' in data &&
'bootStatusCount' in data
);
}

const calculateTimeStamp = (
intervalInDays: number,
): {
Expand Down Expand Up @@ -59,61 +45,46 @@ const HardwareListingPage = ({
setTimeStamps(calculateTimeStamp(intervalInDays));
}, [intervalInDays]);

const { data: fastData, status: fastStatus } = useHardwareListingFast(
const { data, error, status } = useHardwareListing(
startTimestampInSeconds,
endTimestampInSeconds,
);

const { data, error, isLoading } = useHardwareListingSlow(
startTimestampInSeconds,
endTimestampInSeconds,
{
enabled: fastStatus === 'success' && !!fastData,
},
);

const listItems: HardwareTableItem[] = useMemo(() => {
if (!fastData || fastStatus === 'error') return [];
if (!data || error) return [];

const hasCompleteData = !isLoading && !!data;
const currentData = hasCompleteData ? data.hardware : fastData.hardware;
const currentData = data.hardware;

return currentData
.filter(hardware => {
return hardware.hardwareName?.includes(inputFilter);
})
.map((hardware): HardwareTableItem => {
const buildCount = isCompleteHardware(hardware)
? {
valid: hardware.buildCount?.valid,
invalid: hardware.buildCount?.invalid,
null: hardware.buildCount?.null,
}
: undefined;

const testStatusCount = isCompleteHardware(hardware)
? {
DONE: hardware.testStatusCount.DONE,
ERROR: hardware.testStatusCount.ERROR,
FAIL: hardware.testStatusCount.FAIL,
MISS: hardware.testStatusCount.MISS,
PASS: hardware.testStatusCount.PASS,
SKIP: hardware.testStatusCount.SKIP,
NULL: hardware.testStatusCount.NULL,
}
: undefined;

const bootStatusCount = isCompleteHardware(hardware)
? {
DONE: hardware.bootStatusCount.DONE,
ERROR: hardware.bootStatusCount.ERROR,
FAIL: hardware.bootStatusCount.FAIL,
MISS: hardware.bootStatusCount.MISS,
PASS: hardware.bootStatusCount.PASS,
SKIP: hardware.bootStatusCount.SKIP,
NULL: hardware.bootStatusCount.NULL,
}
: undefined;
const buildCount = {
valid: hardware.buildCount?.valid,
invalid: hardware.buildCount?.invalid,
null: hardware.buildCount?.null,
};

const testStatusCount = {
DONE: hardware.testStatusCount.DONE,
ERROR: hardware.testStatusCount.ERROR,
FAIL: hardware.testStatusCount.FAIL,
MISS: hardware.testStatusCount.MISS,
PASS: hardware.testStatusCount.PASS,
SKIP: hardware.testStatusCount.SKIP,
NULL: hardware.testStatusCount.NULL,
};

const bootStatusCount = {
DONE: hardware.bootStatusCount.DONE,
ERROR: hardware.bootStatusCount.ERROR,
FAIL: hardware.bootStatusCount.FAIL,
MISS: hardware.bootStatusCount.MISS,
PASS: hardware.bootStatusCount.PASS,
SKIP: hardware.bootStatusCount.SKIP,
NULL: hardware.bootStatusCount.NULL,
};

return {
hardwareName: hardware.hardwareName ?? '',
Expand All @@ -123,14 +94,14 @@ const HardwareListingPage = ({
};
})
.sort((a, b) => a.hardwareName.localeCompare(b.hardwareName));
}, [data, fastData, inputFilter, isLoading, fastStatus]);
}, [data, error, inputFilter]);

if (error) {
return <div>Error: {error.message}</div>;
}

return (
<QuerySwitcher status={fastStatus} data={fastData}>
<QuerySwitcher status={status} data={data}>
<Toaster />
<div className="flex flex-col gap-6">
<HardwareTable
Expand Down
14 changes: 4 additions & 10 deletions dashboard/src/types/hardware.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
import type { StatusCount } from './general';

export interface HardwareFastItem {
hardwareName: string;
}
export type HardwareFastResponse = {
hardware: HardwareFastItem[];
};

interface BuildCount {
valid: number;
invalid: number;
null: number;
}

export interface HardwareRestItem {
export interface HardwareItem {
hardwareName: string;
buildCount: BuildCount;
testStatusCount: StatusCount;
bootStatusCount: StatusCount;
}

export type HardwareListingItem = HardwareRestItem & HardwareFastItem;
export type HardwareListingItem = HardwareItem;

export interface HardwareListingResponse {
hardware: HardwareListingItem[];
}

export type HardwareTableItem = HardwareFastItem & Partial<HardwareRestItem>;
export type HardwareTableItem = HardwareItem;

0 comments on commit e227a57

Please sign in to comment.