Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion dashboard/src/api/testDetails.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { UseQueryResult } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import { useQuery, useQueryClient } from '@tanstack/react-query';

import type {
TTestDetails,
Expand All @@ -9,6 +9,7 @@ import type {

import type { TIssue } from '@/types/issues';
import type { ApiUseQueryOptions } from '@/types/api';
import { isBadRequestError, DEFAULT_QUERY_RETRY_COUNT } from '@/utils/query';

import { RequestData } from './commonRequest';

Expand Down Expand Up @@ -64,9 +65,30 @@ const fetchTestStatusHistory = async (
export const useTestStatusHistory = (
params?: TestStatusHistoryParams,
): UseQueryResult<TestStatusHistory> => {
const queryClient = useQueryClient();

return useQuery({
queryKey: ['testStatusHistoryData', params],
queryFn: () => fetchTestStatusHistory(params),
retry: (failureCount, error) => {
if (isBadRequestError(error)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This might be a sensible default (to not retry on bad request).
If so, maybe we could just include the check for isBadRequest on the default retryHandler?

return false;
}

const globalRetry =
queryClient.getDefaultOptions().queries?.retry ??
DEFAULT_QUERY_RETRY_COUNT;

if (typeof globalRetry === 'function') {
return globalRetry(failureCount, error);
}

if (typeof globalRetry === 'number') {
return failureCount < globalRetry;
}

return globalRetry;
},
enabled: params !== undefined && Object.keys(params).length > 0,
});
};
26 changes: 16 additions & 10 deletions dashboard/src/components/TestDetails/TestDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import { processLogData } from '@/hooks/useLogData';

import { dateObjectToTimestampInSeconds, daysToSeconds } from '@/utils/date';
import { REDUCED_TIME_SEARCH } from '@/utils/constants/general';
import { isBadRequestError } from '@/utils/query';

import { MemoizedKcidevFooter } from '@/components/Footer/KcidevFooter';

Expand Down Expand Up @@ -223,9 +224,8 @@ const TestDetailsSections = ({
}, [statusHistory?.status_history, test.id]);

const regressionSection: ISection | undefined = useMemo(() => {
if (statusHistoryStatus === 'error') {
return;
}
const cannotFetchHistory =
statusHistoryStatus === 'error' && isBadRequestError(statusHistoryError);

const regressionTypeTooltip: string | null = ((): string | null => {
switch (statusHistory?.regression_type) {
Expand Down Expand Up @@ -294,12 +294,18 @@ const TestDetailsSections = ({
status={statusHistoryStatus}
data={statusHistory}
customError={
<MemoizedSectionError
isLoading={statusHistoryStatus === 'pending'}
errorMessage={statusHistoryError?.message}
emptyLabel="global.error"
variant="warning"
/>
cannotFetchHistory ? (
<div className="text-weak-gray flex flex-col items-center py-6 text-2xl font-semibold">
<FormattedMessage id="testDetails.cannotFetchHistory" />
</div>
) : (
<MemoizedSectionError
isLoading={statusHistoryStatus === 'pending'}
errorMessage={statusHistoryError?.message}
emptyLabel="global.error"
variant="warning"
/>
)
}
>
<div className="flex items-center">{regressionData}</div>
Expand All @@ -314,7 +320,7 @@ const TestDetailsSections = ({
formatMessage,
regressionData,
statusHistory,
statusHistoryError?.message,
statusHistoryError,
statusHistoryStatus,
]);

Expand Down
1 change: 1 addition & 0 deletions dashboard/src/locales/messages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ export const messages = {
'Inconclusive - test concluded with inconclusive results such as infrastructure errors.{br}{br}' +
'Inconclusive groups tests with ERROR, MISS, SKIP, DONE, and unknown statuses defined by KCIDB.',
'testDetails.buildInfo': 'Build Info',
'testDetails.cannotFetchHistory': 'No tracking information available',
'testDetails.notFound': 'Test not found',
'testDetails.regressionTooltip.fixed':
'Test was failing but passed in the last iterations',
Expand Down
17 changes: 17 additions & 0 deletions dashboard/src/utils/query.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { AxiosError, HttpStatusCode } from 'axios';

export const DEFAULT_QUERY_RETRY_COUNT = 3;

export const retryHandler = (retryCount: number | boolean = 3) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

might be a nit: but we are using a hardcoded default argument here, that might differ from the constant we introduced.

return (failureCount: number, error: Error): boolean => {
const splittedError = error.message.split(':');
Expand All @@ -19,3 +23,16 @@ export const retryHandler = (retryCount: number | boolean = 3) => {
return true;
};
};

export const isBadRequestError = (error: unknown): boolean => {
if (error instanceof AxiosError) {
return error.response?.status === HttpStatusCode.BadRequest;
}

if (error instanceof Error) {
const statusCode = Number(error.message.split(':')[0]);
return statusCode === HttpStatusCode.BadRequest;
}
Comment on lines +32 to +35

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is this really necessary? I don't like relying on the message string to infer http statuses


return false;
};
Loading