Skip to content
Open
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
137 changes: 62 additions & 75 deletions dashboard/src/components/Filter/CodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,48 +107,33 @@ const HighlightCounts = ({
return (
<div className="py-4 pl-3">
<ul className={cn('flex gap-2 pb-2', highlightsClassnames)}>
<li>
<span className="flex gap-1">
<span className="font-bold">
<FormattedMessage
id="codeBlock.highlights"
defaultMessage={'Highlights:'}
/>
</span>
</span>
</li>
<li className="flex gap-1">
<ColoredCircle
quantity={highlightedCode.failCount}
backgroundClassName="bg-light-red"
/>
<FormattedMessage id="global.fails" defaultMessage={'Fails'} />
<FormattedMessage
id="codeBlock.suspectedFail"
defaultMessage={'Suspected fail'}
/>
</li>
<li className="flex gap-1">
<ColoredCircle
quantity={highlightedCode.errorCount}
backgroundClassName="bg-orange-200"
/>
<FormattedMessage id="global.errors" defaultMessage={'Errors'} />
</li>
<li className="flex gap-1">
<ColoredCircle
quantity={
highlightedCode.highlightCount -
highlightedCode.failCount -
highlightedCode.errorCount
}
backgroundClassName="bg-medium-gray"
<FormattedMessage
id="codeBlock.suspectedError"
defaultMessage={'Suspected error'}
/>
<FormattedMessage id="global.others" defaultMessage={'Others'} />
</li>
</ul>
<div className="flex items-center">
<LiaInfoCircleSolid />
<p className="pl-1 text-sm">
<FormattedMessage
id="codeBlock.highlightsTooltip"
defaultMessage="Test"
defaultMessage="Heuristic keyword search in the log — counts may not match the test status"
/>
</p>
</div>
Expand All @@ -157,7 +142,6 @@ const HighlightCounts = ({
};

export const generateHighlightedCode = (code: string): IHighlightedCode => {
let highlights = 0;
let fails = 0;
let errors = 0;

Expand All @@ -168,59 +152,62 @@ export const generateHighlightedCode = (code: string): IHighlightedCode => {
return match;
});

newCode = newCode.replace(
// matches any line with the occurrence of error or fail
/^.*(error|fail).*$/gim,
match => {
highlights++;
if (
// matches failed to/with, more than 0 fails/failed and no flags
match.search(
new RegExp(
[
'.*(',
'((\\bfailed\\s*(to|with|$|([\\b\\s:]*\\(*-*[1-9]))))', // failed to/with or failed: N
'|',
'(',
'(((([1-9][0]*\\s*)|[=:])fail[s]*(?!\\s*:\\s*0))', // N fail[s] (not N fail[s]:0)
'|',
'(fail[s]*(([:,][\\b\\s:]*[^0\\s])|$|\\s+-[1-9]))', // fail[s]: x (not fail[s]: 0)
')',
'(?![|/]))', // Not match fail flags
')',
].join(''),
'i',
),
) !== -1
) {
fails++;
return '<span class="text-red">' + match + '</span>';
}
// matches error codes greater than 0 or more than 0 errors
if (
match.search(
new RegExp(
[
'.*(',
'([1-9][0]*\\s*error[s]*(?!\\s*:\\s*0))', // N error[s] (not N error[s]:0)
'|',
'(?<!Ignore\\s*)', // Not match "Ignore errors"
'(error[s]*(([:,][\\b\\s:\\(-]*[^0\\s])|$|\\s+-[1-9]|\\s[a-z]))', // error[s]: x or error -N (not error[s]: 0)
')',
].join(''),
'i',
),
) !== -1
) {
errors++;
return '<span class="text-orange-500">' + match + '</span>';
}
return '<span class="text-sky-600">' + match + '</span>';
},
);
newCode = newCode.replace(/^.*(error|\bfail).*$/gim, match => {
// drops LAVA test names and zeroed counters (kselftest "fail:0 error:0" totals)
const stripped = match.replace(
/\w*error_mode|_0_errors|\b(?:fail|error)s?:\s*0+\b/gi,
'',
);
if (!/^.*(error|\bfail).*$/im.test(stripped)) {
return match;
}
if (
// matches failed to/with, more than 0 fails/failed and no flags
stripped.search(
new RegExp(
[
'.*(',
'((\\bfailed\\s*(to|with|$|([\\b\\s:]*\\(*-*[1-9]))))', // failed to/with or failed: N
'|',
'(',
'(((([1-9][0]*\\s*)|[=:])\\bfail[s]*(?!\\s*:\\s*0))', // N fail[s] (not N fail[s]:0)
'|',
'(\\bfail[s]*(([:,][\\b\\s:]*[^0\\s])|$|\\s+-[1-9]))', // fail[s]: x (not fail[s]: 0)
')',
'(?![|/]))', // Not match fail flags
')',
].join(''),
'i',
),
) !== -1
) {
fails++;
return '<span class="text-red">' + match + '</span>';
}
// matches error codes greater than 0 or more than 0 errors
if (
stripped.search(
new RegExp(
[
'.*(',
'([1-9][0]*\\s*error[s]*(?!\\s*:\\s*0))', // N error[s] (not N error[s]:0)
'|',
'(?<!Ignore\\s*)', // Not match "Ignore errors"
'(error[s]*(([:,][\\b\\s:\\(-]*[^0\\s])|$|\\s+-[1-9]|\\s[a-z]))', // error[s]: x or error -N (not error[s]: 0)
')',
].join(''),
'i',
),
) !== -1
) {
errors++;
return '<span class="text-orange-500">' + match + '</span>';
}
return match;
});
return {
highlightedCode: newCode,
highlightCount: highlights,
highlightCount: fails + errors,
failCount: fails,
errorCount: errors,
};
Expand Down
57 changes: 50 additions & 7 deletions dashboard/src/components/Filter/highlightedCode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,61 @@ import { generateHighlightedCode } from './CodeBlock';
describe('highlightCode', () => {
it('Gets n errors', () => {
const result = generateHighlightedCode(
'There was 1 error\n' + 'Then there were 200 errors',
'There was 1 error\n' +
'Then there were 200 errors\n' +
'<LAVA_SIGNAL_TESTCASE TEST_CASE_ID=arm64_check_buffer_fill_sync_error_mode RESULT=pass>\n' +
'<LAVA_SIGNAL_TESTCASE TEST_CASE_ID=arm64_vec-syscfg_SVE_prctl_set_all_VLs_0_errors RESULT=pass>',
);
expect(result.errorCount).toBe(2);
});

it('Gets n fails', () => {
const result = generateHighlightedCode(
'There was 1 fail\n' + 'Then there were 200 fails',
'There was 1 fail\n' + 'Then there were 200 fails\n' + 'set -o pipefail',
);
expect(result.failCount).toBe(2);
});

it('Ignores kselftest totals with zero fail and error', () => {
const result = generateHighlightedCode(
'# Totals: pass:18 fail:0 xfail:0 xpass:0 skip:0 error:0',
);
expect(result.highlightCount).toBe(0);
expect(result.failCount).toBe(0);
expect(result.errorCount).toBe(0);
});

it('Ignores kselftest totals with only expected failures (xfail)', () => {
const result = generateHighlightedCode(
'# Totals: pass:1 fail:0 xfail:2 xpass:0 skip:0 error:0',
);
expect(result.highlightCount).toBe(0);
});

it('Highlights kselftest totals when fail is greater than zero', () => {
const result = generateHighlightedCode(
'# # Totals: pass:1 fail:2 xfail:0 xpass:0 skip:0 error:0\n' +
'[ 12.345678] # Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0',
);
expect(result.failCount).toBe(1);
expect(result.highlightCount).toBe(1);
});

it('Highlights kselftest totals when error is greater than zero', () => {
const result = generateHighlightedCode(
'# Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:2',
);
expect(result.errorCount).toBe(1);
expect(result.highlightCount).toBe(1);
});

it('Highlights real failures interleaved with a zeroed totals line', () => {
const result = generateHighlightedCode(
'[ 99.3] # Totals: pass:18 fail:0 error:0 [ 99.4] pci 0000:31:00.0: BAR 0: failed to assign',
);
expect(result.failCount).toBe(1);
});

it('Gets error:/errors: N', () => {
const testString = 'E summary was error: 5\n' + 'and then errors: 2';
const result = generateHighlightedCode(testString);
Expand All @@ -28,7 +71,7 @@ describe('highlightCode', () => {
const testString = 'E summary was error: 0\n' + 'and then errors: 0';
const result = generateHighlightedCode(testString);
expect(result.errorCount).toBe(0);
expect(result.highlightCount).toBe(2);
expect(result.highlightCount).toBe(0);
});

it('Gets fail:/fails:/failed: N', () => {
Expand All @@ -43,7 +86,7 @@ describe('highlightCode', () => {
'Summary was fail: 0\n' + 'and then fails: 0\n' + 'and finally failed: 0';
const result = generateHighlightedCode(testString);
expect(result.failCount).toBe(0);
expect(result.highlightCount).toBe(3);
expect(result.highlightCount).toBe(0);
});

it('Gets failed to/with', () => {
Expand All @@ -66,21 +109,21 @@ describe('highlightCode', () => {
const testString = 'Summary was pass:5 fail:0';
const result = generateHighlightedCode(testString);
expect(result.failCount).toBe(0);
expect(result.highlightCount).toBe(1);
expect(result.highlightCount).toBe(0);
});

it('Does not consider backward count on error', () => {
const testString = 'E summary was pass:5 error:0';
const result = generateHighlightedCode(testString);
expect(result.errorCount).toBe(0);
expect(result.highlightCount).toBe(1);
expect(result.highlightCount).toBe(0);
});

it('Ignores ignore errors', () => {
const testString = 'Ignore error in the next command';
const result = generateHighlightedCode(testString);
expect(result.errorCount).toBe(0);
expect(result.highlightCount).toBe(1);
expect(result.highlightCount).toBe(0);
});

it('Considers the result:fail', () => {
Expand Down
6 changes: 4 additions & 2 deletions dashboard/src/locales/messages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ export const messages = {
'buildDetails.startTime': 'Start Time',
'buildDetails.testResults': 'Test Results',
'buildTab.buildStatus': 'Build status',
'codeBlock.highlights': 'Highlights:',
'codeBlock.highlightsTooltip': 'Counting estimated based on text output',
'codeBlock.highlightsTooltip':
'Heuristic keyword search in the log — counts may not match the test status',
'codeBlock.suspectedError': 'Suspected error',
'codeBlock.suspectedFail': 'Suspected fail',
'commonDetails.artifacts': 'Artifacts',
'commonDetails.environmentMiscData': 'Environment Misc Data',
'commonDetails.gitCommitHash': 'Git Commit Hash',
Expand Down
Loading