From 34ac84d4f5e80ae7cfb37333555afea0aa205495 Mon Sep 17 00:00:00 2001 From: Oscar Reyes Date: Wed, 22 Nov 2023 15:38:11 -0600 Subject: [PATCH] feat: Run Source (#3391) --- api/tests.yaml | 1 - cli/runner/orchestrator.go | 7 +- server/executor/test_suite_runner.go | 2 +- server/testsuite/testsuite_run_entities.go | 9 ++ web/src/components/RunCard/TestRunCard.tsx | 22 ++-- .../components/RunCard/TestSuiteRunCard.tsx | 117 +++++++++--------- .../components/RunDetailLayout/HeaderLeft.tsx | 21 +++- .../ResponseMetadata.tsx | 31 +++++ .../RunDetailTriggerResponse.tsx | 5 + .../VariableSet/VariableSetForm.tsx | 1 - web/src/models/RunMetadata.model.ts | 44 +++++++ web/src/models/TestRun.model.ts | 4 +- web/src/models/TestSuiteRun.model.ts | 5 +- .../Tracetest/endpoints/TestRun.endpoint.ts | 4 + .../endpoints/TestSuiteRun.endpoint.ts | 3 +- 15 files changed, 191 insertions(+), 85 deletions(-) create mode 100644 web/src/components/RunDetailTriggerResponse/ResponseMetadata.tsx create mode 100644 web/src/models/RunMetadata.model.ts diff --git a/api/tests.yaml b/api/tests.yaml index 700db2a2d4..236de0010c 100644 --- a/api/tests.yaml +++ b/api/tests.yaml @@ -1,7 +1,6 @@ openapi: 3.0.0 components: schemas: - TestResourceList: type: object properties: diff --git a/cli/runner/orchestrator.go b/cli/runner/orchestrator.go index 2431432ec4..210f66f05d 100644 --- a/cli/runner/orchestrator.go +++ b/cli/runner/orchestrator.go @@ -335,16 +335,21 @@ func (a orchestrator) writeJUnitReport(ctx context.Context, r Runner, result Run return err } +var source = "cli" + func getMetadata() map[string]string { ci := cienvironment.DetectCIEnvironment() if ci == nil { - return map[string]string{} + return map[string]string{ + "source": source, + } } metadata := map[string]string{ "name": ci.Name, "url": ci.URL, "buildNumber": ci.BuildNumber, + "source": source, } if ci.Git != nil { diff --git a/server/executor/test_suite_runner.go b/server/executor/test_suite_runner.go index d92669a386..c40101f984 100644 --- a/server/executor/test_suite_runner.go +++ b/server/executor/test_suite_runner.go @@ -94,7 +94,7 @@ func (r persistentTransactionRunner) ProcessItem(ctx context.Context, job Job) { } func (r persistentTransactionRunner) runTransactionStep(ctx context.Context, tr testsuite.TestSuiteRun, step int, testObj test.Test) (testsuite.TestSuiteRun, error) { - testRun := r.testRunner.Run(ctx, testObj, tr.Metadata, tr.VariableSet, tr.RequiredGates) + testRun := r.testRunner.Run(ctx, testObj, tr.RunMetadata(step), tr.VariableSet, tr.RequiredGates) tr, err := r.updateStepRun(ctx, tr, step, testRun) if err != nil { return testsuite.TestSuiteRun{}, fmt.Errorf("could not update transaction run: %w", err) diff --git a/server/testsuite/testsuite_run_entities.go b/server/testsuite/testsuite_run_entities.go index 57599e6506..2221ee88bc 100644 --- a/server/testsuite/testsuite_run_entities.go +++ b/server/testsuite/testsuite_run_entities.go @@ -68,3 +68,12 @@ func (tr TestSuiteRun) StepsGatesValidation() bool { return true } + +func (tr TestSuiteRun) RunMetadata(step int) test.RunMetadata { + tr.Metadata["step"] = fmt.Sprintf("%d", step+1) + tr.Metadata["testsuite_run_id"] = fmt.Sprintf("%d", tr.ID) + tr.Metadata["testsuite_id"] = string(tr.TestSuiteID) + tr.Metadata["testsuite_version"] = fmt.Sprintf("%d", tr.TestSuiteVersion) + + return tr.Metadata +} diff --git a/web/src/components/RunCard/TestRunCard.tsx b/web/src/components/RunCard/TestRunCard.tsx index dc5b495945..f487336963 100644 --- a/web/src/components/RunCard/TestRunCard.tsx +++ b/web/src/components/RunCard/TestRunCard.tsx @@ -27,7 +27,7 @@ const TestRunCard = ({ state, createdAt, testVersion, - metadata, + metadata: {name, buildNumber, branch, url, source}, testSuiteId, testSuiteRunId, linter, @@ -37,10 +37,6 @@ const TestRunCard = ({ linkTo, }: IProps) => { const {navigate} = useDashboard(); - const metadataName = metadata?.name; - const metadataBuildNumber = metadata?.buildNumber; - const metadataBranch = metadata?.branch; - const metadataUrl = metadata?.url; const handleResultClick = ( event: React.MouseEvent, @@ -64,13 +60,14 @@ const TestRunCard = ({ {isRunStateFinished(state) &&  • {executionTime}s} + {source &&  • Run via {source.toUpperCase()}} - {metadataName && ( - event.stopPropagation()}> -  • {`${metadataName} ${metadataBuildNumber}`} + {name && ( + event.stopPropagation()}> +  • {`${name} ${buildNumber}`} )} - {metadataBranch &&  • Branch: {metadataBranch}} + {branch &&  • Branch: {branch}} @@ -108,12 +105,7 @@ const TestRunCard = ({ )}
- +
diff --git a/web/src/components/RunCard/TestSuiteRunCard.tsx b/web/src/components/RunCard/TestSuiteRunCard.tsx index ddbdc436da..ec2ef09b78 100644 --- a/web/src/components/RunCard/TestSuiteRunCard.tsx +++ b/web/src/components/RunCard/TestSuiteRunCard.tsx @@ -15,68 +15,71 @@ interface IProps { } const TestSuiteRunCard = ({ - run: {id: runId, createdAt, state, metadata, version, pass, fail, allStepsRequiredGatesPassed}, + run: { + id: runId, + createdAt, + state, + metadata: {name, buildNumber, branch, url, source}, + version, + pass, + fail, + allStepsRequiredGatesPassed, + }, testSuiteId, linkTo, -}: IProps) => { - const metadataName = metadata?.name; - const metadataBuildNumber = metadata?.buildNumber; - const metadataBranch = metadata?.branch; - const metadataUrl = metadata?.url; - - return ( - - - - -
- v{version} -
- - - {Date.getTimeAgo(createdAt)} - - {/* Adding this latter when is available */} - {/*  • 0s (executionTime missing from API) */} - - {metadataName && ( - event.stopPropagation()}> -  • {`${metadataName} ${metadataBuildNumber}`} - - )} - {metadataBranch &&  • Branch: {metadataBranch}} - -
- - {state !== TestStateEnum.FAILED && state !== TestStateEnum.FINISHED && ( -
- -
- )} +}: IProps) => ( + + + + +
+ v{version} +
+ + + {Date.getTimeAgo(createdAt)} + + {source &&  • Run via {source.toUpperCase()}} + {/* Adding this latter when is available */} + {/*  • 0s (executionTime missing from API) */} - {(state === TestStateEnum.FAILED || state === TestStateEnum.FINISHED) && ( - - - - - {pass} - - - - - - {fail} - - - - )} + {name && ( + event.stopPropagation()}> +  • {`${name} ${buildNumber}`} + + )} + {branch &&  • Branch: {branch}} + +
+ {state !== TestStateEnum.FAILED && state !== TestStateEnum.FINISHED && (
- +
-
- - ); -}; + )} + + {(state === TestStateEnum.FAILED || state === TestStateEnum.FINISHED) && ( + + + + + {pass} + + + + + + {fail} + + + + )} + +
+ +
+
+ +); export default TestSuiteRunCard; diff --git a/web/src/components/RunDetailLayout/HeaderLeft.tsx b/web/src/components/RunDetailLayout/HeaderLeft.tsx index 41edcef1fb..79ca222300 100644 --- a/web/src/components/RunDetailLayout/HeaderLeft.tsx +++ b/web/src/components/RunDetailLayout/HeaderLeft.tsx @@ -18,8 +18,19 @@ interface IProps { } const HeaderLeft = ({name, triggerType, origin}: IProps) => { - const {run: {createdAt, testSuiteId, testSuiteRunId, executionTime, trace, traceId, testVersion} = {}, run} = - useTestRun(); + const { + run: { + createdAt, + testSuiteId, + testSuiteRunId, + executionTime, + trace, + traceId, + testVersion, + metadata: {source} = {}, + } = {}, + run, + } = useTestRun(); const {onEdit, isEditLoading: isLoading, test} = useTest(); const createdTimeAgo = Date.getTimeAgo(createdAt ?? ''); const {navigate} = useDashboard(); @@ -33,8 +44,8 @@ const HeaderLeft = ({name, triggerType, origin}: IProps) => { const description = useMemo(() => { return ( <> - v{testVersion} • {triggerType} • Ran {createdTimeAgo} - {testSuiteId && testSuiteRunId && ( + v{testVersion} • {triggerType} • Ran {createdTimeAgo} • {source && <>Run via {source.toUpperCase()}} + {testSuiteId && !!testSuiteRunId && ( <> {' '} •{' '} @@ -45,7 +56,7 @@ const HeaderLeft = ({name, triggerType, origin}: IProps) => { )} ); - }, [triggerType, createdTimeAgo, testSuiteId, testSuiteRunId, testVersion]); + }, [testVersion, triggerType, createdTimeAgo, source, testSuiteId, testSuiteRunId]); return ( diff --git a/web/src/components/RunDetailTriggerResponse/ResponseMetadata.tsx b/web/src/components/RunDetailTriggerResponse/ResponseMetadata.tsx new file mode 100644 index 0000000000..1bbf9f93b9 --- /dev/null +++ b/web/src/components/RunDetailTriggerResponse/ResponseMetadata.tsx @@ -0,0 +1,31 @@ +import {useTestRun} from 'providers/TestRun/TestRun.provider'; +import {useMemo} from 'react'; +import * as S from './RunDetailTriggerResponse.styled'; +import KeyValueRow from '../KeyValueRow'; + +const ResponseMetadata = () => { + const { + run: {metadata}, + } = useTestRun(); + + const entries = useMemo(() => Object.entries(metadata).filter(([, value]) => !!value), [metadata]); + + if (!entries.length) { + return ( + + + There are no metadata entries used in this test + + ); + } + + return ( + + {entries.map(([key, value]) => ( + + ))} + + ); +}; + +export default ResponseMetadata; diff --git a/web/src/components/RunDetailTriggerResponse/RunDetailTriggerResponse.tsx b/web/src/components/RunDetailTriggerResponse/RunDetailTriggerResponse.tsx index 3cf79f1161..2a31984cc3 100644 --- a/web/src/components/RunDetailTriggerResponse/RunDetailTriggerResponse.tsx +++ b/web/src/components/RunDetailTriggerResponse/RunDetailTriggerResponse.tsx @@ -18,11 +18,13 @@ import ResponseVariableSet from './ResponseVariableSet'; import ResponseHeaders from './ResponseHeaders'; import * as S from './RunDetailTriggerResponse.styled'; import {IPropsComponent} from './RunDetailTriggerResponseFactory'; +import ResponseMetadata from './ResponseMetadata'; const TabsKeys = { Body: 'body', Headers: 'headers', VariableSet: 'variable-set', + Metadata: 'metadata', }; const tracetestTriggerSelector = 'span[tracetest.span.type="general" name="Tracetest trigger"]'; @@ -146,6 +148,9 @@ const RunDetailTriggerResponse = ({ + + + diff --git a/web/src/components/VariableSet/VariableSetForm.tsx b/web/src/components/VariableSet/VariableSetForm.tsx index aca1d30773..c779b99f41 100644 --- a/web/src/components/VariableSet/VariableSetForm.tsx +++ b/web/src/components/VariableSet/VariableSetForm.tsx @@ -31,7 +31,6 @@ const VariableSetForm = ({form, initialValues, onSubmit, onValidate}: IProps) => diff --git a/web/src/models/RunMetadata.model.ts b/web/src/models/RunMetadata.model.ts new file mode 100644 index 0000000000..d85ae9e2b9 --- /dev/null +++ b/web/src/models/RunMetadata.model.ts @@ -0,0 +1,44 @@ +import {Model} from 'types/Common.types'; + +export type TRawRunMetadata = Record; + +export enum KnownSources { + WEB = 'web', + CLI = 'cli', + API = 'api', + K6 = 'k6', + UNKNOWN = 'unknown', +} + +type TKnownSources = KnownSources | string; + +type RunMetadata = Model< + Record, + { + name: string; + buildNumber: string; + branch: string; + url: string; + source: TKnownSources; + } +>; + +function RunMetadata({ + name = '', + buildNumber = '', + branch = '', + url = '', + source = '', + ...rest +}: TRawRunMetadata): RunMetadata { + return { + name, + buildNumber, + branch, + url, + source, + ...rest, + }; +} + +export default RunMetadata; diff --git a/web/src/models/TestRun.model.ts b/web/src/models/TestRun.model.ts index 17b3644dfa..4e39fedef8 100644 --- a/web/src/models/TestRun.model.ts +++ b/web/src/models/TestRun.model.ts @@ -8,6 +8,7 @@ import TestRunOutput from './TestRunOutput.model'; import Trace from './Trace.model'; import TriggerResult from './TriggerResult.model'; import RequiredGatesResult from './RequiredGatesResult.model'; +import RunMetadata from './RunMetadata.model'; export type TRawTestRun = Modify< TTestSchemas['TestRun'], @@ -35,6 +36,7 @@ type TestRun = Model< linter: LinterResult; requiredGatesResult: RequiredGatesResult; testSuiteRunId: number; + metadata: RunMetadata; } >; @@ -140,7 +142,7 @@ const TestRun = ({ totalAssertionCount: getTestResultCount(result), failedAssertionCount: getTestResultCount(result, 'failed'), passedAssertionCount: getTestResultCount(result, 'passed'), - metadata, + metadata: RunMetadata(metadata), outputs: outputs?.map(rawOutput => TestRunOutput(rawOutput)), variableSet: VariableSet.fromRun(variableSet), testSuiteId, diff --git a/web/src/models/TestSuiteRun.model.ts b/web/src/models/TestSuiteRun.model.ts index 61d8ca4865..ba033a7073 100644 --- a/web/src/models/TestSuiteRun.model.ts +++ b/web/src/models/TestSuiteRun.model.ts @@ -1,6 +1,7 @@ import {Model, TTestSuiteSchemas} from 'types/Common.types'; import VariableSet from './VariableSet.model'; import TestRun from './TestRun.model'; +import RunMetadata from './RunMetadata.model'; export type TRawTestSuiteRunResourceRun = TTestSuiteSchemas['TestSuiteRun']; type TestSuiteRun = Model< @@ -8,7 +9,7 @@ type TestSuiteRun = Model< { steps: TestRun[]; variableSet?: VariableSet; - metadata?: {[key: string]: string}; + metadata: RunMetadata; } >; @@ -37,7 +38,7 @@ const TestSuiteRun = ({ steps: steps.map(step => TestRun(step)), variableSet: VariableSet.fromRun(variableSet), allStepsRequiredGatesPassed, - metadata, + metadata: RunMetadata(metadata), version, pass, fail, diff --git a/web/src/redux/apis/Tracetest/endpoints/TestRun.endpoint.ts b/web/src/redux/apis/Tracetest/endpoints/TestRun.endpoint.ts index 523a9b04d8..e19a9ff977 100644 --- a/web/src/redux/apis/Tracetest/endpoints/TestRun.endpoint.ts +++ b/web/src/redux/apis/Tracetest/endpoints/TestRun.endpoint.ts @@ -8,6 +8,7 @@ import SelectedSpans, {TRawSelectedSpans} from 'models/SelectedSpans.model'; import Test from 'models/Test.model'; import TestRun, {TRawTestRun} from 'models/TestRun.model'; import TestRunEvent, {TRawTestRunEvent} from 'models/TestRunEvent.model'; +import {KnownSources} from 'models/RunMetadata.model'; import {TRawTestSpecs} from 'models/TestSpecs.model'; import {TTestApiEndpointBuilder} from '../Tracetest.api'; @@ -23,6 +24,9 @@ export const testRunEndpoints = (builder: TTestApiEndpointBuilder) => ({ body: { variableSetId, variables, + metadata: { + source: KnownSources.WEB, + }, }, }), invalidatesTags: (response, error, {testId}) => [ diff --git a/web/src/redux/apis/Tracetest/endpoints/TestSuiteRun.endpoint.ts b/web/src/redux/apis/Tracetest/endpoints/TestSuiteRun.endpoint.ts index e2a1bac6b2..f4abcdff65 100644 --- a/web/src/redux/apis/Tracetest/endpoints/TestSuiteRun.endpoint.ts +++ b/web/src/redux/apis/Tracetest/endpoints/TestSuiteRun.endpoint.ts @@ -4,6 +4,7 @@ import {PaginationResponse} from 'hooks/usePagination'; import {TVariableSetValue} from 'models/VariableSet.model'; import RunError from 'models/RunError.model'; import TestSuiteRun, {TRawTestSuiteRunResourceRun} from 'models/TestSuiteRun.model'; +import {KnownSources} from 'models/RunMetadata.model'; import {getTotalCountFromHeaders} from 'utils/Common'; import {TTestApiEndpointBuilder} from '../Tracetest.api'; @@ -15,7 +16,7 @@ export const testSuiteRunEndpoints = (builder: TTestApiEndpointBuilder) => ({ query: ({testSuiteId, variableSetId, variables = []}) => ({ url: `/testsuites/${testSuiteId}/run`, method: HTTP_METHOD.POST, - body: {variableSetId, variables}, + body: {variableSetId, variables, metadata: {source: KnownSources.WEB}}, }), invalidatesTags: (result, error, {testSuiteId}) => [ {type: TracetestApiTags.TESTSUITE_RUN, id: `${testSuiteId}-LIST`},