Skip to content

Commit c5d6257

Browse files
Remove testDetails.php API endpoint (Kitware#3667)
All but the file download parts of dual-use API endpoint are no longer used by CDash. As such, this PR removes them. I plan to follow up with another PR which refactors the file download portions of this endpoint.
1 parent 455d342 commit c5d6257

12 files changed

Lines changed: 69 additions & 788 deletions

app/cdash/app/Controller/Api/TestDetails.php

Lines changed: 2 additions & 304 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717

1818
namespace CDash\Controller\Api;
1919

20-
use App\Models\Project as EloquentProject;
21-
use App\Models\Test;
22-
use App\Utils\RepositoryUtils;
20+
use Exception;
2321
use Illuminate\Http\JsonResponse;
2422
use Illuminate\Support\Facades\DB;
2523
use Symfony\Component\HttpFoundation\StreamedResponse;
@@ -56,306 +54,6 @@ function () use ($query): void {
5654
);
5755
}
5856

59-
$response = begin_JSON_response();
60-
61-
$site = $this->build->GetSite();
62-
63-
$this->setDate($this->build->GetDate());
64-
65-
$response['title'] = "{$this->project->Name} - Tests";
66-
get_dashboard_JSON($this->project->Name, $this->date, $response);
67-
68-
$project_response = [];
69-
$project_response['showtesttime'] = $this->project->ShowTestTime;
70-
$response['project'] = $project_response;
71-
72-
$stmt = $this->db->prepare('
73-
SELECT
74-
*,
75-
b2t.id as testid
76-
FROM build2test b2t
77-
JOIN testoutput ON (testoutput.id = b2t.outputid)
78-
WHERE b2t.id = :buildtestid
79-
');
80-
$this->db->execute($stmt, [':buildtestid' => $this->buildtest->id]);
81-
$testRow = $stmt->fetch();
82-
$testName = $testRow['testname'];
83-
$outputid = $testRow['outputid'];
84-
$testid = $testRow['testid'];
85-
86-
$menu = [];
87-
$menu['back'] = "viewTest.php?buildid={$this->build->Id}";
88-
89-
// Did the user request a specific chart?
90-
// If so we should make that chart appears when they click next or previous.
91-
$extra_url = '';
92-
if (array_key_exists('graph', $_GET)) {
93-
$extra_url = '?graph=' . $_GET['graph'];
94-
}
95-
96-
// Get previous/current/next results for this buildtest.
97-
$previous_buildtestid = $this->getRelatedBuildTest('previous');
98-
$current_buildtestid = $this->getRelatedBuildTest('current');
99-
$next_buildtestid = $this->getRelatedBuildTest('next');
100-
101-
// Navigation menu entry for 'Previous'.
102-
if ($previous_buildtestid) {
103-
$menu['previous'] = "/tests/{$previous_buildtestid}{$extra_url}";
104-
} else {
105-
$menu['previous'] = false;
106-
}
107-
108-
// Current
109-
if ($current_buildtestid) {
110-
$menu['current'] = "/tests/{$current_buildtestid}{$extra_url}";
111-
} else {
112-
$menu['current'] = false;
113-
}
114-
115-
// Next
116-
if ($next_buildtestid) {
117-
$menu['next'] = "/tests/{$next_buildtestid}{$extra_url}";
118-
} else {
119-
$menu['next'] = false;
120-
}
121-
122-
$response['menu'] = $menu;
123-
124-
$test_response = [];
125-
$test_response['buildid'] = $this->build->Id;
126-
$test_response['build'] = $this->build->Name;
127-
$test_response['buildstarttime'] = date(FMT_DATETIMESTD, strtotime($this->build->StartTime . ' UTC'));
128-
$test_response['site'] = $site->name;
129-
$test_response['siteid'] = $site->id;
130-
$test_response['test'] = $testName;
131-
$test_response['time'] = time_difference($testRow['time'], true, '', true);
132-
$test_response['command'] = $testRow['command'];
133-
$test_response['details'] = $testRow['details'];
134-
$test_response['output'] = $this->utf8_for_xml($testRow['output']);
135-
136-
if ($this->project->DisplayLabels) {
137-
$test_response['labels'] = $this->buildtest->getLabels()->keys()->implode(', ');
138-
} else {
139-
$test_response['labels'] = '';
140-
}
141-
142-
$test_response['summaryLink'] = "queryTests.php?project={$this->project->Name}&filtercount=1&showfilters=1&field1=testname&compare1=61&value1={$testName}&date={$this->date}";
143-
switch ($testRow['status']) {
144-
case 'passed':
145-
$test_response['status'] = 'Passed';
146-
$test_response['statusColor'] = 'normal-text';
147-
break;
148-
case 'failed':
149-
$test_response['status'] = 'Failed';
150-
$test_response['statusColor'] = 'error-text';
151-
break;
152-
case 'notrun':
153-
$test_response['status'] = 'Not Run';
154-
$test_response['statusColor'] = 'warning-text';
155-
break;
156-
}
157-
158-
// Find the repository revision.
159-
$update_response = [
160-
'revision' => '',
161-
'priorrevision' => '',
162-
'path' => '',
163-
'revisionurl' => '',
164-
'revisiondiff' => '',
165-
];
166-
$stmt = $this->db->prepare(
167-
'SELECT status, revision, priorrevision, path
168-
FROM buildupdate bu
169-
JOIN build b ON (b.updateid = bu.id)
170-
WHERE b.id = :buildid');
171-
$this->db->execute($stmt, [':buildid' => $this->build->Id]);
172-
$status_array = $stmt->fetch();
173-
if (is_array($status_array)) {
174-
if (strlen($status_array['status']) > 0 && $status_array['status'] != '0') {
175-
$update_response['status'] = $status_array['status'];
176-
}
177-
$update_response['revision'] = $status_array['revision'];
178-
$update_response['priorrevision'] = $status_array['priorrevision'];
179-
$update_response['path'] = $status_array['path'];
180-
$update_response['revisionurl'] =
181-
RepositoryUtils::get_revision_url($this->project->Id, $status_array['revision'], $status_array['priorrevision']);
182-
$update_response['revisiondiff'] =
183-
RepositoryUtils::get_revision_url($this->project->Id, $status_array['priorrevision'], ''); // no prior revision...
184-
}
185-
$test_response['update'] = $update_response;
186-
187-
$test_response['timemean'] = $testRow['timemean'];
188-
$test_response['timestd'] = $testRow['timestd'];
189-
190-
$testtimemaxstatus = $this->project->TestTimeMaxStatus;
191-
if ($testRow['timestatus'] == 0) {
192-
$test_response['timestatus'] = 'Passed';
193-
$test_response['timeStatusColor'] = 'normal-text';
194-
} else {
195-
$threshold = $test_response['timemean'] +
196-
$this->project->TestTimeStd * $test_response['timestd'];
197-
$test_response['threshold'] = time_difference($threshold, true, '', true);
198-
if ($testRow['timestatus'] >= $testtimemaxstatus) {
199-
$test_response['timestatus'] = 'Failed';
200-
$test_response['timeStatusColor'] = 'error-text';
201-
} else {
202-
$test_response['timestatus'] = 'Warning';
203-
$test_response['timeStatusColor'] = 'warning-text';
204-
}
205-
}
206-
207-
// Get any images associated with this test.
208-
$compareimages_response = [];
209-
$test_images = Test::findOrFail((int) $testid)
210-
->testImages()
211-
->whereIn('role', [
212-
'TestImage',
213-
'ValidImage',
214-
'BaselineImage',
215-
'DifferenceImage2',
216-
])->get();
217-
foreach ($test_images as $row) {
218-
$compareimages_response[] = [
219-
'imgid' => $row->imgid,
220-
'role' => $row->role,
221-
];
222-
}
223-
if (!empty($compareimages_response)) {
224-
$test_response['compareimages'] = $compareimages_response;
225-
}
226-
227-
$images_response = [];
228-
$test_images = Test::findOrFail((int) $testid)
229-
->testImages()
230-
->whereNotIn('role', [
231-
'ValidImage',
232-
'BaselineImage',
233-
'DifferenceImage2',
234-
])->get();
235-
foreach ($test_images as $row) {
236-
$images_response[] = [
237-
'imgid' => $row->imgid,
238-
'role' => $row->role,
239-
];
240-
}
241-
if (!empty($images_response)) {
242-
$test_response['images'] = $images_response;
243-
}
244-
245-
// Get any measurements associated with this test.
246-
$measurements_response = [];
247-
$stmt = $this->db->prepare(
248-
'SELECT name, type, value FROM testmeasurement
249-
WHERE testid = :testid
250-
ORDER BY id');
251-
$this->db->execute($stmt, [':testid' => $testid]);
252-
$fileid = 1;
253-
$test_response['environment'] = '';
254-
$preformatted_measurements = [];
255-
256-
while ($row = $stmt->fetch()) {
257-
if ($row['name'] === 'Environment' && $row['type'] === 'text/string') {
258-
$test_response['environment'] = $row['value'];
259-
continue;
260-
} elseif ($row['type'] === 'text/preformatted') {
261-
$preformatted_measurement = ['name' => $row['name'], 'value' => $row['value']];
262-
$preformatted_measurements[] = $preformatted_measurement;
263-
continue;
264-
}
265-
266-
$measurement_response = [];
267-
$measurement_response['name'] = $row['name'];
268-
$measurement_response['type'] = $row['type'];
269-
270-
// CTest base64-encodes the type text/plain...
271-
$value = $row['value'];
272-
if ($row['type'] === 'text/plain') {
273-
if (substr($value, strlen($value) - 2) === '==') {
274-
$value = base64_decode($value);
275-
}
276-
} elseif ($row['type'] === 'file') {
277-
$measurement_response['fileid'] = $fileid++;
278-
}
279-
// Add nl2br for type text/plain and text/string
280-
if ($row['type'] === 'text/plain' || $row['type'] === 'text/string') {
281-
$value = nl2br($value);
282-
}
283-
284-
// If the type is a file we just don't pass the text (too big) to the output
285-
if ($row['type'] === 'file') {
286-
$value = '';
287-
}
288-
289-
$measurement_response['value'] = $value;
290-
$measurements_response[] = $measurement_response;
291-
}
292-
293-
// Get the list of extra test measurements that have been explicitly added to this project.
294-
$extra_measurements = EloquentProject::findOrFail($this->project->Id)
295-
->pinnedTestMeasurements()
296-
->orderBy('position')
297-
->pluck('name')
298-
->toArray();
299-
300-
// Sort measurements: put those listed explicitly first (sorted by position)
301-
// then sort the rest alphabetically by name.
302-
$sort_measurements = function ($a, $b) use ($extra_measurements) {
303-
$index_a = array_search($a['name'], $extra_measurements);
304-
$index_b = array_search($b['name'], $extra_measurements);
305-
if ($index_a !== false && $index_b !== false) {
306-
return ($index_a < $index_b) ? -1 : 1;
307-
} elseif ($index_a !== false) {
308-
return -1;
309-
} elseif ($index_b !== false) {
310-
return 1;
311-
}
312-
return strcmp($a['name'], $b['name']);
313-
};
314-
usort($measurements_response, $sort_measurements);
315-
$test_response['measurements'] = $measurements_response;
316-
usort($preformatted_measurements, $sort_measurements);
317-
$test_response['preformatted_measurements'] = $preformatted_measurements;
318-
$response['test'] = $test_response;
319-
$this->pageTimer->end($response);
320-
return response()->json($response);
321-
}
322-
323-
private function getRelatedBuildTest($which_buildtest)
324-
{
325-
switch ($which_buildtest) {
326-
case 'previous':
327-
$this->testHistoryQueryOrder = 'DESC';
328-
$this->testHistoryQueryExtraWheres = 'AND b.starttime < :starttime';
329-
$this->testHistoryQueryParams[':starttime'] = $this->build->StartTime;
330-
break;
331-
case 'next':
332-
$this->testHistoryQueryOrder = 'ASC';
333-
$this->testHistoryQueryExtraWheres = 'AND b.starttime > :starttime';
334-
$this->testHistoryQueryParams[':starttime'] = $this->build->StartTime;
335-
break;
336-
case 'current':
337-
default:
338-
$this->testHistoryQueryOrder = 'DESC';
339-
$this->testHistoryQueryExtraWheres = '';
340-
if (array_key_exists(':starttime', $this->testHistoryQueryParams)) {
341-
unset($this->testHistoryQueryParams[':starttime']);
342-
}
343-
break;
344-
}
345-
$this->testHistoryQueryLimit = 'LIMIT 1';
346-
$this->generateTestHistoryQuery();
347-
$stmt = $this->db->prepare($this->testHistoryQuery);
348-
$this->db->execute($stmt, $this->testHistoryQueryParams);
349-
$row = $stmt->fetch();
350-
if (is_array($row)) {
351-
return $row['buildtestid'];
352-
}
353-
return null;
354-
}
355-
356-
// Remove bad characters for XML parser
357-
private function utf8_for_xml($string): string
358-
{
359-
return preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{001b}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $string);
57+
throw new Exception('fileid query parameter is required');
36058
}
36159
}

0 commit comments

Comments
 (0)