Skip to content

Commit 1cd98ab

Browse files
authored
feat(frontend): stop a test run (#2295)
1 parent ba47e42 commit 1cd98ab

File tree

19 files changed

+190
-82
lines changed

19 files changed

+190
-82
lines changed

.github/workflows/pull-request.yaml

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -391,25 +391,25 @@ jobs:
391391
env:
392392
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
393393

394-
# cleanup:
395-
# name: Cleanup test infra
396-
# runs-on: ubuntu-latest
397-
# needs: [trace-testing, e2e]
398-
# if: always()
399-
# steps:
400-
# - uses: google-github-actions/setup-gcloud@94337306dda8180d967a56932ceb4ddcf01edae7
401-
# with:
402-
# service_account_key: ${{ secrets.GKE_SA_KEY }}
403-
# project_id: ${{ secrets.GKE_PROJECT }}
404-
405-
# - uses: google-github-actions/get-gke-credentials@fb08709ba27618c31c09e014e1d8364b02e5042e
406-
# with:
407-
# cluster_name: ${{ secrets.GKE_CLUSTER }}
408-
# location: ${{ secrets.GKE_ZONE }}
409-
# credentials: ${{ secrets.GKE_SA_KEY }}
410-
411-
# - name: Uninstall tracetest
412-
# run: |
413-
# helm delete tracetest-pr-${{ github.event.pull_request.number }} \
414-
# --namespace tracetest-pr-${{ github.event.pull_request.number }}
415-
# kubectl delete ns tracetest-pr-${{ github.event.pull_request.number }}
394+
cleanup:
395+
name: Cleanup test infra
396+
runs-on: ubuntu-latest
397+
needs: [trace-testing, e2e]
398+
if: always()
399+
steps:
400+
- uses: google-github-actions/setup-gcloud@94337306dda8180d967a56932ceb4ddcf01edae7
401+
with:
402+
service_account_key: ${{ secrets.GKE_SA_KEY }}
403+
project_id: ${{ secrets.GKE_PROJECT }}
404+
405+
- uses: google-github-actions/get-gke-credentials@fb08709ba27618c31c09e014e1d8364b02e5042e
406+
with:
407+
cluster_name: ${{ secrets.GKE_CLUSTER }}
408+
location: ${{ secrets.GKE_ZONE }}
409+
credentials: ${{ secrets.GKE_SA_KEY }}
410+
411+
- name: Uninstall tracetest
412+
run: |
413+
helm delete tracetest-pr-${{ github.event.pull_request.number }} \
414+
--namespace tracetest-pr-${{ github.event.pull_request.number }}
415+
kubectl delete ns tracetest-pr-${{ github.event.pull_request.number }}

web/src/components/RunCard/RunCard.styled.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {CheckCircleFilled, MinusCircleFilled, MoreOutlined} from '@ant-design/icons';
1+
import {CheckCircleFilled, InfoCircleFilled, MinusCircleFilled, MoreOutlined} from '@ant-design/icons';
22
import {Typography} from 'antd';
33
import styled from 'styled-components';
44

@@ -49,6 +49,10 @@ export const IconFail = styled(MinusCircleFilled)`
4949
color: ${({theme}) => theme.color.error};
5050
`;
5151

52+
export const IconInfo = styled(InfoCircleFilled)`
53+
color: ${({theme}) => theme.color.textLight};
54+
`;
55+
5256
export const Info = styled.div`
5357
flex: 1;
5458
`;

web/src/components/RunCard/TestRunCard.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {Tooltip} from 'antd';
22
import {Link} from 'react-router-dom';
33
import RunActionsMenu from 'components/RunActionsMenu';
44
import TestState from 'components/TestState';
5-
import TestRun, {isRunStateFailed, isRunStateFinished} from 'models/TestRun.model';
5+
import TestRun, {isRunStateFailed, isRunStateFinished, isRunStateStopped} from 'models/TestRun.model';
66
import Date from 'utils/Date';
77
import * as S from './RunCard.styled';
88

@@ -16,6 +16,9 @@ function getIcon(state: TestRun['state'], failedAssertions: number) {
1616
if (!isRunStateFinished(state)) {
1717
return null;
1818
}
19+
if (isRunStateStopped(state)) {
20+
return <S.IconInfo />;
21+
}
1922
if (isRunStateFailed(state) || failedAssertions > 0) {
2023
return <S.IconFail />;
2124
}

web/src/components/RunDetailLayout/HeaderRight.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {Button} from 'antd';
1+
import {CloseCircleOutlined} from '@ant-design/icons';
2+
import {Button, Tooltip} from 'antd';
23
import RunActionsMenu from 'components/RunActionsMenu';
34
import TestActions from 'components/TestActions';
45
import TestState from 'components/TestState';
@@ -19,7 +20,7 @@ const HeaderRight = ({testId, testVersion}: IProps) => {
1920
const {isDraftMode: isTestSpecsDraftMode} = useTestSpecs();
2021
const {isDraftMode: isTestOutputsDraftMode} = useTestOutput();
2122
const isDraftMode = isTestSpecsDraftMode || isTestOutputsDraftMode;
22-
const {run} = useTestRun();
23+
const {isLoadingStop, run, stopRun} = useTestRun();
2324
const {onRun} = useTest();
2425
const state = run.state;
2526

@@ -30,6 +31,19 @@ const HeaderRight = ({testId, testVersion}: IProps) => {
3031
<S.StateContainer data-cy="test-run-result-status">
3132
<S.StateText>Test status:</S.StateText>
3233
<TestState testState={state} />
34+
{state === TestStateEnum.AWAITING_TRACE && (
35+
<S.StopContainer>
36+
<Tooltip title="Stop test execution">
37+
<Button
38+
disabled={isLoadingStop}
39+
icon={<CloseCircleOutlined />}
40+
onClick={stopRun}
41+
shape="circle"
42+
type="link"
43+
/>
44+
</Tooltip>
45+
</S.StopContainer>
46+
)}
3347
</S.StateContainer>
3448
)}
3549
{!isDraftMode && state && isRunStateFinished(state) && (

web/src/components/RunDetailLayout/RunDetailLayout.styled.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ export const StateContainer = styled.div`
9595
justify-self: flex-end;
9696
`;
9797

98+
export const StopContainer = styled.div`
99+
margin-left: 12px;
100+
`;
101+
98102
export const StateText = styled(Typography.Text)`
99103
&& {
100104
margin-right: 8px;

web/src/components/RunDetailTest/Visualization.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import RunEvents from 'components/RunEvents';
66
import {useTestSpecForm} from 'components/TestSpecForm/TestSpecForm.provider';
77
import DAG from 'components/Visualization/components/DAG';
88
import Timeline from 'components/Visualization/components/Timeline';
9-
import {TestState} from 'constants/TestRun.constants';
109
import {TestRunStage} from 'constants/TestRunEvents.constants';
1110
import Span from 'models/Span.model';
1211
import TestRunEvent from 'models/TestRunEvent.model';
@@ -16,6 +15,7 @@ import {initNodes, onNodesChange as onNodesChangeAction} from 'redux/slices/DAG.
1615
import DAGSelectors from 'selectors/DAG.selectors';
1716
import TraceAnalyticsService from 'services/Analytics/TestRunAnalytics.service';
1817
import TraceDiagramAnalyticsService from 'services/Analytics/TraceDiagramAnalytics.service';
18+
import TestRunService from 'services/TestRun.service';
1919
import {TTestRunState} from 'types/TestRun.types';
2020

2121
export interface IProps {
@@ -69,7 +69,7 @@ const Visualization = ({runEvents, runState, spans, type}: IProps) => {
6969
[onSelectSpan, onSetFocusedSpan]
7070
);
7171

72-
if (runState !== TestState.FINISHED) {
72+
if (TestRunService.shouldDisplayTraceEvents(runState, spans.length)) {
7373
return <RunEvents events={runEvents} stage={TestRunStage.Trace} state={runState} />;
7474
}
7575

web/src/components/RunDetailTrace/Visualization.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import RunEvents from 'components/RunEvents';
2-
import {TestState} from 'constants/TestRun.constants';
32
import {TestRunStage} from 'constants/TestRunEvents.constants';
43
import TestRunEvent from 'models/TestRunEvent.model';
54
import {useCallback, useEffect} from 'react';
@@ -9,6 +8,7 @@ import {changeNodes, initNodes, selectSpan} from 'redux/slices/Trace.slice';
98
import TraceSelectors from 'selectors/Trace.selectors';
109
import TraceAnalyticsService from 'services/Analytics/TestRunAnalytics.service';
1110
import TraceDiagramAnalyticsService from 'services/Analytics/TraceDiagramAnalytics.service';
11+
import TestRunService from 'services/TestRun.service';
1212
import {TTestRunState} from 'types/TestRun.types';
1313
import Span from 'models/Span.model';
1414
import {useDrawer} from '../Drawer/Drawer';
@@ -69,7 +69,7 @@ const Visualization = ({runEvents, runState, spans, type}: IProps) => {
6969
[dispatch]
7070
);
7171

72-
if (runState !== TestState.FINISHED) {
72+
if (TestRunService.shouldDisplayTraceEvents(runState, spans.length)) {
7373
return <RunEvents events={runEvents} stage={TestRunStage.Trace} state={runState} />;
7474
}
7575

web/src/components/RunEvents/RunEvents.styled.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,17 @@ export const EventContainer = styled.div`
5858
position: relative;
5959
`;
6060

61-
export const InfoIcon = styled(InfoCircleFilled)`
61+
export const InfoIcon = styled(InfoCircleFilled)<{$isLarge?: boolean}>`
6262
color: ${({theme}) => theme.color.textLight};
6363
margin-top: 3px;
64+
65+
${({$isLarge}) =>
66+
$isLarge &&
67+
css`
68+
font-size: 32px;
69+
margin-bottom: 26px;
70+
margin-top: 0;
71+
`}
6472
`;
6573

6674
export const Link = styled(Typography.Link)`

web/src/components/RunEvents/RunEventsTrace.tsx

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1-
import {Typography} from 'antd';
2-
3-
import {TRACE_DOCUMENTATION_URL} from 'constants/Common.constants';
41
import {TestState} from 'constants/TestRun.constants';
52
import {TraceEventType} from 'constants/TestRunEvents.constants';
6-
import {isRunStateFailed} from 'models/TestRun.model';
73
import TestRunService from 'services/TestRun.service';
84
import RunEvent, {IPropsEvent} from './RunEvent';
95
import RunEventDataStore from './RunEventDataStore';
106
import RunEventPolling from './RunEventPolling';
117
import {IPropsComponent} from './RunEvents';
128
import * as S from './RunEvents.styled';
9+
import FailedTraceHeader from './TraceHeader/FailedTraceHeader';
10+
import FailedTriggerHeader from './TraceHeader/FailedTriggerHeader';
11+
import LoadingHeader from './TraceHeader/LoadingHeader';
12+
import StoppedHeader from './TraceHeader/StoppedHeader';
13+
14+
type TestStateType = TestState.TRIGGER_FAILED | TestState.TRACE_FAILED | TestState.STOPPED;
15+
16+
const HeaderComponentMap: Record<TestStateType, () => React.ReactElement> = {
17+
[TestState.TRIGGER_FAILED]: FailedTriggerHeader,
18+
[TestState.TRACE_FAILED]: FailedTraceHeader,
19+
[TestState.STOPPED]: StoppedHeader,
20+
};
1321

1422
type TraceEventTypeWithoutFetching = Exclude<
1523
TraceEventType,
@@ -23,51 +31,11 @@ const ComponentMap: Record<TraceEventTypeWithoutFetching, (props: IPropsEvent) =
2331

2432
const RunEventsTrace = ({events, state}: IPropsComponent) => {
2533
const filteredEvents = TestRunService.getTestRunTraceEvents(events);
26-
27-
const loadingHeader = (
28-
<>
29-
<S.LoadingIcon />
30-
<Typography.Title level={3} type="secondary">
31-
We are working to gather the trace associated with this test run
32-
</Typography.Title>
33-
<S.Paragraph type="secondary">
34-
Want to know more about traces? Head to the official{' '}
35-
<S.Link href={TRACE_DOCUMENTATION_URL} target="_blank">
36-
Open Telemetry Documentation
37-
</S.Link>
38-
</S.Paragraph>
39-
</>
40-
);
41-
42-
const failedTriggerHeader = (
43-
<>
44-
<S.ErrorIcon />
45-
<Typography.Title level={2} type="secondary">
46-
Test Trigger Failed
47-
</Typography.Title>
48-
<S.Paragraph type="secondary">
49-
The test failed in the Trigger stage, review the Trigger tab to see the breakdown of diagnostic steps.
50-
</S.Paragraph>
51-
</>
52-
);
53-
54-
const failedTraceHeader = (
55-
<>
56-
<S.ErrorIcon />
57-
<Typography.Title level={2} type="secondary">
58-
Trace Fetch Failed
59-
</Typography.Title>
60-
<S.Paragraph type="secondary">
61-
We prepared the breakdown of diagnostic steps and tips to help identify the source of the issue:
62-
</S.Paragraph>
63-
</>
64-
);
34+
const HeaderComponent = HeaderComponentMap[state as TestStateType] ?? LoadingHeader;
6535

6636
return (
6737
<S.Container $hasScroll>
68-
{state === TestState.TRIGGER_FAILED && failedTriggerHeader}
69-
{state === TestState.TRACE_FAILED && failedTraceHeader}
70-
{!isRunStateFailed(state) && loadingHeader}
38+
<HeaderComponent />
7139

7240
<S.ListContainer>
7341
{filteredEvents.map(event => {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import {Typography} from 'antd';
2+
import * as S from '../RunEvents.styled';
3+
4+
const FailedTraceHeader = () => (
5+
<>
6+
<S.ErrorIcon />
7+
<Typography.Title level={2} type="secondary">
8+
Trace Fetch Failed
9+
</Typography.Title>
10+
<S.Paragraph type="secondary">
11+
We prepared the breakdown of diagnostic steps and tips to help identify the source of the issue:
12+
</S.Paragraph>
13+
</>
14+
);
15+
16+
export default FailedTraceHeader;

0 commit comments

Comments
 (0)