Skip to content

Commit d656db0

Browse files
committed
Improve SARIF parser and interpreter tests
1 parent 9fe8fd8 commit d656db0

1 file changed

Lines changed: 155 additions & 110 deletions

File tree

extensions/ql-vscode/src/vscode-tests/no-workspace/query-results.test.ts

Lines changed: 155 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { tmpDir } from '../../helpers';
1212
import { slurpQueryHistory, splatQueryHistory } from '../../query-serialization';
1313
import { formatLegacyMessage, QueryInProgress } from '../../legacy-query-server/run-queries';
1414
import { EvaluationResult, QueryResultType } from '../../pure/legacy-messages';
15+
import Sinon = require('sinon');
1516

1617
describe('query-results', () => {
1718
let disposeSpy: sinon.SinonSpy;
@@ -156,149 +157,193 @@ describe('query-results', () => {
156157
});
157158
});
158159

159-
it('should interpretResultsSarif', async function() {
160-
// up to 2 minutes per test
161-
this.timeout(2 * 60 * 1000);
162-
163-
const spy = sandbox.mock();
164-
spy.returns({ a: '1234' });
165-
const mockServer = {
166-
interpretBqrsSarif: spy
167-
} as unknown as CodeQLCliServer;
168-
169-
const interpretedResultsPath = path.join(tmpDir.name, 'interpreted.json');
170-
const resultsPath = '123';
171-
const sourceInfo = {};
160+
describe('interpretResultsSarif', () => {
161+
let mockServer: CodeQLCliServer;
162+
let spy: Sinon.SinonExpectation;
172163
const metadata = {
173164
kind: 'my-kind',
174165
id: 'my-id' as string | undefined,
175166
scored: undefined
176167
};
177-
const results1 = await interpretResultsSarif(
178-
mockServer,
179-
metadata,
180-
{
181-
resultsPath, interpretedResultsPath
182-
},
183-
sourceInfo as SourceInfo
184-
);
168+
const resultsPath = '123';
169+
const interpretedResultsPath = path.join(tmpDir.name, 'interpreted.json');
170+
const sourceInfo = {};
185171

186-
expect(results1).to.deep.eq({ a: '1234', t: 'SarifInterpretationData' });
187-
expect(spy).to.have.been.calledWith(
188-
metadata,
189-
resultsPath, interpretedResultsPath, sourceInfo
190-
);
172+
beforeEach(() => {
173+
spy = sandbox.mock();
174+
spy.returns({ a: '1234' });
191175

192-
// Try again, but with no id
193-
spy.reset();
194-
spy.returns({ a: '1234' });
195-
delete metadata.id;
196-
const results2 = await interpretResultsSarif(
197-
mockServer,
198-
metadata,
199-
{
200-
resultsPath, interpretedResultsPath
201-
},
202-
sourceInfo as SourceInfo
203-
);
204-
expect(results2).to.deep.eq({ a: '1234', t: 'SarifInterpretationData' });
205-
expect(spy).to.have.been.calledWith(
206-
{ kind: 'my-kind', id: 'dummy-id', scored: undefined },
207-
resultsPath, interpretedResultsPath, sourceInfo
208-
);
176+
mockServer = {
177+
interpretBqrsSarif: spy
178+
} as unknown as CodeQLCliServer;
179+
});
209180

210-
// try a third time, but this time we get from a valid small SARIF file
211-
spy.reset();
212-
fs.writeFileSync(interpretedResultsPath, JSON.stringify({
213-
runs: [{ results: [] }] // A run needs results to succeed.
214-
}), 'utf8');
215-
const results3 = await interpretResultsSarif(
216-
mockServer,
217-
metadata,
218-
{
219-
resultsPath, interpretedResultsPath
220-
},
221-
sourceInfo as SourceInfo
222-
);
223-
// We do not re-interpret if we are reading from a SARIF file.
224-
expect(spy).to.not.have.been.called;
181+
afterEach(async () => {
182+
sandbox.restore();
183+
await del(interpretedResultsPath);
184+
});
225185

226-
expect(results3).to.have.property('t', 'SarifInterpretationData');
227-
expect(results3).to.have.nested.property('runs[0].results');
186+
it('should interpretResultsSarif', async function() {
187+
// up to 2 minutes per test
188+
this.timeout(2 * 60 * 1000);
189+
190+
const results = await interpretResultsSarif(
191+
mockServer,
192+
metadata,
193+
{
194+
resultsPath, interpretedResultsPath
195+
},
196+
sourceInfo as SourceInfo
197+
);
198+
199+
expect(results).to.deep.eq({ a: '1234', t: 'SarifInterpretationData' });
200+
expect(spy).to.have.been.calledWith(
201+
metadata,
202+
resultsPath, interpretedResultsPath, sourceInfo
203+
);
204+
});
228205

229-
// try a fourth time, but this time we use an invalid small SARIF file
230-
spy.reset();
231-
fs.writeFileSync(interpretedResultsPath, JSON.stringify({
232-
a: '6' // Invalid: no runs or results
233-
}), 'utf8');
206+
it('should interpretBqrsSarif without ID', async function() {
207+
// up to 2 minutes per test
208+
this.timeout(2 * 60 * 1000);
234209

235-
await expect(
236-
interpretResultsSarif(
210+
delete metadata.id;
211+
const results = await interpretResultsSarif(
237212
mockServer,
238213
metadata,
239214
{
240215
resultsPath, interpretedResultsPath
241216
},
242-
sourceInfo as SourceInfo)
243-
).to.be.rejectedWith('Parsing output of interpretation failed: Invalid SARIF file: expecting at least one run with result.');
217+
sourceInfo as SourceInfo
218+
);
219+
expect(results).to.deep.eq({ a: '1234', t: 'SarifInterpretationData' });
220+
expect(spy).to.have.been.calledWith(
221+
{ kind: 'my-kind', id: 'dummy-id', scored: undefined },
222+
resultsPath, interpretedResultsPath, sourceInfo
223+
);
224+
});
225+
226+
it('should use sarifParser on a valid small SARIF file', async function() {
227+
// up to 2 minutes per test
228+
this.timeout(2 * 60 * 1000);
244229

245-
// We do not attempt to re-interpret if we are reading from a SARIF file.
246-
expect(spy).to.not.have.been.called;
230+
fs.writeFileSync(interpretedResultsPath, JSON.stringify({
231+
runs: [{ results: [] }] // A run needs results to succeed.
232+
}), 'utf8');
233+
const results = await interpretResultsSarif(
234+
mockServer,
235+
metadata,
236+
{
237+
resultsPath, interpretedResultsPath
238+
},
239+
sourceInfo as SourceInfo
240+
);
241+
// We do not re-interpret if we are reading from a SARIF file.
242+
expect(spy).to.not.have.been.called;
247243

248-
// Try a fifth time with a valid large SARIF file
249-
spy.reset();
250-
const validSarifStream = fs.createWriteStream(interpretedResultsPath, { flags: 'w' });
244+
expect(results).to.have.property('t', 'SarifInterpretationData');
245+
expect(results).to.have.nested.property('runs[0].results');
246+
});
251247

252-
validSarifStream.write(JSON.stringify({
253-
runs: [{ results: [] }] // A run needs results to succeed.
254-
}), 'utf8');
248+
it('should throw an error on an invalid small SARIF file', async function() {
249+
// up to 2 minutes per test
250+
this.timeout(2 * 60 * 1000);
255251

256-
for (let i = 0; i < 10000000; i++) {
257-
validSarifStream.write(JSON.stringify({
258-
a: '6'
252+
fs.writeFileSync(interpretedResultsPath, JSON.stringify({
253+
a: '6' // Invalid: no runs or results
259254
}), 'utf8');
260-
}
261-
validSarifStream.end();
262255

263-
const results5 = await interpretResultsSarif(
264-
mockServer,
265-
metadata,
266-
{
267-
resultsPath, interpretedResultsPath
268-
},
269-
sourceInfo as SourceInfo
270-
);
271-
// We do not re-interpret if we are reading from a SARIF file.
272-
expect(spy).to.not.have.been.called;
256+
await expect(
257+
interpretResultsSarif(
258+
mockServer,
259+
metadata,
260+
{
261+
resultsPath, interpretedResultsPath
262+
},
263+
sourceInfo as SourceInfo)
264+
).to.be.rejectedWith('Parsing output of interpretation failed: Invalid SARIF file: expecting at least one run with result.');
265+
266+
// We do not attempt to re-interpret if we are reading from a SARIF file.
267+
expect(spy).to.not.have.been.called;
268+
});
269+
270+
it('should use sarifParser on a valid large SARIF file', async function() {
271+
// up to 2 minutes per test
272+
this.timeout(2 * 60 * 1000);
273273

274-
expect(results5).to.have.property('t', 'SarifInterpretationData');
275-
expect(results5).to.have.nested.property('runs[0].results');
274+
const validSarifStream = fs.createWriteStream(interpretedResultsPath, { flags: 'w' });
276275

277-
// Explicitly delete the large SARIF file — overwriting causes odd errors.
278-
await del(interpretedResultsPath);
276+
const finished = new Promise((res, rej) => {
277+
validSarifStream.addListener('finish', res);
278+
validSarifStream.addListener('error', rej);
279+
});
279280

280-
// Try a sixth time with an invalid large SARIF file
281-
spy.reset();
282-
const invalidSarifStream = fs.createWriteStream(interpretedResultsPath, { flags: 'w' });
283-
for (let i = 0; i < 10000000; i++) {
284-
invalidSarifStream.write(JSON.stringify({
285-
a: '6'
281+
validSarifStream.write(JSON.stringify({
282+
runs: [{ results: [] }] // A run needs results to succeed.
286283
}), 'utf8');
287-
}
288-
invalidSarifStream.end();
289284

290-
await expect(
291-
interpretResultsSarif(
285+
const iterations = 10_000_000;
286+
for (let i = 0; i < iterations; i++) {
287+
validSarifStream.write(JSON.stringify({
288+
a: '6'
289+
}), 'utf8');
290+
}
291+
validSarifStream.end();
292+
await finished;
293+
294+
const results = await interpretResultsSarif(
292295
mockServer,
293296
metadata,
294297
{
295298
resultsPath, interpretedResultsPath
296299
},
297-
sourceInfo as SourceInfo)
298-
).to.be.rejectedWith('Parsing output of interpretation failed: Invalid SARIF file: expecting at least one run with result.');
300+
sourceInfo as SourceInfo
301+
);
302+
// We do not re-interpret if we are reading from a SARIF file.
303+
expect(spy).to.not.have.been.called;
299304

300-
// We do not attempt to re-interpret if we are reading from a SARIF file.
301-
expect(spy).to.not.have.been.called;
305+
expect(results).to.have.property('t', 'SarifInterpretationData');
306+
expect(results).to.have.nested.property('runs[0].results');
307+
});
308+
309+
it('should throw an error on an invalid large SARIF file', async function() {
310+
// up to 2 minutes per test
311+
this.timeout(2 * 60 * 1000);
312+
313+
const invalidSarifStream = fs.createWriteStream(interpretedResultsPath, { flags: 'w' });
314+
315+
const finished = new Promise((res, rej) => {
316+
invalidSarifStream.addListener('finish', res);
317+
invalidSarifStream.addListener('error', rej);
318+
});
319+
320+
invalidSarifStream.write('[', 'utf8');
321+
const iterations = 10;
322+
for (let i = 0; i < iterations; i++) {
323+
invalidSarifStream.write(JSON.stringify({
324+
a: '6'
325+
}), 'utf8');
326+
if (i < iterations - 1) {
327+
invalidSarifStream.write(',');
328+
}
329+
}
330+
invalidSarifStream.write(']', 'utf8');
331+
invalidSarifStream.end();
332+
await finished;
333+
334+
await expect(
335+
interpretResultsSarif(
336+
mockServer,
337+
metadata,
338+
{
339+
resultsPath, interpretedResultsPath
340+
},
341+
sourceInfo as SourceInfo)
342+
).to.be.rejectedWith('Parsing output of interpretation failed: Invalid SARIF file: expecting at least one run with result.');
343+
344+
// We do not attempt to re-interpret if we are reading from a SARIF file.
345+
expect(spy).to.not.have.been.called;
346+
});
302347
});
303348

304349
describe('splat and slurp', () => {

0 commit comments

Comments
 (0)