Skip to content
Merged
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
16 changes: 13 additions & 3 deletions app/Http/Controllers/BuildController.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,22 +121,32 @@ public function update(int $build_id): View
]);
}

public function tests(int $build_id): View
public function tests(Request $request, int $build_id): View
{
$this->setBuildById($build_id);

$filters = json_decode(request()->query('filters')) ?? ['all' => []];

$eloquent_project = Project::findOrFail((int) $this->project->Id);

return $this->vue('build-tests-page', 'Tests', [
$params = [
'build-id' => $this->build->Id,
'show-test-time-status' => (bool) $eloquent_project->showtesttime,
'project-name' => $eloquent_project->name,
'build-time' => Carbon::parse($this->build->StartTime)->toIso8601String(),
'initial-filters' => $filters,
'pinned-measurements' => $eloquent_project->pinnedTestMeasurements()->orderBy('position')->pluck('name')->toArray(),
]);
];

if ($request->has('onlydelta')) {
$params['only-delta'] = true;
$previousBuildId = $this->build->GetPreviousBuildId();
if ($previousBuildId > 0) {
$params['previous-build-id'] = $previousBuildId;
}
}

return $this->vue('build-tests-page', 'Tests', $params);
}

public function coverage(int $build_id): View
Expand Down
10 changes: 5 additions & 5 deletions resources/js/angular/views/partials/build.html
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@
<a class="cdash-link" ng-href="{{ 'builds/' + build.id + '/tests?filters=%7B%22all%22%3A%5B%7B%22eq%22%3A%7B%22status%22%3A%22NOT_RUN%22%7D%7D%5D%7D' }}">
{{::build.test.notrun}}
</a>
<a ng-if="::build.test.nnotrundiffp > 0" class="sup cdash-link" ng-href="viewTest.php?onlydelta&buildid={{::build.id}}{{::cdash.testfilters}}">
<a ng-if="::build.test.nnotrundiffp > 0" class="sup cdash-link" ng-href="{{ 'builds/' + build.id + '/tests?onlydelta&filters=%7B%22all%22%3A%5B%7B%22eq%22%3A%7B%22status%22%3A%22NOT_RUN%22%7D%7D%5D%7D' }}">
+{{::build.test.nnotrundiffp}}
</a>
<span ng-if="::build.test.nnotrundiffn > 0" class="sub">-{{::build.test.nnotrundiffn}}</span>
Expand All @@ -348,7 +348,7 @@
<a class="cdash-link" ng-href="{{'builds/' + build.id + '/tests?filters=%7B%22all%22%3A%5B%7B%22eq%22%3A%7B%22status%22%3A%22FAILED%22%7D%7D%5D%7D' }}">
{{::build.test.fail}}
</a>
<a ng-if="::build.test.nfaildiffp > 0" class="sup cdash-link" ng-href="viewTest.php?onlydelta&buildid={{::build.id}}{{::cdash.testfilters}}">
<a ng-if="::build.test.nfaildiffp > 0" class="sup cdash-link" ng-href="{{'builds/' + build.id + '/tests?onlydelta&filters=%7B%22all%22%3A%5B%7B%22eq%22%3A%7B%22status%22%3A%22FAILED%22%7D%7D%5D%7D' }}">
+{{::build.test.nfaildiffp}}
</a>
<span ng-if="::build.test.nfaildiffn > 0" class="sub">
Expand All @@ -363,7 +363,7 @@
<a class="cdash-link" ng-href="{{ 'builds/' + build.id + '/tests?filters=%7B%22all%22%3A%5B%7B%22eq%22%3A%7B%22status%22%3A%22PASSED%22%7D%7D%5D%7D' }}">
{{::build.test.pass}}
</a>
<a ng-if="::build.test.npassdiffp > 0" class="sup cdash-link" ng-href="viewTest.php?onlydelta&buildid={{::build.id}}{{::cdash.testfilters}}">
<a ng-if="::build.test.npassdiffp > 0" class="sup cdash-link" ng-href="{{ 'builds/' + build.id + '/tests?onlydelta&filters=%7B%22all%22%3A%5B%7B%22eq%22%3A%7B%22status%22%3A%22PASSED%22%7D%7D%5D%7D' }}">
+{{::build.test.npassdiffp}}
</a>

Expand All @@ -382,7 +382,7 @@
<a class="cdash-link" ng-href="{{ 'builds/' + build.id + '/tests?filters=%7B%22all%22%3A%5B%7B%22eq%22%3A%7B%22timeStatusCategory%22%3A%22FAILED%22%7D%7D%5D%7D' }}">
{{::build.test.timestatus}}
</a>
<a ng-if="::build.test.ntimediffp > 0" class="sup cdash-link" ng-href="viewTest.php?onlydelta&buildid={{::build.id}}{{::cdash.testfilters}}">
<a ng-if="::build.test.ntimediffp > 0" class="sup cdash-link" ng-href="{{ 'builds/' + build.id + '/tests?onlydelta&filters=%7B%22all%22%3A%5B%7B%22eq%22%3A%7B%22timeStatusCategory%22%3A%22FAILED%22%7D%7D%5D%7D' }}">
+{{::build.test.ntimediffp}}
</a>
<span ng-if="::build.test.ntimediffn > 0" class="sub">
Expand All @@ -392,7 +392,7 @@

<span ng-if="::build.test.timestatus">
{{::build.test.time}}
<a ng-if="::build.test.ntimediffp > 0" class="sup cdash-link" ng-href="viewTest.php?onlydelta&buildid={{::buildid}}{{::cdash.testfilters}}">
<a ng-if="::build.test.ntimediffp > 0" class="sup cdash-link" ng-href="{{ 'builds/' + build.id + '/tests?onlydelta&filters=%7B%22all%22%3A%5B%7B%22eq%22%3A%7B%22timeStatusCategory%22%3A%22FAILED%22%7D%7D%5D%7D' }}">
+{{::build.test.ntimediffp}}
</a>
<span ng-if="::build.test.ntimediffn > 0" class="sub">
Expand Down
210 changes: 149 additions & 61 deletions resources/js/vue/components/BuildTestsPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,15 @@
:execute-query-link="executeQueryLink"
@change-filters="filters => changedFilters = filters"
/>
<loading-indicator :is-loading="!tests">
<loading-indicator :is-loading="!tests || (onlyDelta && !previousTests && previousBuildId !== null)">
<div
v-if="onlyDelta && tests && filteredTests.length === 0"
class="tw-self-center"
>
No tests with changed state for this build.
</div>
<data-table
v-if="!onlyDelta || filteredTests.length > 0"
:columns="[
...(hasSubProjects ? [{
name: 'subProject',
Expand Down Expand Up @@ -67,6 +74,63 @@ import BuildSummaryCard from './shared/BuildSummaryCard.vue';
import BuildSidebar from './shared/BuildSidebar.vue';
import {DateTime} from 'luxon';

const TEST_QUERY = gql`
query(
$buildid: ID,
$filters: BuildTestsFiltersMultiFilterInput,
$measurementFilters: TestTestMeasurementsFiltersMultiFilterInput,
) {
build(id: $buildid) {
id
tests(filters: $filters, first: 1000000) {
edges {
node {
id
name
status
details
runningTime
timeStatusCategory
testMeasurements(filters: $measurementFilters) {
id
name
value
}
}
}
}
children(first: 100000) {
edges {
node {
id
tests(filters: $filters, first: 1000000) {
edges {
node {
id
name
status
details
runningTime
timeStatusCategory
testMeasurements(filters: $measurementFilters) {
id
name
value
}
}
}
}
subProject {
id
name
}
}
}
}
}
}
`;

export default {
name: 'BuildTestsPage',

Expand Down Expand Up @@ -109,68 +173,28 @@ export default {
type: Array,
required: true,
},

onlyDelta: {
type: Boolean,
required: false,
default: false,
},

previousBuildId: {
type: [Number, null],
required: false,
default: null,
},
},

apollo: {
tests: {
query: gql`
query(
$buildid: ID,
$filters: BuildTestsFiltersMultiFilterInput,
$measurementFilters: TestTestMeasurementsFiltersMultiFilterInput,
) {
build(id: $buildid) {
id
tests(filters: $filters, first: 1000000) {
edges {
node {
id
name
status
details
runningTime
timeStatusCategory
testMeasurements(filters: $measurementFilters) {
id
name
value
}
}
}
}
children(first: 100000) {
edges {
node {
id
tests(filters: $filters, first: 1000000) {
edges {
node {
id
name
status
details
runningTime
timeStatusCategory
testMeasurements(filters: $measurementFilters) {
id
name
value
}
}
}
}
subProject {
id
name
}
}
}
}
}
}
`,
query: TEST_QUERY,
update: (data) => {
let tests = [...data.build.tests.edges];
let tests = data.build.tests.edges.map((test) => ({
...test,
subProject: '',
}));
data.build.children.edges.forEach((child) => {
tests = tests.concat(
child.node.tests.edges.map((test) => ({
Expand All @@ -195,6 +219,41 @@ export default {
};
},
},

previousTests: {
query: TEST_QUERY,
update: (data) => {
let tests = data.build.tests.edges.map((test) => ({
...test,
subProject: '',
}));
data.build.children.edges.forEach((child) => {
tests = tests.concat(
child.node.tests.edges.map((test) => ({
...test,
subProject: child.node.subProject.name,
})),
);
});
return tests;
},
variables() {
return {
buildid: this.previousBuildId,
filters: this.initialFilters,
measurementFilters: {
any: this.pinnedMeasurements.map((name) => ({
eq: {
name: name,
},
})),
},
};
},
skip() {
return !this.onlyDelta || this.previousBuildId === null;
},
},
},

data() {
Expand All @@ -204,8 +263,33 @@ export default {
},

computed: {
filteredTests() {
if (!this.onlyDelta) {
return this.tests;
}

if (!this.tests) {
return [];
}

if (!this.previousTests) {
return [];
}

const previousTestsMap = new Map(this.previousTests.map(test => [
`${test.subProject}:${test.node.name}`,
test.node.status,
]));

return this.tests.filter(test => {
const key = `${test.subProject}:${test.node.name}`;
const previousStatus = previousTestsMap.get(key);
return previousStatus !== test.node.status;
});
},

hasSubProjects() {
return this.tests?.some((element) => element.subProject) ?? false;
return this.filteredTests?.some((element) => element.subProject) ?? false;
},

pinnedMeasurementColumns() {
Expand All @@ -216,11 +300,15 @@ export default {
},

executeQueryLink() {
return `${window.location.origin}${window.location.pathname}?filters=${encodeURIComponent(JSON.stringify(this.changedFilters))}`;
let link = `${window.location.origin}${window.location.pathname}?filters=${encodeURIComponent(JSON.stringify(this.changedFilters))}`;
if (this.onlyDelta) {
link += '&onlydelta';
}
return link;
},

formattedTestRows() {
return this.tests?.map(edge => {
return this.filteredTests?.map(edge => {
return {
name: {
value: edge.node.name,
Expand Down
Loading