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

Collection Job - Per-test status updates #1000

Merged
merged 15 commits into from
May 8, 2024
152 changes: 60 additions & 92 deletions client/components/BotRunTestStatusList/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import {
COLLECTION_JOB_STATUS_BY_TEST_PLAN_RUN_ID_QUERY,
TEST_PLAN_RUNS_TEST_RESULTS_QUERY
} from './queries';
import { useLazyQuery, useQuery } from '@apollo/client';
import { TEST_PLAN_RUNS_TEST_RESULTS_QUERY } from './queries';
import { useQuery } from '@apollo/client';
import styled from '@emotion/styled';
import ReportStatusDot from '../common/ReportStatusDot';
import { isBot } from '../../utils/automation';

const BotRunTestStatusUnorderedList = styled.ul`
list-style-type: none;
Expand Down Expand Up @@ -35,121 +31,93 @@ const BotRunTestStatusUnorderedList = styled.ul`
const testCountString = (count, status) =>
`${count} Test${count === 1 ? '' : 's'} ${status}`;

const BotRunTestStatusList = ({ testPlanReportId, runnableTestsLength }) => {
const pollInterval = 2000;

const BotRunTestStatusList = ({ testPlanReportId }) => {
const {
data: testPlanRunsQueryResult,
startPolling,
stopPolling
} = useQuery(TEST_PLAN_RUNS_TEST_RESULTS_QUERY, {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wow I had no idea these existed, nice use of the tech 😮

variables: { testPlanReportId },
fetchPolicy: 'cache-and-network',
pollInterval: 2000
pollInterval
});

const [getCollectionJobStatus, { data: collectionJobStatusQueryResult }] =
useLazyQuery(COLLECTION_JOB_STATUS_BY_TEST_PLAN_RUN_ID_QUERY, {
fetchPolicy: 'cache-and-network'
});

const [collectedData, setCollectedData] = useState([]);
const requestedTestRunIds = useRef(new Set());

const botTestPlanRuns = useMemo(() => {
if (!testPlanRunsQueryResult?.testPlanRuns) {
return [];
}
return testPlanRunsQueryResult.testPlanRuns.filter(testPlanRun =>
isBot(testPlanRun.tester)
);
}, [testPlanRunsQueryResult?.testPlanRuns]);

useEffect(() => {
const ids = botTestPlanRuns.map(run => run.id);
for (const id of ids) {
if (!requestedTestRunIds.current.has(id)) {
requestedTestRunIds.current.add(id);
getCollectionJobStatus({
variables: { testPlanRunId: id }
});
}
}
}, [botTestPlanRuns]);

useEffect(() => {
if (collectionJobStatusQueryResult?.collectionJobByTestPlanRunId) {
const { status } =
collectionJobStatusQueryResult.collectionJobByTestPlanRunId;
setCollectedData(prev => [...prev, status]);
}
}, [collectionJobStatusQueryResult?.collectionJobByTestPlanRunId]);

const [numTestsCompleted, numTestsQueued, numTestsCancelled] =
useMemo(() => {
const res = [0, 0, 0];
if (
botTestPlanRuns &&
botTestPlanRuns.length &&
collectedData.length === botTestPlanRuns.length
) {
for (let i = 0; i < botTestPlanRuns.length; i++) {
const status = collectedData[i];
res[0] += botTestPlanRuns[i].testResults.length;
switch (status) {
case 'COMPLETED':
case 'RUNNING':
case 'QUEUED':
res[1] +=
runnableTestsLength -
botTestPlanRuns[i].testResults.length;
break;
case 'CANCELLED':
res[2] +=
runnableTestsLength -
botTestPlanRuns[i].testResults.length;
break;
default:
break;
const { COMPLETED, ERROR, RUNNING, CANCELLED, QUEUED } = useMemo(() => {
const counter = {
COMPLETED: 0,
ERROR: 0,
RUNNING: 0,
CANCELLED: 0,
QUEUED: 0
};
let anyPossibleUpdates = false;
if (testPlanRunsQueryResult?.testPlanRuns) {
for (const {
collectionJob
} of testPlanRunsQueryResult.testPlanRuns) {
if (collectionJob?.testStatus) {
for (const { status } of collectionJob.testStatus) {
counter[status]++;
if (status === 'QUEUED' || status === 'RUNNING') {
anyPossibleUpdates = true;
}
}
}
if (
res[0] + res[2] ===
runnableTestsLength * botTestPlanRuns.length
) {
stopPolling();
}
}
return res;
}, [testPlanRunsQueryResult, collectedData, stopPolling, startPolling]);
// it's possible that we got incomplete data on first fetch and
// stopped the polling, so restart the polling if we detect any
// possible future updates, otherwise stop.
if (anyPossibleUpdates) {
startPolling(pollInterval);
} else {
stopPolling();
}
}
return counter;
}, [testPlanRunsQueryResult, stopPolling, startPolling]);

if (
!botTestPlanRuns ||
botTestPlanRuns.length === 0 ||
!collectedData ||
!(collectedData.length === botTestPlanRuns.length)
!testPlanRunsQueryResult ||
testPlanRunsQueryResult.testPlanRuns.length === 0
) {
return null;
}
return (
<BotRunTestStatusUnorderedList className="text-secondary fs-6">
{RUNNING > 0 && (
<li className="m-2">
<ReportStatusDot className="tests-running" />
{testCountString(RUNNING, 'Running')}
</li>
)}
{ERROR > 0 && (
<li className="m-2">
<ReportStatusDot className="tests-error" />
{testCountString(ERROR, 'Error')}
</li>
)}
<li className="m-2">
<ReportStatusDot className="tests-complete" />
{testCountString(numTestsCompleted, 'Completed')}
{testCountString(COMPLETED, 'Completed')}
</li>
<li className="m-2">
<ReportStatusDot className="tests-queued" />
{testCountString(numTestsQueued, 'Queued')}
</li>
<li className="m-2">
<ReportStatusDot className="tests-cancelled" />
{testCountString(numTestsCancelled, 'Cancelled')}
{testCountString(QUEUED, 'Queued')}
</li>
{CANCELLED > 0 && (
<li className="m-2">
<ReportStatusDot className="tests-cancelled" />
{testCountString(CANCELLED, 'Cancelled')}
</li>
)}
</BotRunTestStatusUnorderedList>
);
};

BotRunTestStatusList.propTypes = {
testPlanReportId: PropTypes.string.isRequired,
runnableTestsLength: PropTypes.number.isRequired
testPlanReportId: PropTypes.string.isRequired
};

export default BotRunTestStatusList;
15 changes: 6 additions & 9 deletions client/components/BotRunTestStatusList/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,12 @@ export const TEST_PLAN_RUNS_TEST_RESULTS_QUERY = gql`
}
}
}
}
}
`;

export const COLLECTION_JOB_STATUS_BY_TEST_PLAN_RUN_ID_QUERY = gql`
query CollectionJobStatusByTestPlanRunId($testPlanRunId: ID!) {
collectionJobByTestPlanRunId(testPlanRunId: $testPlanRunId) {
id
status
collectionJob {
status
testStatus {
status
}
}
}
}
`;
13 changes: 12 additions & 1 deletion client/components/common/ReportStatusDot/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ const ReportStatusDot = styled.span`
background: #7c7c7c;
}

&.tests-running {
border: 2px solid #1e8f37;
background: #d2d5d9;
}

&.tests-error {
background: #e3261f;
}

&.tests-queued,
&.reports-in-progress {
background: #3876e8;
Expand All @@ -27,7 +36,9 @@ const ReportStatusDot = styled.span`
background: #2ba51c;
}

&.tests-cancelled,
&.tests-cancelled {
background: #a231ff;
}
&.reports-missing {
background: #ce1b4c;
}
Expand Down
Loading
Loading